blob: 673482a7d5e86f1e57cf5da342e938d4a24f77ae [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/*
William M. Brackd1757ab2004-10-02 22:07:48 +0000139 * TODO:
140 * There are a few spots where some tests are done which depend upon ascii
141 * data. These should be enhanced for full UTF8 support (see particularly
142 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
143 */
Kasimier T. Buchcik97258712006-01-05 12:30:43 +0000144
Denis Pauke28c8a12013-08-03 14:22:54 +0300145#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
146/**
147 * xmlXPathCmpNodesExt:
148 * @node1: the first node
149 * @node2: the second node
150 *
151 * Compare two nodes w.r.t document order.
152 * This one is optimized for handling of non-element nodes.
153 *
154 * Returns -2 in case of error 1 if first point < second point, 0 if
155 * it's the same node, -1 otherwise
156 */
157static int
158xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
159 int depth1, depth2;
160 int misc = 0, precedence1 = 0, precedence2 = 0;
161 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
162 xmlNodePtr cur, root;
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200163 ptrdiff_t l1, l2;
Denis Pauke28c8a12013-08-03 14:22:54 +0300164
165 if ((node1 == NULL) || (node2 == NULL))
166 return(-2);
167
168 if (node1 == node2)
169 return(0);
170
171 /*
172 * a couple of optimizations which will avoid computations in most cases
173 */
174 switch (node1->type) {
175 case XML_ELEMENT_NODE:
176 if (node2->type == XML_ELEMENT_NODE) {
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200177 if ((0 > (ptrdiff_t) node1->content) &&
178 (0 > (ptrdiff_t) node2->content) &&
Denis Pauke28c8a12013-08-03 14:22:54 +0300179 (node1->doc == node2->doc))
180 {
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200181 l1 = -((ptrdiff_t) node1->content);
182 l2 = -((ptrdiff_t) node2->content);
Denis Pauke28c8a12013-08-03 14:22:54 +0300183 if (l1 < l2)
184 return(1);
185 if (l1 > l2)
186 return(-1);
187 } else
188 goto turtle_comparison;
189 }
190 break;
191 case XML_ATTRIBUTE_NODE:
192 precedence1 = 1; /* element is owner */
193 miscNode1 = node1;
194 node1 = node1->parent;
195 misc = 1;
196 break;
197 case XML_TEXT_NODE:
198 case XML_CDATA_SECTION_NODE:
199 case XML_COMMENT_NODE:
200 case XML_PI_NODE: {
201 miscNode1 = node1;
202 /*
203 * Find nearest element node.
204 */
205 if (node1->prev != NULL) {
206 do {
207 node1 = node1->prev;
208 if (node1->type == XML_ELEMENT_NODE) {
209 precedence1 = 3; /* element in prev-sibl axis */
210 break;
211 }
212 if (node1->prev == NULL) {
213 precedence1 = 2; /* element is parent */
214 /*
215 * URGENT TODO: Are there any cases, where the
216 * parent of such a node is not an element node?
217 */
218 node1 = node1->parent;
219 break;
220 }
221 } while (1);
222 } else {
223 precedence1 = 2; /* element is parent */
224 node1 = node1->parent;
225 }
226 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200227 (0 <= (ptrdiff_t) node1->content)) {
Denis Pauke28c8a12013-08-03 14:22:54 +0300228 /*
229 * Fallback for whatever case.
230 */
231 node1 = miscNode1;
232 precedence1 = 0;
233 } else
234 misc = 1;
235 }
236 break;
237 case XML_NAMESPACE_DECL:
238 /*
239 * TODO: why do we return 1 for namespace nodes?
240 */
241 return(1);
242 default:
243 break;
244 }
245 switch (node2->type) {
246 case XML_ELEMENT_NODE:
247 break;
248 case XML_ATTRIBUTE_NODE:
249 precedence2 = 1; /* element is owner */
250 miscNode2 = node2;
251 node2 = node2->parent;
252 misc = 1;
253 break;
254 case XML_TEXT_NODE:
255 case XML_CDATA_SECTION_NODE:
256 case XML_COMMENT_NODE:
257 case XML_PI_NODE: {
258 miscNode2 = node2;
259 if (node2->prev != NULL) {
260 do {
261 node2 = node2->prev;
262 if (node2->type == XML_ELEMENT_NODE) {
263 precedence2 = 3; /* element in prev-sibl axis */
264 break;
265 }
266 if (node2->prev == NULL) {
267 precedence2 = 2; /* element is parent */
268 node2 = node2->parent;
269 break;
270 }
271 } while (1);
272 } else {
273 precedence2 = 2; /* element is parent */
274 node2 = node2->parent;
275 }
276 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200277 (0 <= (ptrdiff_t) node2->content))
Denis Pauke28c8a12013-08-03 14:22:54 +0300278 {
279 node2 = miscNode2;
280 precedence2 = 0;
281 } else
282 misc = 1;
283 }
284 break;
285 case XML_NAMESPACE_DECL:
286 return(1);
287 default:
288 break;
289 }
290 if (misc) {
291 if (node1 == node2) {
292 if (precedence1 == precedence2) {
293 /*
294 * The ugly case; but normally there aren't many
295 * adjacent non-element nodes around.
296 */
297 cur = miscNode2->prev;
298 while (cur != NULL) {
299 if (cur == miscNode1)
300 return(1);
301 if (cur->type == XML_ELEMENT_NODE)
302 return(-1);
303 cur = cur->prev;
304 }
305 return (-1);
306 } else {
307 /*
308 * Evaluate based on higher precedence wrt to the element.
309 * TODO: This assumes attributes are sorted before content.
310 * Is this 100% correct?
311 */
312 if (precedence1 < precedence2)
313 return(1);
314 else
315 return(-1);
316 }
317 }
318 /*
319 * Special case: One of the helper-elements is contained by the other.
320 * <foo>
321 * <node2>
322 * <node1>Text-1(precedence1 == 2)</node1>
323 * </node2>
324 * Text-6(precedence2 == 3)
325 * </foo>
326 */
327 if ((precedence2 == 3) && (precedence1 > 1)) {
328 cur = node1->parent;
329 while (cur) {
330 if (cur == node2)
331 return(1);
332 cur = cur->parent;
333 }
334 }
335 if ((precedence1 == 3) && (precedence2 > 1)) {
336 cur = node2->parent;
337 while (cur) {
338 if (cur == node1)
339 return(-1);
340 cur = cur->parent;
341 }
342 }
343 }
344
345 /*
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700346 * Speedup using document order if available.
Denis Pauke28c8a12013-08-03 14:22:54 +0300347 */
348 if ((node1->type == XML_ELEMENT_NODE) &&
349 (node2->type == XML_ELEMENT_NODE) &&
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200350 (0 > (ptrdiff_t) node1->content) &&
351 (0 > (ptrdiff_t) node2->content) &&
Denis Pauke28c8a12013-08-03 14:22:54 +0300352 (node1->doc == node2->doc)) {
353
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200354 l1 = -((ptrdiff_t) node1->content);
355 l2 = -((ptrdiff_t) node2->content);
Denis Pauke28c8a12013-08-03 14:22:54 +0300356 if (l1 < l2)
357 return(1);
358 if (l1 > l2)
359 return(-1);
360 }
361
362turtle_comparison:
363
364 if (node1 == node2->prev)
365 return(1);
366 if (node1 == node2->next)
367 return(-1);
368 /*
369 * compute depth to root
370 */
Nick Wellnhofer3eaedba2015-07-11 14:27:34 +0200371 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
372 if (cur->parent == node1)
Denis Pauke28c8a12013-08-03 14:22:54 +0300373 return(1);
374 depth2++;
375 }
376 root = cur;
Nick Wellnhofer3eaedba2015-07-11 14:27:34 +0200377 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
378 if (cur->parent == node2)
Denis Pauke28c8a12013-08-03 14:22:54 +0300379 return(-1);
380 depth1++;
381 }
382 /*
383 * Distinct document (or distinct entities :-( ) case.
384 */
385 if (root != cur) {
386 return(-2);
387 }
388 /*
389 * get the nearest common ancestor.
390 */
391 while (depth1 > depth2) {
392 depth1--;
393 node1 = node1->parent;
394 }
395 while (depth2 > depth1) {
396 depth2--;
397 node2 = node2->parent;
398 }
399 while (node1->parent != node2->parent) {
400 node1 = node1->parent;
401 node2 = node2->parent;
402 /* should not happen but just in case ... */
403 if ((node1 == NULL) || (node2 == NULL))
404 return(-2);
405 }
406 /*
407 * Find who's first.
408 */
409 if (node1 == node2->prev)
410 return(1);
411 if (node1 == node2->next)
412 return(-1);
413 /*
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700414 * Speedup using document order if available.
Denis Pauke28c8a12013-08-03 14:22:54 +0300415 */
416 if ((node1->type == XML_ELEMENT_NODE) &&
417 (node2->type == XML_ELEMENT_NODE) &&
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200418 (0 > (ptrdiff_t) node1->content) &&
419 (0 > (ptrdiff_t) node2->content) &&
Denis Pauke28c8a12013-08-03 14:22:54 +0300420 (node1->doc == node2->doc)) {
421
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200422 l1 = -((ptrdiff_t) node1->content);
423 l2 = -((ptrdiff_t) node2->content);
Denis Pauke28c8a12013-08-03 14:22:54 +0300424 if (l1 < l2)
425 return(1);
426 if (l1 > l2)
427 return(-1);
428 }
429
430 for (cur = node1->next;cur != NULL;cur = cur->next)
431 if (cur == node2)
432 return(1);
433 return(-1); /* assume there is no sibling list corruption */
434}
435#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
436
Vojtech Fried3e031b72012-08-24 16:52:44 +0800437/*
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700438 * Wrapper for the Timsort algorithm from timsort.h
Vojtech Fried3e031b72012-08-24 16:52:44 +0800439 */
440#ifdef WITH_TIM_SORT
441#define SORT_NAME libxml_domnode
442#define SORT_TYPE xmlNodePtr
443/**
444 * wrap_cmp:
445 * @x: a node
446 * @y: another node
447 *
448 * Comparison function for the Timsort implementation
449 *
Daniel Veillard510e7582012-09-04 11:50:36 +0800450 * Returns -2 in case of error -1 if first point < second point, 0 if
451 * it's the same node, +1 otherwise
Vojtech Fried3e031b72012-08-24 16:52:44 +0800452 */
453static
454int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
455#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Vojtech Fried3e031b72012-08-24 16:52:44 +0800456 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
457 {
458 int res = xmlXPathCmpNodesExt(x, y);
459 return res == -2 ? res : -res;
460 }
461#else
462 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
463 {
464 int res = xmlXPathCmpNodes(x, y);
465 return res == -2 ? res : -res;
466 }
467#endif
468#define SORT_CMP(x, y) (wrap_cmp(x, y))
469#include "timsort.h"
470#endif /* WITH_TIM_SORT */
471
William M. Brack21e4ef22005-01-02 09:53:13 +0000472#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000473
474/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000475 * *
476 * Floating point stuff *
477 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000478 ************************************************************************/
479
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200480#ifndef INFINITY
Elliott Hughes7fbecab2019-01-10 16:42:03 -0800481#define INFINITY (DBL_MAX * DBL_MAX)
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200482#endif
483
Elliott Hughes7fbecab2019-01-10 16:42:03 -0800484#ifndef NAN
485#define NAN (INFINITY / INFINITY)
486#endif
487
488double xmlXPathNAN;
489double xmlXPathPINF;
490double xmlXPathNINF;
Owen Taylor3473f882001-02-23 17:55:21 +0000491
Owen Taylor3473f882001-02-23 17:55:21 +0000492/**
493 * xmlXPathInit:
494 *
495 * Initialize the XPath environment
496 */
497void
498xmlXPathInit(void) {
Elliott Hughes7fbecab2019-01-10 16:42:03 -0800499 xmlXPathNAN = NAN;
500 xmlXPathPINF = INFINITY;
501 xmlXPathNINF = -INFINITY;
Owen Taylor3473f882001-02-23 17:55:21 +0000502}
503
Daniel Veillardcda96922001-08-21 10:56:31 +0000504/**
505 * xmlXPathIsNaN:
506 * @val: a double value
507 *
Daniel Veillardcda96922001-08-21 10:56:31 +0000508 * Returns 1 if the value is a NaN, 0 otherwise
509 */
510int
511xmlXPathIsNaN(double val) {
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200512#ifdef isnan
513 return isnan(val);
514#else
515 return !(val == val);
516#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000517}
518
519/**
520 * xmlXPathIsInf:
521 * @val: a double value
522 *
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200523 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
Daniel Veillardcda96922001-08-21 10:56:31 +0000524 */
525int
526xmlXPathIsInf(double val) {
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200527#ifdef isinf
Nick Wellnhoferddbb0752017-11-27 14:30:19 +0100528 return isinf(val) ? (val > 0 ? 1 : -1) : 0;
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200529#else
Elliott Hughes7fbecab2019-01-10 16:42:03 -0800530 if (val >= INFINITY)
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200531 return 1;
Elliott Hughes7fbecab2019-01-10 16:42:03 -0800532 if (val <= -INFINITY)
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200533 return -1;
534 return 0;
535#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000536}
537
Daniel Veillard4432df22003-09-28 18:58:27 +0000538#endif /* SCHEMAS or XPATH */
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000539
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200540#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000541
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000542/*
543 * TODO: when compatibility allows remove all "fake node libxslt" strings
544 * the test should just be name[0] = ' '
545 */
Daniel Veillard074f37e2008-09-01 13:38:22 +0000546#ifdef DEBUG_XPATH_EXPRESSION
547#define DEBUG_STEP
548#define DEBUG_EXPR
549#define DEBUG_EVAL_COUNTS
550#endif
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000551
552static xmlNs xmlXPathXMLNamespaceStruct = {
553 NULL,
554 XML_NAMESPACE_DECL,
555 XML_XML_NAMESPACE,
556 BAD_CAST "xml",
William M. Brackee0b9822007-03-07 08:15:01 +0000557 NULL,
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000558 NULL
559};
560static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
561#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard45490ae2008-07-29 09:13:19 +0000562/*
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000563 * Optimizer is disabled only when threaded apps are detected while
564 * the library ain't compiled for thread safety.
565 */
566static int xmlXPathDisableOptimizer = 0;
567#endif
568
Owen Taylor3473f882001-02-23 17:55:21 +0000569/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000570 * *
571 * Error handling routines *
572 * *
573 ************************************************************************/
574
Daniel Veillard24505b02005-07-28 23:49:35 +0000575/**
576 * XP_ERRORNULL:
577 * @X: the error code
578 *
579 * Macro to raise an XPath error and return NULL.
580 */
581#define XP_ERRORNULL(X) \
582 { xmlXPathErr(ctxt, X); return(NULL); }
583
William M. Brack08171912003-12-29 02:52:11 +0000584/*
585 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
586 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000587static const char *xmlXPathErrorMessages[] = {
588 "Ok\n",
589 "Number encoding\n",
590 "Unfinished literal\n",
591 "Start of literal\n",
592 "Expected $ for variable reference\n",
593 "Undefined variable\n",
594 "Invalid predicate\n",
595 "Invalid expression\n",
596 "Missing closing curly brace\n",
597 "Unregistered function\n",
598 "Invalid operand\n",
599 "Invalid type\n",
600 "Invalid number of arguments\n",
601 "Invalid context size\n",
602 "Invalid context position\n",
603 "Memory allocation error\n",
604 "Syntax error\n",
605 "Resource error\n",
606 "Sub resource error\n",
607 "Undefined namespace prefix\n",
608 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000609 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000610 "Invalid or incomplete context\n",
Jan Pokorný75801652013-12-19 15:09:14 +0100611 "Stack usage error\n",
Daniel Veillard47881282012-09-07 14:24:50 +0800612 "Forbidden variable\n",
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700613 "Operation limit exceeded\n",
614 "Recursion limit exceeded\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000615 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000616};
William M. Brackcd65bc92005-01-06 09:39:18 +0000617#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
618 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000619/**
620 * xmlXPathErrMemory:
621 * @ctxt: an XPath context
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700622 * @extra: extra information
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000623 *
624 * Handle a redefinition of attribute error
625 */
626static void
627xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
628{
629 if (ctxt != NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700630 xmlResetError(&ctxt->lastError);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000631 if (extra) {
632 xmlChar buf[200];
633
634 xmlStrPrintf(buf, 200,
David Kilzer4472c3a2016-05-13 15:13:17 +0800635 "Memory allocation failed : %s\n",
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000636 extra);
637 ctxt->lastError.message = (char *) xmlStrdup(buf);
638 } else {
639 ctxt->lastError.message = (char *)
640 xmlStrdup(BAD_CAST "Memory allocation failed\n");
641 }
642 ctxt->lastError.domain = XML_FROM_XPATH;
643 ctxt->lastError.code = XML_ERR_NO_MEMORY;
644 if (ctxt->error != NULL)
645 ctxt->error(ctxt->userData, &ctxt->lastError);
646 } else {
647 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000648 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000649 NULL, NULL, XML_FROM_XPATH,
650 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
651 extra, NULL, NULL, 0, 0,
652 "Memory allocation failed : %s\n", extra);
653 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000654 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000655 NULL, NULL, XML_FROM_XPATH,
656 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
657 NULL, NULL, NULL, 0, 0,
658 "Memory allocation failed\n");
659 }
660}
661
662/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000663 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000664 * @ctxt: an XPath parser context
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700665 * @extra: extra information
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000666 *
667 * Handle a redefinition of attribute error
668 */
669static void
670xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
671{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000672 if (ctxt == NULL)
673 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000674 else {
675 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000676 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000677 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000678}
679
680/**
681 * xmlXPathErr:
682 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000683 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000684 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000685 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000686 */
687void
688xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
689{
William M. Brackcd65bc92005-01-06 09:39:18 +0000690 if ((error < 0) || (error > MAXERRNO))
691 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000692 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000693 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000694 NULL, NULL, XML_FROM_XPATH,
695 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
696 XML_ERR_ERROR, NULL, 0,
697 NULL, NULL, NULL, 0, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200698 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000699 return;
700 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000701 ctxt->error = error;
702 if (ctxt->context == NULL) {
703 __xmlRaiseError(NULL, NULL, NULL,
704 NULL, NULL, XML_FROM_XPATH,
705 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
706 XML_ERR_ERROR, NULL, 0,
707 (const char *) ctxt->base, NULL, NULL,
708 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200709 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000710 return;
711 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000712
713 /* cleanup current last error */
Daniel Veillard45490ae2008-07-29 09:13:19 +0000714 xmlResetError(&ctxt->context->lastError);
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000715
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000716 ctxt->context->lastError.domain = XML_FROM_XPATH;
717 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
718 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000719 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000720 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
721 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
722 ctxt->context->lastError.node = ctxt->context->debugNode;
723 if (ctxt->context->error != NULL) {
724 ctxt->context->error(ctxt->context->userData,
725 &ctxt->context->lastError);
726 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000727 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000728 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
729 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
730 XML_ERR_ERROR, NULL, 0,
731 (const char *) ctxt->base, NULL, NULL,
732 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200733 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000734 }
735
736}
737
738/**
739 * xmlXPatherror:
740 * @ctxt: the XPath Parser context
741 * @file: the file name
742 * @line: the line number
743 * @no: the error number
744 *
745 * Formats an error message.
746 */
747void
748xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
749 int line ATTRIBUTE_UNUSED, int no) {
750 xmlXPathErr(ctxt, no);
751}
752
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700753/**
754 * xmlXPathCheckOpLimit:
755 * @ctxt: the XPath Parser context
756 * @opCount: the number of operations to be added
757 *
758 * Adds opCount to the running total of operations and returns -1 if the
759 * operation limit is exceeded. Returns 0 otherwise.
760 */
761static int
762xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
763 xmlXPathContextPtr xpctxt = ctxt->context;
764
765 if ((opCount > xpctxt->opLimit) ||
766 (xpctxt->opCount > xpctxt->opLimit - opCount)) {
767 xpctxt->opCount = xpctxt->opLimit;
768 xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
769 return(-1);
770 }
771
772 xpctxt->opCount += opCount;
773 return(0);
774}
775
776#define OP_LIMIT_EXCEEDED(ctxt, n) \
777 ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
778
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000779/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000780 * *
781 * Utilities *
782 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000783 ************************************************************************/
784
785/**
786 * xsltPointerList:
787 *
788 * Pointer-list for various purposes.
789 */
790typedef struct _xmlPointerList xmlPointerList;
791typedef xmlPointerList *xmlPointerListPtr;
792struct _xmlPointerList {
793 void **items;
794 int number;
795 int size;
796};
797/*
798* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
799* and here, we should make the functions public.
800*/
801static int
Daniel Veillard45490ae2008-07-29 09:13:19 +0000802xmlPointerListAddSize(xmlPointerListPtr list,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000803 void *item,
804 int initialSize)
805{
806 if (list->items == NULL) {
807 if (initialSize <= 0)
808 initialSize = 1;
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800809 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000810 if (list->items == NULL) {
811 xmlXPathErrMemory(NULL,
812 "xmlPointerListCreate: allocating item\n");
813 return(-1);
814 }
815 list->number = 0;
816 list->size = initialSize;
817 } else if (list->size <= list->number) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800818 if (list->size > 50000000) {
819 xmlXPathErrMemory(NULL,
820 "xmlPointerListAddSize: re-allocating item\n");
821 return(-1);
822 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000823 list->size *= 2;
824 list->items = (void **) xmlRealloc(list->items,
825 list->size * sizeof(void *));
826 if (list->items == NULL) {
827 xmlXPathErrMemory(NULL,
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800828 "xmlPointerListAddSize: re-allocating item\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000829 list->size = 0;
830 return(-1);
831 }
832 }
833 list->items[list->number++] = item;
834 return(0);
835}
836
837/**
838 * xsltPointerListCreate:
839 *
840 * Creates an xsltPointerList structure.
841 *
842 * Returns a xsltPointerList structure or NULL in case of an error.
843 */
844static xmlPointerListPtr
845xmlPointerListCreate(int initialSize)
846{
847 xmlPointerListPtr ret;
848
849 ret = xmlMalloc(sizeof(xmlPointerList));
850 if (ret == NULL) {
851 xmlXPathErrMemory(NULL,
852 "xmlPointerListCreate: allocating item\n");
853 return (NULL);
854 }
855 memset(ret, 0, sizeof(xmlPointerList));
856 if (initialSize > 0) {
857 xmlPointerListAddSize(ret, NULL, initialSize);
858 ret->number = 0;
859 }
860 return (ret);
861}
862
863/**
864 * xsltPointerListFree:
865 *
866 * Frees the xsltPointerList structure. This does not free
867 * the content of the list.
868 */
869static void
870xmlPointerListFree(xmlPointerListPtr list)
871{
872 if (list == NULL)
873 return;
874 if (list->items != NULL)
875 xmlFree(list->items);
876 xmlFree(list);
877}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000878
879/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000880 * *
881 * Parser Types *
882 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000883 ************************************************************************/
884
885/*
886 * Types are private:
887 */
888
889typedef enum {
890 XPATH_OP_END=0,
891 XPATH_OP_AND,
892 XPATH_OP_OR,
893 XPATH_OP_EQUAL,
894 XPATH_OP_CMP,
895 XPATH_OP_PLUS,
896 XPATH_OP_MULT,
897 XPATH_OP_UNION,
898 XPATH_OP_ROOT,
899 XPATH_OP_NODE,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000900 XPATH_OP_COLLECT,
Elliott Hughes7fbecab2019-01-10 16:42:03 -0800901 XPATH_OP_VALUE, /* 11 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000902 XPATH_OP_VARIABLE,
903 XPATH_OP_FUNCTION,
904 XPATH_OP_ARG,
905 XPATH_OP_PREDICATE,
Elliott Hughes7fbecab2019-01-10 16:42:03 -0800906 XPATH_OP_FILTER, /* 16 */
907 XPATH_OP_SORT /* 17 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000908#ifdef LIBXML_XPTR_ENABLED
909 ,XPATH_OP_RANGETO
910#endif
911} xmlXPathOp;
912
913typedef enum {
914 AXIS_ANCESTOR = 1,
915 AXIS_ANCESTOR_OR_SELF,
916 AXIS_ATTRIBUTE,
917 AXIS_CHILD,
918 AXIS_DESCENDANT,
919 AXIS_DESCENDANT_OR_SELF,
920 AXIS_FOLLOWING,
921 AXIS_FOLLOWING_SIBLING,
922 AXIS_NAMESPACE,
923 AXIS_PARENT,
924 AXIS_PRECEDING,
925 AXIS_PRECEDING_SIBLING,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000926 AXIS_SELF
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000927} xmlXPathAxisVal;
928
929typedef enum {
930 NODE_TEST_NONE = 0,
931 NODE_TEST_TYPE = 1,
932 NODE_TEST_PI = 2,
933 NODE_TEST_ALL = 3,
934 NODE_TEST_NS = 4,
935 NODE_TEST_NAME = 5
936} xmlXPathTestVal;
937
938typedef enum {
939 NODE_TYPE_NODE = 0,
940 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
941 NODE_TYPE_TEXT = XML_TEXT_NODE,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000942 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000943} xmlXPathTypeVal;
944
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000945typedef struct _xmlXPathStepOp xmlXPathStepOp;
946typedef xmlXPathStepOp *xmlXPathStepOpPtr;
947struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000948 xmlXPathOp op; /* The identifier of the operation */
949 int ch1; /* First child */
950 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000951 int value;
952 int value2;
953 int value3;
954 void *value4;
955 void *value5;
Nick Wellnhofer229d1f92016-08-22 13:21:57 +0200956 xmlXPathFunction cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000957 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000958};
959
960struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000961 int nbStep; /* Number of steps in this expression */
962 int maxStep; /* Maximum number of steps allocated */
963 xmlXPathStepOp *steps; /* ops for computation of this expression */
964 int last; /* index of last step in expression */
965 xmlChar *expr; /* the expression being computed */
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200966 xmlDictPtr dict; /* the dictionary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000967#ifdef DEBUG_EVAL_COUNTS
968 int nb;
969 xmlChar *string;
970#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000971#ifdef XPATH_STREAMING
972 xmlPatternPtr stream;
973#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000974};
975
976/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000977 * *
978 * Forward declarations *
979 * *
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000980 ************************************************************************/
981static void
982xmlXPathFreeValueTree(xmlNodeSetPtr obj);
983static void
984xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
985static int
986xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
987 xmlXPathStepOpPtr op, xmlNodePtr *first);
988static int
989xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +0000990 xmlXPathStepOpPtr op,
991 int isPredicate);
Nick Wellnhofere03f0a12017-11-09 16:42:47 +0100992static void
993xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000994
995/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000996 * *
997 * Parser Type functions *
998 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000999 ************************************************************************/
1000
1001/**
1002 * xmlXPathNewCompExpr:
1003 *
1004 * Create a new Xpath component
1005 *
1006 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1007 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001008static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001009xmlXPathNewCompExpr(void) {
1010 xmlXPathCompExprPtr cur;
1011
1012 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1013 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001014 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001015 return(NULL);
1016 }
1017 memset(cur, 0, sizeof(xmlXPathCompExpr));
1018 cur->maxStep = 10;
1019 cur->nbStep = 0;
1020 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1021 sizeof(xmlXPathStepOp));
1022 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001023 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001024 xmlFree(cur);
1025 return(NULL);
1026 }
1027 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1028 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +00001029#ifdef DEBUG_EVAL_COUNTS
1030 cur->nb = 0;
1031#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001032 return(cur);
1033}
1034
1035/**
1036 * xmlXPathFreeCompExpr:
1037 * @comp: an XPATH comp
1038 *
1039 * Free up the memory allocated by @comp
1040 */
1041void
Daniel Veillardf06307e2001-07-03 10:35:50 +00001042xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1043{
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001044 xmlXPathStepOpPtr op;
1045 int i;
1046
1047 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00001048 return;
Daniel Veillard4773df22004-01-23 13:15:13 +00001049 if (comp->dict == NULL) {
1050 for (i = 0; i < comp->nbStep; i++) {
1051 op = &comp->steps[i];
1052 if (op->value4 != NULL) {
1053 if (op->op == XPATH_OP_VALUE)
1054 xmlXPathFreeObject(op->value4);
1055 else
1056 xmlFree(op->value4);
1057 }
1058 if (op->value5 != NULL)
1059 xmlFree(op->value5);
1060 }
1061 } else {
1062 for (i = 0; i < comp->nbStep; i++) {
1063 op = &comp->steps[i];
1064 if (op->value4 != NULL) {
1065 if (op->op == XPATH_OP_VALUE)
1066 xmlXPathFreeObject(op->value4);
1067 }
1068 }
1069 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001070 }
1071 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00001072 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001073 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00001074#ifdef DEBUG_EVAL_COUNTS
1075 if (comp->string != NULL) {
1076 xmlFree(comp->string);
1077 }
1078#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +00001079#ifdef XPATH_STREAMING
1080 if (comp->stream != NULL) {
1081 xmlFreePatternList(comp->stream);
1082 }
1083#endif
Daniel Veillard118aed72002-09-24 14:13:13 +00001084 if (comp->expr != NULL) {
1085 xmlFree(comp->expr);
1086 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00001087
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001088 xmlFree(comp);
1089}
1090
1091/**
1092 * xmlXPathCompExprAdd:
1093 * @comp: the compiled expression
1094 * @ch1: first child index
1095 * @ch2: second child index
1096 * @op: an op
1097 * @value: the first int value
1098 * @value2: the second int value
1099 * @value3: the third int value
1100 * @value4: the first string value
1101 * @value5: the second string value
1102 *
William M. Brack08171912003-12-29 02:52:11 +00001103 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001104 *
1105 * Returns -1 in case of failure, the index otherwise
1106 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001107static int
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001108xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001109 xmlXPathOp op, int value,
1110 int value2, int value3, void *value4, void *value5) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001111 xmlXPathCompExprPtr comp = ctxt->comp;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001112 if (comp->nbStep >= comp->maxStep) {
1113 xmlXPathStepOp *real;
1114
Daniel Veillardcd852ad2012-07-30 10:12:18 +08001115 if (comp->maxStep >= XPATH_MAX_STEPS) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001116 xmlXPathPErrMemory(ctxt, "adding step\n");
Daniel Veillardcd852ad2012-07-30 10:12:18 +08001117 return(-1);
1118 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001119 comp->maxStep *= 2;
1120 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1121 comp->maxStep * sizeof(xmlXPathStepOp));
1122 if (real == NULL) {
1123 comp->maxStep /= 2;
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001124 xmlXPathPErrMemory(ctxt, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001125 return(-1);
1126 }
1127 comp->steps = real;
1128 }
1129 comp->last = comp->nbStep;
1130 comp->steps[comp->nbStep].ch1 = ch1;
1131 comp->steps[comp->nbStep].ch2 = ch2;
1132 comp->steps[comp->nbStep].op = op;
1133 comp->steps[comp->nbStep].value = value;
1134 comp->steps[comp->nbStep].value2 = value2;
1135 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +00001136 if ((comp->dict != NULL) &&
1137 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1138 (op == XPATH_OP_COLLECT))) {
1139 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +00001140 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +00001141 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001142 xmlFree(value4);
1143 } else
1144 comp->steps[comp->nbStep].value4 = NULL;
1145 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +00001146 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +00001147 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001148 xmlFree(value5);
1149 } else
1150 comp->steps[comp->nbStep].value5 = NULL;
1151 } else {
1152 comp->steps[comp->nbStep].value4 = value4;
1153 comp->steps[comp->nbStep].value5 = value5;
1154 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +00001155 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001156 return(comp->nbStep++);
1157}
1158
Daniel Veillardf06307e2001-07-03 10:35:50 +00001159/**
1160 * xmlXPathCompSwap:
1161 * @comp: the compiled expression
1162 * @op: operation index
1163 *
1164 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +00001165 */
1166static void
1167xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1168 int tmp;
1169
Daniel Veillardbc6f7592002-04-16 07:49:59 +00001170#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +00001171 /*
1172 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +00001173 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +00001174 * application
1175 */
1176 if (xmlXPathDisableOptimizer)
1177 return;
1178#endif
1179
Daniel Veillardf06307e2001-07-03 10:35:50 +00001180 tmp = op->ch1;
1181 op->ch1 = op->ch2;
1182 op->ch2 = tmp;
1183}
1184
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001185#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001186 xmlXPathCompExprAdd(ctxt, (op1), (op2), \
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001187 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001188#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001189 xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001190 (op), (val), (val2), (val3), (val4), (val5))
1191
Daniel Veillard45490ae2008-07-29 09:13:19 +00001192#define PUSH_LEAVE_EXPR(op, val, val2) \
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001193xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001194
Daniel Veillard45490ae2008-07-29 09:13:19 +00001195#define PUSH_UNARY_EXPR(op, ch, val, val2) \
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001196xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001197
Daniel Veillard45490ae2008-07-29 09:13:19 +00001198#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001199xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
William M. Brack08171912003-12-29 02:52:11 +00001200 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001201
1202/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +00001203 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00001204 * XPath object cache structures *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001205 * *
1206 ************************************************************************/
1207
1208/* #define XP_DEFAULT_CACHE_ON */
1209
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001210#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001211
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001212typedef struct _xmlXPathContextCache xmlXPathContextCache;
1213typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1214struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00001215 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1216 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1217 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1218 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1219 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001220 int maxNodeset;
1221 int maxString;
1222 int maxBoolean;
1223 int maxNumber;
1224 int maxMisc;
1225#ifdef XP_DEBUG_OBJ_USAGE
1226 int dbgCachedAll;
1227 int dbgCachedNodeset;
1228 int dbgCachedString;
1229 int dbgCachedBool;
1230 int dbgCachedNumber;
1231 int dbgCachedPoint;
1232 int dbgCachedRange;
1233 int dbgCachedLocset;
1234 int dbgCachedUsers;
1235 int dbgCachedXSLTTree;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001236 int dbgCachedUndefined;
1237
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001238
1239 int dbgReusedAll;
1240 int dbgReusedNodeset;
1241 int dbgReusedString;
1242 int dbgReusedBool;
1243 int dbgReusedNumber;
1244 int dbgReusedPoint;
1245 int dbgReusedRange;
1246 int dbgReusedLocset;
1247 int dbgReusedUsers;
1248 int dbgReusedXSLTTree;
1249 int dbgReusedUndefined;
1250
1251#endif
1252};
1253
1254/************************************************************************
1255 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00001256 * Debugging related functions *
Owen Taylor3473f882001-02-23 17:55:21 +00001257 * *
1258 ************************************************************************/
1259
Daniel Veillard45490ae2008-07-29 09:13:19 +00001260#define STRANGE \
Owen Taylor3473f882001-02-23 17:55:21 +00001261 xmlGenericError(xmlGenericErrorContext, \
1262 "Internal error at %s:%d\n", \
1263 __FILE__, __LINE__);
1264
1265#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001266static void
1267xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001268 int i;
1269 char shift[100];
1270
1271 for (i = 0;((i < depth) && (i < 25));i++)
1272 shift[2 * i] = shift[2 * i + 1] = ' ';
1273 shift[2 * i] = shift[2 * i + 1] = 0;
1274 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001275 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001276 fprintf(output, "Node is NULL !\n");
1277 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001278
Owen Taylor3473f882001-02-23 17:55:21 +00001279 }
1280
1281 if ((cur->type == XML_DOCUMENT_NODE) ||
1282 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001283 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001284 fprintf(output, " /\n");
1285 } else if (cur->type == XML_ATTRIBUTE_NODE)
1286 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1287 else
1288 xmlDebugDumpOneNode(output, cur, depth);
1289}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001290static void
1291xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001292 xmlNodePtr tmp;
1293 int i;
1294 char shift[100];
1295
1296 for (i = 0;((i < depth) && (i < 25));i++)
1297 shift[2 * i] = shift[2 * i + 1] = ' ';
1298 shift[2 * i] = shift[2 * i + 1] = 0;
1299 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001300 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001301 fprintf(output, "Node is NULL !\n");
1302 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001303
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001304 }
1305
1306 while (cur != NULL) {
1307 tmp = cur;
1308 cur = cur->next;
1309 xmlDebugDumpOneNode(output, tmp, depth);
1310 }
1311}
Owen Taylor3473f882001-02-23 17:55:21 +00001312
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001313static void
1314xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001315 int i;
1316 char shift[100];
1317
1318 for (i = 0;((i < depth) && (i < 25));i++)
1319 shift[2 * i] = shift[2 * i + 1] = ' ';
1320 shift[2 * i] = shift[2 * i + 1] = 0;
1321
1322 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001323 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001324 fprintf(output, "NodeSet is NULL !\n");
1325 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001326
Owen Taylor3473f882001-02-23 17:55:21 +00001327 }
1328
Daniel Veillard911f49a2001-04-07 15:39:35 +00001329 if (cur != NULL) {
1330 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1331 for (i = 0;i < cur->nodeNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001332 fprintf(output, "%s", shift);
Daniel Veillard911f49a2001-04-07 15:39:35 +00001333 fprintf(output, "%d", i + 1);
1334 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1335 }
Owen Taylor3473f882001-02-23 17:55:21 +00001336 }
1337}
1338
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001339static void
1340xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001341 int i;
1342 char shift[100];
1343
1344 for (i = 0;((i < depth) && (i < 25));i++)
1345 shift[2 * i] = shift[2 * i + 1] = ' ';
1346 shift[2 * i] = shift[2 * i + 1] = 0;
1347
1348 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001349 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001350 fprintf(output, "Value Tree is NULL !\n");
1351 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001352
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001353 }
1354
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001355 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001356 fprintf(output, "%d", i + 1);
1357 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1358}
Owen Taylor3473f882001-02-23 17:55:21 +00001359#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001360static void
1361xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001362 int i;
1363 char shift[100];
1364
1365 for (i = 0;((i < depth) && (i < 25));i++)
1366 shift[2 * i] = shift[2 * i + 1] = ' ';
1367 shift[2 * i] = shift[2 * i + 1] = 0;
1368
1369 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001370 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001371 fprintf(output, "LocationSet is NULL !\n");
1372 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001373
Owen Taylor3473f882001-02-23 17:55:21 +00001374 }
1375
1376 for (i = 0;i < cur->locNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001377 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001378 fprintf(output, "%d : ", i + 1);
1379 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1380 }
1381}
Daniel Veillard017b1082001-06-21 11:20:21 +00001382#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001383
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00001384/**
1385 * xmlXPathDebugDumpObject:
1386 * @output: the FILE * to dump the output
1387 * @cur: the object to inspect
1388 * @depth: indentation level
1389 *
1390 * Dump the content of the object for debugging purposes
1391 */
1392void
1393xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001394 int i;
1395 char shift[100];
1396
Daniel Veillarda82b1822004-11-08 16:24:57 +00001397 if (output == NULL) return;
1398
Owen Taylor3473f882001-02-23 17:55:21 +00001399 for (i = 0;((i < depth) && (i < 25));i++)
1400 shift[2 * i] = shift[2 * i + 1] = ' ';
1401 shift[2 * i] = shift[2 * i + 1] = 0;
1402
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001403
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001404 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001405
1406 if (cur == NULL) {
1407 fprintf(output, "Object is empty (NULL)\n");
1408 return;
1409 }
1410 switch(cur->type) {
1411 case XPATH_UNDEFINED:
1412 fprintf(output, "Object is uninitialized\n");
1413 break;
1414 case XPATH_NODESET:
1415 fprintf(output, "Object is a Node Set :\n");
1416 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1417 break;
1418 case XPATH_XSLT_TREE:
1419 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001420 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001421 break;
1422 case XPATH_BOOLEAN:
1423 fprintf(output, "Object is a Boolean : ");
1424 if (cur->boolval) fprintf(output, "true\n");
1425 else fprintf(output, "false\n");
1426 break;
1427 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001428 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001429 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001430 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001431 break;
1432 case -1:
1433 fprintf(output, "Object is a number : -Infinity\n");
1434 break;
1435 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001436 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001437 fprintf(output, "Object is a number : NaN\n");
Nick Wellnhofer8813f392017-09-21 00:11:26 +02001438 } else if (cur->floatval == 0) {
1439 /* Omit sign for negative zero. */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001440 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001441 } else {
1442 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1443 }
1444 }
Owen Taylor3473f882001-02-23 17:55:21 +00001445 break;
1446 case XPATH_STRING:
1447 fprintf(output, "Object is a string : ");
1448 xmlDebugDumpString(output, cur->stringval);
1449 fprintf(output, "\n");
1450 break;
1451 case XPATH_POINT:
1452 fprintf(output, "Object is a point : index %d in node", cur->index);
1453 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1454 fprintf(output, "\n");
1455 break;
1456 case XPATH_RANGE:
1457 if ((cur->user2 == NULL) ||
1458 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1459 fprintf(output, "Object is a collapsed range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001460 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001461 if (cur->index >= 0)
1462 fprintf(output, "index %d in ", cur->index);
1463 fprintf(output, "node\n");
1464 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1465 depth + 1);
1466 } else {
1467 fprintf(output, "Object is a range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001468 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001469 fprintf(output, "From ");
1470 if (cur->index >= 0)
1471 fprintf(output, "index %d in ", cur->index);
1472 fprintf(output, "node\n");
1473 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1474 depth + 1);
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001475 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001476 fprintf(output, "To ");
1477 if (cur->index2 >= 0)
1478 fprintf(output, "index %d in ", cur->index2);
1479 fprintf(output, "node\n");
1480 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1481 depth + 1);
1482 fprintf(output, "\n");
1483 }
1484 break;
1485 case XPATH_LOCATIONSET:
1486#if defined(LIBXML_XPTR_ENABLED)
1487 fprintf(output, "Object is a Location Set:\n");
1488 xmlXPathDebugDumpLocationSet(output,
1489 (xmlLocationSetPtr) cur->user, depth);
1490#endif
1491 break;
1492 case XPATH_USERS:
1493 fprintf(output, "Object is user defined\n");
1494 break;
1495 }
1496}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001497
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001498static void
1499xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001500 xmlXPathStepOpPtr op, int depth) {
1501 int i;
1502 char shift[100];
1503
1504 for (i = 0;((i < depth) && (i < 25));i++)
1505 shift[2 * i] = shift[2 * i + 1] = ' ';
1506 shift[2 * i] = shift[2 * i + 1] = 0;
1507
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001508 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001509 if (op == NULL) {
1510 fprintf(output, "Step is NULL\n");
1511 return;
1512 }
1513 switch (op->op) {
1514 case XPATH_OP_END:
1515 fprintf(output, "END"); break;
1516 case XPATH_OP_AND:
1517 fprintf(output, "AND"); break;
1518 case XPATH_OP_OR:
1519 fprintf(output, "OR"); break;
1520 case XPATH_OP_EQUAL:
1521 if (op->value)
1522 fprintf(output, "EQUAL =");
1523 else
1524 fprintf(output, "EQUAL !=");
1525 break;
1526 case XPATH_OP_CMP:
1527 if (op->value)
1528 fprintf(output, "CMP <");
1529 else
1530 fprintf(output, "CMP >");
1531 if (!op->value2)
1532 fprintf(output, "=");
1533 break;
1534 case XPATH_OP_PLUS:
1535 if (op->value == 0)
1536 fprintf(output, "PLUS -");
1537 else if (op->value == 1)
1538 fprintf(output, "PLUS +");
1539 else if (op->value == 2)
1540 fprintf(output, "PLUS unary -");
1541 else if (op->value == 3)
1542 fprintf(output, "PLUS unary - -");
1543 break;
1544 case XPATH_OP_MULT:
1545 if (op->value == 0)
1546 fprintf(output, "MULT *");
1547 else if (op->value == 1)
1548 fprintf(output, "MULT div");
1549 else
1550 fprintf(output, "MULT mod");
1551 break;
1552 case XPATH_OP_UNION:
1553 fprintf(output, "UNION"); break;
1554 case XPATH_OP_ROOT:
1555 fprintf(output, "ROOT"); break;
1556 case XPATH_OP_NODE:
1557 fprintf(output, "NODE"); break;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001558 case XPATH_OP_SORT:
1559 fprintf(output, "SORT"); break;
1560 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001561 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1562 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1563 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001564 const xmlChar *prefix = op->value4;
1565 const xmlChar *name = op->value5;
1566
1567 fprintf(output, "COLLECT ");
1568 switch (axis) {
1569 case AXIS_ANCESTOR:
1570 fprintf(output, " 'ancestors' "); break;
1571 case AXIS_ANCESTOR_OR_SELF:
1572 fprintf(output, " 'ancestors-or-self' "); break;
1573 case AXIS_ATTRIBUTE:
1574 fprintf(output, " 'attributes' "); break;
1575 case AXIS_CHILD:
1576 fprintf(output, " 'child' "); break;
1577 case AXIS_DESCENDANT:
1578 fprintf(output, " 'descendant' "); break;
1579 case AXIS_DESCENDANT_OR_SELF:
1580 fprintf(output, " 'descendant-or-self' "); break;
1581 case AXIS_FOLLOWING:
1582 fprintf(output, " 'following' "); break;
1583 case AXIS_FOLLOWING_SIBLING:
1584 fprintf(output, " 'following-siblings' "); break;
1585 case AXIS_NAMESPACE:
1586 fprintf(output, " 'namespace' "); break;
1587 case AXIS_PARENT:
1588 fprintf(output, " 'parent' "); break;
1589 case AXIS_PRECEDING:
1590 fprintf(output, " 'preceding' "); break;
1591 case AXIS_PRECEDING_SIBLING:
1592 fprintf(output, " 'preceding-sibling' "); break;
1593 case AXIS_SELF:
1594 fprintf(output, " 'self' "); break;
1595 }
1596 switch (test) {
1597 case NODE_TEST_NONE:
1598 fprintf(output, "'none' "); break;
1599 case NODE_TEST_TYPE:
1600 fprintf(output, "'type' "); break;
1601 case NODE_TEST_PI:
1602 fprintf(output, "'PI' "); break;
1603 case NODE_TEST_ALL:
1604 fprintf(output, "'all' "); break;
1605 case NODE_TEST_NS:
1606 fprintf(output, "'namespace' "); break;
1607 case NODE_TEST_NAME:
1608 fprintf(output, "'name' "); break;
1609 }
1610 switch (type) {
1611 case NODE_TYPE_NODE:
1612 fprintf(output, "'node' "); break;
1613 case NODE_TYPE_COMMENT:
1614 fprintf(output, "'comment' "); break;
1615 case NODE_TYPE_TEXT:
1616 fprintf(output, "'text' "); break;
1617 case NODE_TYPE_PI:
1618 fprintf(output, "'PI' "); break;
1619 }
1620 if (prefix != NULL)
1621 fprintf(output, "%s:", prefix);
1622 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001623 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001624 break;
1625
1626 }
1627 case XPATH_OP_VALUE: {
1628 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1629
1630 fprintf(output, "ELEM ");
1631 xmlXPathDebugDumpObject(output, object, 0);
1632 goto finish;
1633 }
1634 case XPATH_OP_VARIABLE: {
1635 const xmlChar *prefix = op->value5;
1636 const xmlChar *name = op->value4;
1637
1638 if (prefix != NULL)
1639 fprintf(output, "VARIABLE %s:%s", prefix, name);
1640 else
1641 fprintf(output, "VARIABLE %s", name);
1642 break;
1643 }
1644 case XPATH_OP_FUNCTION: {
1645 int nbargs = op->value;
1646 const xmlChar *prefix = op->value5;
1647 const xmlChar *name = op->value4;
1648
1649 if (prefix != NULL)
1650 fprintf(output, "FUNCTION %s:%s(%d args)",
1651 prefix, name, nbargs);
1652 else
1653 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1654 break;
1655 }
1656 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1657 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001658 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001659#ifdef LIBXML_XPTR_ENABLED
1660 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1661#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001662 default:
1663 fprintf(output, "UNKNOWN %d\n", op->op); return;
1664 }
1665 fprintf(output, "\n");
1666finish:
1667 if (op->ch1 >= 0)
1668 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1669 if (op->ch2 >= 0)
1670 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1671}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001672
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001673/**
1674 * xmlXPathDebugDumpCompExpr:
1675 * @output: the FILE * for the output
1676 * @comp: the precompiled XPath expression
1677 * @depth: the indentation level.
1678 *
1679 * Dumps the tree of the compiled XPath expression.
1680 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001681void
1682xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1683 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001684 int i;
1685 char shift[100];
1686
Daniel Veillarda82b1822004-11-08 16:24:57 +00001687 if ((output == NULL) || (comp == NULL)) return;
1688
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001689 for (i = 0;((i < depth) && (i < 25));i++)
1690 shift[2 * i] = shift[2 * i + 1] = ' ';
1691 shift[2 * i] = shift[2 * i + 1] = 0;
1692
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001693 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001694
Nick Wellnhoferca8635b2017-09-07 15:46:12 +02001695#ifdef XPATH_STREAMING
1696 if (comp->stream) {
1697 fprintf(output, "Streaming Expression\n");
1698 } else
1699#endif
1700 {
1701 fprintf(output, "Compiled Expression : %d elements\n",
1702 comp->nbStep);
1703 i = comp->last;
1704 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1705 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001706}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001707
1708#ifdef XP_DEBUG_OBJ_USAGE
1709
1710/*
1711* XPath object usage related debugging variables.
1712*/
1713static int xmlXPathDebugObjCounterUndefined = 0;
1714static int xmlXPathDebugObjCounterNodeset = 0;
1715static int xmlXPathDebugObjCounterBool = 0;
1716static int xmlXPathDebugObjCounterNumber = 0;
1717static int xmlXPathDebugObjCounterString = 0;
1718static int xmlXPathDebugObjCounterPoint = 0;
1719static int xmlXPathDebugObjCounterRange = 0;
1720static int xmlXPathDebugObjCounterLocset = 0;
1721static int xmlXPathDebugObjCounterUsers = 0;
1722static int xmlXPathDebugObjCounterXSLTTree = 0;
1723static int xmlXPathDebugObjCounterAll = 0;
1724
1725static int xmlXPathDebugObjTotalUndefined = 0;
1726static int xmlXPathDebugObjTotalNodeset = 0;
1727static int xmlXPathDebugObjTotalBool = 0;
1728static int xmlXPathDebugObjTotalNumber = 0;
1729static int xmlXPathDebugObjTotalString = 0;
1730static int xmlXPathDebugObjTotalPoint = 0;
1731static int xmlXPathDebugObjTotalRange = 0;
1732static int xmlXPathDebugObjTotalLocset = 0;
1733static int xmlXPathDebugObjTotalUsers = 0;
1734static int xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001735static int xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001736
1737static int xmlXPathDebugObjMaxUndefined = 0;
1738static int xmlXPathDebugObjMaxNodeset = 0;
1739static int xmlXPathDebugObjMaxBool = 0;
1740static int xmlXPathDebugObjMaxNumber = 0;
1741static int xmlXPathDebugObjMaxString = 0;
1742static int xmlXPathDebugObjMaxPoint = 0;
1743static int xmlXPathDebugObjMaxRange = 0;
1744static int xmlXPathDebugObjMaxLocset = 0;
1745static int xmlXPathDebugObjMaxUsers = 0;
1746static int xmlXPathDebugObjMaxXSLTTree = 0;
1747static int xmlXPathDebugObjMaxAll = 0;
1748
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001749static void
1750xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1751{
1752 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001753 if (ctxt->cache != NULL) {
1754 xmlXPathContextCachePtr cache =
1755 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001756
1757 cache->dbgCachedAll = 0;
1758 cache->dbgCachedNodeset = 0;
1759 cache->dbgCachedString = 0;
1760 cache->dbgCachedBool = 0;
1761 cache->dbgCachedNumber = 0;
1762 cache->dbgCachedPoint = 0;
1763 cache->dbgCachedRange = 0;
1764 cache->dbgCachedLocset = 0;
1765 cache->dbgCachedUsers = 0;
1766 cache->dbgCachedXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001767 cache->dbgCachedUndefined = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001768
1769 cache->dbgReusedAll = 0;
1770 cache->dbgReusedNodeset = 0;
1771 cache->dbgReusedString = 0;
1772 cache->dbgReusedBool = 0;
1773 cache->dbgReusedNumber = 0;
1774 cache->dbgReusedPoint = 0;
1775 cache->dbgReusedRange = 0;
1776 cache->dbgReusedLocset = 0;
1777 cache->dbgReusedUsers = 0;
1778 cache->dbgReusedXSLTTree = 0;
1779 cache->dbgReusedUndefined = 0;
1780 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001781 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001782
1783 xmlXPathDebugObjCounterUndefined = 0;
1784 xmlXPathDebugObjCounterNodeset = 0;
1785 xmlXPathDebugObjCounterBool = 0;
1786 xmlXPathDebugObjCounterNumber = 0;
1787 xmlXPathDebugObjCounterString = 0;
1788 xmlXPathDebugObjCounterPoint = 0;
1789 xmlXPathDebugObjCounterRange = 0;
1790 xmlXPathDebugObjCounterLocset = 0;
1791 xmlXPathDebugObjCounterUsers = 0;
1792 xmlXPathDebugObjCounterXSLTTree = 0;
1793 xmlXPathDebugObjCounterAll = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001794
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001795 xmlXPathDebugObjTotalUndefined = 0;
1796 xmlXPathDebugObjTotalNodeset = 0;
1797 xmlXPathDebugObjTotalBool = 0;
1798 xmlXPathDebugObjTotalNumber = 0;
1799 xmlXPathDebugObjTotalString = 0;
1800 xmlXPathDebugObjTotalPoint = 0;
1801 xmlXPathDebugObjTotalRange = 0;
1802 xmlXPathDebugObjTotalLocset = 0;
1803 xmlXPathDebugObjTotalUsers = 0;
1804 xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001805 xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001806
1807 xmlXPathDebugObjMaxUndefined = 0;
1808 xmlXPathDebugObjMaxNodeset = 0;
1809 xmlXPathDebugObjMaxBool = 0;
1810 xmlXPathDebugObjMaxNumber = 0;
1811 xmlXPathDebugObjMaxString = 0;
1812 xmlXPathDebugObjMaxPoint = 0;
1813 xmlXPathDebugObjMaxRange = 0;
1814 xmlXPathDebugObjMaxLocset = 0;
1815 xmlXPathDebugObjMaxUsers = 0;
1816 xmlXPathDebugObjMaxXSLTTree = 0;
1817 xmlXPathDebugObjMaxAll = 0;
1818
1819}
1820
1821static void
1822xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1823 xmlXPathObjectType objType)
1824{
1825 int isCached = 0;
1826
1827 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001828 if (ctxt->cache != NULL) {
1829 xmlXPathContextCachePtr cache =
1830 (xmlXPathContextCachePtr) ctxt->cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001831
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001832 isCached = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001833
1834 cache->dbgReusedAll++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001835 switch (objType) {
1836 case XPATH_UNDEFINED:
1837 cache->dbgReusedUndefined++;
1838 break;
1839 case XPATH_NODESET:
1840 cache->dbgReusedNodeset++;
1841 break;
1842 case XPATH_BOOLEAN:
1843 cache->dbgReusedBool++;
1844 break;
1845 case XPATH_NUMBER:
1846 cache->dbgReusedNumber++;
1847 break;
1848 case XPATH_STRING:
1849 cache->dbgReusedString++;
1850 break;
1851 case XPATH_POINT:
1852 cache->dbgReusedPoint++;
1853 break;
1854 case XPATH_RANGE:
1855 cache->dbgReusedRange++;
1856 break;
1857 case XPATH_LOCATIONSET:
1858 cache->dbgReusedLocset++;
1859 break;
1860 case XPATH_USERS:
1861 cache->dbgReusedUsers++;
1862 break;
1863 case XPATH_XSLT_TREE:
1864 cache->dbgReusedXSLTTree++;
1865 break;
1866 default:
1867 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001868 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001869 }
1870 }
1871
1872 switch (objType) {
1873 case XPATH_UNDEFINED:
1874 if (! isCached)
1875 xmlXPathDebugObjTotalUndefined++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001876 xmlXPathDebugObjCounterUndefined++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001877 if (xmlXPathDebugObjCounterUndefined >
1878 xmlXPathDebugObjMaxUndefined)
1879 xmlXPathDebugObjMaxUndefined =
1880 xmlXPathDebugObjCounterUndefined;
1881 break;
1882 case XPATH_NODESET:
1883 if (! isCached)
1884 xmlXPathDebugObjTotalNodeset++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001885 xmlXPathDebugObjCounterNodeset++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001886 if (xmlXPathDebugObjCounterNodeset >
1887 xmlXPathDebugObjMaxNodeset)
1888 xmlXPathDebugObjMaxNodeset =
1889 xmlXPathDebugObjCounterNodeset;
1890 break;
1891 case XPATH_BOOLEAN:
1892 if (! isCached)
1893 xmlXPathDebugObjTotalBool++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001894 xmlXPathDebugObjCounterBool++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001895 if (xmlXPathDebugObjCounterBool >
1896 xmlXPathDebugObjMaxBool)
1897 xmlXPathDebugObjMaxBool =
1898 xmlXPathDebugObjCounterBool;
1899 break;
1900 case XPATH_NUMBER:
1901 if (! isCached)
1902 xmlXPathDebugObjTotalNumber++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001903 xmlXPathDebugObjCounterNumber++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001904 if (xmlXPathDebugObjCounterNumber >
1905 xmlXPathDebugObjMaxNumber)
1906 xmlXPathDebugObjMaxNumber =
1907 xmlXPathDebugObjCounterNumber;
1908 break;
1909 case XPATH_STRING:
1910 if (! isCached)
1911 xmlXPathDebugObjTotalString++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001912 xmlXPathDebugObjCounterString++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001913 if (xmlXPathDebugObjCounterString >
1914 xmlXPathDebugObjMaxString)
1915 xmlXPathDebugObjMaxString =
1916 xmlXPathDebugObjCounterString;
1917 break;
1918 case XPATH_POINT:
1919 if (! isCached)
1920 xmlXPathDebugObjTotalPoint++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001921 xmlXPathDebugObjCounterPoint++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001922 if (xmlXPathDebugObjCounterPoint >
1923 xmlXPathDebugObjMaxPoint)
1924 xmlXPathDebugObjMaxPoint =
1925 xmlXPathDebugObjCounterPoint;
1926 break;
1927 case XPATH_RANGE:
1928 if (! isCached)
1929 xmlXPathDebugObjTotalRange++;
1930 xmlXPathDebugObjCounterRange++;
1931 if (xmlXPathDebugObjCounterRange >
1932 xmlXPathDebugObjMaxRange)
1933 xmlXPathDebugObjMaxRange =
1934 xmlXPathDebugObjCounterRange;
1935 break;
1936 case XPATH_LOCATIONSET:
1937 if (! isCached)
1938 xmlXPathDebugObjTotalLocset++;
1939 xmlXPathDebugObjCounterLocset++;
1940 if (xmlXPathDebugObjCounterLocset >
1941 xmlXPathDebugObjMaxLocset)
1942 xmlXPathDebugObjMaxLocset =
1943 xmlXPathDebugObjCounterLocset;
1944 break;
1945 case XPATH_USERS:
1946 if (! isCached)
1947 xmlXPathDebugObjTotalUsers++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001948 xmlXPathDebugObjCounterUsers++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001949 if (xmlXPathDebugObjCounterUsers >
1950 xmlXPathDebugObjMaxUsers)
1951 xmlXPathDebugObjMaxUsers =
1952 xmlXPathDebugObjCounterUsers;
1953 break;
1954 case XPATH_XSLT_TREE:
1955 if (! isCached)
1956 xmlXPathDebugObjTotalXSLTTree++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001957 xmlXPathDebugObjCounterXSLTTree++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001958 if (xmlXPathDebugObjCounterXSLTTree >
1959 xmlXPathDebugObjMaxXSLTTree)
1960 xmlXPathDebugObjMaxXSLTTree =
1961 xmlXPathDebugObjCounterXSLTTree;
1962 break;
1963 default:
1964 break;
1965 }
1966 if (! isCached)
1967 xmlXPathDebugObjTotalAll++;
1968 xmlXPathDebugObjCounterAll++;
1969 if (xmlXPathDebugObjCounterAll >
1970 xmlXPathDebugObjMaxAll)
1971 xmlXPathDebugObjMaxAll =
1972 xmlXPathDebugObjCounterAll;
1973}
1974
1975static void
1976xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1977 xmlXPathObjectType objType)
1978{
1979 int isCached = 0;
1980
1981 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001982 if (ctxt->cache != NULL) {
1983 xmlXPathContextCachePtr cache =
1984 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001985
Daniel Veillard45490ae2008-07-29 09:13:19 +00001986 isCached = 1;
1987
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001988 cache->dbgCachedAll++;
1989 switch (objType) {
1990 case XPATH_UNDEFINED:
1991 cache->dbgCachedUndefined++;
1992 break;
1993 case XPATH_NODESET:
1994 cache->dbgCachedNodeset++;
1995 break;
1996 case XPATH_BOOLEAN:
1997 cache->dbgCachedBool++;
1998 break;
1999 case XPATH_NUMBER:
2000 cache->dbgCachedNumber++;
2001 break;
2002 case XPATH_STRING:
2003 cache->dbgCachedString++;
2004 break;
2005 case XPATH_POINT:
2006 cache->dbgCachedPoint++;
2007 break;
2008 case XPATH_RANGE:
2009 cache->dbgCachedRange++;
2010 break;
2011 case XPATH_LOCATIONSET:
2012 cache->dbgCachedLocset++;
2013 break;
2014 case XPATH_USERS:
2015 cache->dbgCachedUsers++;
2016 break;
2017 case XPATH_XSLT_TREE:
2018 cache->dbgCachedXSLTTree++;
2019 break;
2020 default:
2021 break;
2022 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00002023
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002024 }
2025 }
2026 switch (objType) {
2027 case XPATH_UNDEFINED:
2028 xmlXPathDebugObjCounterUndefined--;
2029 break;
2030 case XPATH_NODESET:
2031 xmlXPathDebugObjCounterNodeset--;
2032 break;
2033 case XPATH_BOOLEAN:
2034 xmlXPathDebugObjCounterBool--;
2035 break;
2036 case XPATH_NUMBER:
2037 xmlXPathDebugObjCounterNumber--;
2038 break;
2039 case XPATH_STRING:
2040 xmlXPathDebugObjCounterString--;
2041 break;
2042 case XPATH_POINT:
2043 xmlXPathDebugObjCounterPoint--;
2044 break;
2045 case XPATH_RANGE:
2046 xmlXPathDebugObjCounterRange--;
2047 break;
2048 case XPATH_LOCATIONSET:
2049 xmlXPathDebugObjCounterLocset--;
2050 break;
2051 case XPATH_USERS:
2052 xmlXPathDebugObjCounterUsers--;
2053 break;
2054 case XPATH_XSLT_TREE:
2055 xmlXPathDebugObjCounterXSLTTree--;
2056 break;
2057 default:
2058 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002059 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002060 xmlXPathDebugObjCounterAll--;
2061}
2062
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002063static void
2064xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2065{
2066 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2067 reqXSLTTree, reqUndefined;
2068 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2069 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2070 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2071 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2072 int leftObjs = xmlXPathDebugObjCounterAll;
2073
2074 reqAll = xmlXPathDebugObjTotalAll;
2075 reqNodeset = xmlXPathDebugObjTotalNodeset;
2076 reqString = xmlXPathDebugObjTotalString;
2077 reqBool = xmlXPathDebugObjTotalBool;
2078 reqNumber = xmlXPathDebugObjTotalNumber;
2079 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2080 reqUndefined = xmlXPathDebugObjTotalUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002081
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002082 printf("# XPath object usage:\n");
2083
2084 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002085 if (ctxt->cache != NULL) {
2086 xmlXPathContextCachePtr cache =
2087 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002088
2089 reAll = cache->dbgReusedAll;
2090 reqAll += reAll;
2091 reNodeset = cache->dbgReusedNodeset;
2092 reqNodeset += reNodeset;
2093 reString = cache->dbgReusedString;
2094 reqString += reString;
2095 reBool = cache->dbgReusedBool;
2096 reqBool += reBool;
2097 reNumber = cache->dbgReusedNumber;
2098 reqNumber += reNumber;
2099 reXSLTTree = cache->dbgReusedXSLTTree;
2100 reqXSLTTree += reXSLTTree;
2101 reUndefined = cache->dbgReusedUndefined;
2102 reqUndefined += reUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002103
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002104 caAll = cache->dbgCachedAll;
2105 caBool = cache->dbgCachedBool;
2106 caNodeset = cache->dbgCachedNodeset;
2107 caString = cache->dbgCachedString;
2108 caNumber = cache->dbgCachedNumber;
2109 caXSLTTree = cache->dbgCachedXSLTTree;
2110 caUndefined = cache->dbgCachedUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002111
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002112 if (cache->nodesetObjs)
2113 leftObjs -= cache->nodesetObjs->number;
2114 if (cache->stringObjs)
2115 leftObjs -= cache->stringObjs->number;
2116 if (cache->booleanObjs)
2117 leftObjs -= cache->booleanObjs->number;
2118 if (cache->numberObjs)
2119 leftObjs -= cache->numberObjs->number;
2120 if (cache->miscObjs)
2121 leftObjs -= cache->miscObjs->number;
2122 }
2123 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00002124
2125 printf("# all\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002126 printf("# total : %d\n", reqAll);
2127 printf("# left : %d\n", leftObjs);
2128 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2129 printf("# reused : %d\n", reAll);
2130 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2131
2132 printf("# node-sets\n");
2133 printf("# total : %d\n", reqNodeset);
2134 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2135 printf("# reused : %d\n", reNodeset);
2136 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2137
2138 printf("# strings\n");
2139 printf("# total : %d\n", reqString);
2140 printf("# created: %d\n", xmlXPathDebugObjTotalString);
2141 printf("# reused : %d\n", reString);
2142 printf("# max : %d\n", xmlXPathDebugObjMaxString);
2143
2144 printf("# booleans\n");
2145 printf("# total : %d\n", reqBool);
2146 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2147 printf("# reused : %d\n", reBool);
2148 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2149
2150 printf("# numbers\n");
2151 printf("# total : %d\n", reqNumber);
2152 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2153 printf("# reused : %d\n", reNumber);
2154 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2155
2156 printf("# XSLT result tree fragments\n");
2157 printf("# total : %d\n", reqXSLTTree);
2158 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2159 printf("# reused : %d\n", reXSLTTree);
2160 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2161
2162 printf("# undefined\n");
2163 printf("# total : %d\n", reqUndefined);
2164 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2165 printf("# reused : %d\n", reUndefined);
2166 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2167
2168}
2169
2170#endif /* XP_DEBUG_OBJ_USAGE */
2171
Daniel Veillard017b1082001-06-21 11:20:21 +00002172#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002173
2174/************************************************************************
2175 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002176 * XPath object caching *
2177 * *
2178 ************************************************************************/
2179
2180/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002181 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002182 *
2183 * Create a new object cache
2184 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002185 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002186 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002187static xmlXPathContextCachePtr
2188xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002189{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002190 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002191
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002192 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002193 if (ret == NULL) {
2194 xmlXPathErrMemory(NULL, "creating object cache\n");
2195 return(NULL);
2196 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002197 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002198 ret->maxNodeset = 100;
2199 ret->maxString = 100;
2200 ret->maxBoolean = 100;
2201 ret->maxNumber = 100;
2202 ret->maxMisc = 100;
2203 return(ret);
2204}
2205
2206static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002207xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002208{
2209 int i;
2210 xmlXPathObjectPtr obj;
2211
2212 if (list == NULL)
2213 return;
2214
2215 for (i = 0; i < list->number; i++) {
2216 obj = list->items[i];
2217 /*
2218 * Note that it is already assured that we don't need to
2219 * look out for namespace nodes in the node-set.
2220 */
2221 if (obj->nodesetval != NULL) {
2222 if (obj->nodesetval->nodeTab != NULL)
2223 xmlFree(obj->nodesetval->nodeTab);
2224 xmlFree(obj->nodesetval);
2225 }
2226 xmlFree(obj);
2227#ifdef XP_DEBUG_OBJ_USAGE
2228 xmlXPathDebugObjCounterAll--;
2229#endif
2230 }
2231 xmlPointerListFree(list);
2232}
2233
2234static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002235xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002236{
2237 if (cache == NULL)
2238 return;
2239 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002240 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002241 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002242 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002243 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002244 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002245 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002246 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002247 if (cache->miscObjs)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002248 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002249 xmlFree(cache);
2250}
2251
2252/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002253 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002254 *
2255 * @ctxt: the XPath context
2256 * @active: enables/disables (creates/frees) the cache
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002257 * @value: a value with semantics dependent on @options
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002258 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002259 *
2260 * Creates/frees an object cache on the XPath context.
2261 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002262 * to be reused.
2263 * @options:
2264 * 0: This will set the XPath object caching:
2265 * @value:
2266 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002267 * to be cached per slot
2268 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002269 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002270 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002271 *
2272 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2273 */
2274int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002275xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2276 int active,
2277 int value,
2278 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002279{
2280 if (ctxt == NULL)
2281 return(-1);
2282 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002283 xmlXPathContextCachePtr cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002284
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002285 if (ctxt->cache == NULL) {
2286 ctxt->cache = xmlXPathNewCache();
2287 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002288 return(-1);
2289 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002290 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002291 if (options == 0) {
2292 if (value < 0)
2293 value = 100;
2294 cache->maxNodeset = value;
2295 cache->maxString = value;
2296 cache->maxNumber = value;
2297 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002298 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002299 }
2300 } else if (ctxt->cache != NULL) {
2301 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2302 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002303 }
2304 return(0);
2305}
2306
2307/**
2308 * xmlXPathCacheWrapNodeSet:
2309 * @ctxt: the XPath context
2310 * @val: the NodePtr value
2311 *
2312 * This is the cached version of xmlXPathWrapNodeSet().
2313 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2314 *
2315 * Returns the created or reused object.
2316 */
2317static xmlXPathObjectPtr
2318xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002319{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002320 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2321 xmlXPathContextCachePtr cache =
2322 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002323
2324 if ((cache->miscObjs != NULL) &&
2325 (cache->miscObjs->number != 0))
2326 {
2327 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002328
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002329 ret = (xmlXPathObjectPtr)
2330 cache->miscObjs->items[--cache->miscObjs->number];
2331 ret->type = XPATH_NODESET;
2332 ret->nodesetval = val;
2333#ifdef XP_DEBUG_OBJ_USAGE
2334 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2335#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00002336 return(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002337 }
2338 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00002339
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002340 return(xmlXPathWrapNodeSet(val));
Daniel Veillard45490ae2008-07-29 09:13:19 +00002341
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002342}
2343
2344/**
2345 * xmlXPathCacheWrapString:
2346 * @ctxt: the XPath context
2347 * @val: the xmlChar * value
2348 *
2349 * This is the cached version of xmlXPathWrapString().
2350 * Wraps the @val string into an XPath object.
2351 *
2352 * Returns the created or reused object.
2353 */
2354static xmlXPathObjectPtr
2355xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002356{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002357 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2358 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002359
2360 if ((cache->stringObjs != NULL) &&
2361 (cache->stringObjs->number != 0))
2362 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002363
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002364 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002365
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002366 ret = (xmlXPathObjectPtr)
2367 cache->stringObjs->items[--cache->stringObjs->number];
2368 ret->type = XPATH_STRING;
2369 ret->stringval = val;
2370#ifdef XP_DEBUG_OBJ_USAGE
2371 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2372#endif
2373 return(ret);
2374 } else if ((cache->miscObjs != NULL) &&
2375 (cache->miscObjs->number != 0))
2376 {
2377 xmlXPathObjectPtr ret;
2378 /*
2379 * Fallback to misc-cache.
2380 */
2381 ret = (xmlXPathObjectPtr)
2382 cache->miscObjs->items[--cache->miscObjs->number];
2383
2384 ret->type = XPATH_STRING;
2385 ret->stringval = val;
2386#ifdef XP_DEBUG_OBJ_USAGE
2387 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2388#endif
2389 return(ret);
2390 }
2391 }
2392 return(xmlXPathWrapString(val));
2393}
2394
2395/**
2396 * xmlXPathCacheNewNodeSet:
2397 * @ctxt: the XPath context
2398 * @val: the NodePtr value
2399 *
2400 * This is the cached version of xmlXPathNewNodeSet().
2401 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2402 * it with the single Node @val
2403 *
2404 * Returns the created or reused object.
2405 */
2406static xmlXPathObjectPtr
2407xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2408{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002409 if ((ctxt != NULL) && (ctxt->cache)) {
2410 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002411
2412 if ((cache->nodesetObjs != NULL) &&
2413 (cache->nodesetObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002414 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002415 xmlXPathObjectPtr ret;
2416 /*
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002417 * Use the nodeset-cache.
Daniel Veillard45490ae2008-07-29 09:13:19 +00002418 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002419 ret = (xmlXPathObjectPtr)
2420 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2421 ret->type = XPATH_NODESET;
2422 ret->boolval = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002423 if (val) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002424 if ((ret->nodesetval->nodeMax == 0) ||
2425 (val->type == XML_NAMESPACE_DECL))
2426 {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002427 /* TODO: Check memory error. */
Daniel Veillard45490ae2008-07-29 09:13:19 +00002428 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002429 } else {
2430 ret->nodesetval->nodeTab[0] = val;
2431 ret->nodesetval->nodeNr = 1;
2432 }
2433 }
2434#ifdef XP_DEBUG_OBJ_USAGE
2435 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2436#endif
2437 return(ret);
2438 } else if ((cache->miscObjs != NULL) &&
2439 (cache->miscObjs->number != 0))
2440 {
2441 xmlXPathObjectPtr ret;
2442 /*
2443 * Fallback to misc-cache.
2444 */
2445
2446 ret = (xmlXPathObjectPtr)
2447 cache->miscObjs->items[--cache->miscObjs->number];
2448
2449 ret->type = XPATH_NODESET;
2450 ret->boolval = 0;
2451 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08002452 if (ret->nodesetval == NULL) {
2453 ctxt->lastError.domain = XML_FROM_XPATH;
2454 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2455 return(NULL);
2456 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002457#ifdef XP_DEBUG_OBJ_USAGE
2458 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2459#endif
2460 return(ret);
2461 }
2462 }
2463 return(xmlXPathNewNodeSet(val));
2464}
2465
2466/**
2467 * xmlXPathCacheNewCString:
2468 * @ctxt: the XPath context
2469 * @val: the char * value
2470 *
2471 * This is the cached version of xmlXPathNewCString().
2472 * Acquire an xmlXPathObjectPtr of type string and of value @val
2473 *
2474 * Returns the created or reused object.
2475 */
2476static xmlXPathObjectPtr
2477xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002478{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002479 if ((ctxt != NULL) && (ctxt->cache)) {
2480 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002481
2482 if ((cache->stringObjs != NULL) &&
2483 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002484 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002485 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002486
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002487 ret = (xmlXPathObjectPtr)
2488 cache->stringObjs->items[--cache->stringObjs->number];
2489
2490 ret->type = XPATH_STRING;
2491 ret->stringval = xmlStrdup(BAD_CAST val);
2492#ifdef XP_DEBUG_OBJ_USAGE
2493 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2494#endif
2495 return(ret);
2496 } else if ((cache->miscObjs != NULL) &&
2497 (cache->miscObjs->number != 0))
2498 {
2499 xmlXPathObjectPtr ret;
2500
2501 ret = (xmlXPathObjectPtr)
2502 cache->miscObjs->items[--cache->miscObjs->number];
2503
2504 ret->type = XPATH_STRING;
2505 ret->stringval = xmlStrdup(BAD_CAST val);
2506#ifdef XP_DEBUG_OBJ_USAGE
2507 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2508#endif
2509 return(ret);
2510 }
2511 }
2512 return(xmlXPathNewCString(val));
2513}
2514
2515/**
2516 * xmlXPathCacheNewString:
2517 * @ctxt: the XPath context
2518 * @val: the xmlChar * value
2519 *
2520 * This is the cached version of xmlXPathNewString().
2521 * Acquire an xmlXPathObjectPtr of type string and of value @val
2522 *
2523 * Returns the created or reused object.
2524 */
2525static xmlXPathObjectPtr
2526xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002527{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002528 if ((ctxt != NULL) && (ctxt->cache)) {
2529 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002530
2531 if ((cache->stringObjs != NULL) &&
2532 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002533 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002534 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002535
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002536 ret = (xmlXPathObjectPtr)
2537 cache->stringObjs->items[--cache->stringObjs->number];
2538 ret->type = XPATH_STRING;
2539 if (val != NULL)
2540 ret->stringval = xmlStrdup(val);
2541 else
2542 ret->stringval = xmlStrdup((const xmlChar *)"");
2543#ifdef XP_DEBUG_OBJ_USAGE
2544 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2545#endif
2546 return(ret);
2547 } else if ((cache->miscObjs != NULL) &&
2548 (cache->miscObjs->number != 0))
2549 {
2550 xmlXPathObjectPtr ret;
2551
2552 ret = (xmlXPathObjectPtr)
2553 cache->miscObjs->items[--cache->miscObjs->number];
2554
2555 ret->type = XPATH_STRING;
2556 if (val != NULL)
2557 ret->stringval = xmlStrdup(val);
2558 else
2559 ret->stringval = xmlStrdup((const xmlChar *)"");
2560#ifdef XP_DEBUG_OBJ_USAGE
2561 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2562#endif
2563 return(ret);
2564 }
2565 }
2566 return(xmlXPathNewString(val));
2567}
2568
2569/**
2570 * xmlXPathCacheNewBoolean:
2571 * @ctxt: the XPath context
2572 * @val: the boolean value
2573 *
2574 * This is the cached version of xmlXPathNewBoolean().
2575 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2576 *
2577 * Returns the created or reused object.
2578 */
2579static xmlXPathObjectPtr
2580xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002581{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002582 if ((ctxt != NULL) && (ctxt->cache)) {
2583 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002584
2585 if ((cache->booleanObjs != NULL) &&
2586 (cache->booleanObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002587 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002588 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002589
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002590 ret = (xmlXPathObjectPtr)
2591 cache->booleanObjs->items[--cache->booleanObjs->number];
2592 ret->type = XPATH_BOOLEAN;
2593 ret->boolval = (val != 0);
2594#ifdef XP_DEBUG_OBJ_USAGE
2595 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2596#endif
2597 return(ret);
2598 } else if ((cache->miscObjs != NULL) &&
2599 (cache->miscObjs->number != 0))
2600 {
2601 xmlXPathObjectPtr ret;
2602
2603 ret = (xmlXPathObjectPtr)
2604 cache->miscObjs->items[--cache->miscObjs->number];
2605
2606 ret->type = XPATH_BOOLEAN;
2607 ret->boolval = (val != 0);
2608#ifdef XP_DEBUG_OBJ_USAGE
2609 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2610#endif
2611 return(ret);
2612 }
2613 }
2614 return(xmlXPathNewBoolean(val));
2615}
2616
2617/**
2618 * xmlXPathCacheNewFloat:
2619 * @ctxt: the XPath context
2620 * @val: the double value
2621 *
2622 * This is the cached version of xmlXPathNewFloat().
2623 * Acquires an xmlXPathObjectPtr of type double and of value @val
2624 *
2625 * Returns the created or reused object.
2626 */
2627static xmlXPathObjectPtr
2628xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2629{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002630 if ((ctxt != NULL) && (ctxt->cache)) {
2631 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002632
2633 if ((cache->numberObjs != NULL) &&
2634 (cache->numberObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002635 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002636 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002637
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002638 ret = (xmlXPathObjectPtr)
2639 cache->numberObjs->items[--cache->numberObjs->number];
2640 ret->type = XPATH_NUMBER;
2641 ret->floatval = val;
2642#ifdef XP_DEBUG_OBJ_USAGE
2643 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2644#endif
2645 return(ret);
2646 } else if ((cache->miscObjs != NULL) &&
2647 (cache->miscObjs->number != 0))
2648 {
2649 xmlXPathObjectPtr ret;
2650
2651 ret = (xmlXPathObjectPtr)
2652 cache->miscObjs->items[--cache->miscObjs->number];
2653
2654 ret->type = XPATH_NUMBER;
2655 ret->floatval = val;
2656#ifdef XP_DEBUG_OBJ_USAGE
2657 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2658#endif
2659 return(ret);
2660 }
2661 }
2662 return(xmlXPathNewFloat(val));
2663}
2664
2665/**
2666 * xmlXPathCacheConvertString:
2667 * @ctxt: the XPath context
2668 * @val: an XPath object
2669 *
2670 * This is the cached version of xmlXPathConvertString().
2671 * Converts an existing object to its string() equivalent
2672 *
2673 * Returns a created or reused object, the old one is freed (cached)
2674 * (or the operation is done directly on @val)
2675 */
2676
2677static xmlXPathObjectPtr
2678xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002679 xmlChar *res = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002680
2681 if (val == NULL)
2682 return(xmlXPathCacheNewCString(ctxt, ""));
2683
2684 switch (val->type) {
2685 case XPATH_UNDEFINED:
2686#ifdef DEBUG_EXPR
2687 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2688#endif
2689 break;
2690 case XPATH_NODESET:
2691 case XPATH_XSLT_TREE:
2692 res = xmlXPathCastNodeSetToString(val->nodesetval);
2693 break;
2694 case XPATH_STRING:
2695 return(val);
2696 case XPATH_BOOLEAN:
2697 res = xmlXPathCastBooleanToString(val->boolval);
2698 break;
2699 case XPATH_NUMBER:
2700 res = xmlXPathCastNumberToString(val->floatval);
2701 break;
2702 case XPATH_USERS:
2703 case XPATH_POINT:
2704 case XPATH_RANGE:
2705 case XPATH_LOCATIONSET:
2706 TODO;
2707 break;
2708 }
2709 xmlXPathReleaseObject(ctxt, val);
2710 if (res == NULL)
2711 return(xmlXPathCacheNewCString(ctxt, ""));
2712 return(xmlXPathCacheWrapString(ctxt, res));
2713}
2714
2715/**
2716 * xmlXPathCacheObjectCopy:
2717 * @ctxt: the XPath context
2718 * @val: the original object
2719 *
2720 * This is the cached version of xmlXPathObjectCopy().
2721 * Acquire a copy of a given object
2722 *
2723 * Returns a created or reused created object.
2724 */
2725static xmlXPathObjectPtr
2726xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2727{
2728 if (val == NULL)
2729 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002730
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002731 if (XP_HAS_CACHE(ctxt)) {
2732 switch (val->type) {
2733 case XPATH_NODESET:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002734 return(xmlXPathCacheWrapNodeSet(ctxt,
2735 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002736 case XPATH_STRING:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002737 return(xmlXPathCacheNewString(ctxt, val->stringval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002738 case XPATH_BOOLEAN:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002739 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002740 case XPATH_NUMBER:
2741 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2742 default:
2743 break;
2744 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002745 }
2746 return(xmlXPathObjectCopy(val));
2747}
2748
2749/**
2750 * xmlXPathCacheConvertBoolean:
2751 * @ctxt: the XPath context
2752 * @val: an XPath object
2753 *
2754 * This is the cached version of xmlXPathConvertBoolean().
2755 * Converts an existing object to its boolean() equivalent
2756 *
2757 * Returns a created or reused object, the old one is freed (or the operation
2758 * is done directly on @val)
2759 */
2760static xmlXPathObjectPtr
2761xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2762 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002763
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002764 if (val == NULL)
2765 return(xmlXPathCacheNewBoolean(ctxt, 0));
2766 if (val->type == XPATH_BOOLEAN)
2767 return(val);
2768 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2769 xmlXPathReleaseObject(ctxt, val);
2770 return(ret);
2771}
2772
2773/**
2774 * xmlXPathCacheConvertNumber:
2775 * @ctxt: the XPath context
2776 * @val: an XPath object
2777 *
2778 * This is the cached version of xmlXPathConvertNumber().
2779 * Converts an existing object to its number() equivalent
2780 *
2781 * Returns a created or reused object, the old one is freed (or the operation
2782 * is done directly on @val)
2783 */
2784static xmlXPathObjectPtr
2785xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2786 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002787
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002788 if (val == NULL)
2789 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2790 if (val->type == XPATH_NUMBER)
2791 return(val);
2792 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2793 xmlXPathReleaseObject(ctxt, val);
2794 return(ret);
2795}
2796
2797/************************************************************************
2798 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00002799 * Parser stacks related functions and macros *
Owen Taylor3473f882001-02-23 17:55:21 +00002800 * *
2801 ************************************************************************/
2802
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002803/**
Daniel Veillardf5048b32011-08-18 17:10:13 +08002804 * xmlXPathSetFrame:
2805 * @ctxt: an XPath parser context
2806 *
2807 * Set the callee evaluation frame
2808 *
2809 * Returns the previous frame value to be restored once done
2810 */
2811static int
2812xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2813 int ret;
2814
2815 if (ctxt == NULL)
2816 return(0);
2817 ret = ctxt->valueFrame;
2818 ctxt->valueFrame = ctxt->valueNr;
2819 return(ret);
2820}
2821
2822/**
2823 * xmlXPathPopFrame:
2824 * @ctxt: an XPath parser context
2825 * @frame: the previous frame value
2826 *
2827 * Remove the callee evaluation frame
2828 */
2829static void
2830xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2831 if (ctxt == NULL)
2832 return;
2833 if (ctxt->valueNr < ctxt->valueFrame) {
2834 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2835 }
2836 ctxt->valueFrame = frame;
2837}
2838
2839/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002840 * valuePop:
2841 * @ctxt: an XPath evaluation context
2842 *
2843 * Pops the top XPath object from the value stack
2844 *
2845 * Returns the XPath object just removed
2846 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002847xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002848valuePop(xmlXPathParserContextPtr ctxt)
2849{
2850 xmlXPathObjectPtr ret;
2851
Daniel Veillarda82b1822004-11-08 16:24:57 +00002852 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002853 return (NULL);
Daniel Veillardf5048b32011-08-18 17:10:13 +08002854
2855 if (ctxt->valueNr <= ctxt->valueFrame) {
2856 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2857 return (NULL);
2858 }
2859
Daniel Veillard1c732d22002-11-30 11:22:59 +00002860 ctxt->valueNr--;
2861 if (ctxt->valueNr > 0)
2862 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2863 else
2864 ctxt->value = NULL;
2865 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002866 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002867 return (ret);
2868}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002869/**
2870 * valuePush:
2871 * @ctxt: an XPath evaluation context
2872 * @value: the XPath object
2873 *
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002874 * Pushes a new XPath object on top of the value stack. If value is NULL,
2875 * a memory error is recorded in the parser context.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002876 *
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002877 * Returns the number of items on the value stack, or -1 in case of error.
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002878 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002879int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002880valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2881{
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002882 if (ctxt == NULL) return(-1);
2883 if (value == NULL) {
2884 /*
2885 * A NULL value typically indicates that a memory allocation failed,
2886 * so we set ctxt->error here to propagate the error.
2887 */
2888 ctxt->error = XPATH_MEMORY_ERROR;
2889 return(-1);
2890 }
Daniel Veillard1c732d22002-11-30 11:22:59 +00002891 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002892 xmlXPathObjectPtr *tmp;
2893
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002894 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002895 xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2896 return (-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002897 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002898 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2899 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002900 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002901 if (tmp == NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002902 xmlXPathPErrMemory(ctxt, "pushing value\n");
2903 return (-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002904 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002905 ctxt->valueMax *= 2;
2906 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002907 }
2908 ctxt->valueTab[ctxt->valueNr] = value;
2909 ctxt->value = value;
2910 return (ctxt->valueNr++);
2911}
Owen Taylor3473f882001-02-23 17:55:21 +00002912
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002913/**
2914 * xmlXPathPopBoolean:
2915 * @ctxt: an XPath parser context
2916 *
2917 * Pops a boolean from the stack, handling conversion if needed.
2918 * Check error with #xmlXPathCheckError.
2919 *
2920 * Returns the boolean
2921 */
2922int
2923xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2924 xmlXPathObjectPtr obj;
2925 int ret;
2926
2927 obj = valuePop(ctxt);
2928 if (obj == NULL) {
2929 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2930 return(0);
2931 }
William M. Brack08171912003-12-29 02:52:11 +00002932 if (obj->type != XPATH_BOOLEAN)
2933 ret = xmlXPathCastToBoolean(obj);
2934 else
2935 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002936 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002937 return(ret);
2938}
2939
2940/**
2941 * xmlXPathPopNumber:
2942 * @ctxt: an XPath parser context
2943 *
2944 * Pops a number from the stack, handling conversion if needed.
2945 * Check error with #xmlXPathCheckError.
2946 *
2947 * Returns the number
2948 */
2949double
2950xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2951 xmlXPathObjectPtr obj;
2952 double ret;
2953
2954 obj = valuePop(ctxt);
2955 if (obj == NULL) {
2956 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2957 return(0);
2958 }
William M. Brack08171912003-12-29 02:52:11 +00002959 if (obj->type != XPATH_NUMBER)
2960 ret = xmlXPathCastToNumber(obj);
2961 else
2962 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002963 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002964 return(ret);
2965}
2966
2967/**
2968 * xmlXPathPopString:
2969 * @ctxt: an XPath parser context
2970 *
2971 * Pops a string from the stack, handling conversion if needed.
2972 * Check error with #xmlXPathCheckError.
2973 *
2974 * Returns the string
2975 */
2976xmlChar *
2977xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2978 xmlXPathObjectPtr obj;
2979 xmlChar * ret;
2980
2981 obj = valuePop(ctxt);
2982 if (obj == NULL) {
2983 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2984 return(NULL);
2985 }
William M. Brack08171912003-12-29 02:52:11 +00002986 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002987 /* TODO: needs refactoring somewhere else */
2988 if (obj->stringval == ret)
2989 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002990 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002991 return(ret);
2992}
2993
2994/**
2995 * xmlXPathPopNodeSet:
2996 * @ctxt: an XPath parser context
2997 *
2998 * Pops a node-set from the stack, handling conversion if needed.
2999 * Check error with #xmlXPathCheckError.
3000 *
3001 * Returns the node-set
3002 */
3003xmlNodeSetPtr
3004xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
3005 xmlXPathObjectPtr obj;
3006 xmlNodeSetPtr ret;
3007
Daniel Veillardf2a36f92004-11-08 17:55:01 +00003008 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003009 if (ctxt->value == NULL) {
3010 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3011 return(NULL);
3012 }
3013 if (!xmlXPathStackIsNodeSet(ctxt)) {
3014 xmlXPathSetTypeError(ctxt);
3015 return(NULL);
3016 }
3017 obj = valuePop(ctxt);
3018 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00003019#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00003020 /* to fix memory leak of not clearing obj->user */
3021 if (obj->boolval && obj->user != NULL)
3022 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00003023#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003024 obj->nodesetval = NULL;
3025 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003026 return(ret);
3027}
3028
3029/**
3030 * xmlXPathPopExternal:
3031 * @ctxt: an XPath parser context
3032 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003033 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003034 * Check error with #xmlXPathCheckError.
3035 *
3036 * Returns the object
3037 */
3038void *
3039xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3040 xmlXPathObjectPtr obj;
3041 void * ret;
3042
Daniel Veillarda82b1822004-11-08 16:24:57 +00003043 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003044 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3045 return(NULL);
3046 }
3047 if (ctxt->value->type != XPATH_USERS) {
3048 xmlXPathSetTypeError(ctxt);
3049 return(NULL);
3050 }
3051 obj = valuePop(ctxt);
3052 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003053 obj->user = NULL;
3054 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003055 return(ret);
3056}
3057
Owen Taylor3473f882001-02-23 17:55:21 +00003058/*
3059 * Macros for accessing the content. Those should be used only by the parser,
3060 * and not exported.
3061 *
3062 * Dirty macros, i.e. one need to make assumption on the context to use them
3063 *
3064 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3065 * CUR returns the current xmlChar value, i.e. a 8 bit value
3066 * in ISO-Latin or UTF-8.
3067 * This should be used internally by the parser
3068 * only to compare to ASCII values otherwise it would break when
3069 * running with UTF-8 encoding.
3070 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3071 * to compare on ASCII based substring.
3072 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3073 * strings within the parser.
3074 * CURRENT Returns the current char value, with the full decoding of
3075 * UTF-8 if we are using this mode. It returns an int.
3076 * NEXT Skip to the next character, this does the proper decoding
3077 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3078 * It returns the pointer to the current xmlChar.
3079 */
3080
3081#define CUR (*ctxt->cur)
3082#define SKIP(val) ctxt->cur += (val)
3083#define NXT(val) ctxt->cur[(val)]
3084#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00003085#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3086
3087#define COPY_BUF(l,b,i,v) \
3088 if (l == 1) b[i++] = (xmlChar) v; \
3089 else i += xmlCopyChar(l,&b[i],v)
3090
3091#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00003092
Daniel Veillard45490ae2008-07-29 09:13:19 +00003093#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00003094 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00003095
3096#define CURRENT (*ctxt->cur)
3097#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3098
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003099
3100#ifndef DBL_DIG
3101#define DBL_DIG 16
3102#endif
3103#ifndef DBL_EPSILON
3104#define DBL_EPSILON 1E-9
3105#endif
3106
3107#define UPPER_DOUBLE 1E9
3108#define LOWER_DOUBLE 1E-5
William M. Brackca797882007-05-11 14:45:53 +00003109#define LOWER_DOUBLE_EXP 5
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003110
3111#define INTEGER_DIGITS DBL_DIG
William M. Brackca797882007-05-11 14:45:53 +00003112#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003113#define EXPONENT_DIGITS (3 + 2)
3114
3115/**
3116 * xmlXPathFormatNumber:
3117 * @number: number to format
3118 * @buffer: output buffer
3119 * @buffersize: size of output buffer
3120 *
3121 * Convert the number into a string representation.
3122 */
3123static void
3124xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3125{
Daniel Veillardcda96922001-08-21 10:56:31 +00003126 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003127 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003128 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003129 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003130 break;
3131 case -1:
3132 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003133 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003134 break;
3135 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003136 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003137 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003138 snprintf(buffer, buffersize, "NaN");
Nick Wellnhofer8813f392017-09-21 00:11:26 +02003139 } else if (number == 0) {
3140 /* Omit sign for negative zero. */
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003141 snprintf(buffer, buffersize, "0");
Nick Wellnhofer7482f412017-06-01 22:00:19 +02003142 } else if ((number > INT_MIN) && (number < INT_MAX) &&
3143 (number == (int) number)) {
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003144 char work[30];
3145 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00003146 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003147
3148 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003149 if (value == 0) {
3150 *ptr++ = '0';
3151 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00003152 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003153 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00003154 while ((*cur) && (ptr - buffer < buffersize)) {
3155 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003156 }
3157 }
3158 if (ptr - buffer < buffersize) {
3159 *ptr = 0;
3160 } else if (buffersize > 0) {
3161 ptr--;
3162 *ptr = 0;
3163 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003164 } else {
William M. Brackca797882007-05-11 14:45:53 +00003165 /*
3166 For the dimension of work,
3167 DBL_DIG is number of significant digits
3168 EXPONENT is only needed for "scientific notation"
3169 3 is sign, decimal point, and terminating zero
3170 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3171 Note that this dimension is slightly (a few characters)
3172 larger than actually necessary.
3173 */
3174 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
Bjorn Reese70a9da52001-04-21 16:57:29 +00003175 int integer_place, fraction_place;
3176 char *ptr;
3177 char *after_fraction;
3178 double absolute_value;
3179 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003180
Bjorn Reese70a9da52001-04-21 16:57:29 +00003181 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003182
Bjorn Reese70a9da52001-04-21 16:57:29 +00003183 /*
3184 * First choose format - scientific or regular floating point.
3185 * In either case, result is in work, and after_fraction points
3186 * just past the fractional part.
3187 */
3188 if ( ((absolute_value > UPPER_DOUBLE) ||
3189 (absolute_value < LOWER_DOUBLE)) &&
3190 (absolute_value != 0.0) ) {
3191 /* Use scientific notation */
3192 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3193 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00003194 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00003195 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00003196 while ((size > 0) && (work[size] != 'e')) size--;
Daniel Veillard11ce4002006-03-10 00:36:23 +00003197
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003198 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00003199 else {
3200 /* Use regular notation */
William M. Brackca797882007-05-11 14:45:53 +00003201 if (absolute_value > 0.0) {
3202 integer_place = (int)log10(absolute_value);
3203 if (integer_place > 0)
3204 fraction_place = DBL_DIG - integer_place - 1;
3205 else
3206 fraction_place = DBL_DIG - integer_place;
3207 } else {
3208 fraction_place = 1;
3209 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00003210 size = snprintf(work, sizeof(work), "%0.*f",
3211 fraction_place, number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003212 }
3213
Daniel Veillardb9e4d5b2013-07-22 13:21:31 +08003214 /* Remove leading spaces sometimes inserted by snprintf */
3215 while (work[0] == ' ') {
3216 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3217 size--;
3218 }
3219
Bjorn Reese70a9da52001-04-21 16:57:29 +00003220 /* Remove fractional trailing zeroes */
William M. Brackca797882007-05-11 14:45:53 +00003221 after_fraction = work + size;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003222 ptr = after_fraction;
3223 while (*(--ptr) == '0')
3224 ;
3225 if (*ptr != '.')
3226 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00003227 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003228
3229 /* Finally copy result back to caller */
3230 size = strlen(work) + 1;
3231 if (size > buffersize) {
3232 work[buffersize - 1] = 0;
3233 size = buffersize;
3234 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00003235 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003236 }
3237 break;
3238 }
3239}
3240
Owen Taylor3473f882001-02-23 17:55:21 +00003241
3242/************************************************************************
3243 * *
3244 * Routines to handle NodeSets *
3245 * *
3246 ************************************************************************/
3247
3248/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003249 * xmlXPathOrderDocElems:
3250 * @doc: an input document
3251 *
3252 * Call this routine to speed up XPath computation on static documents.
3253 * This stamps all the element nodes with the document order
3254 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00003255 * field, the value stored is actually - the node number (starting at -1)
3256 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003257 *
William M. Brack08171912003-12-29 02:52:11 +00003258 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003259 * of error.
3260 */
3261long
3262xmlXPathOrderDocElems(xmlDocPtr doc) {
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003263 ptrdiff_t count = 0;
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003264 xmlNodePtr cur;
3265
3266 if (doc == NULL)
3267 return(-1);
3268 cur = doc->children;
3269 while (cur != NULL) {
3270 if (cur->type == XML_ELEMENT_NODE) {
3271 cur->content = (void *) (-(++count));
3272 if (cur->children != NULL) {
3273 cur = cur->children;
3274 continue;
3275 }
3276 }
3277 if (cur->next != NULL) {
3278 cur = cur->next;
3279 continue;
3280 }
3281 do {
3282 cur = cur->parent;
3283 if (cur == NULL)
3284 break;
3285 if (cur == (xmlNodePtr) doc) {
3286 cur = NULL;
3287 break;
3288 }
3289 if (cur->next != NULL) {
3290 cur = cur->next;
3291 break;
3292 }
3293 } while (cur != NULL);
3294 }
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003295 return((long) count);
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003296}
3297
3298/**
Owen Taylor3473f882001-02-23 17:55:21 +00003299 * xmlXPathCmpNodes:
3300 * @node1: the first node
3301 * @node2: the second node
3302 *
3303 * Compare two nodes w.r.t document order
3304 *
3305 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00003306 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003307 */
3308int
3309xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3310 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003311 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003312 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003313 xmlNodePtr cur, root;
3314
3315 if ((node1 == NULL) || (node2 == NULL))
3316 return(-2);
3317 /*
3318 * a couple of optimizations which will avoid computations in most cases
3319 */
William M. Brackee0b9822007-03-07 08:15:01 +00003320 if (node1 == node2) /* trivial case */
3321 return(0);
Daniel Veillardedfd5882003-03-07 14:20:40 +00003322 if (node1->type == XML_ATTRIBUTE_NODE) {
3323 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003324 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003325 node1 = node1->parent;
3326 }
3327 if (node2->type == XML_ATTRIBUTE_NODE) {
3328 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003329 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003330 node2 = node2->parent;
3331 }
3332 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00003333 if (attr1 == attr2) {
3334 /* not required, but we keep attributes in order */
3335 if (attr1 != 0) {
3336 cur = attrNode2->prev;
3337 while (cur != NULL) {
3338 if (cur == attrNode1)
3339 return (1);
3340 cur = cur->prev;
3341 }
3342 return (-1);
3343 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003344 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00003345 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003346 if (attr2 == 1)
3347 return(1);
3348 return(-1);
3349 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003350 if ((node1->type == XML_NAMESPACE_DECL) ||
3351 (node2->type == XML_NAMESPACE_DECL))
3352 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003353 if (node1 == node2->prev)
3354 return(1);
3355 if (node1 == node2->next)
3356 return(-1);
3357
3358 /*
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003359 * Speedup using document order if available.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003360 */
3361 if ((node1->type == XML_ELEMENT_NODE) &&
3362 (node2->type == XML_ELEMENT_NODE) &&
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003363 (0 > (ptrdiff_t) node1->content) &&
3364 (0 > (ptrdiff_t) node2->content) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003365 (node1->doc == node2->doc)) {
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003366 ptrdiff_t l1, l2;
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003367
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003368 l1 = -((ptrdiff_t) node1->content);
3369 l2 = -((ptrdiff_t) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003370 if (l1 < l2)
3371 return(1);
3372 if (l1 > l2)
3373 return(-1);
3374 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003375
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003376 /*
Owen Taylor3473f882001-02-23 17:55:21 +00003377 * compute depth to root
3378 */
3379 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
Nick Wellnhofera0051992016-06-28 14:19:58 +02003380 if (cur->parent == node1)
Owen Taylor3473f882001-02-23 17:55:21 +00003381 return(1);
3382 depth2++;
3383 }
3384 root = cur;
3385 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
Nick Wellnhofera0051992016-06-28 14:19:58 +02003386 if (cur->parent == node2)
Owen Taylor3473f882001-02-23 17:55:21 +00003387 return(-1);
3388 depth1++;
3389 }
3390 /*
3391 * Distinct document (or distinct entities :-( ) case.
3392 */
3393 if (root != cur) {
3394 return(-2);
3395 }
3396 /*
3397 * get the nearest common ancestor.
3398 */
3399 while (depth1 > depth2) {
3400 depth1--;
3401 node1 = node1->parent;
3402 }
3403 while (depth2 > depth1) {
3404 depth2--;
3405 node2 = node2->parent;
3406 }
3407 while (node1->parent != node2->parent) {
3408 node1 = node1->parent;
3409 node2 = node2->parent;
3410 /* should not happen but just in case ... */
3411 if ((node1 == NULL) || (node2 == NULL))
3412 return(-2);
3413 }
3414 /*
3415 * Find who's first.
3416 */
Daniel Veillardf49be472004-02-17 11:48:18 +00003417 if (node1 == node2->prev)
3418 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003419 if (node1 == node2->next)
3420 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00003421 /*
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003422 * Speedup using document order if available.
Daniel Veillardf49be472004-02-17 11:48:18 +00003423 */
3424 if ((node1->type == XML_ELEMENT_NODE) &&
3425 (node2->type == XML_ELEMENT_NODE) &&
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003426 (0 > (ptrdiff_t) node1->content) &&
3427 (0 > (ptrdiff_t) node2->content) &&
Daniel Veillardf49be472004-02-17 11:48:18 +00003428 (node1->doc == node2->doc)) {
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003429 ptrdiff_t l1, l2;
Daniel Veillardf49be472004-02-17 11:48:18 +00003430
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003431 l1 = -((ptrdiff_t) node1->content);
3432 l2 = -((ptrdiff_t) node2->content);
Daniel Veillardf49be472004-02-17 11:48:18 +00003433 if (l1 < l2)
3434 return(1);
3435 if (l1 > l2)
3436 return(-1);
3437 }
3438
Owen Taylor3473f882001-02-23 17:55:21 +00003439 for (cur = node1->next;cur != NULL;cur = cur->next)
3440 if (cur == node2)
3441 return(1);
3442 return(-1); /* assume there is no sibling list corruption */
3443}
3444
3445/**
3446 * xmlXPathNodeSetSort:
3447 * @set: the node set
3448 *
3449 * Sort the node set in document order
3450 */
3451void
3452xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Vojtech Fried3e031b72012-08-24 16:52:44 +08003453#ifndef WITH_TIM_SORT
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003454 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003455 xmlNodePtr tmp;
Vojtech Fried3e031b72012-08-24 16:52:44 +08003456#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003457
3458 if (set == NULL)
3459 return;
3460
Vojtech Fried3e031b72012-08-24 16:52:44 +08003461#ifndef WITH_TIM_SORT
3462 /*
3463 * Use the old Shell's sort implementation to sort the node-set
3464 * Timsort ought to be quite faster
3465 */
Owen Taylor3473f882001-02-23 17:55:21 +00003466 len = set->nodeNr;
3467 for (incr = len / 2; incr > 0; incr /= 2) {
3468 for (i = incr; i < len; i++) {
3469 j = i - incr;
3470 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003471#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003472 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3473 set->nodeTab[j + incr]) == -1)
3474#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003475 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003476 set->nodeTab[j + incr]) == -1)
3477#endif
3478 {
Owen Taylor3473f882001-02-23 17:55:21 +00003479 tmp = set->nodeTab[j];
3480 set->nodeTab[j] = set->nodeTab[j + incr];
3481 set->nodeTab[j + incr] = tmp;
3482 j -= incr;
3483 } else
3484 break;
3485 }
3486 }
3487 }
Vojtech Fried3e031b72012-08-24 16:52:44 +08003488#else /* WITH_TIM_SORT */
3489 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3490#endif /* WITH_TIM_SORT */
Owen Taylor3473f882001-02-23 17:55:21 +00003491}
3492
3493#define XML_NODESET_DEFAULT 10
3494/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003495 * xmlXPathNodeSetDupNs:
3496 * @node: the parent node of the namespace XPath node
3497 * @ns: the libxml namespace declaration node.
3498 *
3499 * Namespace node in libxml don't match the XPath semantic. In a node set
3500 * the namespace nodes are duplicated and the next pointer is set to the
3501 * parent node in the XPath semantic.
3502 *
3503 * Returns the newly created object.
3504 */
3505static xmlNodePtr
3506xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3507 xmlNsPtr cur;
3508
3509 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3510 return(NULL);
3511 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3512 return((xmlNodePtr) ns);
3513
3514 /*
3515 * Allocate a new Namespace and fill the fields.
3516 */
3517 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3518 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003519 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003520 return(NULL);
3521 }
3522 memset(cur, 0, sizeof(xmlNs));
3523 cur->type = XML_NAMESPACE_DECL;
3524 if (ns->href != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003525 cur->href = xmlStrdup(ns->href);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003526 if (ns->prefix != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003527 cur->prefix = xmlStrdup(ns->prefix);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003528 cur->next = (xmlNsPtr) node;
3529 return((xmlNodePtr) cur);
3530}
3531
3532/**
3533 * xmlXPathNodeSetFreeNs:
3534 * @ns: the XPath namespace node found in a nodeset.
3535 *
William M. Brack08171912003-12-29 02:52:11 +00003536 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003537 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003538 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003539 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003540void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003541xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3542 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3543 return;
3544
3545 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3546 if (ns->href != NULL)
3547 xmlFree((xmlChar *)ns->href);
3548 if (ns->prefix != NULL)
3549 xmlFree((xmlChar *)ns->prefix);
3550 xmlFree(ns);
3551 }
3552}
3553
3554/**
Owen Taylor3473f882001-02-23 17:55:21 +00003555 * xmlXPathNodeSetCreate:
3556 * @val: an initial xmlNodePtr, or NULL
3557 *
3558 * Create a new xmlNodeSetPtr of type double and of value @val
3559 *
3560 * Returns the newly created object.
3561 */
3562xmlNodeSetPtr
3563xmlXPathNodeSetCreate(xmlNodePtr val) {
3564 xmlNodeSetPtr ret;
3565
3566 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3567 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003568 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003569 return(NULL);
3570 }
3571 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3572 if (val != NULL) {
3573 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3574 sizeof(xmlNodePtr));
3575 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003576 xmlXPathErrMemory(NULL, "creating nodeset\n");
3577 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003578 return(NULL);
3579 }
3580 memset(ret->nodeTab, 0 ,
3581 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3582 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003583 if (val->type == XML_NAMESPACE_DECL) {
3584 xmlNsPtr ns = (xmlNsPtr) val;
3585
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003586 /* TODO: Check memory error. */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003587 ret->nodeTab[ret->nodeNr++] =
3588 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3589 } else
3590 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003591 }
3592 return(ret);
3593}
3594
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003595/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003596 * xmlXPathNodeSetContains:
3597 * @cur: the node-set
3598 * @val: the node
3599 *
3600 * checks whether @cur contains @val
3601 *
3602 * Returns true (1) if @cur contains @val, false (0) otherwise
3603 */
3604int
3605xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3606 int i;
3607
Daniel Veillarda82b1822004-11-08 16:24:57 +00003608 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003609 if (val->type == XML_NAMESPACE_DECL) {
3610 for (i = 0; i < cur->nodeNr; i++) {
3611 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3612 xmlNsPtr ns1, ns2;
3613
3614 ns1 = (xmlNsPtr) val;
3615 ns2 = (xmlNsPtr) cur->nodeTab[i];
3616 if (ns1 == ns2)
3617 return(1);
3618 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3619 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3620 return(1);
3621 }
3622 }
3623 } else {
3624 for (i = 0; i < cur->nodeNr; i++) {
3625 if (cur->nodeTab[i] == val)
3626 return(1);
3627 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003628 }
3629 return(0);
3630}
3631
3632/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003633 * xmlXPathNodeSetAddNs:
3634 * @cur: the initial node set
3635 * @node: the hosting node
3636 * @ns: a the namespace node
3637 *
3638 * add a new namespace node to an existing NodeSet
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003639 *
3640 * Returns 0 in case of success and -1 in case of error
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003641 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003642int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003643xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3644 int i;
3645
Daniel Veillard45490ae2008-07-29 09:13:19 +00003646
Daniel Veillarda82b1822004-11-08 16:24:57 +00003647 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3648 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003649 (node->type != XML_ELEMENT_NODE))
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003650 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003651
William M. Brack08171912003-12-29 02:52:11 +00003652 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003653 /*
William M. Brack08171912003-12-29 02:52:11 +00003654 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003655 */
3656 for (i = 0;i < cur->nodeNr;i++) {
3657 if ((cur->nodeTab[i] != NULL) &&
3658 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003659 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003660 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003661 return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003662 }
3663
3664 /*
3665 * grow the nodeTab if needed
3666 */
3667 if (cur->nodeMax == 0) {
3668 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3669 sizeof(xmlNodePtr));
3670 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003671 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003672 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003673 }
3674 memset(cur->nodeTab, 0 ,
3675 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3676 cur->nodeMax = XML_NODESET_DEFAULT;
3677 } else if (cur->nodeNr == cur->nodeMax) {
3678 xmlNodePtr *temp;
3679
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003680 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3681 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003682 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003683 }
Chris Evansd7958b22011-03-23 08:13:06 +08003684 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003685 sizeof(xmlNodePtr));
3686 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003687 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003688 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003689 }
Chris Evansd7958b22011-03-23 08:13:06 +08003690 cur->nodeMax *= 2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003691 cur->nodeTab = temp;
3692 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003693 /* TODO: Check memory error. */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003694 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003695 return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003696}
3697
3698/**
Owen Taylor3473f882001-02-23 17:55:21 +00003699 * xmlXPathNodeSetAdd:
3700 * @cur: the initial node set
3701 * @val: a new xmlNodePtr
3702 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003703 * add a new xmlNodePtr to an existing NodeSet
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003704 *
3705 * Returns 0 in case of success, and -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00003706 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003707int
Owen Taylor3473f882001-02-23 17:55:21 +00003708xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3709 int i;
3710
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003711 if ((cur == NULL) || (val == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003712
William M. Brack08171912003-12-29 02:52:11 +00003713 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003714 /*
Shlomi Fishd5bd2a92016-04-03 05:14:44 +03003715 * prevent duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003716 */
3717 for (i = 0;i < cur->nodeNr;i++)
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003718 if (cur->nodeTab[i] == val) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003719
3720 /*
3721 * grow the nodeTab if needed
3722 */
3723 if (cur->nodeMax == 0) {
3724 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3725 sizeof(xmlNodePtr));
3726 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003727 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003728 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003729 }
3730 memset(cur->nodeTab, 0 ,
3731 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3732 cur->nodeMax = XML_NODESET_DEFAULT;
3733 } else if (cur->nodeNr == cur->nodeMax) {
3734 xmlNodePtr *temp;
3735
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003736 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3737 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003738 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003739 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003740 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003741 sizeof(xmlNodePtr));
3742 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003743 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003744 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003745 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003746 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003747 cur->nodeTab = temp;
3748 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003749 if (val->type == XML_NAMESPACE_DECL) {
3750 xmlNsPtr ns = (xmlNsPtr) val;
3751
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003752 /* TODO: Check memory error. */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003753 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003754 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3755 } else
3756 cur->nodeTab[cur->nodeNr++] = val;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003757 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003758}
3759
3760/**
3761 * xmlXPathNodeSetAddUnique:
3762 * @cur: the initial node set
3763 * @val: a new xmlNodePtr
3764 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003765 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003766 * when we are sure the node is not already in the set.
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003767 *
3768 * Returns 0 in case of success and -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00003769 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003770int
Owen Taylor3473f882001-02-23 17:55:21 +00003771xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003772 if ((cur == NULL) || (val == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003773
William M. Brack08171912003-12-29 02:52:11 +00003774 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003775 /*
3776 * grow the nodeTab if needed
3777 */
3778 if (cur->nodeMax == 0) {
3779 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3780 sizeof(xmlNodePtr));
3781 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003782 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003783 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003784 }
3785 memset(cur->nodeTab, 0 ,
3786 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3787 cur->nodeMax = XML_NODESET_DEFAULT;
3788 } else if (cur->nodeNr == cur->nodeMax) {
3789 xmlNodePtr *temp;
3790
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003791 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3792 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003793 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003794 }
Chris Evansd7958b22011-03-23 08:13:06 +08003795 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003796 sizeof(xmlNodePtr));
3797 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003798 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003799 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003800 }
3801 cur->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003802 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003803 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003804 if (val->type == XML_NAMESPACE_DECL) {
3805 xmlNsPtr ns = (xmlNsPtr) val;
3806
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003807 /* TODO: Check memory error. */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003808 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003809 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3810 } else
3811 cur->nodeTab[cur->nodeNr++] = val;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003812 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003813}
3814
3815/**
3816 * xmlXPathNodeSetMerge:
3817 * @val1: the first NodeSet or NULL
3818 * @val2: the second NodeSet
3819 *
3820 * Merges two nodesets, all nodes from @val2 are added to @val1
3821 * if @val1 is NULL, a new set is created and copied from @val2
3822 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003823 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003824 */
3825xmlNodeSetPtr
3826xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003827 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003828 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003829
3830 if (val2 == NULL) return(val1);
3831 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003832 val1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00003833 if (val1 == NULL)
3834 return (NULL);
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003835#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003836 /*
3837 * TODO: The optimization won't work in every case, since
3838 * those nasty namespace nodes need to be added with
3839 * xmlXPathNodeSetDupNs() to the set; thus a pure
3840 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003841 * If there was a flag on the nodesetval, indicating that
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003842 * some temporary nodes are in, that would be helpful.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003843 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003844 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003845 * Optimization: Create an equally sized node-set
3846 * and memcpy the content.
3847 */
3848 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3849 if (val1 == NULL)
3850 return(NULL);
3851 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003852 if (val2->nodeNr == 1)
3853 *(val1->nodeTab) = *(val2->nodeTab);
3854 else {
3855 memcpy(val1->nodeTab, val2->nodeTab,
3856 val2->nodeNr * sizeof(xmlNodePtr));
3857 }
3858 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003859 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003860 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003861#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003862 }
3863
William M. Brack08171912003-12-29 02:52:11 +00003864 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003865 initNr = val1->nodeNr;
3866
3867 for (i = 0;i < val2->nodeNr;i++) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003868 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003869 /*
William M. Brack08171912003-12-29 02:52:11 +00003870 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003871 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003872 skip = 0;
3873 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003874 n1 = val1->nodeTab[j];
3875 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003876 skip = 1;
3877 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003878 } else if ((n1->type == XML_NAMESPACE_DECL) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003879 (n2->type == XML_NAMESPACE_DECL)) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003880 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3881 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3882 ((xmlNsPtr) n2)->prefix)))
3883 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003884 skip = 1;
3885 break;
3886 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003887 }
3888 }
3889 if (skip)
3890 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003891
3892 /*
3893 * grow the nodeTab if needed
3894 */
3895 if (val1->nodeMax == 0) {
3896 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3897 sizeof(xmlNodePtr));
3898 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003899 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003900 return(NULL);
3901 }
3902 memset(val1->nodeTab, 0 ,
3903 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3904 val1->nodeMax = XML_NODESET_DEFAULT;
3905 } else if (val1->nodeNr == val1->nodeMax) {
3906 xmlNodePtr *temp;
3907
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003908 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3909 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3910 return(NULL);
3911 }
Chris Evansd7958b22011-03-23 08:13:06 +08003912 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003913 sizeof(xmlNodePtr));
3914 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003915 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003916 return(NULL);
3917 }
3918 val1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003919 val1->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003920 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003921 if (n2->type == XML_NAMESPACE_DECL) {
3922 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003923
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003924 /* TODO: Check memory error. */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003925 val1->nodeTab[val1->nodeNr++] =
3926 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3927 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003928 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003929 }
3930
3931 return(val1);
3932}
3933
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003934
3935/**
3936 * xmlXPathNodeSetMergeAndClear:
3937 * @set1: the first NodeSet or NULL
3938 * @set2: the second NodeSet
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003939 *
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003940 * Merges two nodesets, all nodes from @set2 are added to @set1.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003941 * Checks for duplicate nodes. Clears set2.
3942 *
3943 * Returns @set1 once extended or NULL in case of error.
3944 */
3945static xmlNodeSetPtr
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003946xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003947{
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003948 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003949 int i, j, initNbSet1;
3950 xmlNodePtr n1, n2;
3951
Daniel Veillard45490ae2008-07-29 09:13:19 +00003952 initNbSet1 = set1->nodeNr;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003953 for (i = 0;i < set2->nodeNr;i++) {
3954 n2 = set2->nodeTab[i];
3955 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003956 * Skip duplicates.
3957 */
3958 for (j = 0; j < initNbSet1; j++) {
3959 n1 = set1->nodeTab[j];
Daniel Veillard45490ae2008-07-29 09:13:19 +00003960 if (n1 == n2) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003961 goto skip_node;
3962 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3963 (n2->type == XML_NAMESPACE_DECL))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003964 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003965 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3966 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3967 ((xmlNsPtr) n2)->prefix)))
3968 {
3969 /*
3970 * Free the namespace node.
3971 */
3972 set2->nodeTab[i] = NULL;
3973 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3974 goto skip_node;
3975 }
3976 }
3977 }
3978 /*
3979 * grow the nodeTab if needed
3980 */
3981 if (set1->nodeMax == 0) {
3982 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3983 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3984 if (set1->nodeTab == NULL) {
3985 xmlXPathErrMemory(NULL, "merging nodeset\n");
3986 return(NULL);
3987 }
3988 memset(set1->nodeTab, 0,
3989 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3990 set1->nodeMax = XML_NODESET_DEFAULT;
3991 } else if (set1->nodeNr >= set1->nodeMax) {
3992 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003993
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003994 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3995 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3996 return(NULL);
3997 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003998 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08003999 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004000 if (temp == NULL) {
4001 xmlXPathErrMemory(NULL, "merging nodeset\n");
4002 return(NULL);
4003 }
4004 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004005 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004006 }
Nick Wellnhofer9d08b342017-05-21 16:46:12 +02004007 set1->nodeTab[set1->nodeNr++] = n2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004008skip_node:
4009 {}
4010 }
4011 }
4012 set2->nodeNr = 0;
4013 return(set1);
4014}
4015
4016/**
4017 * xmlXPathNodeSetMergeAndClearNoDupls:
4018 * @set1: the first NodeSet or NULL
4019 * @set2: the second NodeSet
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004020 *
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004021 * Merges two nodesets, all nodes from @set2 are added to @set1.
4022 * Doesn't check for duplicate nodes. Clears set2.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004023 *
4024 * Returns @set1 once extended or NULL in case of error.
4025 */
4026static xmlNodeSetPtr
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004027xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004028{
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004029 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004030 int i;
4031 xmlNodePtr n2;
4032
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004033 for (i = 0;i < set2->nodeNr;i++) {
4034 n2 = set2->nodeTab[i];
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004035 if (set1->nodeMax == 0) {
4036 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4037 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4038 if (set1->nodeTab == NULL) {
4039 xmlXPathErrMemory(NULL, "merging nodeset\n");
4040 return(NULL);
4041 }
4042 memset(set1->nodeTab, 0,
4043 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4044 set1->nodeMax = XML_NODESET_DEFAULT;
4045 } else if (set1->nodeNr >= set1->nodeMax) {
4046 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004047
Daniel Veillardcd852ad2012-07-30 10:12:18 +08004048 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4049 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4050 return(NULL);
4051 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004052 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004053 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004054 if (temp == NULL) {
4055 xmlXPathErrMemory(NULL, "merging nodeset\n");
4056 return(NULL);
4057 }
4058 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004059 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004060 }
4061 set1->nodeTab[set1->nodeNr++] = n2;
4062 }
4063 }
4064 set2->nodeNr = 0;
4065 return(set1);
4066}
Daniel Veillard75be0132002-03-13 10:03:35 +00004067
4068/**
Owen Taylor3473f882001-02-23 17:55:21 +00004069 * xmlXPathNodeSetDel:
4070 * @cur: the initial node set
4071 * @val: an xmlNodePtr
4072 *
4073 * Removes an xmlNodePtr from an existing NodeSet
4074 */
4075void
4076xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4077 int i;
4078
4079 if (cur == NULL) return;
4080 if (val == NULL) return;
4081
4082 /*
William M. Brack08171912003-12-29 02:52:11 +00004083 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004084 */
4085 for (i = 0;i < cur->nodeNr;i++)
4086 if (cur->nodeTab[i] == val) break;
4087
William M. Brack08171912003-12-29 02:52:11 +00004088 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004089#ifdef DEBUG
Daniel Veillard45490ae2008-07-29 09:13:19 +00004090 xmlGenericError(xmlGenericErrorContext,
Owen Taylor3473f882001-02-23 17:55:21 +00004091 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4092 val->name);
4093#endif
4094 return;
4095 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004096 if ((cur->nodeTab[i] != NULL) &&
4097 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4098 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004099 cur->nodeNr--;
4100 for (;i < cur->nodeNr;i++)
4101 cur->nodeTab[i] = cur->nodeTab[i + 1];
4102 cur->nodeTab[cur->nodeNr] = NULL;
4103}
4104
4105/**
4106 * xmlXPathNodeSetRemove:
4107 * @cur: the initial node set
4108 * @val: the index to remove
4109 *
4110 * Removes an entry from an existing NodeSet list.
4111 */
4112void
4113xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4114 if (cur == NULL) return;
4115 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004116 if ((cur->nodeTab[val] != NULL) &&
4117 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4118 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004119 cur->nodeNr--;
4120 for (;val < cur->nodeNr;val++)
4121 cur->nodeTab[val] = cur->nodeTab[val + 1];
4122 cur->nodeTab[cur->nodeNr] = NULL;
4123}
4124
4125/**
4126 * xmlXPathFreeNodeSet:
4127 * @obj: the xmlNodeSetPtr to free
4128 *
4129 * Free the NodeSet compound (not the actual nodes !).
4130 */
4131void
4132xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4133 if (obj == NULL) return;
4134 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004135 int i;
4136
William M. Brack08171912003-12-29 02:52:11 +00004137 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004138 for (i = 0;i < obj->nodeNr;i++)
4139 if ((obj->nodeTab[i] != NULL) &&
4140 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4141 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004142 xmlFree(obj->nodeTab);
4143 }
Owen Taylor3473f882001-02-23 17:55:21 +00004144 xmlFree(obj);
4145}
4146
4147/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004148 * xmlXPathNodeSetClearFromPos:
4149 * @set: the node set to be cleared
4150 * @pos: the start position to clear from
Daniel Veillard45490ae2008-07-29 09:13:19 +00004151 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004152 * Clears the list from temporary XPath objects (e.g. namespace nodes
4153 * are feed) starting with the entry at @pos, but does *not* free the list
4154 * itself. Sets the length of the list to @pos.
4155 */
4156static void
4157xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4158{
Nick Wellnhofer95a92492017-05-21 15:18:58 +02004159 if ((set == NULL) || (pos >= set->nodeNr))
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004160 return;
4161 else if ((hasNsNodes)) {
4162 int i;
4163 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004164
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004165 for (i = pos; i < set->nodeNr; i++) {
4166 node = set->nodeTab[i];
4167 if ((node != NULL) &&
4168 (node->type == XML_NAMESPACE_DECL))
4169 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004170 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004171 }
4172 set->nodeNr = pos;
4173}
4174
4175/**
Nick Wellnhofer95a92492017-05-21 15:18:58 +02004176 * xmlXPathNodeSetClear:
4177 * @set: the node set to clear
4178 *
4179 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4180 * are feed), but does *not* free the list itself. Sets the length of the
4181 * list to 0.
4182 */
4183static void
4184xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4185{
4186 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4187}
4188
4189/**
4190 * xmlXPathNodeSetKeepLast:
4191 * @set: the node set to be cleared
4192 *
4193 * Move the last node to the first position and clear temporary XPath objects
4194 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4195 * to 1.
4196 */
4197static void
4198xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4199{
4200 int i;
4201 xmlNodePtr node;
4202
4203 if ((set == NULL) || (set->nodeNr <= 1))
4204 return;
4205 for (i = 0; i < set->nodeNr - 1; i++) {
4206 node = set->nodeTab[i];
4207 if ((node != NULL) &&
4208 (node->type == XML_NAMESPACE_DECL))
4209 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4210 }
4211 set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4212 set->nodeNr = 1;
4213}
4214
4215/**
Owen Taylor3473f882001-02-23 17:55:21 +00004216 * xmlXPathFreeValueTree:
4217 * @obj: the xmlNodeSetPtr to free
4218 *
4219 * Free the NodeSet compound and the actual tree, this is different
4220 * from xmlXPathFreeNodeSet()
4221 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004222static void
Owen Taylor3473f882001-02-23 17:55:21 +00004223xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4224 int i;
4225
4226 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004227
4228 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004229 for (i = 0;i < obj->nodeNr;i++) {
4230 if (obj->nodeTab[i] != NULL) {
4231 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4232 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4233 } else {
4234 xmlFreeNodeList(obj->nodeTab[i]);
4235 }
4236 }
4237 }
Owen Taylor3473f882001-02-23 17:55:21 +00004238 xmlFree(obj->nodeTab);
4239 }
Owen Taylor3473f882001-02-23 17:55:21 +00004240 xmlFree(obj);
4241}
4242
4243#if defined(DEBUG) || defined(DEBUG_STEP)
4244/**
4245 * xmlGenericErrorContextNodeSet:
4246 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004247 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004248 *
4249 * Quick display of a NodeSet
4250 */
4251void
4252xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4253 int i;
4254
4255 if (output == NULL) output = xmlGenericErrorContext;
4256 if (obj == NULL) {
4257 fprintf(output, "NodeSet == NULL !\n");
4258 return;
4259 }
4260 if (obj->nodeNr == 0) {
4261 fprintf(output, "NodeSet is empty\n");
4262 return;
4263 }
4264 if (obj->nodeTab == NULL) {
4265 fprintf(output, " nodeTab == NULL !\n");
4266 return;
4267 }
4268 for (i = 0; i < obj->nodeNr; i++) {
4269 if (obj->nodeTab[i] == NULL) {
4270 fprintf(output, " NULL !\n");
4271 return;
4272 }
4273 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4274 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4275 fprintf(output, " /");
4276 else if (obj->nodeTab[i]->name == NULL)
4277 fprintf(output, " noname!");
4278 else fprintf(output, " %s", obj->nodeTab[i]->name);
4279 }
4280 fprintf(output, "\n");
4281}
4282#endif
4283
4284/**
4285 * xmlXPathNewNodeSet:
4286 * @val: the NodePtr value
4287 *
4288 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4289 * it with the single Node @val
4290 *
4291 * Returns the newly created object.
4292 */
4293xmlXPathObjectPtr
4294xmlXPathNewNodeSet(xmlNodePtr val) {
4295 xmlXPathObjectPtr ret;
4296
4297 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4298 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004299 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004300 return(NULL);
4301 }
4302 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4303 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004304 ret->boolval = 0;
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004305 /* TODO: Check memory error. */
Owen Taylor3473f882001-02-23 17:55:21 +00004306 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004307 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004308#ifdef XP_DEBUG_OBJ_USAGE
4309 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4310#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004311 return(ret);
4312}
4313
4314/**
4315 * xmlXPathNewValueTree:
4316 * @val: the NodePtr value
4317 *
4318 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4319 * it with the tree root @val
4320 *
4321 * Returns the newly created object.
4322 */
4323xmlXPathObjectPtr
4324xmlXPathNewValueTree(xmlNodePtr val) {
4325 xmlXPathObjectPtr ret;
4326
4327 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4328 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004329 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004330 return(NULL);
4331 }
4332 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4333 ret->type = XPATH_XSLT_TREE;
Elliott Hughes7fbecab2019-01-10 16:42:03 -08004334 ret->boolval = 1;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004335 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004336 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004337#ifdef XP_DEBUG_OBJ_USAGE
4338 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4339#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004340 return(ret);
4341}
4342
4343/**
4344 * xmlXPathNewNodeSetList:
4345 * @val: an existing NodeSet
4346 *
4347 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4348 * it with the Nodeset @val
4349 *
4350 * Returns the newly created object.
4351 */
4352xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004353xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4354{
Owen Taylor3473f882001-02-23 17:55:21 +00004355 xmlXPathObjectPtr ret;
4356 int i;
4357
4358 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004359 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004360 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004361 ret = xmlXPathNewNodeSet(NULL);
4362 else {
4363 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004364 if (ret) {
4365 for (i = 1; i < val->nodeNr; ++i) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004366 /* TODO: Propagate memory error. */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004367 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4368 < 0) break;
4369 }
4370 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004371 }
Owen Taylor3473f882001-02-23 17:55:21 +00004372
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004373 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004374}
4375
4376/**
4377 * xmlXPathWrapNodeSet:
4378 * @val: the NodePtr value
4379 *
4380 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4381 *
4382 * Returns the newly created object.
4383 */
4384xmlXPathObjectPtr
4385xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4386 xmlXPathObjectPtr ret;
4387
4388 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4389 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004390 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004391 return(NULL);
4392 }
4393 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4394 ret->type = XPATH_NODESET;
4395 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004396#ifdef XP_DEBUG_OBJ_USAGE
4397 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4398#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004399 return(ret);
4400}
4401
4402/**
4403 * xmlXPathFreeNodeSetList:
4404 * @obj: an existing NodeSetList object
4405 *
4406 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4407 * the list contrary to xmlXPathFreeObject().
4408 */
4409void
4410xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4411 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004412#ifdef XP_DEBUG_OBJ_USAGE
4413 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4414#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004415 xmlFree(obj);
4416}
4417
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004418/**
4419 * xmlXPathDifference:
4420 * @nodes1: a node-set
4421 * @nodes2: a node-set
4422 *
4423 * Implements the EXSLT - Sets difference() function:
4424 * node-set set:difference (node-set, node-set)
4425 *
4426 * Returns the difference between the two node sets, or nodes1 if
4427 * nodes2 is empty
4428 */
4429xmlNodeSetPtr
4430xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4431 xmlNodeSetPtr ret;
4432 int i, l1;
4433 xmlNodePtr cur;
4434
4435 if (xmlXPathNodeSetIsEmpty(nodes2))
4436 return(nodes1);
4437
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004438 /* TODO: Check memory error. */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004439 ret = xmlXPathNodeSetCreate(NULL);
4440 if (xmlXPathNodeSetIsEmpty(nodes1))
4441 return(ret);
4442
4443 l1 = xmlXPathNodeSetGetLength(nodes1);
4444
4445 for (i = 0; i < l1; i++) {
4446 cur = xmlXPathNodeSetItem(nodes1, i);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004447 if (!xmlXPathNodeSetContains(nodes2, cur)) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004448 /* TODO: Propagate memory error. */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004449 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4450 break;
4451 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004452 }
4453 return(ret);
4454}
4455
4456/**
4457 * xmlXPathIntersection:
4458 * @nodes1: a node-set
4459 * @nodes2: a node-set
4460 *
4461 * Implements the EXSLT - Sets intersection() function:
4462 * node-set set:intersection (node-set, node-set)
4463 *
4464 * Returns a node set comprising the nodes that are within both the
4465 * node sets passed as arguments
4466 */
4467xmlNodeSetPtr
4468xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4469 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4470 int i, l1;
4471 xmlNodePtr cur;
4472
Daniel Veillardf88d8492008-04-01 08:00:31 +00004473 if (ret == NULL)
4474 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004475 if (xmlXPathNodeSetIsEmpty(nodes1))
4476 return(ret);
4477 if (xmlXPathNodeSetIsEmpty(nodes2))
4478 return(ret);
4479
4480 l1 = xmlXPathNodeSetGetLength(nodes1);
4481
4482 for (i = 0; i < l1; i++) {
4483 cur = xmlXPathNodeSetItem(nodes1, i);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004484 if (xmlXPathNodeSetContains(nodes2, cur)) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004485 /* TODO: Propagate memory error. */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004486 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4487 break;
4488 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004489 }
4490 return(ret);
4491}
4492
4493/**
4494 * xmlXPathDistinctSorted:
4495 * @nodes: a node-set, sorted by document order
4496 *
4497 * Implements the EXSLT - Sets distinct() function:
4498 * node-set set:distinct (node-set)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004499 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004500 * Returns a subset of the nodes contained in @nodes, or @nodes if
4501 * it is empty
4502 */
4503xmlNodeSetPtr
4504xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4505 xmlNodeSetPtr ret;
4506 xmlHashTablePtr hash;
4507 int i, l;
4508 xmlChar * strval;
4509 xmlNodePtr cur;
4510
4511 if (xmlXPathNodeSetIsEmpty(nodes))
4512 return(nodes);
4513
4514 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004515 if (ret == NULL)
4516 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004517 l = xmlXPathNodeSetGetLength(nodes);
4518 hash = xmlHashCreate (l);
4519 for (i = 0; i < l; i++) {
4520 cur = xmlXPathNodeSetItem(nodes, i);
4521 strval = xmlXPathCastNodeToString(cur);
4522 if (xmlHashLookup(hash, strval) == NULL) {
4523 xmlHashAddEntry(hash, strval, strval);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004524 /* TODO: Propagate memory error. */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004525 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4526 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004527 } else {
4528 xmlFree(strval);
4529 }
4530 }
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01004531 xmlHashFree(hash, xmlHashDefaultDeallocator);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004532 return(ret);
4533}
4534
4535/**
4536 * xmlXPathDistinct:
4537 * @nodes: a node-set
4538 *
4539 * Implements the EXSLT - Sets distinct() function:
4540 * node-set set:distinct (node-set)
4541 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4542 * is called with the sorted node-set
4543 *
4544 * Returns a subset of the nodes contained in @nodes, or @nodes if
4545 * it is empty
4546 */
4547xmlNodeSetPtr
4548xmlXPathDistinct (xmlNodeSetPtr nodes) {
4549 if (xmlXPathNodeSetIsEmpty(nodes))
4550 return(nodes);
4551
4552 xmlXPathNodeSetSort(nodes);
4553 return(xmlXPathDistinctSorted(nodes));
4554}
4555
4556/**
4557 * xmlXPathHasSameNodes:
4558 * @nodes1: a node-set
4559 * @nodes2: a node-set
4560 *
4561 * Implements the EXSLT - Sets has-same-nodes function:
4562 * boolean set:has-same-node(node-set, node-set)
4563 *
4564 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4565 * otherwise
4566 */
4567int
4568xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4569 int i, l;
4570 xmlNodePtr cur;
4571
4572 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4573 xmlXPathNodeSetIsEmpty(nodes2))
4574 return(0);
4575
4576 l = xmlXPathNodeSetGetLength(nodes1);
4577 for (i = 0; i < l; i++) {
4578 cur = xmlXPathNodeSetItem(nodes1, i);
4579 if (xmlXPathNodeSetContains(nodes2, cur))
4580 return(1);
4581 }
4582 return(0);
4583}
4584
4585/**
4586 * xmlXPathNodeLeadingSorted:
4587 * @nodes: a node-set, sorted by document order
4588 * @node: a node
4589 *
4590 * Implements the EXSLT - Sets leading() function:
4591 * node-set set:leading (node-set, node-set)
4592 *
4593 * Returns the nodes in @nodes that precede @node in document order,
4594 * @nodes if @node is NULL or an empty node-set if @nodes
4595 * doesn't contain @node
4596 */
4597xmlNodeSetPtr
4598xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4599 int i, l;
4600 xmlNodePtr cur;
4601 xmlNodeSetPtr ret;
4602
4603 if (node == NULL)
4604 return(nodes);
4605
4606 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004607 if (ret == NULL)
4608 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004609 if (xmlXPathNodeSetIsEmpty(nodes) ||
4610 (!xmlXPathNodeSetContains(nodes, node)))
4611 return(ret);
4612
4613 l = xmlXPathNodeSetGetLength(nodes);
4614 for (i = 0; i < l; i++) {
4615 cur = xmlXPathNodeSetItem(nodes, i);
4616 if (cur == node)
4617 break;
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004618 /* TODO: Propagate memory error. */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004619 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4620 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004621 }
4622 return(ret);
4623}
4624
4625/**
4626 * xmlXPathNodeLeading:
4627 * @nodes: a node-set
4628 * @node: a node
4629 *
4630 * Implements the EXSLT - Sets leading() function:
4631 * node-set set:leading (node-set, node-set)
4632 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4633 * is called.
4634 *
4635 * Returns the nodes in @nodes that precede @node in document order,
4636 * @nodes if @node is NULL or an empty node-set if @nodes
4637 * doesn't contain @node
4638 */
4639xmlNodeSetPtr
4640xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4641 xmlXPathNodeSetSort(nodes);
4642 return(xmlXPathNodeLeadingSorted(nodes, node));
4643}
4644
4645/**
4646 * xmlXPathLeadingSorted:
4647 * @nodes1: a node-set, sorted by document order
4648 * @nodes2: a node-set, sorted by document order
4649 *
4650 * Implements the EXSLT - Sets leading() function:
4651 * node-set set:leading (node-set, node-set)
4652 *
4653 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4654 * in document order, @nodes1 if @nodes2 is NULL or empty or
4655 * an empty node-set if @nodes1 doesn't contain @nodes2
4656 */
4657xmlNodeSetPtr
4658xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4659 if (xmlXPathNodeSetIsEmpty(nodes2))
4660 return(nodes1);
4661 return(xmlXPathNodeLeadingSorted(nodes1,
4662 xmlXPathNodeSetItem(nodes2, 1)));
4663}
4664
4665/**
4666 * xmlXPathLeading:
4667 * @nodes1: a node-set
4668 * @nodes2: a node-set
4669 *
4670 * Implements the EXSLT - Sets leading() function:
4671 * node-set set:leading (node-set, node-set)
4672 * @nodes1 and @nodes2 are sorted by document order, then
4673 * #exslSetsLeadingSorted is called.
4674 *
4675 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4676 * in document order, @nodes1 if @nodes2 is NULL or empty or
4677 * an empty node-set if @nodes1 doesn't contain @nodes2
4678 */
4679xmlNodeSetPtr
4680xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4681 if (xmlXPathNodeSetIsEmpty(nodes2))
4682 return(nodes1);
4683 if (xmlXPathNodeSetIsEmpty(nodes1))
4684 return(xmlXPathNodeSetCreate(NULL));
4685 xmlXPathNodeSetSort(nodes1);
4686 xmlXPathNodeSetSort(nodes2);
4687 return(xmlXPathNodeLeadingSorted(nodes1,
4688 xmlXPathNodeSetItem(nodes2, 1)));
4689}
4690
4691/**
4692 * xmlXPathNodeTrailingSorted:
4693 * @nodes: a node-set, sorted by document order
4694 * @node: a node
4695 *
4696 * Implements the EXSLT - Sets trailing() function:
4697 * node-set set:trailing (node-set, node-set)
4698 *
4699 * Returns the nodes in @nodes that follow @node in document order,
4700 * @nodes if @node is NULL or an empty node-set if @nodes
4701 * doesn't contain @node
4702 */
4703xmlNodeSetPtr
4704xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4705 int i, l;
4706 xmlNodePtr cur;
4707 xmlNodeSetPtr ret;
4708
4709 if (node == NULL)
4710 return(nodes);
4711
4712 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004713 if (ret == NULL)
4714 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004715 if (xmlXPathNodeSetIsEmpty(nodes) ||
4716 (!xmlXPathNodeSetContains(nodes, node)))
4717 return(ret);
4718
4719 l = xmlXPathNodeSetGetLength(nodes);
William M. Brack97ac8192007-06-06 17:19:24 +00004720 for (i = l - 1; i >= 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004721 cur = xmlXPathNodeSetItem(nodes, i);
4722 if (cur == node)
4723 break;
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004724 /* TODO: Propagate memory error. */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004725 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4726 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004727 }
William M. Brack97ac8192007-06-06 17:19:24 +00004728 xmlXPathNodeSetSort(ret); /* bug 413451 */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004729 return(ret);
4730}
4731
4732/**
4733 * xmlXPathNodeTrailing:
4734 * @nodes: a node-set
4735 * @node: a node
4736 *
4737 * Implements the EXSLT - Sets trailing() function:
4738 * node-set set:trailing (node-set, node-set)
4739 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4740 * is called.
4741 *
4742 * Returns the nodes in @nodes that follow @node in document order,
4743 * @nodes if @node is NULL or an empty node-set if @nodes
4744 * doesn't contain @node
4745 */
4746xmlNodeSetPtr
4747xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4748 xmlXPathNodeSetSort(nodes);
4749 return(xmlXPathNodeTrailingSorted(nodes, node));
4750}
4751
4752/**
4753 * xmlXPathTrailingSorted:
4754 * @nodes1: a node-set, sorted by document order
4755 * @nodes2: a node-set, sorted by document order
4756 *
4757 * Implements the EXSLT - Sets trailing() function:
4758 * node-set set:trailing (node-set, node-set)
4759 *
4760 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4761 * in document order, @nodes1 if @nodes2 is NULL or empty or
4762 * an empty node-set if @nodes1 doesn't contain @nodes2
4763 */
4764xmlNodeSetPtr
4765xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4766 if (xmlXPathNodeSetIsEmpty(nodes2))
4767 return(nodes1);
4768 return(xmlXPathNodeTrailingSorted(nodes1,
4769 xmlXPathNodeSetItem(nodes2, 0)));
4770}
4771
4772/**
4773 * xmlXPathTrailing:
4774 * @nodes1: a node-set
4775 * @nodes2: a node-set
4776 *
4777 * Implements the EXSLT - Sets trailing() function:
4778 * node-set set:trailing (node-set, node-set)
4779 * @nodes1 and @nodes2 are sorted by document order, then
4780 * #xmlXPathTrailingSorted is called.
4781 *
4782 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4783 * in document order, @nodes1 if @nodes2 is NULL or empty or
4784 * an empty node-set if @nodes1 doesn't contain @nodes2
4785 */
4786xmlNodeSetPtr
4787xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4788 if (xmlXPathNodeSetIsEmpty(nodes2))
4789 return(nodes1);
4790 if (xmlXPathNodeSetIsEmpty(nodes1))
4791 return(xmlXPathNodeSetCreate(NULL));
4792 xmlXPathNodeSetSort(nodes1);
4793 xmlXPathNodeSetSort(nodes2);
4794 return(xmlXPathNodeTrailingSorted(nodes1,
4795 xmlXPathNodeSetItem(nodes2, 0)));
4796}
4797
Owen Taylor3473f882001-02-23 17:55:21 +00004798/************************************************************************
4799 * *
4800 * Routines to handle extra functions *
4801 * *
4802 ************************************************************************/
4803
4804/**
4805 * xmlXPathRegisterFunc:
4806 * @ctxt: the XPath context
4807 * @name: the function name
4808 * @f: the function implementation or NULL
4809 *
4810 * Register a new function. If @f is NULL it unregisters the function
4811 *
4812 * Returns 0 in case of success, -1 in case of error
4813 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004814int
Owen Taylor3473f882001-02-23 17:55:21 +00004815xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4816 xmlXPathFunction f) {
4817 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4818}
4819
4820/**
4821 * xmlXPathRegisterFuncNS:
4822 * @ctxt: the XPath context
4823 * @name: the function name
4824 * @ns_uri: the function namespace URI
4825 * @f: the function implementation or NULL
4826 *
4827 * Register a new function. If @f is NULL it unregisters the function
4828 *
4829 * Returns 0 in case of success, -1 in case of error
4830 */
4831int
4832xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4833 const xmlChar *ns_uri, xmlXPathFunction f) {
4834 if (ctxt == NULL)
4835 return(-1);
4836 if (name == NULL)
4837 return(-1);
4838
4839 if (ctxt->funcHash == NULL)
4840 ctxt->funcHash = xmlHashCreate(0);
4841 if (ctxt->funcHash == NULL)
4842 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004843 if (f == NULL)
4844 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
Nick Wellnhofer13acadb2017-11-12 17:28:12 +01004845XML_IGNORE_PEDANTIC_WARNINGS
4846 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4847XML_POP_WARNINGS
Owen Taylor3473f882001-02-23 17:55:21 +00004848}
4849
4850/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004851 * xmlXPathRegisterFuncLookup:
4852 * @ctxt: the XPath context
4853 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004854 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004855 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004856 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004857 */
4858void
4859xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4860 xmlXPathFuncLookupFunc f,
4861 void *funcCtxt) {
4862 if (ctxt == NULL)
4863 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004864 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004865 ctxt->funcLookupData = funcCtxt;
4866}
4867
4868/**
Owen Taylor3473f882001-02-23 17:55:21 +00004869 * xmlXPathFunctionLookup:
4870 * @ctxt: the XPath context
4871 * @name: the function name
4872 *
4873 * Search in the Function array of the context for the given
4874 * function.
4875 *
4876 * Returns the xmlXPathFunction or NULL if not found
4877 */
4878xmlXPathFunction
4879xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004880 if (ctxt == NULL)
4881 return (NULL);
4882
4883 if (ctxt->funcLookupFunc != NULL) {
4884 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004885 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004886
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004887 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004888 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004889 if (ret != NULL)
4890 return(ret);
4891 }
Owen Taylor3473f882001-02-23 17:55:21 +00004892 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4893}
4894
4895/**
4896 * xmlXPathFunctionLookupNS:
4897 * @ctxt: the XPath context
4898 * @name: the function name
4899 * @ns_uri: the function namespace URI
4900 *
4901 * Search in the Function array of the context for the given
4902 * function.
4903 *
4904 * Returns the xmlXPathFunction or NULL if not found
4905 */
4906xmlXPathFunction
4907xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4908 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004909 xmlXPathFunction ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004910
Owen Taylor3473f882001-02-23 17:55:21 +00004911 if (ctxt == NULL)
4912 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004913 if (name == NULL)
4914 return(NULL);
4915
Thomas Broyerba4ad322001-07-26 16:55:21 +00004916 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004917 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004918
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004919 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004920 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004921 if (ret != NULL)
4922 return(ret);
4923 }
4924
4925 if (ctxt->funcHash == NULL)
4926 return(NULL);
4927
Nick Wellnhofer13acadb2017-11-12 17:28:12 +01004928XML_IGNORE_PEDANTIC_WARNINGS
4929 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4930XML_POP_WARNINGS
William M. Brackad0e67c2004-12-01 14:35:10 +00004931 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004932}
4933
4934/**
4935 * xmlXPathRegisteredFuncsCleanup:
4936 * @ctxt: the XPath context
4937 *
4938 * Cleanup the XPath context data associated to registered functions
4939 */
4940void
4941xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4942 if (ctxt == NULL)
4943 return;
4944
4945 xmlHashFree(ctxt->funcHash, NULL);
4946 ctxt->funcHash = NULL;
4947}
4948
4949/************************************************************************
4950 * *
William M. Brack08171912003-12-29 02:52:11 +00004951 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004952 * *
4953 ************************************************************************/
4954
4955/**
4956 * xmlXPathRegisterVariable:
4957 * @ctxt: the XPath context
4958 * @name: the variable name
4959 * @value: the variable value or NULL
4960 *
4961 * Register a new variable value. If @value is NULL it unregisters
4962 * the variable
4963 *
4964 * Returns 0 in case of success, -1 in case of error
4965 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004966int
Owen Taylor3473f882001-02-23 17:55:21 +00004967xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4968 xmlXPathObjectPtr value) {
4969 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4970}
4971
4972/**
4973 * xmlXPathRegisterVariableNS:
4974 * @ctxt: the XPath context
4975 * @name: the variable name
4976 * @ns_uri: the variable namespace URI
4977 * @value: the variable value or NULL
4978 *
4979 * Register a new variable value. If @value is NULL it unregisters
4980 * the variable
4981 *
4982 * Returns 0 in case of success, -1 in case of error
4983 */
4984int
4985xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4986 const xmlChar *ns_uri,
4987 xmlXPathObjectPtr value) {
4988 if (ctxt == NULL)
4989 return(-1);
4990 if (name == NULL)
4991 return(-1);
4992
4993 if (ctxt->varHash == NULL)
4994 ctxt->varHash = xmlHashCreate(0);
4995 if (ctxt->varHash == NULL)
4996 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004997 if (value == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004998 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01004999 xmlXPathFreeObjectEntry));
Owen Taylor3473f882001-02-23 17:55:21 +00005000 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005001 (void *) value, xmlXPathFreeObjectEntry));
Owen Taylor3473f882001-02-23 17:55:21 +00005002}
5003
5004/**
5005 * xmlXPathRegisterVariableLookup:
5006 * @ctxt: the XPath context
5007 * @f: the lookup function
5008 * @data: the lookup data
5009 *
5010 * register an external mechanism to do variable lookup
5011 */
5012void
5013xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5014 xmlXPathVariableLookupFunc f, void *data) {
5015 if (ctxt == NULL)
5016 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00005017 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00005018 ctxt->varLookupData = data;
5019}
5020
5021/**
5022 * xmlXPathVariableLookup:
5023 * @ctxt: the XPath context
5024 * @name: the variable name
5025 *
5026 * Search in the Variable array of the context for the given
5027 * variable value.
5028 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005029 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005030 */
5031xmlXPathObjectPtr
5032xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5033 if (ctxt == NULL)
5034 return(NULL);
5035
5036 if (ctxt->varLookupFunc != NULL) {
5037 xmlXPathObjectPtr ret;
5038
5039 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5040 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00005041 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005042 }
5043 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5044}
5045
5046/**
5047 * xmlXPathVariableLookupNS:
5048 * @ctxt: the XPath context
5049 * @name: the variable name
5050 * @ns_uri: the variable namespace URI
5051 *
5052 * Search in the Variable array of the context for the given
Daniel Veillard45490ae2008-07-29 09:13:19 +00005053 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00005054 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005055 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005056 */
5057xmlXPathObjectPtr
5058xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5059 const xmlChar *ns_uri) {
5060 if (ctxt == NULL)
5061 return(NULL);
5062
5063 if (ctxt->varLookupFunc != NULL) {
5064 xmlXPathObjectPtr ret;
5065
5066 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5067 (ctxt->varLookupData, name, ns_uri);
5068 if (ret != NULL) return(ret);
5069 }
5070
5071 if (ctxt->varHash == NULL)
5072 return(NULL);
5073 if (name == NULL)
5074 return(NULL);
5075
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005076 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00005077 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00005078}
5079
5080/**
5081 * xmlXPathRegisteredVariablesCleanup:
5082 * @ctxt: the XPath context
5083 *
5084 * Cleanup the XPath context data associated to registered variables
5085 */
5086void
5087xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5088 if (ctxt == NULL)
5089 return;
5090
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005091 xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
Owen Taylor3473f882001-02-23 17:55:21 +00005092 ctxt->varHash = NULL;
5093}
5094
5095/**
5096 * xmlXPathRegisterNs:
5097 * @ctxt: the XPath context
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005098 * @prefix: the namespace prefix cannot be NULL or empty string
Owen Taylor3473f882001-02-23 17:55:21 +00005099 * @ns_uri: the namespace name
5100 *
5101 * Register a new namespace. If @ns_uri is NULL it unregisters
5102 * the namespace
5103 *
5104 * Returns 0 in case of success, -1 in case of error
5105 */
5106int
5107xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5108 const xmlChar *ns_uri) {
5109 if (ctxt == NULL)
5110 return(-1);
5111 if (prefix == NULL)
5112 return(-1);
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005113 if (prefix[0] == 0)
5114 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005115
5116 if (ctxt->nsHash == NULL)
5117 ctxt->nsHash = xmlHashCreate(10);
5118 if (ctxt->nsHash == NULL)
5119 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00005120 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00005121 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005122 xmlHashDefaultDeallocator));
Daniel Veillard42766c02002-08-22 20:52:17 +00005123 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005124 xmlHashDefaultDeallocator));
Owen Taylor3473f882001-02-23 17:55:21 +00005125}
5126
5127/**
5128 * xmlXPathNsLookup:
5129 * @ctxt: the XPath context
5130 * @prefix: the namespace prefix value
5131 *
5132 * Search in the namespace declaration array of the context for the given
5133 * namespace name associated to the given prefix
5134 *
5135 * Returns the value or NULL if not found
5136 */
5137const xmlChar *
5138xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5139 if (ctxt == NULL)
5140 return(NULL);
5141 if (prefix == NULL)
5142 return(NULL);
5143
5144#ifdef XML_XML_NAMESPACE
5145 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5146 return(XML_XML_NAMESPACE);
5147#endif
5148
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005149 if (ctxt->namespaces != NULL) {
5150 int i;
5151
5152 for (i = 0;i < ctxt->nsNr;i++) {
5153 if ((ctxt->namespaces[i] != NULL) &&
5154 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5155 return(ctxt->namespaces[i]->href);
5156 }
5157 }
Owen Taylor3473f882001-02-23 17:55:21 +00005158
5159 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5160}
5161
5162/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005163 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005164 * @ctxt: the XPath context
5165 *
5166 * Cleanup the XPath context data associated to registered variables
5167 */
5168void
5169xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5170 if (ctxt == NULL)
5171 return;
5172
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005173 xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
Owen Taylor3473f882001-02-23 17:55:21 +00005174 ctxt->nsHash = NULL;
5175}
5176
5177/************************************************************************
5178 * *
5179 * Routines to handle Values *
5180 * *
5181 ************************************************************************/
5182
William M. Brack08171912003-12-29 02:52:11 +00005183/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005184
5185/**
5186 * xmlXPathNewFloat:
5187 * @val: the double value
5188 *
5189 * Create a new xmlXPathObjectPtr of type double and of value @val
5190 *
5191 * Returns the newly created object.
5192 */
5193xmlXPathObjectPtr
5194xmlXPathNewFloat(double val) {
5195 xmlXPathObjectPtr ret;
5196
5197 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5198 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005199 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005200 return(NULL);
5201 }
5202 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5203 ret->type = XPATH_NUMBER;
5204 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005205#ifdef XP_DEBUG_OBJ_USAGE
5206 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5207#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005208 return(ret);
5209}
5210
5211/**
5212 * xmlXPathNewBoolean:
5213 * @val: the boolean value
5214 *
5215 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5216 *
5217 * Returns the newly created object.
5218 */
5219xmlXPathObjectPtr
5220xmlXPathNewBoolean(int val) {
5221 xmlXPathObjectPtr ret;
5222
5223 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5224 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005225 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005226 return(NULL);
5227 }
5228 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5229 ret->type = XPATH_BOOLEAN;
5230 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005231#ifdef XP_DEBUG_OBJ_USAGE
5232 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5233#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005234 return(ret);
5235}
5236
5237/**
5238 * xmlXPathNewString:
5239 * @val: the xmlChar * value
5240 *
5241 * Create a new xmlXPathObjectPtr of type string and of value @val
5242 *
5243 * Returns the newly created object.
5244 */
5245xmlXPathObjectPtr
5246xmlXPathNewString(const xmlChar *val) {
5247 xmlXPathObjectPtr ret;
5248
5249 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5250 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005251 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005252 return(NULL);
5253 }
5254 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5255 ret->type = XPATH_STRING;
5256 if (val != NULL)
5257 ret->stringval = xmlStrdup(val);
5258 else
5259 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005260#ifdef XP_DEBUG_OBJ_USAGE
5261 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5262#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005263 return(ret);
5264}
5265
5266/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005267 * xmlXPathWrapString:
5268 * @val: the xmlChar * value
5269 *
5270 * Wraps the @val string into an XPath object.
5271 *
5272 * Returns the newly created object.
5273 */
5274xmlXPathObjectPtr
5275xmlXPathWrapString (xmlChar *val) {
5276 xmlXPathObjectPtr ret;
5277
5278 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5279 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005280 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005281 return(NULL);
5282 }
5283 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5284 ret->type = XPATH_STRING;
5285 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005286#ifdef XP_DEBUG_OBJ_USAGE
5287 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5288#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005289 return(ret);
5290}
5291
5292/**
Owen Taylor3473f882001-02-23 17:55:21 +00005293 * xmlXPathNewCString:
5294 * @val: the char * value
5295 *
5296 * Create a new xmlXPathObjectPtr of type string and of value @val
5297 *
5298 * Returns the newly created object.
5299 */
5300xmlXPathObjectPtr
5301xmlXPathNewCString(const char *val) {
5302 xmlXPathObjectPtr ret;
5303
5304 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5305 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005306 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005307 return(NULL);
5308 }
5309 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5310 ret->type = XPATH_STRING;
5311 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005312#ifdef XP_DEBUG_OBJ_USAGE
5313 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5314#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005315 return(ret);
5316}
5317
5318/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005319 * xmlXPathWrapCString:
5320 * @val: the char * value
5321 *
5322 * Wraps a string into an XPath object.
5323 *
5324 * Returns the newly created object.
5325 */
5326xmlXPathObjectPtr
5327xmlXPathWrapCString (char * val) {
5328 return(xmlXPathWrapString((xmlChar *)(val)));
5329}
5330
5331/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005332 * xmlXPathWrapExternal:
5333 * @val: the user data
5334 *
5335 * Wraps the @val data into an XPath object.
5336 *
5337 * Returns the newly created object.
5338 */
5339xmlXPathObjectPtr
5340xmlXPathWrapExternal (void *val) {
5341 xmlXPathObjectPtr ret;
5342
5343 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5344 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005345 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005346 return(NULL);
5347 }
5348 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5349 ret->type = XPATH_USERS;
5350 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005351#ifdef XP_DEBUG_OBJ_USAGE
5352 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5353#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005354 return(ret);
5355}
5356
5357/**
Owen Taylor3473f882001-02-23 17:55:21 +00005358 * xmlXPathObjectCopy:
5359 * @val: the original object
5360 *
5361 * allocate a new copy of a given object
5362 *
5363 * Returns the newly created object.
5364 */
5365xmlXPathObjectPtr
5366xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5367 xmlXPathObjectPtr ret;
5368
5369 if (val == NULL)
5370 return(NULL);
5371
5372 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5373 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005374 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005375 return(NULL);
5376 }
5377 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005378#ifdef XP_DEBUG_OBJ_USAGE
5379 xmlXPathDebugObjUsageRequested(NULL, val->type);
5380#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005381 switch (val->type) {
5382 case XPATH_BOOLEAN:
5383 case XPATH_NUMBER:
5384 case XPATH_POINT:
5385 case XPATH_RANGE:
5386 break;
5387 case XPATH_STRING:
5388 ret->stringval = xmlStrdup(val->stringval);
5389 break;
5390 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005391#if 0
5392/*
5393 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5394 this previous handling is no longer correct, and can cause some serious
5395 problems (ref. bug 145547)
5396*/
Owen Taylor3473f882001-02-23 17:55:21 +00005397 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005398 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005399 xmlNodePtr cur, tmp;
5400 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005401
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005402 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005403 top = xmlNewDoc(NULL);
5404 top->name = (char *)
5405 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005406 ret->user = top;
5407 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005408 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005409 cur = val->nodesetval->nodeTab[0]->children;
5410 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005411 tmp = xmlDocCopyNode(cur, top, 1);
5412 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005413 cur = cur->next;
5414 }
5415 }
William M. Bracke9449c52004-07-11 14:41:20 +00005416
Daniel Veillard9adc0462003-03-24 18:39:54 +00005417 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005418 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005419 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005420 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005421 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005422#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005423 case XPATH_NODESET:
Haibo Huangcfd91dc2020-07-30 23:01:33 -07005424 /* TODO: Check memory error. */
Owen Taylor3473f882001-02-23 17:55:21 +00005425 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005426 /* Do not deallocate the copied tree value */
5427 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005428 break;
5429 case XPATH_LOCATIONSET:
5430#ifdef LIBXML_XPTR_ENABLED
5431 {
5432 xmlLocationSetPtr loc = val->user;
5433 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5434 break;
5435 }
5436#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005437 case XPATH_USERS:
5438 ret->user = val->user;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005439 break;
Thomas Broyer47334c02001-10-07 16:41:52 +00005440 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005441 xmlGenericError(xmlGenericErrorContext,
5442 "xmlXPathObjectCopy: unsupported type %d\n",
5443 val->type);
5444 break;
5445 }
5446 return(ret);
5447}
5448
5449/**
5450 * xmlXPathFreeObject:
5451 * @obj: the object to free
5452 *
5453 * Free up an xmlXPathObjectPtr object.
5454 */
5455void
5456xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5457 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005458 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005459 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005460#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005461 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005462 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005463 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005464 } else
5465#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005466 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005467 if (obj->nodesetval != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005468 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005469 } else {
5470 if (obj->nodesetval != NULL)
5471 xmlXPathFreeNodeSet(obj->nodesetval);
5472 }
Owen Taylor3473f882001-02-23 17:55:21 +00005473#ifdef LIBXML_XPTR_ENABLED
5474 } else if (obj->type == XPATH_LOCATIONSET) {
5475 if (obj->user != NULL)
5476 xmlXPtrFreeLocationSet(obj->user);
5477#endif
5478 } else if (obj->type == XPATH_STRING) {
5479 if (obj->stringval != NULL)
5480 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005481 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005482#ifdef XP_DEBUG_OBJ_USAGE
5483 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5484#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00005485 xmlFree(obj);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005486}
Owen Taylor3473f882001-02-23 17:55:21 +00005487
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005488static void
5489xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5490 xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5491}
5492
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005493/**
5494 * xmlXPathReleaseObject:
5495 * @obj: the xmlXPathObjectPtr to free or to cache
5496 *
5497 * Depending on the state of the cache this frees the given
5498 * XPath object or stores it in the cache.
5499 */
5500static void
5501xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5502{
5503#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5504 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5505 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5506
5507#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5508
5509 if (obj == NULL)
5510 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005511 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005512 xmlXPathFreeObject(obj);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005513 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005514 xmlXPathContextCachePtr cache =
5515 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005516
5517 switch (obj->type) {
5518 case XPATH_NODESET:
5519 case XPATH_XSLT_TREE:
5520 if (obj->nodesetval != NULL) {
5521 if (obj->boolval) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00005522 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005523 * It looks like the @boolval is used for
5524 * evaluation if this an XSLT Result Tree Fragment.
5525 * TODO: Check if this assumption is correct.
5526 */
5527 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5528 xmlXPathFreeValueTree(obj->nodesetval);
5529 obj->nodesetval = NULL;
5530 } else if ((obj->nodesetval->nodeMax <= 40) &&
5531 (XP_CACHE_WANTS(cache->nodesetObjs,
5532 cache->maxNodeset)))
5533 {
5534 XP_CACHE_ADD(cache->nodesetObjs, obj);
5535 goto obj_cached;
5536 } else {
5537 xmlXPathFreeNodeSet(obj->nodesetval);
5538 obj->nodesetval = NULL;
5539 }
5540 }
5541 break;
5542 case XPATH_STRING:
5543 if (obj->stringval != NULL)
5544 xmlFree(obj->stringval);
5545
5546 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5547 XP_CACHE_ADD(cache->stringObjs, obj);
5548 goto obj_cached;
5549 }
5550 break;
5551 case XPATH_BOOLEAN:
5552 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5553 XP_CACHE_ADD(cache->booleanObjs, obj);
5554 goto obj_cached;
5555 }
5556 break;
5557 case XPATH_NUMBER:
5558 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5559 XP_CACHE_ADD(cache->numberObjs, obj);
5560 goto obj_cached;
5561 }
5562 break;
5563#ifdef LIBXML_XPTR_ENABLED
5564 case XPATH_LOCATIONSET:
5565 if (obj->user != NULL) {
5566 xmlXPtrFreeLocationSet(obj->user);
5567 }
5568 goto free_obj;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005569#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005570 default:
5571 goto free_obj;
5572 }
5573
5574 /*
5575 * Fallback to adding to the misc-objects slot.
5576 */
5577 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5578 XP_CACHE_ADD(cache->miscObjs, obj);
5579 } else
5580 goto free_obj;
5581
5582obj_cached:
5583
5584#ifdef XP_DEBUG_OBJ_USAGE
5585 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5586#endif
5587
5588 if (obj->nodesetval != NULL) {
5589 xmlNodeSetPtr tmpset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005590
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005591 /*
5592 * TODO: Due to those nasty ns-nodes, we need to traverse
5593 * the list and free the ns-nodes.
5594 * URGENT TODO: Check if it's actually slowing things down.
5595 * Maybe we shouldn't try to preserve the list.
5596 */
5597 if (tmpset->nodeNr > 1) {
5598 int i;
5599 xmlNodePtr node;
5600
5601 for (i = 0; i < tmpset->nodeNr; i++) {
5602 node = tmpset->nodeTab[i];
5603 if ((node != NULL) &&
5604 (node->type == XML_NAMESPACE_DECL))
5605 {
5606 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5607 }
5608 }
5609 } else if (tmpset->nodeNr == 1) {
5610 if ((tmpset->nodeTab[0] != NULL) &&
5611 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5612 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005613 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005614 tmpset->nodeNr = 0;
5615 memset(obj, 0, sizeof(xmlXPathObject));
5616 obj->nodesetval = tmpset;
5617 } else
5618 memset(obj, 0, sizeof(xmlXPathObject));
5619
5620 return;
5621
5622free_obj:
5623 /*
5624 * Cache is full; free the object.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005625 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005626 if (obj->nodesetval != NULL)
5627 xmlXPathFreeNodeSet(obj->nodesetval);
5628#ifdef XP_DEBUG_OBJ_USAGE
5629 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5630#endif
5631 xmlFree(obj);
5632 }
5633 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005634}
5635
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005636
5637/************************************************************************
5638 * *
5639 * Type Casting Routines *
5640 * *
5641 ************************************************************************/
5642
5643/**
5644 * xmlXPathCastBooleanToString:
5645 * @val: a boolean
5646 *
5647 * Converts a boolean to its string value.
5648 *
5649 * Returns a newly allocated string.
5650 */
5651xmlChar *
5652xmlXPathCastBooleanToString (int val) {
5653 xmlChar *ret;
5654 if (val)
5655 ret = xmlStrdup((const xmlChar *) "true");
5656 else
5657 ret = xmlStrdup((const xmlChar *) "false");
5658 return(ret);
5659}
5660
5661/**
5662 * xmlXPathCastNumberToString:
5663 * @val: a number
5664 *
5665 * Converts a number to its string value.
5666 *
5667 * Returns a newly allocated string.
5668 */
5669xmlChar *
5670xmlXPathCastNumberToString (double val) {
5671 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005672 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005673 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005674 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005675 break;
5676 case -1:
5677 ret = xmlStrdup((const xmlChar *) "-Infinity");
5678 break;
5679 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005680 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005681 ret = xmlStrdup((const xmlChar *) "NaN");
Nick Wellnhofer8813f392017-09-21 00:11:26 +02005682 } else if (val == 0) {
5683 /* Omit sign for negative zero. */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005684 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005685 } else {
5686 /* could be improved */
5687 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005688 xmlXPathFormatNumber(val, buf, 99);
5689 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005690 ret = xmlStrdup((const xmlChar *) buf);
5691 }
5692 }
5693 return(ret);
5694}
5695
5696/**
5697 * xmlXPathCastNodeToString:
5698 * @node: a node
5699 *
5700 * Converts a node to its string value.
5701 *
5702 * Returns a newly allocated string.
5703 */
5704xmlChar *
5705xmlXPathCastNodeToString (xmlNodePtr node) {
William M. Brackd611c882007-05-31 05:07:17 +00005706xmlChar *ret;
5707 if ((ret = xmlNodeGetContent(node)) == NULL)
5708 ret = xmlStrdup((const xmlChar *) "");
5709 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005710}
5711
5712/**
5713 * xmlXPathCastNodeSetToString:
5714 * @ns: a node-set
5715 *
5716 * Converts a node-set to its string value.
5717 *
5718 * Returns a newly allocated string.
5719 */
5720xmlChar *
5721xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5722 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5723 return(xmlStrdup((const xmlChar *) ""));
5724
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005725 if (ns->nodeNr > 1)
5726 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005727 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5728}
5729
5730/**
5731 * xmlXPathCastToString:
5732 * @val: an XPath object
5733 *
5734 * Converts an existing object to its string() equivalent
5735 *
Kasimier T. Buchcik50128ad2006-08-15 13:04:07 +00005736 * Returns the allocated string value of the object, NULL in case of error.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005737 * It's up to the caller to free the string memory with xmlFree().
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005738 */
5739xmlChar *
5740xmlXPathCastToString(xmlXPathObjectPtr val) {
5741 xmlChar *ret = NULL;
5742
5743 if (val == NULL)
5744 return(xmlStrdup((const xmlChar *) ""));
5745 switch (val->type) {
5746 case XPATH_UNDEFINED:
5747#ifdef DEBUG_EXPR
5748 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5749#endif
5750 ret = xmlStrdup((const xmlChar *) "");
5751 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005752 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005753 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005754 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5755 break;
5756 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005757 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005758 case XPATH_BOOLEAN:
5759 ret = xmlXPathCastBooleanToString(val->boolval);
5760 break;
5761 case XPATH_NUMBER: {
5762 ret = xmlXPathCastNumberToString(val->floatval);
5763 break;
5764 }
5765 case XPATH_USERS:
5766 case XPATH_POINT:
5767 case XPATH_RANGE:
5768 case XPATH_LOCATIONSET:
5769 TODO
5770 ret = xmlStrdup((const xmlChar *) "");
5771 break;
5772 }
5773 return(ret);
5774}
5775
5776/**
5777 * xmlXPathConvertString:
5778 * @val: an XPath object
5779 *
5780 * Converts an existing object to its string() equivalent
5781 *
5782 * Returns the new object, the old one is freed (or the operation
5783 * is done directly on @val)
5784 */
5785xmlXPathObjectPtr
5786xmlXPathConvertString(xmlXPathObjectPtr val) {
5787 xmlChar *res = NULL;
5788
5789 if (val == NULL)
5790 return(xmlXPathNewCString(""));
5791
5792 switch (val->type) {
5793 case XPATH_UNDEFINED:
5794#ifdef DEBUG_EXPR
5795 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5796#endif
5797 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005798 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005799 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005800 res = xmlXPathCastNodeSetToString(val->nodesetval);
5801 break;
5802 case XPATH_STRING:
5803 return(val);
5804 case XPATH_BOOLEAN:
5805 res = xmlXPathCastBooleanToString(val->boolval);
5806 break;
5807 case XPATH_NUMBER:
5808 res = xmlXPathCastNumberToString(val->floatval);
5809 break;
5810 case XPATH_USERS:
5811 case XPATH_POINT:
5812 case XPATH_RANGE:
5813 case XPATH_LOCATIONSET:
5814 TODO;
5815 break;
5816 }
5817 xmlXPathFreeObject(val);
5818 if (res == NULL)
5819 return(xmlXPathNewCString(""));
5820 return(xmlXPathWrapString(res));
5821}
5822
5823/**
5824 * xmlXPathCastBooleanToNumber:
5825 * @val: a boolean
5826 *
5827 * Converts a boolean to its number value
5828 *
5829 * Returns the number value
5830 */
5831double
5832xmlXPathCastBooleanToNumber(int val) {
5833 if (val)
5834 return(1.0);
5835 return(0.0);
5836}
5837
5838/**
5839 * xmlXPathCastStringToNumber:
5840 * @val: a string
5841 *
5842 * Converts a string to its number value
5843 *
5844 * Returns the number value
5845 */
5846double
5847xmlXPathCastStringToNumber(const xmlChar * val) {
5848 return(xmlXPathStringEvalNumber(val));
5849}
5850
5851/**
5852 * xmlXPathCastNodeToNumber:
5853 * @node: a node
5854 *
5855 * Converts a node to its number value
5856 *
5857 * Returns the number value
5858 */
5859double
5860xmlXPathCastNodeToNumber (xmlNodePtr node) {
5861 xmlChar *strval;
5862 double ret;
5863
5864 if (node == NULL)
Nick Wellnhofer8813f392017-09-21 00:11:26 +02005865 return(NAN);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005866 strval = xmlXPathCastNodeToString(node);
5867 if (strval == NULL)
Nick Wellnhofer8813f392017-09-21 00:11:26 +02005868 return(NAN);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005869 ret = xmlXPathCastStringToNumber(strval);
5870 xmlFree(strval);
5871
5872 return(ret);
5873}
5874
5875/**
5876 * xmlXPathCastNodeSetToNumber:
5877 * @ns: a node-set
5878 *
5879 * Converts a node-set to its number value
5880 *
5881 * Returns the number value
5882 */
5883double
5884xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5885 xmlChar *str;
5886 double ret;
5887
5888 if (ns == NULL)
Nick Wellnhofer8813f392017-09-21 00:11:26 +02005889 return(NAN);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005890 str = xmlXPathCastNodeSetToString(ns);
5891 ret = xmlXPathCastStringToNumber(str);
5892 xmlFree(str);
5893 return(ret);
5894}
5895
5896/**
5897 * xmlXPathCastToNumber:
5898 * @val: an XPath object
5899 *
5900 * Converts an XPath object to its number value
5901 *
5902 * Returns the number value
5903 */
5904double
5905xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5906 double ret = 0.0;
5907
5908 if (val == NULL)
Nick Wellnhofer8813f392017-09-21 00:11:26 +02005909 return(NAN);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005910 switch (val->type) {
5911 case XPATH_UNDEFINED:
Haibo Huangcfd91dc2020-07-30 23:01:33 -07005912#ifdef DEBUG_EXPR
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005913 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5914#endif
Nick Wellnhofer8813f392017-09-21 00:11:26 +02005915 ret = NAN;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005916 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005917 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005918 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005919 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5920 break;
5921 case XPATH_STRING:
5922 ret = xmlXPathCastStringToNumber(val->stringval);
5923 break;
5924 case XPATH_NUMBER:
5925 ret = val->floatval;
5926 break;
5927 case XPATH_BOOLEAN:
5928 ret = xmlXPathCastBooleanToNumber(val->boolval);
5929 break;
5930 case XPATH_USERS:
5931 case XPATH_POINT:
5932 case XPATH_RANGE:
5933 case XPATH_LOCATIONSET:
5934 TODO;
Nick Wellnhofer8813f392017-09-21 00:11:26 +02005935 ret = NAN;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005936 break;
5937 }
5938 return(ret);
5939}
5940
5941/**
5942 * xmlXPathConvertNumber:
5943 * @val: an XPath object
5944 *
5945 * Converts an existing object to its number() equivalent
5946 *
5947 * Returns the new object, the old one is freed (or the operation
5948 * is done directly on @val)
5949 */
5950xmlXPathObjectPtr
5951xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5952 xmlXPathObjectPtr ret;
5953
5954 if (val == NULL)
5955 return(xmlXPathNewFloat(0.0));
5956 if (val->type == XPATH_NUMBER)
5957 return(val);
5958 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5959 xmlXPathFreeObject(val);
5960 return(ret);
5961}
5962
5963/**
5964 * xmlXPathCastNumberToBoolean:
5965 * @val: a number
5966 *
5967 * Converts a number to its boolean value
5968 *
5969 * Returns the boolean value
5970 */
5971int
5972xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005973 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005974 return(0);
5975 return(1);
5976}
5977
5978/**
5979 * xmlXPathCastStringToBoolean:
5980 * @val: a string
5981 *
5982 * Converts a string to its boolean value
5983 *
5984 * Returns the boolean value
5985 */
5986int
5987xmlXPathCastStringToBoolean (const xmlChar *val) {
5988 if ((val == NULL) || (xmlStrlen(val) == 0))
5989 return(0);
5990 return(1);
5991}
5992
5993/**
5994 * xmlXPathCastNodeSetToBoolean:
5995 * @ns: a node-set
5996 *
5997 * Converts a node-set to its boolean value
5998 *
5999 * Returns the boolean value
6000 */
6001int
6002xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6003 if ((ns == NULL) || (ns->nodeNr == 0))
6004 return(0);
6005 return(1);
6006}
6007
6008/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006009 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006010 * @val: an XPath object
6011 *
6012 * Converts an XPath object to its boolean value
6013 *
6014 * Returns the boolean value
6015 */
6016int
6017xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6018 int ret = 0;
6019
6020 if (val == NULL)
6021 return(0);
6022 switch (val->type) {
6023 case XPATH_UNDEFINED:
6024#ifdef DEBUG_EXPR
6025 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6026#endif
6027 ret = 0;
6028 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006029 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00006030 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006031 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6032 break;
6033 case XPATH_STRING:
6034 ret = xmlXPathCastStringToBoolean(val->stringval);
6035 break;
6036 case XPATH_NUMBER:
6037 ret = xmlXPathCastNumberToBoolean(val->floatval);
6038 break;
6039 case XPATH_BOOLEAN:
6040 ret = val->boolval;
6041 break;
6042 case XPATH_USERS:
6043 case XPATH_POINT:
6044 case XPATH_RANGE:
6045 case XPATH_LOCATIONSET:
6046 TODO;
6047 ret = 0;
6048 break;
6049 }
6050 return(ret);
6051}
6052
6053
6054/**
6055 * xmlXPathConvertBoolean:
6056 * @val: an XPath object
6057 *
6058 * Converts an existing object to its boolean() equivalent
6059 *
6060 * Returns the new object, the old one is freed (or the operation
6061 * is done directly on @val)
6062 */
6063xmlXPathObjectPtr
6064xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6065 xmlXPathObjectPtr ret;
6066
6067 if (val == NULL)
6068 return(xmlXPathNewBoolean(0));
6069 if (val->type == XPATH_BOOLEAN)
6070 return(val);
6071 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6072 xmlXPathFreeObject(val);
6073 return(ret);
6074}
6075
Owen Taylor3473f882001-02-23 17:55:21 +00006076/************************************************************************
6077 * *
6078 * Routines to handle XPath contexts *
6079 * *
6080 ************************************************************************/
6081
6082/**
6083 * xmlXPathNewContext:
6084 * @doc: the XML document
6085 *
6086 * Create a new xmlXPathContext
6087 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00006088 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00006089 */
6090xmlXPathContextPtr
6091xmlXPathNewContext(xmlDocPtr doc) {
6092 xmlXPathContextPtr ret;
6093
6094 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6095 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006096 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006097 return(NULL);
6098 }
6099 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6100 ret->doc = doc;
6101 ret->node = NULL;
6102
6103 ret->varHash = NULL;
6104
6105 ret->nb_types = 0;
6106 ret->max_types = 0;
6107 ret->types = NULL;
6108
6109 ret->funcHash = xmlHashCreate(0);
6110
6111 ret->nb_axis = 0;
6112 ret->max_axis = 0;
6113 ret->axis = NULL;
6114
6115 ret->nsHash = NULL;
6116 ret->user = NULL;
6117
6118 ret->contextSize = -1;
6119 ret->proximityPosition = -1;
6120
Haibo Huangcfd91dc2020-07-30 23:01:33 -07006121 ret->maxDepth = INT_MAX;
6122 ret->maxParserDepth = INT_MAX;
6123
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006124#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006125 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006126 xmlXPathFreeContext(ret);
6127 return(NULL);
6128 }
6129#endif
6130
Daniel Veillard45490ae2008-07-29 09:13:19 +00006131 xmlXPathRegisterAllFunctions(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006132
Owen Taylor3473f882001-02-23 17:55:21 +00006133 return(ret);
6134}
6135
6136/**
6137 * xmlXPathFreeContext:
6138 * @ctxt: the context to free
6139 *
6140 * Free up an xmlXPathContext
6141 */
6142void
6143xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006144 if (ctxt == NULL) return;
6145
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006146 if (ctxt->cache != NULL)
6147 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006148 xmlXPathRegisteredNsCleanup(ctxt);
6149 xmlXPathRegisteredFuncsCleanup(ctxt);
6150 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006151 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006152 xmlFree(ctxt);
6153}
6154
6155/************************************************************************
6156 * *
6157 * Routines to handle XPath parser contexts *
6158 * *
6159 ************************************************************************/
6160
6161#define CHECK_CTXT(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006162 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006163 __xmlRaiseError(NULL, NULL, NULL, \
6164 NULL, NULL, XML_FROM_XPATH, \
6165 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6166 __FILE__, __LINE__, \
6167 NULL, NULL, NULL, 0, 0, \
6168 "NULL context pointer\n"); \
6169 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006170 } \
6171
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006172#define CHECK_CTXT_NEG(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006173 if (ctxt == NULL) { \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006174 __xmlRaiseError(NULL, NULL, NULL, \
6175 NULL, NULL, XML_FROM_XPATH, \
6176 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6177 __FILE__, __LINE__, \
6178 NULL, NULL, NULL, 0, 0, \
6179 "NULL context pointer\n"); \
6180 return(-1); \
6181 } \
6182
Owen Taylor3473f882001-02-23 17:55:21 +00006183
6184#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006185 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006186 (ctxt->doc->children == NULL)) { \
Daniel Veillard57b25162004-11-06 14:50:18 +00006187 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006188 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006189 }
Owen Taylor3473f882001-02-23 17:55:21 +00006190
6191
6192/**
6193 * xmlXPathNewParserContext:
6194 * @str: the XPath expression
6195 * @ctxt: the XPath context
6196 *
6197 * Create a new xmlXPathParserContext
6198 *
6199 * Returns the xmlXPathParserContext just allocated.
6200 */
6201xmlXPathParserContextPtr
6202xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6203 xmlXPathParserContextPtr ret;
6204
6205 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6206 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006207 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006208 return(NULL);
6209 }
6210 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6211 ret->cur = ret->base = str;
6212 ret->context = ctxt;
6213
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006214 ret->comp = xmlXPathNewCompExpr();
6215 if (ret->comp == NULL) {
6216 xmlFree(ret->valueTab);
6217 xmlFree(ret);
6218 return(NULL);
6219 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006220 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6221 ret->comp->dict = ctxt->dict;
6222 xmlDictReference(ret->comp->dict);
6223 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006224
6225 return(ret);
6226}
6227
6228/**
6229 * xmlXPathCompParserContext:
6230 * @comp: the XPath compiled expression
6231 * @ctxt: the XPath context
6232 *
6233 * Create a new xmlXPathParserContext when processing a compiled expression
6234 *
6235 * Returns the xmlXPathParserContext just allocated.
6236 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006237static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006238xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6239 xmlXPathParserContextPtr ret;
6240
6241 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6242 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006243 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006244 return(NULL);
6245 }
6246 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6247
Owen Taylor3473f882001-02-23 17:55:21 +00006248 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +00006249 ret->valueTab = (xmlXPathObjectPtr *)
Owen Taylor3473f882001-02-23 17:55:21 +00006250 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006251 if (ret->valueTab == NULL) {
6252 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006253 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006254 return(NULL);
6255 }
Owen Taylor3473f882001-02-23 17:55:21 +00006256 ret->valueNr = 0;
6257 ret->valueMax = 10;
6258 ret->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +08006259 ret->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006260
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006261 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006262 ret->comp = comp;
6263
Owen Taylor3473f882001-02-23 17:55:21 +00006264 return(ret);
6265}
6266
6267/**
6268 * xmlXPathFreeParserContext:
6269 * @ctxt: the context to free
6270 *
6271 * Free up an xmlXPathParserContext
6272 */
6273void
6274xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
Nick Wellnhoferc8519702017-05-27 15:26:11 +02006275 int i;
6276
Owen Taylor3473f882001-02-23 17:55:21 +00006277 if (ctxt->valueTab != NULL) {
Nick Wellnhoferc8519702017-05-27 15:26:11 +02006278 for (i = 0; i < ctxt->valueNr; i++) {
6279 if (ctxt->context)
6280 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6281 else
6282 xmlXPathFreeObject(ctxt->valueTab[i]);
6283 }
Owen Taylor3473f882001-02-23 17:55:21 +00006284 xmlFree(ctxt->valueTab);
6285 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006286 if (ctxt->comp != NULL) {
6287#ifdef XPATH_STREAMING
6288 if (ctxt->comp->stream != NULL) {
6289 xmlFreePatternList(ctxt->comp->stream);
6290 ctxt->comp->stream = NULL;
6291 }
6292#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006293 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006294 }
Owen Taylor3473f882001-02-23 17:55:21 +00006295 xmlFree(ctxt);
6296}
6297
6298/************************************************************************
6299 * *
6300 * The implicit core function library *
6301 * *
6302 ************************************************************************/
6303
Owen Taylor3473f882001-02-23 17:55:21 +00006304/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006305 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006306 * @node: a node pointer
6307 *
6308 * Function computing the beginning of the string value of the node,
6309 * used to speed up comparisons
6310 *
6311 * Returns an int usable as a hash
6312 */
6313static unsigned int
6314xmlXPathNodeValHash(xmlNodePtr node) {
6315 int len = 2;
6316 const xmlChar * string = NULL;
6317 xmlNodePtr tmp = NULL;
6318 unsigned int ret = 0;
6319
6320 if (node == NULL)
6321 return(0);
6322
Daniel Veillard9adc0462003-03-24 18:39:54 +00006323 if (node->type == XML_DOCUMENT_NODE) {
6324 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6325 if (tmp == NULL)
6326 node = node->children;
6327 else
6328 node = tmp;
6329
6330 if (node == NULL)
6331 return(0);
6332 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006333
6334 switch (node->type) {
6335 case XML_COMMENT_NODE:
6336 case XML_PI_NODE:
6337 case XML_CDATA_SECTION_NODE:
6338 case XML_TEXT_NODE:
6339 string = node->content;
6340 if (string == NULL)
6341 return(0);
6342 if (string[0] == 0)
6343 return(0);
6344 return(((unsigned int) string[0]) +
6345 (((unsigned int) string[1]) << 8));
6346 case XML_NAMESPACE_DECL:
6347 string = ((xmlNsPtr)node)->href;
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_ATTRIBUTE_NODE:
6355 tmp = ((xmlAttrPtr) node)->children;
6356 break;
6357 case XML_ELEMENT_NODE:
6358 tmp = node->children;
6359 break;
6360 default:
6361 return(0);
6362 }
6363 while (tmp != NULL) {
6364 switch (tmp->type) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006365 case XML_CDATA_SECTION_NODE:
6366 case XML_TEXT_NODE:
6367 string = tmp->content;
6368 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006369 default:
Nick Wellnhofer5af594d2017-10-07 14:54:45 +02006370 string = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006371 break;
6372 }
6373 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006374 if (len == 1) {
6375 return(ret + (((unsigned int) string[0]) << 8));
6376 }
6377 if (string[1] == 0) {
6378 len = 1;
6379 ret = (unsigned int) string[0];
6380 } else {
6381 return(((unsigned int) string[0]) +
6382 (((unsigned int) string[1]) << 8));
6383 }
6384 }
6385 /*
6386 * Skip to next node
6387 */
6388 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6389 if (tmp->children->type != XML_ENTITY_DECL) {
6390 tmp = tmp->children;
6391 continue;
6392 }
6393 }
6394 if (tmp == node)
6395 break;
6396
6397 if (tmp->next != NULL) {
6398 tmp = tmp->next;
6399 continue;
6400 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00006401
Daniel Veillardf06307e2001-07-03 10:35:50 +00006402 do {
6403 tmp = tmp->parent;
6404 if (tmp == NULL)
6405 break;
6406 if (tmp == node) {
6407 tmp = NULL;
6408 break;
6409 }
6410 if (tmp->next != NULL) {
6411 tmp = tmp->next;
6412 break;
6413 }
6414 } while (tmp != NULL);
6415 }
6416 return(ret);
6417}
6418
6419/**
6420 * xmlXPathStringHash:
6421 * @string: a string
6422 *
6423 * Function computing the beginning of the string value of the node,
6424 * used to speed up comparisons
6425 *
6426 * Returns an int usable as a hash
6427 */
6428static unsigned int
6429xmlXPathStringHash(const xmlChar * string) {
6430 if (string == NULL)
6431 return((unsigned int) 0);
6432 if (string[0] == 0)
6433 return(0);
6434 return(((unsigned int) string[0]) +
6435 (((unsigned int) string[1]) << 8));
6436}
6437
6438/**
Owen Taylor3473f882001-02-23 17:55:21 +00006439 * xmlXPathCompareNodeSetFloat:
6440 * @ctxt: the XPath Parser context
6441 * @inf: less than (1) or greater than (0)
6442 * @strict: is the comparison strict
6443 * @arg: the node set
6444 * @f: the value
6445 *
6446 * Implement the compare operation between a nodeset and a number
6447 * @ns < @val (1, 1, ...
6448 * @ns <= @val (1, 0, ...
6449 * @ns > @val (0, 1, ...
6450 * @ns >= @val (0, 0, ...
6451 *
6452 * If one object to be compared is a node-set and the other is a number,
6453 * then the comparison will be true if and only if there is a node in the
6454 * node-set such that the result of performing the comparison on the number
6455 * to be compared and on the result of converting the string-value of that
6456 * node to a number using the number function is true.
6457 *
6458 * Returns 0 or 1 depending on the results of the test.
6459 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006460static int
Owen Taylor3473f882001-02-23 17:55:21 +00006461xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6462 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6463 int i, ret = 0;
6464 xmlNodeSetPtr ns;
6465 xmlChar *str2;
6466
6467 if ((f == NULL) || (arg == NULL) ||
6468 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006469 xmlXPathReleaseObject(ctxt->context, arg);
6470 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006471 return(0);
6472 }
6473 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006474 if (ns != NULL) {
6475 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006476 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006477 if (str2 != NULL) {
6478 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006479 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006480 xmlFree(str2);
6481 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006482 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006483 ret = xmlXPathCompareValues(ctxt, inf, strict);
6484 if (ret)
6485 break;
6486 }
6487 }
Owen Taylor3473f882001-02-23 17:55:21 +00006488 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006489 xmlXPathReleaseObject(ctxt->context, arg);
6490 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006491 return(ret);
6492}
6493
6494/**
6495 * xmlXPathCompareNodeSetString:
6496 * @ctxt: the XPath Parser context
6497 * @inf: less than (1) or greater than (0)
6498 * @strict: is the comparison strict
6499 * @arg: the node set
6500 * @s: the value
6501 *
6502 * Implement the compare operation between a nodeset and a string
6503 * @ns < @val (1, 1, ...
6504 * @ns <= @val (1, 0, ...
6505 * @ns > @val (0, 1, ...
6506 * @ns >= @val (0, 0, ...
6507 *
6508 * If one object to be compared is a node-set and the other is a string,
6509 * then the comparison will be true if and only if there is a node in
6510 * the node-set such that the result of performing the comparison on the
6511 * string-value of the node and the other string is true.
6512 *
6513 * Returns 0 or 1 depending on the results of the test.
6514 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006515static int
Owen Taylor3473f882001-02-23 17:55:21 +00006516xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6517 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6518 int i, ret = 0;
6519 xmlNodeSetPtr ns;
6520 xmlChar *str2;
6521
6522 if ((s == NULL) || (arg == NULL) ||
6523 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006524 xmlXPathReleaseObject(ctxt->context, arg);
6525 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006526 return(0);
6527 }
6528 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006529 if (ns != NULL) {
6530 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006531 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006532 if (str2 != NULL) {
6533 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006534 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006535 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006536 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006537 ret = xmlXPathCompareValues(ctxt, inf, strict);
6538 if (ret)
6539 break;
6540 }
6541 }
Owen Taylor3473f882001-02-23 17:55:21 +00006542 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006543 xmlXPathReleaseObject(ctxt->context, arg);
6544 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006545 return(ret);
6546}
6547
6548/**
6549 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006550 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006551 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006552 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006553 * @arg2: the second node set object
6554 *
6555 * Implement the compare operation on nodesets:
6556 *
6557 * If both objects to be compared are node-sets, then the comparison
6558 * will be true if and only if there is a node in the first node-set
6559 * and a node in the second node-set such that the result of performing
Daniel Veillard45490ae2008-07-29 09:13:19 +00006560 * the comparison on the string-values of the two nodes is true.
Owen Taylor3473f882001-02-23 17:55:21 +00006561 * ....
6562 * When neither object to be compared is a node-set and the operator
6563 * is <=, <, >= or >, then the objects are compared by converting both
6564 * objects to numbers and comparing the numbers according to IEEE 754.
6565 * ....
6566 * The number function converts its argument to a number as follows:
6567 * - a string that consists of optional whitespace followed by an
6568 * optional minus sign followed by a Number followed by whitespace
6569 * is converted to the IEEE 754 number that is nearest (according
6570 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6571 * represented by the string; any other string is converted to NaN
6572 *
6573 * Conclusion all nodes need to be converted first to their string value
Daniel Veillard45490ae2008-07-29 09:13:19 +00006574 * and then the comparison must be done when possible
Owen Taylor3473f882001-02-23 17:55:21 +00006575 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006576static int
6577xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006578 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6579 int i, j, init = 0;
6580 double val1;
6581 double *values2;
6582 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006583 xmlNodeSetPtr ns1;
6584 xmlNodeSetPtr ns2;
6585
6586 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006587 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6588 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006589 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006590 }
Owen Taylor3473f882001-02-23 17:55:21 +00006591 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006592 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6593 xmlXPathFreeObject(arg1);
6594 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006595 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006596 }
Owen Taylor3473f882001-02-23 17:55:21 +00006597
6598 ns1 = arg1->nodesetval;
6599 ns2 = arg2->nodesetval;
6600
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006601 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006602 xmlXPathFreeObject(arg1);
6603 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006604 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006605 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006606 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006607 xmlXPathFreeObject(arg1);
6608 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006609 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006610 }
Owen Taylor3473f882001-02-23 17:55:21 +00006611
6612 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6613 if (values2 == NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07006614 /* TODO: Propagate memory error. */
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006615 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006616 xmlXPathFreeObject(arg1);
6617 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006618 return(0);
6619 }
6620 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006621 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006622 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006623 continue;
6624 for (j = 0;j < ns2->nodeNr;j++) {
6625 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006626 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006627 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006628 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006629 continue;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006630 if (inf && strict)
Owen Taylor3473f882001-02-23 17:55:21 +00006631 ret = (val1 < values2[j]);
6632 else if (inf && !strict)
6633 ret = (val1 <= values2[j]);
6634 else if (!inf && strict)
6635 ret = (val1 > values2[j]);
6636 else if (!inf && !strict)
6637 ret = (val1 >= values2[j]);
6638 if (ret)
6639 break;
6640 }
6641 if (ret)
6642 break;
6643 init = 1;
6644 }
6645 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006646 xmlXPathFreeObject(arg1);
6647 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006648 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006649}
6650
6651/**
6652 * xmlXPathCompareNodeSetValue:
6653 * @ctxt: the XPath Parser context
6654 * @inf: less than (1) or greater than (0)
6655 * @strict: is the comparison strict
6656 * @arg: the node set
6657 * @val: the value
6658 *
6659 * Implement the compare operation between a nodeset and a value
6660 * @ns < @val (1, 1, ...
6661 * @ns <= @val (1, 0, ...
6662 * @ns > @val (0, 1, ...
6663 * @ns >= @val (0, 0, ...
6664 *
6665 * If one object to be compared is a node-set and the other is a boolean,
6666 * then the comparison will be true if and only if the result of performing
6667 * the comparison on the boolean and on the result of converting
6668 * the node-set to a boolean using the boolean function is true.
6669 *
6670 * Returns 0 or 1 depending on the results of the test.
6671 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006672static int
Owen Taylor3473f882001-02-23 17:55:21 +00006673xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6674 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6675 if ((val == NULL) || (arg == NULL) ||
6676 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6677 return(0);
6678
6679 switch(val->type) {
6680 case XPATH_NUMBER:
6681 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6682 case XPATH_NODESET:
6683 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006684 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006685 case XPATH_STRING:
6686 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6687 case XPATH_BOOLEAN:
6688 valuePush(ctxt, arg);
6689 xmlXPathBooleanFunction(ctxt, 1);
6690 valuePush(ctxt, val);
6691 return(xmlXPathCompareValues(ctxt, inf, strict));
6692 default:
Nick Wellnhofercf60dbe2017-05-25 16:20:56 +02006693 xmlGenericError(xmlGenericErrorContext,
6694 "xmlXPathCompareNodeSetValue: Can't compare node set "
6695 "and object of type %d\n",
6696 val->type);
6697 xmlXPathReleaseObject(ctxt->context, arg);
6698 xmlXPathReleaseObject(ctxt->context, val);
6699 XP_ERROR0(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006700 }
6701 return(0);
6702}
6703
6704/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006705 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006706 * @arg: the nodeset object argument
6707 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006708 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006709 *
6710 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6711 * If one object to be compared is a node-set and the other is a string,
6712 * then the comparison will be true if and only if there is a node in
6713 * the node-set such that the result of performing the comparison on the
6714 * string-value of the node and the other string is true.
6715 *
6716 * Returns 0 or 1 depending on the results of the test.
6717 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006718static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006719xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006720{
Owen Taylor3473f882001-02-23 17:55:21 +00006721 int i;
6722 xmlNodeSetPtr ns;
6723 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006724 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006725
6726 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006727 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6728 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006729 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006730 /*
6731 * A NULL nodeset compared with a string is always false
6732 * (since there is no node equal, and no node not equal)
6733 */
6734 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006735 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006736 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006737 for (i = 0; i < ns->nodeNr; i++) {
6738 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6739 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6740 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6741 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006742 if (neq)
6743 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006744 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006745 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6746 if (neq)
6747 continue;
6748 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006749 } else if (neq) {
6750 if (str2 != NULL)
6751 xmlFree(str2);
6752 return (1);
6753 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006754 if (str2 != NULL)
6755 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006756 } else if (neq)
6757 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006758 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006759 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006760}
6761
6762/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006763 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006764 * @arg: the nodeset object argument
6765 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006766 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006767 *
6768 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6769 * If one object to be compared is a node-set and the other is a number,
6770 * then the comparison will be true if and only if there is a node in
6771 * the node-set such that the result of performing the comparison on the
6772 * number to be compared and on the result of converting the string-value
6773 * of that node to a number using the number function is true.
6774 *
6775 * Returns 0 or 1 depending on the results of the test.
6776 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006777static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006778xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6779 xmlXPathObjectPtr arg, double f, int neq) {
6780 int i, ret=0;
6781 xmlNodeSetPtr ns;
6782 xmlChar *str2;
6783 xmlXPathObjectPtr val;
6784 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006785
6786 if ((arg == NULL) ||
6787 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6788 return(0);
6789
William M. Brack0c022ad2002-07-12 00:56:01 +00006790 ns = arg->nodesetval;
6791 if (ns != NULL) {
6792 for (i=0;i<ns->nodeNr;i++) {
6793 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6794 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006795 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006796 xmlFree(str2);
6797 xmlXPathNumberFunction(ctxt, 1);
6798 val = valuePop(ctxt);
6799 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006800 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006801 if (!xmlXPathIsNaN(v)) {
6802 if ((!neq) && (v==f)) {
6803 ret = 1;
6804 break;
6805 } else if ((neq) && (v!=f)) {
6806 ret = 1;
6807 break;
6808 }
William M. Brack32f0f712005-07-14 07:00:33 +00006809 } else { /* NaN is unequal to any value */
6810 if (neq)
6811 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006812 }
6813 }
6814 }
6815 }
6816
6817 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006818}
6819
6820
6821/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006822 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006823 * @arg1: first nodeset object argument
6824 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006825 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006826 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006827 * Implement the equal / not equal operation on XPath nodesets:
6828 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006829 * If both objects to be compared are node-sets, then the comparison
6830 * will be true if and only if there is a node in the first node-set and
6831 * a node in the second node-set such that the result of performing the
6832 * comparison on the string-values of the two nodes is true.
6833 *
6834 * (needless to say, this is a costly operation)
6835 *
6836 * Returns 0 or 1 depending on the results of the test.
6837 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006838static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006839xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006840 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006841 unsigned int *hashs1;
6842 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006843 xmlChar **values1;
6844 xmlChar **values2;
6845 int ret = 0;
6846 xmlNodeSetPtr ns1;
6847 xmlNodeSetPtr ns2;
6848
6849 if ((arg1 == NULL) ||
6850 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6851 return(0);
6852 if ((arg2 == NULL) ||
6853 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6854 return(0);
6855
6856 ns1 = arg1->nodesetval;
6857 ns2 = arg2->nodesetval;
6858
Daniel Veillard911f49a2001-04-07 15:39:35 +00006859 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006860 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006861 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006862 return(0);
6863
6864 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006865 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006866 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006867 if (neq == 0)
6868 for (i = 0;i < ns1->nodeNr;i++)
6869 for (j = 0;j < ns2->nodeNr;j++)
6870 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6871 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006872
6873 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006874 if (values1 == NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07006875 /* TODO: Propagate memory error. */
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006876 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006877 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006878 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006879 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6880 if (hashs1 == NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07006881 /* TODO: Propagate memory error. */
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006882 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006883 xmlFree(values1);
6884 return(0);
6885 }
Owen Taylor3473f882001-02-23 17:55:21 +00006886 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6887 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6888 if (values2 == 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(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006892 xmlFree(values1);
6893 return(0);
6894 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006895 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6896 if (hashs2 == 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);
6900 xmlFree(values1);
6901 xmlFree(values2);
6902 return(0);
6903 }
Owen Taylor3473f882001-02-23 17:55:21 +00006904 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6905 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006906 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006907 for (j = 0;j < ns2->nodeNr;j++) {
6908 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006909 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006910 if (hashs1[i] != hashs2[j]) {
6911 if (neq) {
6912 ret = 1;
6913 break;
6914 }
6915 }
6916 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006917 if (values1[i] == NULL)
6918 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6919 if (values2[j] == NULL)
6920 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006921 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006922 if (ret)
6923 break;
6924 }
Owen Taylor3473f882001-02-23 17:55:21 +00006925 }
6926 if (ret)
6927 break;
6928 }
6929 for (i = 0;i < ns1->nodeNr;i++)
6930 if (values1[i] != NULL)
6931 xmlFree(values1[i]);
6932 for (j = 0;j < ns2->nodeNr;j++)
6933 if (values2[j] != NULL)
6934 xmlFree(values2[j]);
6935 xmlFree(values1);
6936 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006937 xmlFree(hashs1);
6938 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006939 return(ret);
6940}
6941
William M. Brack0c022ad2002-07-12 00:56:01 +00006942static int
6943xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6944 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006945 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006946 /*
6947 *At this point we are assured neither arg1 nor arg2
6948 *is a nodeset, so we can just pick the appropriate routine.
6949 */
Owen Taylor3473f882001-02-23 17:55:21 +00006950 switch (arg1->type) {
6951 case XPATH_UNDEFINED:
6952#ifdef DEBUG_EXPR
6953 xmlGenericError(xmlGenericErrorContext,
6954 "Equal: undefined\n");
6955#endif
6956 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006957 case XPATH_BOOLEAN:
6958 switch (arg2->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#ifdef DEBUG_EXPR
6967 xmlGenericError(xmlGenericErrorContext,
6968 "Equal: %d boolean %d \n",
6969 arg1->boolval, arg2->boolval);
6970#endif
6971 ret = (arg1->boolval == arg2->boolval);
6972 break;
6973 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006974 ret = (arg1->boolval ==
6975 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006976 break;
6977 case XPATH_STRING:
6978 if ((arg2->stringval == NULL) ||
6979 (arg2->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006980 else
Owen Taylor3473f882001-02-23 17:55:21 +00006981 ret = 1;
6982 ret = (arg1->boolval == ret);
6983 break;
6984 case XPATH_USERS:
6985 case XPATH_POINT:
6986 case XPATH_RANGE:
6987 case XPATH_LOCATIONSET:
6988 TODO
6989 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006990 case XPATH_NODESET:
6991 case XPATH_XSLT_TREE:
6992 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006993 }
6994 break;
6995 case XPATH_NUMBER:
6996 switch (arg2->type) {
6997 case XPATH_UNDEFINED:
6998#ifdef DEBUG_EXPR
6999 xmlGenericError(xmlGenericErrorContext,
7000 "Equal: undefined\n");
7001#endif
7002 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007003 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00007004 ret = (arg2->boolval==
7005 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00007006 break;
7007 case XPATH_STRING:
7008 valuePush(ctxt, arg2);
7009 xmlXPathNumberFunction(ctxt, 1);
7010 arg2 = valuePop(ctxt);
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +02007011 /* Falls through. */
Owen Taylor3473f882001-02-23 17:55:21 +00007012 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007013 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007014 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007015 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007016 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007017 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7018 if (xmlXPathIsInf(arg2->floatval) == 1)
7019 ret = 1;
7020 else
7021 ret = 0;
7022 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7023 if (xmlXPathIsInf(arg2->floatval) == -1)
7024 ret = 1;
7025 else
7026 ret = 0;
7027 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7028 if (xmlXPathIsInf(arg1->floatval) == 1)
7029 ret = 1;
7030 else
7031 ret = 0;
7032 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7033 if (xmlXPathIsInf(arg1->floatval) == -1)
7034 ret = 1;
7035 else
7036 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007037 } else {
7038 ret = (arg1->floatval == arg2->floatval);
7039 }
Owen Taylor3473f882001-02-23 17:55:21 +00007040 break;
7041 case XPATH_USERS:
7042 case XPATH_POINT:
7043 case XPATH_RANGE:
7044 case XPATH_LOCATIONSET:
7045 TODO
7046 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007047 case XPATH_NODESET:
7048 case XPATH_XSLT_TREE:
7049 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007050 }
7051 break;
7052 case XPATH_STRING:
7053 switch (arg2->type) {
7054 case XPATH_UNDEFINED:
7055#ifdef DEBUG_EXPR
7056 xmlGenericError(xmlGenericErrorContext,
7057 "Equal: undefined\n");
7058#endif
7059 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007060 case XPATH_BOOLEAN:
7061 if ((arg1->stringval == NULL) ||
7062 (arg1->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007063 else
Owen Taylor3473f882001-02-23 17:55:21 +00007064 ret = 1;
7065 ret = (arg2->boolval == ret);
7066 break;
7067 case XPATH_STRING:
7068 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7069 break;
7070 case XPATH_NUMBER:
7071 valuePush(ctxt, arg1);
7072 xmlXPathNumberFunction(ctxt, 1);
7073 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007074 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007075 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007076 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007077 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007078 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7079 if (xmlXPathIsInf(arg2->floatval) == 1)
7080 ret = 1;
7081 else
7082 ret = 0;
7083 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7084 if (xmlXPathIsInf(arg2->floatval) == -1)
7085 ret = 1;
7086 else
7087 ret = 0;
7088 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7089 if (xmlXPathIsInf(arg1->floatval) == 1)
7090 ret = 1;
7091 else
7092 ret = 0;
7093 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7094 if (xmlXPathIsInf(arg1->floatval) == -1)
7095 ret = 1;
7096 else
7097 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007098 } else {
7099 ret = (arg1->floatval == arg2->floatval);
7100 }
Owen Taylor3473f882001-02-23 17:55:21 +00007101 break;
7102 case XPATH_USERS:
7103 case XPATH_POINT:
7104 case XPATH_RANGE:
7105 case XPATH_LOCATIONSET:
7106 TODO
7107 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007108 case XPATH_NODESET:
7109 case XPATH_XSLT_TREE:
7110 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007111 }
7112 break;
7113 case XPATH_USERS:
7114 case XPATH_POINT:
7115 case XPATH_RANGE:
7116 case XPATH_LOCATIONSET:
7117 TODO
7118 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007119 case XPATH_NODESET:
7120 case XPATH_XSLT_TREE:
7121 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007122 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007123 xmlXPathReleaseObject(ctxt->context, arg1);
7124 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007125 return(ret);
7126}
7127
William M. Brack0c022ad2002-07-12 00:56:01 +00007128/**
7129 * xmlXPathEqualValues:
7130 * @ctxt: the XPath Parser context
7131 *
7132 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7133 *
7134 * Returns 0 or 1 depending on the results of the test.
7135 */
7136int
7137xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7138 xmlXPathObjectPtr arg1, arg2, argtmp;
7139 int ret = 0;
7140
Daniel Veillard6128c012004-11-08 17:16:15 +00007141 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007142 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007143 arg1 = valuePop(ctxt);
7144 if ((arg1 == NULL) || (arg2 == NULL)) {
7145 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007146 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007147 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007148 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007149 XP_ERROR0(XPATH_INVALID_OPERAND);
7150 }
7151
7152 if (arg1 == arg2) {
7153#ifdef DEBUG_EXPR
7154 xmlGenericError(xmlGenericErrorContext,
7155 "Equal: by pointer\n");
7156#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007157 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007158 return(1);
7159 }
7160
7161 /*
7162 *If either argument is a nodeset, it's a 'special case'
7163 */
7164 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7165 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7166 /*
7167 *Hack it to assure arg1 is the nodeset
7168 */
7169 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7170 argtmp = arg2;
7171 arg2 = arg1;
7172 arg1 = argtmp;
7173 }
7174 switch (arg2->type) {
7175 case XPATH_UNDEFINED:
7176#ifdef DEBUG_EXPR
7177 xmlGenericError(xmlGenericErrorContext,
7178 "Equal: undefined\n");
7179#endif
7180 break;
7181 case XPATH_NODESET:
7182 case XPATH_XSLT_TREE:
7183 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7184 break;
7185 case XPATH_BOOLEAN:
7186 if ((arg1->nodesetval == NULL) ||
7187 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007188 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007189 ret = 1;
7190 ret = (ret == arg2->boolval);
7191 break;
7192 case XPATH_NUMBER:
7193 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7194 break;
7195 case XPATH_STRING:
7196 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7197 break;
7198 case XPATH_USERS:
7199 case XPATH_POINT:
7200 case XPATH_RANGE:
7201 case XPATH_LOCATIONSET:
7202 TODO
7203 break;
7204 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007205 xmlXPathReleaseObject(ctxt->context, arg1);
7206 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007207 return(ret);
7208 }
7209
7210 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7211}
7212
7213/**
7214 * xmlXPathNotEqualValues:
7215 * @ctxt: the XPath Parser context
7216 *
7217 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7218 *
7219 * Returns 0 or 1 depending on the results of the test.
7220 */
7221int
7222xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7223 xmlXPathObjectPtr arg1, arg2, argtmp;
7224 int ret = 0;
7225
Daniel Veillard6128c012004-11-08 17:16:15 +00007226 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007227 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007228 arg1 = valuePop(ctxt);
7229 if ((arg1 == NULL) || (arg2 == NULL)) {
7230 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007231 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007232 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007233 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007234 XP_ERROR0(XPATH_INVALID_OPERAND);
7235 }
7236
7237 if (arg1 == arg2) {
7238#ifdef DEBUG_EXPR
7239 xmlGenericError(xmlGenericErrorContext,
7240 "NotEqual: by pointer\n");
7241#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007242 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007243 return(0);
7244 }
7245
7246 /*
7247 *If either argument is a nodeset, it's a 'special case'
7248 */
7249 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7250 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7251 /*
7252 *Hack it to assure arg1 is the nodeset
7253 */
7254 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7255 argtmp = arg2;
7256 arg2 = arg1;
7257 arg1 = argtmp;
7258 }
7259 switch (arg2->type) {
7260 case XPATH_UNDEFINED:
7261#ifdef DEBUG_EXPR
7262 xmlGenericError(xmlGenericErrorContext,
7263 "NotEqual: undefined\n");
7264#endif
7265 break;
7266 case XPATH_NODESET:
7267 case XPATH_XSLT_TREE:
7268 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7269 break;
7270 case XPATH_BOOLEAN:
7271 if ((arg1->nodesetval == NULL) ||
7272 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007273 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007274 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007275 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007276 break;
7277 case XPATH_NUMBER:
7278 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7279 break;
7280 case XPATH_STRING:
7281 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7282 break;
7283 case XPATH_USERS:
7284 case XPATH_POINT:
7285 case XPATH_RANGE:
7286 case XPATH_LOCATIONSET:
7287 TODO
7288 break;
7289 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007290 xmlXPathReleaseObject(ctxt->context, arg1);
7291 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007292 return(ret);
7293 }
7294
7295 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7296}
Owen Taylor3473f882001-02-23 17:55:21 +00007297
7298/**
7299 * xmlXPathCompareValues:
7300 * @ctxt: the XPath Parser context
7301 * @inf: less than (1) or greater than (0)
7302 * @strict: is the comparison strict
7303 *
Daniel Veillard45490ae2008-07-29 09:13:19 +00007304 * Implement the compare operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007305 * @arg1 < @arg2 (1, 1, ...
7306 * @arg1 <= @arg2 (1, 0, ...
7307 * @arg1 > @arg2 (0, 1, ...
7308 * @arg1 >= @arg2 (0, 0, ...
7309 *
7310 * When neither object to be compared is a node-set and the operator is
7311 * <=, <, >=, >, then the objects are compared by converted both objects
7312 * to numbers and comparing the numbers according to IEEE 754. The <
7313 * comparison will be true if and only if the first number is less than the
7314 * second number. The <= comparison will be true if and only if the first
7315 * number is less than or equal to the second number. The > comparison
7316 * will be true if and only if the first number is greater than the second
7317 * number. The >= comparison will be true if and only if the first number
7318 * is greater than or equal to the second number.
7319 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007320 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007321 */
7322int
7323xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007324 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007325 xmlXPathObjectPtr arg1, arg2;
7326
Daniel Veillard6128c012004-11-08 17:16:15 +00007327 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007328 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007329 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007330 if ((arg1 == NULL) || (arg2 == NULL)) {
7331 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007332 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007333 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007334 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007335 XP_ERROR0(XPATH_INVALID_OPERAND);
7336 }
7337
William M. Brack0c022ad2002-07-12 00:56:01 +00007338 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7339 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007340 /*
7341 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7342 * are not freed from within this routine; they will be freed from the
7343 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7344 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007345 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7346 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007347 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007348 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007349 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007350 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7351 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007352 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007353 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7354 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007355 }
7356 }
7357 return(ret);
7358 }
7359
7360 if (arg1->type != XPATH_NUMBER) {
7361 valuePush(ctxt, arg1);
7362 xmlXPathNumberFunction(ctxt, 1);
7363 arg1 = valuePop(ctxt);
7364 }
7365 if (arg1->type != XPATH_NUMBER) {
7366 xmlXPathFreeObject(arg1);
7367 xmlXPathFreeObject(arg2);
7368 XP_ERROR0(XPATH_INVALID_OPERAND);
7369 }
7370 if (arg2->type != XPATH_NUMBER) {
7371 valuePush(ctxt, arg2);
7372 xmlXPathNumberFunction(ctxt, 1);
7373 arg2 = valuePop(ctxt);
7374 }
7375 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007376 xmlXPathReleaseObject(ctxt->context, arg1);
7377 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007378 XP_ERROR0(XPATH_INVALID_OPERAND);
7379 }
7380 /*
7381 * Add tests for infinity and nan
7382 * => feedback on 3.4 for Inf and NaN
7383 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007384 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007385 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007386 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007387 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007388 arg1i=xmlXPathIsInf(arg1->floatval);
7389 arg2i=xmlXPathIsInf(arg2->floatval);
7390 if (inf && strict) {
7391 if ((arg1i == -1 && arg2i != -1) ||
7392 (arg2i == 1 && arg1i != 1)) {
7393 ret = 1;
7394 } else if (arg1i == 0 && arg2i == 0) {
7395 ret = (arg1->floatval < arg2->floatval);
7396 } else {
7397 ret = 0;
7398 }
7399 }
7400 else if (inf && !strict) {
7401 if (arg1i == -1 || arg2i == 1) {
7402 ret = 1;
7403 } else if (arg1i == 0 && arg2i == 0) {
7404 ret = (arg1->floatval <= arg2->floatval);
7405 } else {
7406 ret = 0;
7407 }
7408 }
7409 else if (!inf && strict) {
7410 if ((arg1i == 1 && arg2i != 1) ||
7411 (arg2i == -1 && arg1i != -1)) {
7412 ret = 1;
7413 } else if (arg1i == 0 && arg2i == 0) {
7414 ret = (arg1->floatval > arg2->floatval);
7415 } else {
7416 ret = 0;
7417 }
7418 }
7419 else if (!inf && !strict) {
7420 if (arg1i == 1 || arg2i == -1) {
7421 ret = 1;
7422 } else if (arg1i == 0 && arg2i == 0) {
7423 ret = (arg1->floatval >= arg2->floatval);
7424 } else {
7425 ret = 0;
7426 }
7427 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007428 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007429 xmlXPathReleaseObject(ctxt->context, arg1);
7430 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007431 return(ret);
7432}
7433
7434/**
7435 * xmlXPathValueFlipSign:
7436 * @ctxt: the XPath Parser context
7437 *
7438 * Implement the unary - operation on an XPath object
7439 * The numeric operators convert their operands to numbers as if
7440 * by calling the number function.
7441 */
7442void
7443xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007444 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007445 CAST_TO_NUMBER;
7446 CHECK_TYPE(XPATH_NUMBER);
Nick Wellnhofer8813f392017-09-21 00:11:26 +02007447 ctxt->value->floatval = -ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007448}
7449
7450/**
7451 * xmlXPathAddValues:
7452 * @ctxt: the XPath Parser context
7453 *
7454 * Implement the add operation on XPath objects:
7455 * The numeric operators convert their operands to numbers as if
7456 * by calling the number function.
7457 */
7458void
7459xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7460 xmlXPathObjectPtr arg;
7461 double val;
7462
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007463 arg = valuePop(ctxt);
7464 if (arg == NULL)
7465 XP_ERROR(XPATH_INVALID_OPERAND);
7466 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007467 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007468 CAST_TO_NUMBER;
7469 CHECK_TYPE(XPATH_NUMBER);
7470 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007471}
7472
7473/**
7474 * xmlXPathSubValues:
7475 * @ctxt: the XPath Parser context
7476 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007477 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007478 * The numeric operators convert their operands to numbers as if
7479 * by calling the number function.
7480 */
7481void
7482xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7483 xmlXPathObjectPtr arg;
7484 double val;
7485
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007486 arg = valuePop(ctxt);
7487 if (arg == NULL)
7488 XP_ERROR(XPATH_INVALID_OPERAND);
7489 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007490 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007491 CAST_TO_NUMBER;
7492 CHECK_TYPE(XPATH_NUMBER);
7493 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007494}
7495
7496/**
7497 * xmlXPathMultValues:
7498 * @ctxt: the XPath Parser context
7499 *
7500 * Implement the multiply operation on XPath objects:
7501 * The numeric operators convert their operands to numbers as if
7502 * by calling the number function.
7503 */
7504void
7505xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7506 xmlXPathObjectPtr arg;
7507 double val;
7508
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007509 arg = valuePop(ctxt);
7510 if (arg == NULL)
7511 XP_ERROR(XPATH_INVALID_OPERAND);
7512 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007513 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007514 CAST_TO_NUMBER;
7515 CHECK_TYPE(XPATH_NUMBER);
7516 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007517}
7518
7519/**
7520 * xmlXPathDivValues:
7521 * @ctxt: the XPath Parser context
7522 *
7523 * Implement the div operation on XPath objects @arg1 / @arg2:
7524 * The numeric operators convert their operands to numbers as if
7525 * by calling the number function.
7526 */
Haibo Huangcfd91dc2020-07-30 23:01:33 -07007527ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
Owen Taylor3473f882001-02-23 17:55:21 +00007528void
7529xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7530 xmlXPathObjectPtr arg;
7531 double val;
7532
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007533 arg = valuePop(ctxt);
7534 if (arg == NULL)
7535 XP_ERROR(XPATH_INVALID_OPERAND);
7536 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007537 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007538 CAST_TO_NUMBER;
7539 CHECK_TYPE(XPATH_NUMBER);
Nick Wellnhofer8813f392017-09-21 00:11:26 +02007540 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007541}
7542
7543/**
7544 * xmlXPathModValues:
7545 * @ctxt: the XPath Parser context
7546 *
7547 * Implement the mod operation on XPath objects: @arg1 / @arg2
7548 * The numeric operators convert their operands to numbers as if
7549 * by calling the number function.
7550 */
7551void
7552xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7553 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007554 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007555
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007556 arg = valuePop(ctxt);
7557 if (arg == NULL)
7558 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007559 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007560 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007561 CAST_TO_NUMBER;
7562 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007563 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007564 if (arg2 == 0)
Nick Wellnhofer8813f392017-09-21 00:11:26 +02007565 ctxt->value->floatval = NAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007566 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007567 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007568 }
Owen Taylor3473f882001-02-23 17:55:21 +00007569}
7570
7571/************************************************************************
7572 * *
7573 * The traversal functions *
7574 * *
7575 ************************************************************************/
7576
Owen Taylor3473f882001-02-23 17:55:21 +00007577/*
7578 * A traversal function enumerates nodes along an axis.
7579 * Initially it must be called with NULL, and it indicates
7580 * termination on the axis by returning NULL.
7581 */
7582typedef xmlNodePtr (*xmlXPathTraversalFunction)
7583 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7584
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007585/*
7586 * xmlXPathTraversalFunctionExt:
7587 * A traversal function enumerates nodes along an axis.
7588 * Initially it must be called with NULL, and it indicates
7589 * termination on the axis by returning NULL.
7590 * The context node of the traversal is specified via @contextNode.
7591 */
7592typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7593 (xmlNodePtr cur, xmlNodePtr contextNode);
7594
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007595/*
7596 * xmlXPathNodeSetMergeFunction:
7597 * Used for merging node sets in xmlXPathCollectAndTest().
7598 */
7599typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
Haibo Huangcfd91dc2020-07-30 23:01:33 -07007600 (xmlNodeSetPtr, xmlNodeSetPtr);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007601
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007602
Owen Taylor3473f882001-02-23 17:55:21 +00007603/**
7604 * xmlXPathNextSelf:
7605 * @ctxt: the XPath Parser context
7606 * @cur: the current node in the traversal
7607 *
7608 * Traversal function for the "self" direction
7609 * The self axis contains just the context node itself
7610 *
7611 * Returns the next element following that axis
7612 */
7613xmlNodePtr
7614xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007615 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007616 if (cur == NULL)
7617 return(ctxt->context->node);
7618 return(NULL);
7619}
7620
7621/**
7622 * xmlXPathNextChild:
7623 * @ctxt: the XPath Parser context
7624 * @cur: the current node in the traversal
7625 *
7626 * Traversal function for the "child" direction
7627 * The child axis contains the children of the context node in document order.
7628 *
7629 * Returns the next element following that axis
7630 */
7631xmlNodePtr
7632xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007633 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007634 if (cur == NULL) {
7635 if (ctxt->context->node == NULL) return(NULL);
7636 switch (ctxt->context->node->type) {
7637 case XML_ELEMENT_NODE:
7638 case XML_TEXT_NODE:
7639 case XML_CDATA_SECTION_NODE:
7640 case XML_ENTITY_REF_NODE:
7641 case XML_ENTITY_NODE:
7642 case XML_PI_NODE:
7643 case XML_COMMENT_NODE:
7644 case XML_NOTATION_NODE:
7645 case XML_DTD_NODE:
7646 return(ctxt->context->node->children);
7647 case XML_DOCUMENT_NODE:
7648 case XML_DOCUMENT_TYPE_NODE:
7649 case XML_DOCUMENT_FRAG_NODE:
7650 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007651#ifdef LIBXML_DOCB_ENABLED
7652 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007653#endif
7654 return(((xmlDocPtr) ctxt->context->node)->children);
7655 case XML_ELEMENT_DECL:
7656 case XML_ATTRIBUTE_DECL:
7657 case XML_ENTITY_DECL:
7658 case XML_ATTRIBUTE_NODE:
7659 case XML_NAMESPACE_DECL:
7660 case XML_XINCLUDE_START:
7661 case XML_XINCLUDE_END:
7662 return(NULL);
7663 }
7664 return(NULL);
7665 }
7666 if ((cur->type == XML_DOCUMENT_NODE) ||
7667 (cur->type == XML_HTML_DOCUMENT_NODE))
7668 return(NULL);
7669 return(cur->next);
7670}
7671
7672/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007673 * xmlXPathNextChildElement:
7674 * @ctxt: the XPath Parser context
7675 * @cur: the current node in the traversal
7676 *
7677 * Traversal function for the "child" direction and nodes of type element.
7678 * The child axis contains the children of the context node in document order.
7679 *
7680 * Returns the next element following that axis
7681 */
7682static xmlNodePtr
7683xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7684 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7685 if (cur == NULL) {
7686 cur = ctxt->context->node;
7687 if (cur == NULL) return(NULL);
7688 /*
7689 * Get the first element child.
7690 */
7691 switch (cur->type) {
7692 case XML_ELEMENT_NODE:
7693 case XML_DOCUMENT_FRAG_NODE:
7694 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7695 case XML_ENTITY_NODE:
7696 cur = cur->children;
7697 if (cur != NULL) {
7698 if (cur->type == XML_ELEMENT_NODE)
7699 return(cur);
7700 do {
7701 cur = cur->next;
7702 } while ((cur != NULL) &&
7703 (cur->type != XML_ELEMENT_NODE));
7704 return(cur);
7705 }
7706 return(NULL);
7707 case XML_DOCUMENT_NODE:
7708 case XML_HTML_DOCUMENT_NODE:
7709#ifdef LIBXML_DOCB_ENABLED
7710 case XML_DOCB_DOCUMENT_NODE:
7711#endif
7712 return(xmlDocGetRootElement((xmlDocPtr) cur));
7713 default:
7714 return(NULL);
7715 }
7716 return(NULL);
7717 }
7718 /*
7719 * Get the next sibling element node.
7720 */
7721 switch (cur->type) {
7722 case XML_ELEMENT_NODE:
7723 case XML_TEXT_NODE:
7724 case XML_ENTITY_REF_NODE:
7725 case XML_ENTITY_NODE:
7726 case XML_CDATA_SECTION_NODE:
7727 case XML_PI_NODE:
7728 case XML_COMMENT_NODE:
7729 case XML_XINCLUDE_END:
7730 break;
7731 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7732 default:
7733 return(NULL);
7734 }
7735 if (cur->next != NULL) {
7736 if (cur->next->type == XML_ELEMENT_NODE)
7737 return(cur->next);
7738 cur = cur->next;
7739 do {
7740 cur = cur->next;
7741 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7742 return(cur);
7743 }
7744 return(NULL);
7745}
7746
Daniel Veillard76516062012-09-11 14:02:08 +08007747#if 0
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007748/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007749 * xmlXPathNextDescendantOrSelfElemParent:
7750 * @ctxt: the XPath Parser context
7751 * @cur: the current node in the traversal
7752 *
7753 * Traversal function for the "descendant-or-self" axis.
7754 * Additionally it returns only nodes which can be parents of
7755 * element nodes.
7756 *
7757 *
7758 * Returns the next element following that axis
7759 */
7760static xmlNodePtr
7761xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7762 xmlNodePtr contextNode)
7763{
7764 if (cur == NULL) {
7765 if (contextNode == NULL)
7766 return(NULL);
7767 switch (contextNode->type) {
7768 case XML_ELEMENT_NODE:
7769 case XML_XINCLUDE_START:
7770 case XML_DOCUMENT_FRAG_NODE:
7771 case XML_DOCUMENT_NODE:
7772#ifdef LIBXML_DOCB_ENABLED
7773 case XML_DOCB_DOCUMENT_NODE:
7774#endif
Daniel Veillardf8e3db02012-09-11 13:26:36 +08007775 case XML_HTML_DOCUMENT_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007776 return(contextNode);
7777 default:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007778 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007779 }
7780 return(NULL);
7781 } else {
7782 xmlNodePtr start = cur;
7783
7784 while (cur != NULL) {
7785 switch (cur->type) {
7786 case XML_ELEMENT_NODE:
7787 /* TODO: OK to have XInclude here? */
7788 case XML_XINCLUDE_START:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007789 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007790 if (cur != start)
7791 return(cur);
7792 if (cur->children != NULL) {
7793 cur = cur->children;
7794 continue;
7795 }
7796 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007797 /* Not sure if we need those here. */
7798 case XML_DOCUMENT_NODE:
Daniel Veillard17970a72006-10-26 08:55:47 +00007799#ifdef LIBXML_DOCB_ENABLED
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007800 case XML_DOCB_DOCUMENT_NODE:
7801#endif
7802 case XML_HTML_DOCUMENT_NODE:
7803 if (cur != start)
7804 return(cur);
7805 return(xmlDocGetRootElement((xmlDocPtr) cur));
7806 default:
7807 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007808 }
7809
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007810next_sibling:
7811 if ((cur == NULL) || (cur == contextNode))
Daniel Veillard45490ae2008-07-29 09:13:19 +00007812 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007813 if (cur->next != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00007814 cur = cur->next;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007815 } else {
7816 cur = cur->parent;
7817 goto next_sibling;
7818 }
7819 }
7820 }
7821 return(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007822}
Daniel Veillard76516062012-09-11 14:02:08 +08007823#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007824
7825/**
Owen Taylor3473f882001-02-23 17:55:21 +00007826 * xmlXPathNextDescendant:
7827 * @ctxt: the XPath Parser context
7828 * @cur: the current node in the traversal
7829 *
7830 * Traversal function for the "descendant" direction
7831 * the descendant axis contains the descendants of the context node in document
7832 * order; a descendant is a child or a child of a child and so on.
7833 *
7834 * Returns the next element following that axis
7835 */
7836xmlNodePtr
7837xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007838 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007839 if (cur == NULL) {
7840 if (ctxt->context->node == NULL)
7841 return(NULL);
7842 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7843 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7844 return(NULL);
7845
7846 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7847 return(ctxt->context->doc->children);
7848 return(ctxt->context->node->children);
7849 }
7850
Daniel Veillard3e62adb2012-08-09 14:24:02 +08007851 if (cur->type == XML_NAMESPACE_DECL)
7852 return(NULL);
Daniel Veillard567e1b42001-08-01 15:53:47 +00007853 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007854 /*
7855 * Do not descend on entities declarations
7856 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00007857 if (cur->children->type != XML_ENTITY_DECL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007858 cur = cur->children;
7859 /*
7860 * Skip DTDs
7861 */
7862 if (cur->type != XML_DTD_NODE)
7863 return(cur);
7864 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007865 }
7866
7867 if (cur == ctxt->context->node) return(NULL);
7868
Daniel Veillard68e9e742002-11-16 15:35:11 +00007869 while (cur->next != NULL) {
7870 cur = cur->next;
7871 if ((cur->type != XML_ENTITY_DECL) &&
7872 (cur->type != XML_DTD_NODE))
7873 return(cur);
7874 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00007875
Owen Taylor3473f882001-02-23 17:55:21 +00007876 do {
7877 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007878 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007879 if (cur == ctxt->context->node) return(NULL);
7880 if (cur->next != NULL) {
7881 cur = cur->next;
7882 return(cur);
7883 }
7884 } while (cur != NULL);
7885 return(cur);
7886}
7887
7888/**
7889 * xmlXPathNextDescendantOrSelf:
7890 * @ctxt: the XPath Parser context
7891 * @cur: the current node in the traversal
7892 *
7893 * Traversal function for the "descendant-or-self" direction
7894 * the descendant-or-self axis contains the context node and the descendants
7895 * of the context node in document order; thus the context node is the first
7896 * node on the axis, and the first child of the context node is the second node
7897 * on the axis
7898 *
7899 * Returns the next element following that axis
7900 */
7901xmlNodePtr
7902xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007903 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Nick Wellnhoferf6aaabc2015-03-08 16:05:26 +01007904 if (cur == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007905 return(ctxt->context->node);
Nick Wellnhoferf6aaabc2015-03-08 16:05:26 +01007906
7907 if (ctxt->context->node == NULL)
7908 return(NULL);
7909 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7910 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7911 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007912
7913 return(xmlXPathNextDescendant(ctxt, cur));
7914}
7915
7916/**
7917 * xmlXPathNextParent:
7918 * @ctxt: the XPath Parser context
7919 * @cur: the current node in the traversal
7920 *
7921 * Traversal function for the "parent" direction
7922 * The parent axis contains the parent of the context node, if there is one.
7923 *
7924 * Returns the next element following that axis
7925 */
7926xmlNodePtr
7927xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007928 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007929 /*
7930 * the parent of an attribute or namespace node is the element
7931 * to which the attribute or namespace node is attached
7932 * Namespace handling !!!
7933 */
7934 if (cur == NULL) {
7935 if (ctxt->context->node == NULL) return(NULL);
7936 switch (ctxt->context->node->type) {
7937 case XML_ELEMENT_NODE:
7938 case XML_TEXT_NODE:
7939 case XML_CDATA_SECTION_NODE:
7940 case XML_ENTITY_REF_NODE:
7941 case XML_ENTITY_NODE:
7942 case XML_PI_NODE:
7943 case XML_COMMENT_NODE:
7944 case XML_NOTATION_NODE:
7945 case XML_DTD_NODE:
7946 case XML_ELEMENT_DECL:
7947 case XML_ATTRIBUTE_DECL:
7948 case XML_XINCLUDE_START:
7949 case XML_XINCLUDE_END:
7950 case XML_ENTITY_DECL:
7951 if (ctxt->context->node->parent == NULL)
7952 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007953 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007954 ((ctxt->context->node->parent->name[0] == ' ') ||
7955 (xmlStrEqual(ctxt->context->node->parent->name,
7956 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007957 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007958 return(ctxt->context->node->parent);
7959 case XML_ATTRIBUTE_NODE: {
7960 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7961
7962 return(att->parent);
7963 }
7964 case XML_DOCUMENT_NODE:
7965 case XML_DOCUMENT_TYPE_NODE:
7966 case XML_DOCUMENT_FRAG_NODE:
7967 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007968#ifdef LIBXML_DOCB_ENABLED
7969 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007970#endif
7971 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007972 case XML_NAMESPACE_DECL: {
7973 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007974
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007975 if ((ns->next != NULL) &&
7976 (ns->next->type != XML_NAMESPACE_DECL))
7977 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00007978 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007979 }
Owen Taylor3473f882001-02-23 17:55:21 +00007980 }
7981 }
7982 return(NULL);
7983}
7984
7985/**
7986 * xmlXPathNextAncestor:
7987 * @ctxt: the XPath Parser context
7988 * @cur: the current node in the traversal
7989 *
7990 * Traversal function for the "ancestor" direction
7991 * the ancestor axis contains the ancestors of the context node; the ancestors
7992 * of the context node consist of the parent of context node and the parent's
7993 * parent and so on; the nodes are ordered in reverse document order; thus the
7994 * parent is the first node on the axis, and the parent's parent is the second
7995 * node on the axis
7996 *
7997 * Returns the next element following that axis
7998 */
7999xmlNodePtr
8000xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008001 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008002 /*
8003 * the parent of an attribute or namespace node is the element
8004 * to which the attribute or namespace node is attached
8005 * !!!!!!!!!!!!!
8006 */
8007 if (cur == NULL) {
8008 if (ctxt->context->node == NULL) return(NULL);
8009 switch (ctxt->context->node->type) {
8010 case XML_ELEMENT_NODE:
8011 case XML_TEXT_NODE:
8012 case XML_CDATA_SECTION_NODE:
8013 case XML_ENTITY_REF_NODE:
8014 case XML_ENTITY_NODE:
8015 case XML_PI_NODE:
8016 case XML_COMMENT_NODE:
8017 case XML_DTD_NODE:
8018 case XML_ELEMENT_DECL:
8019 case XML_ATTRIBUTE_DECL:
8020 case XML_ENTITY_DECL:
8021 case XML_NOTATION_NODE:
8022 case XML_XINCLUDE_START:
8023 case XML_XINCLUDE_END:
8024 if (ctxt->context->node->parent == NULL)
8025 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008026 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008027 ((ctxt->context->node->parent->name[0] == ' ') ||
8028 (xmlStrEqual(ctxt->context->node->parent->name,
8029 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008030 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008031 return(ctxt->context->node->parent);
8032 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008033 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00008034
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008035 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00008036 }
8037 case XML_DOCUMENT_NODE:
8038 case XML_DOCUMENT_TYPE_NODE:
8039 case XML_DOCUMENT_FRAG_NODE:
8040 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008041#ifdef LIBXML_DOCB_ENABLED
8042 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008043#endif
8044 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008045 case XML_NAMESPACE_DECL: {
8046 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008047
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008048 if ((ns->next != NULL) &&
8049 (ns->next->type != XML_NAMESPACE_DECL))
8050 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008051 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00008052 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008053 }
Owen Taylor3473f882001-02-23 17:55:21 +00008054 }
8055 return(NULL);
8056 }
8057 if (cur == ctxt->context->doc->children)
8058 return((xmlNodePtr) ctxt->context->doc);
8059 if (cur == (xmlNodePtr) ctxt->context->doc)
8060 return(NULL);
8061 switch (cur->type) {
8062 case XML_ELEMENT_NODE:
8063 case XML_TEXT_NODE:
8064 case XML_CDATA_SECTION_NODE:
8065 case XML_ENTITY_REF_NODE:
8066 case XML_ENTITY_NODE:
8067 case XML_PI_NODE:
8068 case XML_COMMENT_NODE:
8069 case XML_NOTATION_NODE:
8070 case XML_DTD_NODE:
8071 case XML_ELEMENT_DECL:
8072 case XML_ATTRIBUTE_DECL:
8073 case XML_ENTITY_DECL:
8074 case XML_XINCLUDE_START:
8075 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008076 if (cur->parent == NULL)
8077 return(NULL);
8078 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008079 ((cur->parent->name[0] == ' ') ||
8080 (xmlStrEqual(cur->parent->name,
8081 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008082 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008083 return(cur->parent);
8084 case XML_ATTRIBUTE_NODE: {
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008085 xmlAttrPtr att = (xmlAttrPtr) cur;
Owen Taylor3473f882001-02-23 17:55:21 +00008086
8087 return(att->parent);
8088 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008089 case XML_NAMESPACE_DECL: {
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008090 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008091
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008092 if ((ns->next != NULL) &&
8093 (ns->next->type != XML_NAMESPACE_DECL))
8094 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008095 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008096 return(NULL);
8097 }
Owen Taylor3473f882001-02-23 17:55:21 +00008098 case XML_DOCUMENT_NODE:
8099 case XML_DOCUMENT_TYPE_NODE:
8100 case XML_DOCUMENT_FRAG_NODE:
8101 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008102#ifdef LIBXML_DOCB_ENABLED
8103 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008104#endif
8105 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008106 }
8107 return(NULL);
8108}
8109
8110/**
8111 * xmlXPathNextAncestorOrSelf:
8112 * @ctxt: the XPath Parser context
8113 * @cur: the current node in the traversal
8114 *
8115 * Traversal function for the "ancestor-or-self" direction
8116 * he ancestor-or-self axis contains the context node and ancestors of
8117 * the context node in reverse document order; thus the context node is
8118 * the first node on the axis, and the context node's parent the second;
8119 * parent here is defined the same as with the parent axis.
8120 *
8121 * Returns the next element following that axis
8122 */
8123xmlNodePtr
8124xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008125 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008126 if (cur == NULL)
8127 return(ctxt->context->node);
8128 return(xmlXPathNextAncestor(ctxt, cur));
8129}
8130
8131/**
8132 * xmlXPathNextFollowingSibling:
8133 * @ctxt: the XPath Parser context
8134 * @cur: the current node in the traversal
8135 *
8136 * Traversal function for the "following-sibling" direction
8137 * The following-sibling axis contains the following siblings of the context
8138 * node in document order.
8139 *
8140 * Returns the next element following that axis
8141 */
8142xmlNodePtr
8143xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008144 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008145 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8146 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8147 return(NULL);
8148 if (cur == (xmlNodePtr) ctxt->context->doc)
8149 return(NULL);
8150 if (cur == NULL)
8151 return(ctxt->context->node->next);
8152 return(cur->next);
8153}
8154
8155/**
8156 * xmlXPathNextPrecedingSibling:
8157 * @ctxt: the XPath Parser context
8158 * @cur: the current node in the traversal
8159 *
8160 * Traversal function for the "preceding-sibling" direction
8161 * The preceding-sibling axis contains the preceding siblings of the context
8162 * node in reverse document order; the first preceding sibling is first on the
8163 * axis; the sibling preceding that node is the second on the axis and so on.
8164 *
8165 * Returns the next element following that axis
8166 */
8167xmlNodePtr
8168xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008169 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008170 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8171 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8172 return(NULL);
8173 if (cur == (xmlNodePtr) ctxt->context->doc)
8174 return(NULL);
8175 if (cur == NULL)
8176 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008177 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8178 cur = cur->prev;
8179 if (cur == NULL)
8180 return(ctxt->context->node->prev);
8181 }
Owen Taylor3473f882001-02-23 17:55:21 +00008182 return(cur->prev);
8183}
8184
8185/**
8186 * xmlXPathNextFollowing:
8187 * @ctxt: the XPath Parser context
8188 * @cur: the current node in the traversal
8189 *
8190 * Traversal function for the "following" direction
8191 * The following axis contains all nodes in the same document as the context
8192 * node that are after the context node in document order, excluding any
8193 * descendants and excluding attribute nodes and namespace nodes; the nodes
8194 * are ordered in document order
8195 *
8196 * Returns the next element following that axis
8197 */
8198xmlNodePtr
8199xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008200 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008201 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8202 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8203 return(cur->children);
8204
8205 if (cur == NULL) {
8206 cur = ctxt->context->node;
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008207 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardea90b892010-10-22 15:50:50 +02008208 cur = cur->parent;
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008209 } else if (cur->type == XML_NAMESPACE_DECL) {
8210 xmlNsPtr ns = (xmlNsPtr) cur;
8211
8212 if ((ns->next == NULL) ||
8213 (ns->next->type == XML_NAMESPACE_DECL))
8214 return (NULL);
8215 cur = (xmlNodePtr) ns->next;
8216 }
Daniel Veillard91d19752010-10-15 14:30:52 +02008217 }
Owen Taylor3473f882001-02-23 17:55:21 +00008218 if (cur == NULL) return(NULL) ; /* ERROR */
8219 if (cur->next != NULL) return(cur->next) ;
8220 do {
8221 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008222 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008223 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8224 if (cur->next != NULL) return(cur->next);
8225 } while (cur != NULL);
8226 return(cur);
8227}
8228
8229/*
8230 * xmlXPathIsAncestor:
8231 * @ancestor: the ancestor node
8232 * @node: the current node
8233 *
8234 * Check that @ancestor is a @node's ancestor
8235 *
8236 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8237 */
8238static int
8239xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8240 if ((ancestor == NULL) || (node == NULL)) return(0);
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008241 if (node->type == XML_NAMESPACE_DECL)
8242 return(0);
8243 if (ancestor->type == XML_NAMESPACE_DECL)
8244 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00008245 /* nodes need to be in the same document */
8246 if (ancestor->doc != node->doc) return(0);
8247 /* avoid searching if ancestor or node is the root node */
8248 if (ancestor == (xmlNodePtr) node->doc) return(1);
8249 if (node == (xmlNodePtr) ancestor->doc) return(0);
8250 while (node->parent != NULL) {
8251 if (node->parent == ancestor)
8252 return(1);
8253 node = node->parent;
8254 }
8255 return(0);
8256}
8257
8258/**
8259 * xmlXPathNextPreceding:
8260 * @ctxt: the XPath Parser context
8261 * @cur: the current node in the traversal
8262 *
8263 * Traversal function for the "preceding" direction
8264 * the preceding axis contains all nodes in the same document as the context
8265 * node that are before the context node in document order, excluding any
8266 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8267 * ordered in reverse document order
8268 *
8269 * Returns the next element following that axis
8270 */
8271xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008272xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8273{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008274 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008275 if (cur == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008276 cur = ctxt->context->node;
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008277 if (cur->type == XML_ATTRIBUTE_NODE) {
8278 cur = cur->parent;
8279 } else if (cur->type == XML_NAMESPACE_DECL) {
8280 xmlNsPtr ns = (xmlNsPtr) cur;
8281
8282 if ((ns->next == NULL) ||
8283 (ns->next->type == XML_NAMESPACE_DECL))
8284 return (NULL);
8285 cur = (xmlNodePtr) ns->next;
8286 }
Daniel Veillardea90b892010-10-22 15:50:50 +02008287 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008288 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
Daniel Veillardf06307e2001-07-03 10:35:50 +00008289 return (NULL);
8290 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8291 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008292 do {
8293 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008294 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8295 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008296 }
8297
8298 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008299 if (cur == NULL)
8300 return (NULL);
8301 if (cur == ctxt->context->doc->children)
8302 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008303 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008304 return (cur);
8305}
8306
8307/**
8308 * xmlXPathNextPrecedingInternal:
8309 * @ctxt: the XPath Parser context
8310 * @cur: the current node in the traversal
8311 *
8312 * Traversal function for the "preceding" direction
8313 * the preceding axis contains all nodes in the same document as the context
8314 * node that are before the context node in document order, excluding any
8315 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8316 * ordered in reverse document order
Daniel Veillard45490ae2008-07-29 09:13:19 +00008317 * This is a faster implementation but internal only since it requires a
Daniel Veillardf06307e2001-07-03 10:35:50 +00008318 * state kept in the parser context: ctxt->ancestor.
8319 *
8320 * Returns the next element following that axis
8321 */
8322static xmlNodePtr
8323xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8324 xmlNodePtr cur)
8325{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008326 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008327 if (cur == NULL) {
8328 cur = ctxt->context->node;
8329 if (cur == NULL)
8330 return (NULL);
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008331 if (cur->type == XML_ATTRIBUTE_NODE) {
8332 cur = cur->parent;
8333 } else if (cur->type == XML_NAMESPACE_DECL) {
8334 xmlNsPtr ns = (xmlNsPtr) cur;
8335
8336 if ((ns->next == NULL) ||
8337 (ns->next->type == XML_NAMESPACE_DECL))
8338 return (NULL);
8339 cur = (xmlNodePtr) ns->next;
8340 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00008341 ctxt->ancestor = cur->parent;
8342 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008343 if (cur->type == XML_NAMESPACE_DECL)
8344 return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008345 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8346 cur = cur->prev;
8347 while (cur->prev == NULL) {
8348 cur = cur->parent;
8349 if (cur == NULL)
8350 return (NULL);
8351 if (cur == ctxt->context->doc->children)
8352 return (NULL);
8353 if (cur != ctxt->ancestor)
8354 return (cur);
8355 ctxt->ancestor = cur->parent;
8356 }
8357 cur = cur->prev;
8358 while (cur->last != NULL)
8359 cur = cur->last;
8360 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008361}
8362
8363/**
8364 * xmlXPathNextNamespace:
8365 * @ctxt: the XPath Parser context
8366 * @cur: the current attribute in the traversal
8367 *
8368 * Traversal function for the "namespace" direction
8369 * the namespace axis contains the namespace nodes of the context node;
8370 * the order of nodes on this axis is implementation-defined; the axis will
8371 * be empty unless the context node is an element
8372 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008373 * We keep the XML namespace node at the end of the list.
8374 *
Owen Taylor3473f882001-02-23 17:55:21 +00008375 * Returns the next element following that axis
8376 */
8377xmlNodePtr
8378xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008379 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008380 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Nick Wellnhofer82b73032016-04-30 17:53:10 +02008381 if (cur == NULL) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008382 if (ctxt->context->tmpNsList != NULL)
8383 xmlFree(ctxt->context->tmpNsList);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008384 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008385 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008386 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008387 if (ctxt->context->tmpNsList != NULL) {
8388 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8389 ctxt->context->tmpNsNr++;
8390 }
8391 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008392 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008393 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008394 if (ctxt->context->tmpNsNr > 0) {
8395 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8396 } else {
8397 if (ctxt->context->tmpNsList != NULL)
8398 xmlFree(ctxt->context->tmpNsList);
8399 ctxt->context->tmpNsList = NULL;
8400 return(NULL);
8401 }
Owen Taylor3473f882001-02-23 17:55:21 +00008402}
8403
8404/**
8405 * xmlXPathNextAttribute:
8406 * @ctxt: the XPath Parser context
8407 * @cur: the current attribute in the traversal
8408 *
8409 * Traversal function for the "attribute" direction
8410 * TODO: support DTD inherited default attributes
8411 *
8412 * Returns the next element following that axis
8413 */
8414xmlNodePtr
8415xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008416 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008417 if (ctxt->context->node == NULL)
8418 return(NULL);
8419 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8420 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008421 if (cur == NULL) {
8422 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8423 return(NULL);
8424 return((xmlNodePtr)ctxt->context->node->properties);
8425 }
8426 return((xmlNodePtr)cur->next);
8427}
8428
8429/************************************************************************
8430 * *
8431 * NodeTest Functions *
8432 * *
8433 ************************************************************************/
8434
Owen Taylor3473f882001-02-23 17:55:21 +00008435#define IS_FUNCTION 200
8436
Owen Taylor3473f882001-02-23 17:55:21 +00008437
8438/************************************************************************
8439 * *
8440 * Implicit tree core function library *
8441 * *
8442 ************************************************************************/
8443
8444/**
8445 * xmlXPathRoot:
8446 * @ctxt: the XPath Parser context
8447 *
8448 * Initialize the context to the root of the document
8449 */
8450void
8451xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008452 if ((ctxt == NULL) || (ctxt->context == NULL))
8453 return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008454 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
Elliott Hughes7fbecab2019-01-10 16:42:03 -08008455 (xmlNodePtr) ctxt->context->doc));
Owen Taylor3473f882001-02-23 17:55:21 +00008456}
8457
8458/************************************************************************
8459 * *
8460 * The explicit core function library *
8461 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8462 * *
8463 ************************************************************************/
8464
8465
8466/**
8467 * xmlXPathLastFunction:
8468 * @ctxt: the XPath Parser context
8469 * @nargs: the number of arguments
8470 *
8471 * Implement the last() XPath function
8472 * number last()
8473 * The last function returns the number of nodes in the context node list.
8474 */
8475void
8476xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8477 CHECK_ARITY(0);
8478 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008479 valuePush(ctxt,
8480 xmlXPathCacheNewFloat(ctxt->context,
8481 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008482#ifdef DEBUG_EXPR
8483 xmlGenericError(xmlGenericErrorContext,
8484 "last() : %d\n", ctxt->context->contextSize);
8485#endif
8486 } else {
8487 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8488 }
8489}
8490
8491/**
8492 * xmlXPathPositionFunction:
8493 * @ctxt: the XPath Parser context
8494 * @nargs: the number of arguments
8495 *
8496 * Implement the position() XPath function
8497 * number position()
8498 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008499 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008500 * will be equal to last().
8501 */
8502void
8503xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8504 CHECK_ARITY(0);
8505 if (ctxt->context->proximityPosition >= 0) {
8506 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008507 xmlXPathCacheNewFloat(ctxt->context,
8508 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008509#ifdef DEBUG_EXPR
8510 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8511 ctxt->context->proximityPosition);
8512#endif
8513 } else {
8514 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8515 }
8516}
8517
8518/**
8519 * xmlXPathCountFunction:
8520 * @ctxt: the XPath Parser context
8521 * @nargs: the number of arguments
8522 *
8523 * Implement the count() XPath function
8524 * number count(node-set)
8525 */
8526void
8527xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8528 xmlXPathObjectPtr cur;
8529
8530 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008531 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008532 ((ctxt->value->type != XPATH_NODESET) &&
8533 (ctxt->value->type != XPATH_XSLT_TREE)))
8534 XP_ERROR(XPATH_INVALID_TYPE);
8535 cur = valuePop(ctxt);
8536
Daniel Veillard911f49a2001-04-07 15:39:35 +00008537 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008538 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Haibo Huangcfd91dc2020-07-30 23:01:33 -07008539 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008540 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8541 (double) cur->nodesetval->nodeNr));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008542 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008543}
8544
8545/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008546 * xmlXPathGetElementsByIds:
8547 * @doc: the document
8548 * @ids: a whitespace separated list of IDs
8549 *
8550 * Selects elements by their unique ID.
8551 *
8552 * Returns a node-set of selected elements.
8553 */
8554static xmlNodeSetPtr
8555xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8556 xmlNodeSetPtr ret;
8557 const xmlChar *cur = ids;
8558 xmlChar *ID;
8559 xmlAttrPtr attr;
8560 xmlNodePtr elem = NULL;
8561
Daniel Veillard7a985a12003-07-06 17:57:42 +00008562 if (ids == NULL) return(NULL);
8563
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008564 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008565 if (ret == NULL)
8566 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008567
William M. Brack76e95df2003-10-18 16:20:14 +00008568 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008569 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008570 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008571 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008572
8573 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008574 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008575 /*
8576 * We used to check the fact that the value passed
8577 * was an NCName, but this generated much troubles for
8578 * me and Aleksey Sanin, people blatantly violated that
Haibo Huangcfd91dc2020-07-30 23:01:33 -07008579 * constraint, like Visa3D spec.
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008580 * if (xmlValidateNCName(ID, 1) == 0)
8581 */
8582 attr = xmlGetID(doc, ID);
8583 if (attr != NULL) {
8584 if (attr->type == XML_ATTRIBUTE_NODE)
8585 elem = attr->parent;
8586 else if (attr->type == XML_ELEMENT_NODE)
8587 elem = (xmlNodePtr) attr;
8588 else
8589 elem = NULL;
Haibo Huangcfd91dc2020-07-30 23:01:33 -07008590 /* TODO: Check memory error. */
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008591 if (elem != NULL)
8592 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008593 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008594 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008595 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008596
William M. Brack76e95df2003-10-18 16:20:14 +00008597 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008598 ids = cur;
8599 }
8600 return(ret);
8601}
8602
8603/**
Owen Taylor3473f882001-02-23 17:55:21 +00008604 * xmlXPathIdFunction:
8605 * @ctxt: the XPath Parser context
8606 * @nargs: the number of arguments
8607 *
8608 * Implement the id() XPath function
8609 * node-set id(object)
8610 * The id function selects elements by their unique ID
8611 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8612 * then the result is the union of the result of applying id to the
8613 * string value of each of the nodes in the argument node-set. When the
8614 * argument to id is of any other type, the argument is converted to a
8615 * string as if by a call to the string function; the string is split
8616 * into a whitespace-separated list of tokens (whitespace is any sequence
8617 * of characters matching the production S); the result is a node-set
8618 * containing the elements in the same document as the context node that
8619 * have a unique ID equal to any of the tokens in the list.
8620 */
8621void
8622xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008623 xmlChar *tokens;
8624 xmlNodeSetPtr ret;
8625 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008626
8627 CHECK_ARITY(1);
8628 obj = valuePop(ctxt);
8629 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008630 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008631 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008632 int i;
8633
Haibo Huangcfd91dc2020-07-30 23:01:33 -07008634 /* TODO: Check memory error. */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008635 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008636
Daniel Veillard911f49a2001-04-07 15:39:35 +00008637 if (obj->nodesetval != NULL) {
8638 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008639 tokens =
8640 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8641 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07008642 /* TODO: Check memory error. */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008643 ret = xmlXPathNodeSetMerge(ret, ns);
8644 xmlXPathFreeNodeSet(ns);
8645 if (tokens != NULL)
8646 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008647 }
Owen Taylor3473f882001-02-23 17:55:21 +00008648 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008649 xmlXPathReleaseObject(ctxt->context, obj);
8650 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008651 return;
8652 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008653 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07008654 if (obj == NULL) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008655 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008656 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008657 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008658 return;
8659}
8660
8661/**
8662 * xmlXPathLocalNameFunction:
8663 * @ctxt: the XPath Parser context
8664 * @nargs: the number of arguments
8665 *
8666 * Implement the local-name() XPath function
8667 * string local-name(node-set?)
8668 * The local-name function returns a string containing the local part
8669 * of the name of the node in the argument node-set that is first in
8670 * document order. If the node-set is empty or the first node has no
8671 * name, an empty string is returned. If the argument is omitted it
8672 * defaults to the context node.
8673 */
8674void
8675xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8676 xmlXPathObjectPtr cur;
8677
Daniel Veillarda82b1822004-11-08 16:24:57 +00008678 if (ctxt == NULL) return;
8679
Owen Taylor3473f882001-02-23 17:55:21 +00008680 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008681 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8682 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008683 nargs = 1;
8684 }
8685
8686 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008687 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008688 ((ctxt->value->type != XPATH_NODESET) &&
8689 (ctxt->value->type != XPATH_XSLT_TREE)))
8690 XP_ERROR(XPATH_INVALID_TYPE);
8691 cur = valuePop(ctxt);
8692
Daniel Veillard911f49a2001-04-07 15:39:35 +00008693 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008694 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008695 } else {
8696 int i = 0; /* Should be first in document order !!!!! */
8697 switch (cur->nodesetval->nodeTab[i]->type) {
8698 case XML_ELEMENT_NODE:
8699 case XML_ATTRIBUTE_NODE:
8700 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008701 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008702 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008703 else
8704 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008705 xmlXPathCacheNewString(ctxt->context,
8706 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008707 break;
8708 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008709 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008710 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8711 break;
8712 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008713 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008714 }
8715 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008716 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008717}
8718
8719/**
8720 * xmlXPathNamespaceURIFunction:
8721 * @ctxt: the XPath Parser context
8722 * @nargs: the number of arguments
8723 *
8724 * Implement the namespace-uri() XPath function
8725 * string namespace-uri(node-set?)
8726 * The namespace-uri function returns a string containing the
8727 * namespace URI of the expanded name of the node in the argument
8728 * node-set that is first in document order. If the node-set is empty,
8729 * the first node has no name, or the expanded name has no namespace
8730 * URI, an empty string is returned. If the argument is omitted it
8731 * defaults to the context node.
8732 */
8733void
8734xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8735 xmlXPathObjectPtr cur;
8736
Daniel Veillarda82b1822004-11-08 16:24:57 +00008737 if (ctxt == NULL) return;
8738
Owen Taylor3473f882001-02-23 17:55:21 +00008739 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008740 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8741 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008742 nargs = 1;
8743 }
8744 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008745 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008746 ((ctxt->value->type != XPATH_NODESET) &&
8747 (ctxt->value->type != XPATH_XSLT_TREE)))
8748 XP_ERROR(XPATH_INVALID_TYPE);
8749 cur = valuePop(ctxt);
8750
Daniel Veillard911f49a2001-04-07 15:39:35 +00008751 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008752 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008753 } else {
8754 int i = 0; /* Should be first in document order !!!!! */
8755 switch (cur->nodesetval->nodeTab[i]->type) {
8756 case XML_ELEMENT_NODE:
8757 case XML_ATTRIBUTE_NODE:
8758 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008759 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008760 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008761 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008762 cur->nodesetval->nodeTab[i]->ns->href));
8763 break;
8764 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008765 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008766 }
8767 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008768 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008769}
8770
8771/**
8772 * xmlXPathNameFunction:
8773 * @ctxt: the XPath Parser context
8774 * @nargs: the number of arguments
8775 *
8776 * Implement the name() XPath function
8777 * string name(node-set?)
8778 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008779 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008780 * order. The QName must represent the name with respect to the namespace
8781 * declarations in effect on the node whose name is being represented.
8782 * Typically, this will be the form in which the name occurred in the XML
8783 * source. This need not be the case if there are namespace declarations
8784 * in effect on the node that associate multiple prefixes with the same
8785 * namespace. However, an implementation may include information about
8786 * the original prefix in its representation of nodes; in this case, an
8787 * implementation can ensure that the returned string is always the same
8788 * as the QName used in the XML source. If the argument it omitted it
8789 * defaults to the context node.
8790 * Libxml keep the original prefix so the "real qualified name" used is
8791 * returned.
8792 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008793static void
Daniel Veillard04383752001-07-08 14:27:15 +00008794xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8795{
Owen Taylor3473f882001-02-23 17:55:21 +00008796 xmlXPathObjectPtr cur;
8797
8798 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008799 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8800 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008801 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008802 }
8803
8804 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008805 if ((ctxt->value == NULL) ||
8806 ((ctxt->value->type != XPATH_NODESET) &&
8807 (ctxt->value->type != XPATH_XSLT_TREE)))
8808 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008809 cur = valuePop(ctxt);
8810
Daniel Veillard911f49a2001-04-07 15:39:35 +00008811 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008812 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008813 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008814 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008815
Daniel Veillard04383752001-07-08 14:27:15 +00008816 switch (cur->nodesetval->nodeTab[i]->type) {
8817 case XML_ELEMENT_NODE:
8818 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008819 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008820 valuePush(ctxt,
8821 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008822 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8823 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008824 valuePush(ctxt,
8825 xmlXPathCacheNewString(ctxt->context,
8826 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008827 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008828 xmlChar *fullname;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008829
Daniel Veillardc00cda82003-04-07 10:22:39 +00008830 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8831 cur->nodesetval->nodeTab[i]->ns->prefix,
8832 NULL, 0);
8833 if (fullname == cur->nodesetval->nodeTab[i]->name)
8834 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8835 if (fullname == NULL) {
8836 XP_ERROR(XPATH_MEMORY_ERROR);
8837 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008838 valuePush(ctxt, xmlXPathCacheWrapString(
8839 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008840 }
8841 break;
8842 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008843 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8844 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008845 xmlXPathLocalNameFunction(ctxt, 1);
8846 }
Owen Taylor3473f882001-02-23 17:55:21 +00008847 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008848 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008849}
8850
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008851
8852/**
Owen Taylor3473f882001-02-23 17:55:21 +00008853 * xmlXPathStringFunction:
8854 * @ctxt: the XPath Parser context
8855 * @nargs: the number of arguments
8856 *
8857 * Implement the string() XPath function
8858 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008859 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008860 * - A node-set is converted to a string by returning the value of
8861 * the node in the node-set that is first in document order.
8862 * If the node-set is empty, an empty string is returned.
8863 * - A number is converted to a string as follows
Daniel Veillard45490ae2008-07-29 09:13:19 +00008864 * + NaN is converted to the string NaN
8865 * + positive zero is converted to the string 0
8866 * + negative zero is converted to the string 0
8867 * + positive infinity is converted to the string Infinity
8868 * + negative infinity is converted to the string -Infinity
Owen Taylor3473f882001-02-23 17:55:21 +00008869 * + if the number is an integer, the number is represented in
8870 * decimal form as a Number with no decimal point and no leading
8871 * zeros, preceded by a minus sign (-) if the number is negative
8872 * + otherwise, the number is represented in decimal form as a
8873 * Number including a decimal point with at least one digit
8874 * before the decimal point and at least one digit after the
8875 * decimal point, preceded by a minus sign (-) if the number
8876 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008877 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008878 * before the decimal point; beyond the one required digit
8879 * after the decimal point there must be as many, but only as
8880 * many, more digits as are needed to uniquely distinguish the
8881 * number from all other IEEE 754 numeric values.
8882 * - The boolean false value is converted to the string false.
8883 * The boolean true value is converted to the string true.
8884 *
8885 * If the argument is omitted, it defaults to a node-set with the
8886 * context node as its only member.
8887 */
8888void
8889xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8890 xmlXPathObjectPtr cur;
8891
Daniel Veillarda82b1822004-11-08 16:24:57 +00008892 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008893 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008894 valuePush(ctxt,
8895 xmlXPathCacheWrapString(ctxt->context,
8896 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008897 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008898 }
8899
8900 CHECK_ARITY(1);
8901 cur = valuePop(ctxt);
8902 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008903 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008904}
8905
8906/**
8907 * xmlXPathStringLengthFunction:
8908 * @ctxt: the XPath Parser context
8909 * @nargs: the number of arguments
8910 *
8911 * Implement the string-length() XPath function
8912 * number string-length(string?)
8913 * The string-length returns the number of characters in the string
8914 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8915 * the context node converted to a string, in other words the value
8916 * of the context node.
8917 */
8918void
8919xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8920 xmlXPathObjectPtr cur;
8921
8922 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008923 if ((ctxt == NULL) || (ctxt->context == NULL))
8924 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008925 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008926 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008927 } else {
8928 xmlChar *content;
8929
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008930 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008931 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8932 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008933 xmlFree(content);
8934 }
8935 return;
8936 }
8937 CHECK_ARITY(1);
8938 CAST_TO_STRING;
8939 CHECK_TYPE(XPATH_STRING);
8940 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008941 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
Daniel Veillard45490ae2008-07-29 09:13:19 +00008942 xmlUTF8Strlen(cur->stringval)));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008943 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008944}
8945
8946/**
8947 * xmlXPathConcatFunction:
8948 * @ctxt: the XPath Parser context
8949 * @nargs: the number of arguments
8950 *
8951 * Implement the concat() XPath function
8952 * string concat(string, string, string*)
8953 * The concat function returns the concatenation of its arguments.
8954 */
8955void
8956xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8957 xmlXPathObjectPtr cur, newobj;
8958 xmlChar *tmp;
8959
Daniel Veillarda82b1822004-11-08 16:24:57 +00008960 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008961 if (nargs < 2) {
8962 CHECK_ARITY(2);
8963 }
8964
8965 CAST_TO_STRING;
8966 cur = valuePop(ctxt);
8967 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008968 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008969 return;
8970 }
8971 nargs--;
8972
8973 while (nargs > 0) {
8974 CAST_TO_STRING;
8975 newobj = valuePop(ctxt);
8976 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008977 xmlXPathReleaseObject(ctxt->context, newobj);
8978 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008979 XP_ERROR(XPATH_INVALID_TYPE);
8980 }
8981 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8982 newobj->stringval = cur->stringval;
8983 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008984 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00008985 nargs--;
8986 }
8987 valuePush(ctxt, cur);
8988}
8989
8990/**
8991 * xmlXPathContainsFunction:
8992 * @ctxt: the XPath Parser context
8993 * @nargs: the number of arguments
8994 *
8995 * Implement the contains() XPath function
8996 * boolean contains(string, string)
8997 * The contains function returns true if the first argument string
8998 * contains the second argument string, and otherwise returns false.
8999 */
9000void
9001xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9002 xmlXPathObjectPtr hay, needle;
9003
9004 CHECK_ARITY(2);
9005 CAST_TO_STRING;
9006 CHECK_TYPE(XPATH_STRING);
9007 needle = valuePop(ctxt);
9008 CAST_TO_STRING;
9009 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009010
Owen Taylor3473f882001-02-23 17:55:21 +00009011 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009012 xmlXPathReleaseObject(ctxt->context, hay);
9013 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009014 XP_ERROR(XPATH_INVALID_TYPE);
9015 }
9016 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009017 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009018 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009019 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9020 xmlXPathReleaseObject(ctxt->context, hay);
9021 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009022}
9023
9024/**
9025 * xmlXPathStartsWithFunction:
9026 * @ctxt: the XPath Parser context
9027 * @nargs: the number of arguments
9028 *
9029 * Implement the starts-with() XPath function
9030 * boolean starts-with(string, string)
9031 * The starts-with function returns true if the first argument string
9032 * starts with the second argument string, and otherwise returns false.
9033 */
9034void
9035xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9036 xmlXPathObjectPtr hay, needle;
9037 int n;
9038
9039 CHECK_ARITY(2);
9040 CAST_TO_STRING;
9041 CHECK_TYPE(XPATH_STRING);
9042 needle = valuePop(ctxt);
9043 CAST_TO_STRING;
9044 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009045
Owen Taylor3473f882001-02-23 17:55:21 +00009046 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009047 xmlXPathReleaseObject(ctxt->context, hay);
9048 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009049 XP_ERROR(XPATH_INVALID_TYPE);
9050 }
9051 n = xmlStrlen(needle->stringval);
9052 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009053 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009054 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009055 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9056 xmlXPathReleaseObject(ctxt->context, hay);
9057 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009058}
9059
9060/**
9061 * xmlXPathSubstringFunction:
9062 * @ctxt: the XPath Parser context
9063 * @nargs: the number of arguments
9064 *
9065 * Implement the substring() XPath function
9066 * string substring(string, number, number?)
9067 * The substring function returns the substring of the first argument
9068 * starting at the position specified in the second argument with
9069 * length specified in the third argument. For example,
9070 * substring("12345",2,3) returns "234". If the third argument is not
9071 * specified, it returns the substring starting at the position specified
9072 * in the second argument and continuing to the end of the string. For
9073 * example, substring("12345",2) returns "2345". More precisely, each
9074 * character in the string (see [3.6 Strings]) is considered to have a
9075 * numeric position: the position of the first character is 1, the position
9076 * of the second character is 2 and so on. The returned substring contains
9077 * those characters for which the position of the character is greater than
9078 * or equal to the second argument and, if the third argument is specified,
9079 * less than the sum of the second and third arguments; the comparisons
9080 * and addition used for the above follow the standard IEEE 754 rules. Thus:
Daniel Veillard45490ae2008-07-29 09:13:19 +00009081 * - substring("12345", 1.5, 2.6) returns "234"
9082 * - substring("12345", 0, 3) returns "12"
9083 * - substring("12345", 0 div 0, 3) returns ""
9084 * - substring("12345", 1, 0 div 0) returns ""
9085 * - substring("12345", -42, 1 div 0) returns "12345"
9086 * - substring("12345", -1 div 0, 1 div 0) returns ""
Owen Taylor3473f882001-02-23 17:55:21 +00009087 */
9088void
9089xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9090 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009091 double le=0, in;
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009092 int i = 1, j = INT_MAX;
Owen Taylor3473f882001-02-23 17:55:21 +00009093
Owen Taylor3473f882001-02-23 17:55:21 +00009094 if (nargs < 2) {
9095 CHECK_ARITY(2);
9096 }
9097 if (nargs > 3) {
9098 CHECK_ARITY(3);
9099 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009100 /*
9101 * take care of possible last (position) argument
9102 */
Owen Taylor3473f882001-02-23 17:55:21 +00009103 if (nargs == 3) {
9104 CAST_TO_NUMBER;
9105 CHECK_TYPE(XPATH_NUMBER);
9106 len = valuePop(ctxt);
9107 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009108 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00009109 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009110
Owen Taylor3473f882001-02-23 17:55:21 +00009111 CAST_TO_NUMBER;
9112 CHECK_TYPE(XPATH_NUMBER);
9113 start = valuePop(ctxt);
9114 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009115 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00009116 CAST_TO_STRING;
9117 CHECK_TYPE(XPATH_STRING);
9118 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009119
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009120 if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9121 i = INT_MAX;
9122 } else if (in >= 1.0) {
9123 i = (int)in;
9124 if (in - floor(in) >= 0.5)
9125 i += 1;
Daniel Veillard9e412302002-06-10 15:59:44 +00009126 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009127
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009128 if (nargs == 3) {
9129 double rin, rle, end;
Owen Taylor3473f882001-02-23 17:55:21 +00009130
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009131 rin = floor(in);
9132 if (in - rin >= 0.5)
9133 rin += 1.0;
Daniel Veillard9e412302002-06-10 15:59:44 +00009134
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009135 rle = floor(le);
9136 if (le - rle >= 0.5)
9137 rle += 1.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009138
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009139 end = rin + rle;
9140 if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9141 j = 1;
9142 } else if (end < INT_MAX) {
9143 j = (int)end;
9144 }
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009145 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009146
9147 if (i < j) {
9148 xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009149 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009150 xmlFree(ret);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009151 } else {
9152 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009153 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009154
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009155 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009156}
9157
9158/**
9159 * xmlXPathSubstringBeforeFunction:
9160 * @ctxt: the XPath Parser context
9161 * @nargs: the number of arguments
9162 *
9163 * Implement the substring-before() XPath function
9164 * string substring-before(string, string)
9165 * The substring-before function returns the substring of the first
9166 * argument string that precedes the first occurrence of the second
9167 * argument string in the first argument string, or the empty string
9168 * if the first argument string does not contain the second argument
9169 * string. For example, substring-before("1999/04/01","/") returns 1999.
9170 */
9171void
9172xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9173 xmlXPathObjectPtr str;
9174 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009175 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009176 const xmlChar *point;
9177 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009178
Owen Taylor3473f882001-02-23 17:55:21 +00009179 CHECK_ARITY(2);
9180 CAST_TO_STRING;
9181 find = valuePop(ctxt);
9182 CAST_TO_STRING;
9183 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009184
Daniel Veillardade10f22012-07-12 09:43:27 +08009185 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009186 if (target) {
9187 point = xmlStrstr(str->stringval, find->stringval);
9188 if (point) {
9189 offset = (int)(point - str->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009190 xmlBufAdd(target, str->stringval, offset);
Owen Taylor3473f882001-02-23 17:55:21 +00009191 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009192 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009193 xmlBufContent(target)));
9194 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009195 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009196 xmlXPathReleaseObject(ctxt->context, str);
9197 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009198}
9199
9200/**
9201 * xmlXPathSubstringAfterFunction:
9202 * @ctxt: the XPath Parser context
9203 * @nargs: the number of arguments
9204 *
9205 * Implement the substring-after() XPath function
9206 * string substring-after(string, string)
9207 * The substring-after function returns the substring of the first
9208 * argument string that follows the first occurrence of the second
9209 * argument string in the first argument string, or the empty stringi
9210 * if the first argument string does not contain the second argument
9211 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9212 * and substring-after("1999/04/01","19") returns 99/04/01.
9213 */
9214void
9215xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9216 xmlXPathObjectPtr str;
9217 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009218 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009219 const xmlChar *point;
9220 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009221
Owen Taylor3473f882001-02-23 17:55:21 +00009222 CHECK_ARITY(2);
9223 CAST_TO_STRING;
9224 find = valuePop(ctxt);
9225 CAST_TO_STRING;
9226 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009227
Daniel Veillardade10f22012-07-12 09:43:27 +08009228 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009229 if (target) {
9230 point = xmlStrstr(str->stringval, find->stringval);
9231 if (point) {
9232 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009233 xmlBufAdd(target, &str->stringval[offset],
Owen Taylor3473f882001-02-23 17:55:21 +00009234 xmlStrlen(str->stringval) - offset);
9235 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009236 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009237 xmlBufContent(target)));
9238 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009239 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009240 xmlXPathReleaseObject(ctxt->context, str);
9241 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009242}
9243
9244/**
9245 * xmlXPathNormalizeFunction:
9246 * @ctxt: the XPath Parser context
9247 * @nargs: the number of arguments
9248 *
9249 * Implement the normalize-space() XPath function
9250 * string normalize-space(string?)
9251 * The normalize-space function returns the argument string with white
9252 * space normalized by stripping leading and trailing whitespace
9253 * and replacing sequences of whitespace characters by a single
9254 * space. Whitespace characters are the same allowed by the S production
9255 * in XML. If the argument is omitted, it defaults to the context
9256 * node converted to a string, in other words the value of the context node.
9257 */
9258void
9259xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9260 xmlXPathObjectPtr obj = NULL;
9261 xmlChar *source = NULL;
Daniel Veillardade10f22012-07-12 09:43:27 +08009262 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009263 xmlChar blank;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009264
Daniel Veillarda82b1822004-11-08 16:24:57 +00009265 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009266 if (nargs == 0) {
9267 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009268 valuePush(ctxt,
9269 xmlXPathCacheWrapString(ctxt->context,
9270 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009271 nargs = 1;
9272 }
9273
9274 CHECK_ARITY(1);
9275 CAST_TO_STRING;
9276 CHECK_TYPE(XPATH_STRING);
9277 obj = valuePop(ctxt);
9278 source = obj->stringval;
9279
Daniel Veillardade10f22012-07-12 09:43:27 +08009280 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009281 if (target && source) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00009282
Owen Taylor3473f882001-02-23 17:55:21 +00009283 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009284 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009285 source++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009286
Owen Taylor3473f882001-02-23 17:55:21 +00009287 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9288 blank = 0;
9289 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009290 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009291 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009292 } else {
9293 if (blank) {
Daniel Veillardade10f22012-07-12 09:43:27 +08009294 xmlBufAdd(target, &blank, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009295 blank = 0;
9296 }
Daniel Veillardade10f22012-07-12 09:43:27 +08009297 xmlBufAdd(target, source, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009298 }
9299 source++;
9300 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009301 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009302 xmlBufContent(target)));
9303 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009304 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009305 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009306}
9307
9308/**
9309 * xmlXPathTranslateFunction:
9310 * @ctxt: the XPath Parser context
9311 * @nargs: the number of arguments
9312 *
9313 * Implement the translate() XPath function
9314 * string translate(string, string, string)
9315 * The translate function returns the first argument string with
9316 * occurrences of characters in the second argument string replaced
9317 * by the character at the corresponding position in the third argument
9318 * string. For example, translate("bar","abc","ABC") returns the string
9319 * BAr. If there is a character in the second argument string with no
9320 * character at a corresponding position in the third argument string
9321 * (because the second argument string is longer than the third argument
9322 * string), then occurrences of that character in the first argument
9323 * string are removed. For example, translate("--aaa--","abc-","ABC")
9324 * returns "AAA". If a character occurs more than once in second
9325 * argument string, then the first occurrence determines the replacement
9326 * character. If the third argument string is longer than the second
9327 * argument string, then excess characters are ignored.
9328 */
9329void
9330xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009331 xmlXPathObjectPtr str;
9332 xmlXPathObjectPtr from;
9333 xmlXPathObjectPtr to;
Daniel Veillardade10f22012-07-12 09:43:27 +08009334 xmlBufPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009335 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009336 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009337 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009338 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009339
Daniel Veillarde043ee12001-04-16 14:08:07 +00009340 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009341
Daniel Veillarde043ee12001-04-16 14:08:07 +00009342 CAST_TO_STRING;
9343 to = valuePop(ctxt);
9344 CAST_TO_STRING;
9345 from = valuePop(ctxt);
9346 CAST_TO_STRING;
9347 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009348
Daniel Veillardade10f22012-07-12 09:43:27 +08009349 target = xmlBufCreate();
Daniel Veillarde043ee12001-04-16 14:08:07 +00009350 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009351 max = xmlUTF8Strlen(to->stringval);
9352 for (cptr = str->stringval; (ch=*cptr); ) {
9353 offset = xmlUTF8Strloc(from->stringval, cptr);
9354 if (offset >= 0) {
9355 if (offset < max) {
9356 point = xmlUTF8Strpos(to->stringval, offset);
9357 if (point)
Daniel Veillardade10f22012-07-12 09:43:27 +08009358 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009359 }
9360 } else
Daniel Veillardade10f22012-07-12 09:43:27 +08009361 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009362
9363 /* Step to next character in input */
9364 cptr++;
9365 if ( ch & 0x80 ) {
9366 /* if not simple ascii, verify proper format */
9367 if ( (ch & 0xc0) != 0xc0 ) {
9368 xmlGenericError(xmlGenericErrorContext,
9369 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009370 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009371 break;
9372 }
9373 /* then skip over remaining bytes for this char */
9374 while ( (ch <<= 1) & 0x80 )
9375 if ( (*cptr++ & 0xc0) != 0x80 ) {
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 if (ch & 0x80) /* must have had error encountered */
9382 break;
9383 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009384 }
Owen Taylor3473f882001-02-23 17:55:21 +00009385 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009386 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009387 xmlBufContent(target)));
9388 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009389 xmlXPathReleaseObject(ctxt->context, str);
9390 xmlXPathReleaseObject(ctxt->context, from);
9391 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009392}
9393
9394/**
9395 * xmlXPathBooleanFunction:
9396 * @ctxt: the XPath Parser context
9397 * @nargs: the number of arguments
9398 *
9399 * Implement the boolean() XPath function
9400 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009401 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009402 * - a number is true if and only if it is neither positive or
9403 * negative zero nor NaN
9404 * - a node-set is true if and only if it is non-empty
9405 * - a string is true if and only if its length is non-zero
9406 */
9407void
9408xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9409 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009410
9411 CHECK_ARITY(1);
9412 cur = valuePop(ctxt);
9413 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009414 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009415 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009416}
9417
9418/**
9419 * xmlXPathNotFunction:
9420 * @ctxt: the XPath Parser context
9421 * @nargs: the number of arguments
9422 *
9423 * Implement the not() XPath function
9424 * boolean not(boolean)
9425 * The not function returns true if its argument is false,
9426 * and false otherwise.
9427 */
9428void
9429xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9430 CHECK_ARITY(1);
9431 CAST_TO_BOOLEAN;
9432 CHECK_TYPE(XPATH_BOOLEAN);
9433 ctxt->value->boolval = ! ctxt->value->boolval;
9434}
9435
9436/**
9437 * xmlXPathTrueFunction:
9438 * @ctxt: the XPath Parser context
9439 * @nargs: the number of arguments
9440 *
9441 * Implement the true() XPath function
9442 * boolean true()
9443 */
9444void
9445xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9446 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009447 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009448}
9449
9450/**
9451 * xmlXPathFalseFunction:
9452 * @ctxt: the XPath Parser context
9453 * @nargs: the number of arguments
9454 *
9455 * Implement the false() XPath function
9456 * boolean false()
9457 */
9458void
9459xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9460 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009461 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009462}
9463
9464/**
9465 * xmlXPathLangFunction:
9466 * @ctxt: the XPath Parser context
9467 * @nargs: the number of arguments
9468 *
9469 * Implement the lang() XPath function
9470 * boolean lang(string)
9471 * The lang function returns true or false depending on whether the
9472 * language of the context node as specified by xml:lang attributes
9473 * is the same as or is a sublanguage of the language specified by
9474 * the argument string. The language of the context node is determined
9475 * by the value of the xml:lang attribute on the context node, or, if
9476 * the context node has no xml:lang attribute, by the value of the
9477 * xml:lang attribute on the nearest ancestor of the context node that
9478 * has an xml:lang attribute. If there is no such attribute, then lang
9479 * returns false. If there is such an attribute, then lang returns
9480 * true if the attribute value is equal to the argument ignoring case,
9481 * or if there is some suffix starting with - such that the attribute
9482 * value is equal to the argument ignoring that suffix of the attribute
9483 * value and ignoring case.
9484 */
9485void
9486xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009487 xmlXPathObjectPtr val = NULL;
9488 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009489 const xmlChar *lang;
9490 int ret = 0;
9491 int i;
9492
9493 CHECK_ARITY(1);
9494 CAST_TO_STRING;
9495 CHECK_TYPE(XPATH_STRING);
9496 val = valuePop(ctxt);
9497 lang = val->stringval;
9498 theLang = xmlNodeGetLang(ctxt->context->node);
9499 if ((theLang != NULL) && (lang != NULL)) {
9500 for (i = 0;lang[i] != 0;i++)
9501 if (toupper(lang[i]) != toupper(theLang[i]))
9502 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009503 if ((theLang[i] == 0) || (theLang[i] == '-'))
9504 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009505 }
9506not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009507 if (theLang != NULL)
9508 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009509
9510 xmlXPathReleaseObject(ctxt->context, val);
9511 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009512}
9513
9514/**
9515 * xmlXPathNumberFunction:
9516 * @ctxt: the XPath Parser context
9517 * @nargs: the number of arguments
9518 *
9519 * Implement the number() XPath function
9520 * number number(object?)
9521 */
9522void
9523xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9524 xmlXPathObjectPtr cur;
9525 double res;
9526
Daniel Veillarda82b1822004-11-08 16:24:57 +00009527 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009528 if (nargs == 0) {
9529 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009530 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009531 } else {
9532 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9533
9534 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009535 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009536 xmlFree(content);
9537 }
9538 return;
9539 }
9540
9541 CHECK_ARITY(1);
9542 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009543 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009544}
9545
9546/**
9547 * xmlXPathSumFunction:
9548 * @ctxt: the XPath Parser context
9549 * @nargs: the number of arguments
9550 *
9551 * Implement the sum() XPath function
9552 * number sum(node-set)
9553 * The sum function returns the sum of the values of the nodes in
9554 * the argument node-set.
9555 */
9556void
9557xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9558 xmlXPathObjectPtr cur;
9559 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009560 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009561
9562 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009563 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009564 ((ctxt->value->type != XPATH_NODESET) &&
9565 (ctxt->value->type != XPATH_XSLT_TREE)))
9566 XP_ERROR(XPATH_INVALID_TYPE);
9567 cur = valuePop(ctxt);
9568
William M. Brack08171912003-12-29 02:52:11 +00009569 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009570 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9571 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009572 }
9573 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009574 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9575 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009576}
9577
9578/**
9579 * xmlXPathFloorFunction:
9580 * @ctxt: the XPath Parser context
9581 * @nargs: the number of arguments
9582 *
9583 * Implement the floor() XPath function
9584 * number floor(number)
9585 * The floor function returns the largest (closest to positive infinity)
9586 * number that is not greater than the argument and that is an integer.
9587 */
9588void
9589xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9590 CHECK_ARITY(1);
9591 CAST_TO_NUMBER;
9592 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009593
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009594 ctxt->value->floatval = floor(ctxt->value->floatval);
Owen Taylor3473f882001-02-23 17:55:21 +00009595}
9596
9597/**
9598 * xmlXPathCeilingFunction:
9599 * @ctxt: the XPath Parser context
9600 * @nargs: the number of arguments
9601 *
9602 * Implement the ceiling() XPath function
9603 * number ceiling(number)
9604 * The ceiling function returns the smallest (closest to negative infinity)
9605 * number that is not less than the argument and that is an integer.
9606 */
9607void
9608xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Owen Taylor3473f882001-02-23 17:55:21 +00009609 CHECK_ARITY(1);
9610 CAST_TO_NUMBER;
9611 CHECK_TYPE(XPATH_NUMBER);
9612
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009613#ifdef _AIX
9614 /* Work around buggy ceil() function on AIX */
9615 ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
9616#else
Owen Taylor3473f882001-02-23 17:55:21 +00009617 ctxt->value->floatval = ceil(ctxt->value->floatval);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009618#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009619}
9620
9621/**
9622 * xmlXPathRoundFunction:
9623 * @ctxt: the XPath Parser context
9624 * @nargs: the number of arguments
9625 *
9626 * Implement the round() XPath function
9627 * number round(number)
9628 * The round function returns the number that is closest to the
9629 * argument and that is an integer. If there are two such numbers,
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009630 * then the one that is closest to positive infinity is returned.
Owen Taylor3473f882001-02-23 17:55:21 +00009631 */
9632void
9633xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9634 double f;
9635
9636 CHECK_ARITY(1);
9637 CAST_TO_NUMBER;
9638 CHECK_TYPE(XPATH_NUMBER);
9639
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009640 f = ctxt->value->floatval;
9641
Nick Wellnhofer8813f392017-09-21 00:11:26 +02009642 if ((f >= -0.5) && (f < 0.5)) {
9643 /* Handles negative zero. */
9644 ctxt->value->floatval *= 0.0;
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009645 }
9646 else {
9647 double rounded = floor(f);
9648 if (f - rounded >= 0.5)
9649 rounded += 1.0;
9650 ctxt->value->floatval = rounded;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009651 }
Owen Taylor3473f882001-02-23 17:55:21 +00009652}
9653
9654/************************************************************************
9655 * *
9656 * The Parser *
9657 * *
9658 ************************************************************************/
9659
9660/*
William M. Brack08171912003-12-29 02:52:11 +00009661 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009662 * implementation.
9663 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009664static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009665static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009666static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009667static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009668static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9669 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009670
9671/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009672 * xmlXPathCurrentChar:
9673 * @ctxt: the XPath parser context
9674 * @cur: pointer to the beginning of the char
9675 * @len: pointer to the length of the char read
9676 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009677 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009678 * bytes in the input buffer.
9679 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009680 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009681 */
9682
9683static int
9684xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9685 unsigned char c;
9686 unsigned int val;
9687 const xmlChar *cur;
9688
9689 if (ctxt == NULL)
9690 return(0);
9691 cur = ctxt->cur;
9692
9693 /*
9694 * We are supposed to handle UTF8, check it's valid
9695 * From rfc2044: encoding of the Unicode values on UTF-8:
9696 *
9697 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9698 * 0000 0000-0000 007F 0xxxxxxx
9699 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
Daniel Veillard45490ae2008-07-29 09:13:19 +00009700 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
Daniel Veillard61d80a22001-04-27 17:13:01 +00009701 *
9702 * Check for the 0x110000 limit too
9703 */
9704 c = *cur;
9705 if (c & 0x80) {
9706 if ((cur[1] & 0xc0) != 0x80)
9707 goto encoding_error;
9708 if ((c & 0xe0) == 0xe0) {
9709
9710 if ((cur[2] & 0xc0) != 0x80)
9711 goto encoding_error;
9712 if ((c & 0xf0) == 0xf0) {
9713 if (((c & 0xf8) != 0xf0) ||
9714 ((cur[3] & 0xc0) != 0x80))
9715 goto encoding_error;
9716 /* 4-byte code */
9717 *len = 4;
9718 val = (cur[0] & 0x7) << 18;
9719 val |= (cur[1] & 0x3f) << 12;
9720 val |= (cur[2] & 0x3f) << 6;
9721 val |= cur[3] & 0x3f;
9722 } else {
9723 /* 3-byte code */
9724 *len = 3;
9725 val = (cur[0] & 0xf) << 12;
9726 val |= (cur[1] & 0x3f) << 6;
9727 val |= cur[2] & 0x3f;
9728 }
9729 } else {
9730 /* 2-byte code */
9731 *len = 2;
9732 val = (cur[0] & 0x1f) << 6;
9733 val |= cur[1] & 0x3f;
9734 }
9735 if (!IS_CHAR(val)) {
9736 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009737 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009738 return(val);
9739 } else {
9740 /* 1-byte code */
9741 *len = 1;
9742 return((int) *cur);
9743 }
9744encoding_error:
9745 /*
William M. Brack08171912003-12-29 02:52:11 +00009746 * If we detect an UTF8 error that probably means that the
9747 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009748 * declaration header. Report the error and switch the encoding
9749 * to ISO-Latin-1 (if you don't like this policy, just declare the
9750 * encoding !)
9751 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009752 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009753 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009754}
9755
9756/**
Owen Taylor3473f882001-02-23 17:55:21 +00009757 * xmlXPathParseNCName:
9758 * @ctxt: the XPath Parser context
9759 *
9760 * parse an XML namespace non qualified name.
9761 *
9762 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9763 *
9764 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9765 * CombiningChar | Extender
9766 *
9767 * Returns the namespace name or NULL
9768 */
9769
9770xmlChar *
9771xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009772 const xmlChar *in;
9773 xmlChar *ret;
9774 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009775
Daniel Veillarda82b1822004-11-08 16:24:57 +00009776 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009777 /*
9778 * Accelerator for simple ASCII names
9779 */
9780 in = ctxt->cur;
9781 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9782 ((*in >= 0x41) && (*in <= 0x5A)) ||
9783 (*in == '_')) {
9784 in++;
9785 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9786 ((*in >= 0x41) && (*in <= 0x5A)) ||
9787 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009788 (*in == '_') || (*in == '.') ||
9789 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009790 in++;
9791 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9792 (*in == '[') || (*in == ']') || (*in == ':') ||
9793 (*in == '@') || (*in == '*')) {
9794 count = in - ctxt->cur;
9795 if (count == 0)
9796 return(NULL);
9797 ret = xmlStrndup(ctxt->cur, count);
9798 ctxt->cur = in;
9799 return(ret);
9800 }
9801 }
9802 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009803}
9804
Daniel Veillard2156a562001-04-28 12:24:34 +00009805
Owen Taylor3473f882001-02-23 17:55:21 +00009806/**
9807 * xmlXPathParseQName:
9808 * @ctxt: the XPath Parser context
Daniel Veillard45490ae2008-07-29 09:13:19 +00009809 * @prefix: a xmlChar **
Owen Taylor3473f882001-02-23 17:55:21 +00009810 *
9811 * parse an XML qualified name
9812 *
9813 * [NS 5] QName ::= (Prefix ':')? LocalPart
9814 *
9815 * [NS 6] Prefix ::= NCName
9816 *
9817 * [NS 7] LocalPart ::= NCName
9818 *
9819 * Returns the function returns the local part, and prefix is updated
9820 * to get the Prefix if any.
9821 */
9822
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009823static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009824xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9825 xmlChar *ret = NULL;
9826
9827 *prefix = NULL;
9828 ret = xmlXPathParseNCName(ctxt);
Daniel Veillard074f37e2008-09-01 13:38:22 +00009829 if (ret && CUR == ':') {
Owen Taylor3473f882001-02-23 17:55:21 +00009830 *prefix = ret;
9831 NEXT;
9832 ret = xmlXPathParseNCName(ctxt);
9833 }
9834 return(ret);
9835}
9836
9837/**
9838 * xmlXPathParseName:
9839 * @ctxt: the XPath Parser context
9840 *
9841 * parse an XML name
9842 *
9843 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9844 * CombiningChar | Extender
9845 *
9846 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9847 *
9848 * Returns the namespace name or NULL
9849 */
9850
9851xmlChar *
9852xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009853 const xmlChar *in;
9854 xmlChar *ret;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009855 size_t count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009856
Daniel Veillarda82b1822004-11-08 16:24:57 +00009857 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009858 /*
9859 * Accelerator for simple ASCII names
9860 */
9861 in = ctxt->cur;
9862 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9863 ((*in >= 0x41) && (*in <= 0x5A)) ||
9864 (*in == '_') || (*in == ':')) {
9865 in++;
9866 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9867 ((*in >= 0x41) && (*in <= 0x5A)) ||
9868 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009869 (*in == '_') || (*in == '-') ||
9870 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009871 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009872 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009873 count = in - ctxt->cur;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009874 if (count > XML_MAX_NAME_LENGTH) {
9875 ctxt->cur = in;
9876 XP_ERRORNULL(XPATH_EXPR_ERROR);
9877 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009878 ret = xmlStrndup(ctxt->cur, count);
9879 ctxt->cur = in;
9880 return(ret);
9881 }
9882 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009883 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009884}
9885
Daniel Veillard61d80a22001-04-27 17:13:01 +00009886static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009887xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009888 xmlChar buf[XML_MAX_NAMELEN + 5];
9889 int len = 0, l;
9890 int c;
9891
9892 /*
9893 * Handler for more complex cases
9894 */
9895 c = CUR_CHAR(l);
9896 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009897 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9898 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009899 (!IS_LETTER(c) && (c != '_') &&
Nick Wellnhofere2893902016-04-21 19:19:23 +02009900 ((!qualified) || (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009901 return(NULL);
9902 }
9903
9904 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9905 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9906 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009907 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009908 (IS_COMBINING(c)) ||
9909 (IS_EXTENDER(c)))) {
9910 COPY_BUF(l,buf,len,c);
9911 NEXTL(l);
9912 c = CUR_CHAR(l);
9913 if (len >= XML_MAX_NAMELEN) {
9914 /*
9915 * Okay someone managed to make a huge name, so he's ready to pay
9916 * for the processing speed.
9917 */
9918 xmlChar *buffer;
9919 int max = len * 2;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009920
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009921 if (len > XML_MAX_NAME_LENGTH) {
9922 XP_ERRORNULL(XPATH_EXPR_ERROR);
9923 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009924 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009925 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009926 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009927 }
9928 memcpy(buffer, buf, len);
9929 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9930 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009931 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009932 (IS_COMBINING(c)) ||
9933 (IS_EXTENDER(c))) {
9934 if (len + 10 > max) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009935 xmlChar *tmp;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009936 if (max > XML_MAX_NAME_LENGTH) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009937 xmlFree(buffer);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009938 XP_ERRORNULL(XPATH_EXPR_ERROR);
9939 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009940 max *= 2;
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009941 tmp = (xmlChar *) xmlRealloc(buffer,
9942 max * sizeof(xmlChar));
9943 if (tmp == NULL) {
9944 xmlFree(buffer);
Daniel Veillard24505b02005-07-28 23:49:35 +00009945 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009946 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -07009947 buffer = tmp;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009948 }
9949 COPY_BUF(l,buffer,len,c);
9950 NEXTL(l);
9951 c = CUR_CHAR(l);
9952 }
9953 buffer[len] = 0;
9954 return(buffer);
9955 }
9956 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009957 if (len == 0)
9958 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009959 return(xmlStrndup(buf, len));
9960}
Daniel Veillard3cd72402002-05-13 10:33:30 +00009961
9962#define MAX_FRAC 20
9963
Owen Taylor3473f882001-02-23 17:55:21 +00009964/**
9965 * xmlXPathStringEvalNumber:
9966 * @str: A string to scan
9967 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00009968 * [30a] Float ::= Number ('e' Digits?)?
9969 *
Owen Taylor3473f882001-02-23 17:55:21 +00009970 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +00009971 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +00009972 * [31] Digits ::= [0-9]+
9973 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009974 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00009975 * In complement of the Number expression, this function also handles
9976 * negative values : '-' Number.
9977 *
9978 * Returns the double value.
9979 */
9980double
9981xmlXPathStringEvalNumber(const xmlChar *str) {
9982 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00009983 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009984 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009985 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009986 int exponent = 0;
9987 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009988#ifdef __GNUC__
9989 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009990 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009991#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00009992 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00009993 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009994 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
Nick Wellnhofer8813f392017-09-21 00:11:26 +02009995 return(NAN);
Owen Taylor3473f882001-02-23 17:55:21 +00009996 }
9997 if (*cur == '-') {
9998 isneg = 1;
9999 cur++;
10000 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010001
10002#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010003 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010004 * tmp/temp is a workaround against a gcc compiler bug
10005 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010006 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010007 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010008 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010009 ret = ret * 10;
10010 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +000010011 ok = 1;
10012 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +000010013 temp = (double) tmp;
10014 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010015 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010016#else
Daniel Veillard7b416132002-03-07 08:36:03 +000010017 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010018 while ((*cur >= '0') && (*cur <= '9')) {
10019 ret = ret * 10 + (*cur - '0');
10020 ok = 1;
10021 cur++;
10022 }
10023#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010024
Owen Taylor3473f882001-02-23 17:55:21 +000010025 if (*cur == '.') {
Nick Wellnhofera8518682017-05-29 20:14:42 +020010026 int v, frac = 0, max;
Daniel Veillard3cd72402002-05-13 10:33:30 +000010027 double fraction = 0;
10028
Owen Taylor3473f882001-02-23 17:55:21 +000010029 cur++;
10030 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
Nick Wellnhofer8813f392017-09-21 00:11:26 +020010031 return(NAN);
Owen Taylor3473f882001-02-23 17:55:21 +000010032 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010033 while (*cur == '0') {
10034 frac = frac + 1;
10035 cur++;
10036 }
10037 max = frac + MAX_FRAC;
10038 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
Daniel Veillard3cd72402002-05-13 10:33:30 +000010039 v = (*cur - '0');
10040 fraction = fraction * 10 + v;
10041 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010042 cur++;
10043 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010044 fraction /= pow(10.0, frac);
Daniel Veillard3cd72402002-05-13 10:33:30 +000010045 ret = ret + fraction;
10046 while ((*cur >= '0') && (*cur <= '9'))
10047 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010048 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010049 if ((*cur == 'e') || (*cur == 'E')) {
10050 cur++;
10051 if (*cur == '-') {
10052 is_exponent_negative = 1;
10053 cur++;
William M. Brack99127052004-05-24 02:52:28 +000010054 } else if (*cur == '+') {
10055 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010056 }
10057 while ((*cur >= '0') && (*cur <= '9')) {
Nick Wellnhoferf4029cd2016-04-21 16:37:26 +020010058 if (exponent < 1000000)
10059 exponent = exponent * 10 + (*cur - '0');
Bjorn Reese70a9da52001-04-21 16:57:29 +000010060 cur++;
10061 }
10062 }
William M. Brack76e95df2003-10-18 16:20:14 +000010063 while (IS_BLANK_CH(*cur)) cur++;
Nick Wellnhofer8813f392017-09-21 00:11:26 +020010064 if (*cur != 0) return(NAN);
Owen Taylor3473f882001-02-23 17:55:21 +000010065 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010066 if (is_exponent_negative) exponent = -exponent;
10067 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +000010068 return(ret);
10069}
10070
10071/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010072 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +000010073 * @ctxt: the XPath Parser context
10074 *
10075 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010076 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010077 * [31] Digits ::= [0-9]+
10078 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010079 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +000010080 *
10081 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010082static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010083xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10084{
Owen Taylor3473f882001-02-23 17:55:21 +000010085 double ret = 0.0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010086 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010087 int exponent = 0;
10088 int is_exponent_negative = 0;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010089 xmlXPathObjectPtr num;
Daniel Veillard7b416132002-03-07 08:36:03 +000010090#ifdef __GNUC__
10091 unsigned long tmp = 0;
10092 double temp;
10093#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010094
10095 CHECK_ERROR;
10096 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10097 XP_ERROR(XPATH_NUMBER_ERROR);
10098 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010099#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010100 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010101 * tmp/temp is a workaround against a gcc compiler bug
10102 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010103 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010104 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010105 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010106 ret = ret * 10;
10107 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010108 ok = 1;
10109 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010110 temp = (double) tmp;
10111 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010112 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010113#else
10114 ret = 0;
10115 while ((CUR >= '0') && (CUR <= '9')) {
10116 ret = ret * 10 + (CUR - '0');
10117 ok = 1;
10118 NEXT;
10119 }
10120#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010121 if (CUR == '.') {
Nick Wellnhofera8518682017-05-29 20:14:42 +020010122 int v, frac = 0, max;
Phil Shaferee32ad32010-11-03 20:53:55 +010010123 double fraction = 0;
10124
Owen Taylor3473f882001-02-23 17:55:21 +000010125 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010126 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10127 XP_ERROR(XPATH_NUMBER_ERROR);
10128 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010129 while (CUR == '0') {
10130 frac = frac + 1;
10131 NEXT;
10132 }
10133 max = frac + MAX_FRAC;
10134 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
Phil Shaferee32ad32010-11-03 20:53:55 +010010135 v = (CUR - '0');
10136 fraction = fraction * 10 + v;
10137 frac = frac + 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010138 NEXT;
10139 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010140 fraction /= pow(10.0, frac);
Phil Shaferee32ad32010-11-03 20:53:55 +010010141 ret = ret + fraction;
10142 while ((CUR >= '0') && (CUR <= '9'))
10143 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +000010144 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010145 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010146 NEXT;
10147 if (CUR == '-') {
10148 is_exponent_negative = 1;
10149 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010150 } else if (CUR == '+') {
10151 NEXT;
10152 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010153 while ((CUR >= '0') && (CUR <= '9')) {
Nick Wellnhoferf4029cd2016-04-21 16:37:26 +020010154 if (exponent < 1000000)
10155 exponent = exponent * 10 + (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010156 NEXT;
10157 }
10158 if (is_exponent_negative)
10159 exponent = -exponent;
10160 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010161 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010162 num = xmlXPathCacheNewFloat(ctxt->context, ret);
10163 if (num == NULL) {
10164 ctxt->error = XPATH_MEMORY_ERROR;
10165 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
10166 NULL) == -1) {
10167 xmlXPathReleaseObject(ctxt->context, num);
10168 }
Owen Taylor3473f882001-02-23 17:55:21 +000010169}
10170
10171/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010172 * xmlXPathParseLiteral:
10173 * @ctxt: the XPath Parser context
10174 *
10175 * Parse a Literal
10176 *
10177 * [29] Literal ::= '"' [^"]* '"'
10178 * | "'" [^']* "'"
10179 *
10180 * Returns the value found or NULL in case of error
10181 */
10182static xmlChar *
10183xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10184 const xmlChar *q;
10185 xmlChar *ret = NULL;
10186
10187 if (CUR == '"') {
10188 NEXT;
10189 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010190 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010191 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010192 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010193 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010194 } else {
10195 ret = xmlStrndup(q, CUR_PTR - q);
10196 NEXT;
10197 }
10198 } else if (CUR == '\'') {
10199 NEXT;
10200 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010201 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010202 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010203 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010204 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010205 } else {
10206 ret = xmlStrndup(q, CUR_PTR - q);
10207 NEXT;
10208 }
10209 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010210 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010211 }
10212 return(ret);
10213}
10214
10215/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010216 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010217 * @ctxt: the XPath Parser context
10218 *
10219 * Parse a Literal and push it on the stack.
10220 *
10221 * [29] Literal ::= '"' [^"]* '"'
10222 * | "'" [^']* "'"
10223 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010224 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010225 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010226static void
10227xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010228 const xmlChar *q;
10229 xmlChar *ret = NULL;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010230 xmlXPathObjectPtr lit;
Owen Taylor3473f882001-02-23 17:55:21 +000010231
10232 if (CUR == '"') {
10233 NEXT;
10234 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010235 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010236 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010237 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010238 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10239 } else {
10240 ret = xmlStrndup(q, CUR_PTR - q);
10241 NEXT;
10242 }
10243 } else if (CUR == '\'') {
10244 NEXT;
10245 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010246 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010247 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010248 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010249 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10250 } else {
10251 ret = xmlStrndup(q, CUR_PTR - q);
10252 NEXT;
10253 }
10254 } else {
10255 XP_ERROR(XPATH_START_LITERAL_ERROR);
10256 }
10257 if (ret == NULL) return;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010258 lit = xmlXPathCacheNewString(ctxt->context, ret);
10259 if (lit == NULL) {
10260 ctxt->error = XPATH_MEMORY_ERROR;
10261 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10262 NULL) == -1) {
10263 xmlXPathReleaseObject(ctxt->context, lit);
10264 }
Owen Taylor3473f882001-02-23 17:55:21 +000010265 xmlFree(ret);
10266}
10267
10268/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010269 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010270 * @ctxt: the XPath Parser context
10271 *
10272 * Parse a VariableReference, evaluate it and push it on the stack.
10273 *
10274 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010275 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010276 * of any of the types that are possible for the value of an expression,
10277 * and may also be of additional types not specified here.
10278 *
10279 * Early evaluation is possible since:
10280 * The variable bindings [...] used to evaluate a subexpression are
Daniel Veillard45490ae2008-07-29 09:13:19 +000010281 * always the same as those used to evaluate the containing expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010282 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010283 * [36] VariableReference ::= '$' QName
Owen Taylor3473f882001-02-23 17:55:21 +000010284 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010285static void
10286xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010287 xmlChar *name;
10288 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010289
10290 SKIP_BLANKS;
10291 if (CUR != '$') {
10292 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10293 }
10294 NEXT;
10295 name = xmlXPathParseQName(ctxt, &prefix);
10296 if (name == NULL) {
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020010297 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010298 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10299 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010300 ctxt->comp->last = -1;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010301 if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
10302 xmlFree(prefix);
10303 xmlFree(name);
10304 }
Owen Taylor3473f882001-02-23 17:55:21 +000010305 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010306 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
Daniel Veillard47881282012-09-07 14:24:50 +080010307 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
Daniel Veillardb3d14912005-09-04 20:47:39 +000010308 }
Owen Taylor3473f882001-02-23 17:55:21 +000010309}
10310
10311/**
10312 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010313 * @name: a name string
10314 *
10315 * Is the name given a NodeType one.
10316 *
10317 * [38] NodeType ::= 'comment'
10318 * | 'text'
10319 * | 'processing-instruction'
10320 * | 'node'
10321 *
10322 * Returns 1 if true 0 otherwise
10323 */
10324int
10325xmlXPathIsNodeType(const xmlChar *name) {
10326 if (name == NULL)
10327 return(0);
10328
Daniel Veillard1971ee22002-01-31 20:29:19 +000010329 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010330 return(1);
10331 if (xmlStrEqual(name, BAD_CAST "text"))
10332 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010333 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010334 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010335 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010336 return(1);
10337 return(0);
10338}
10339
10340/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010341 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010342 * @ctxt: the XPath Parser context
10343 *
10344 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010345 * [17] Argument ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010346 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010347 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010348 * pushed on the stack
10349 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010350static void
10351xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010352 xmlChar *name;
10353 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010354 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010355 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010356
10357 name = xmlXPathParseQName(ctxt, &prefix);
10358 if (name == NULL) {
Daniel Veillard074f37e2008-09-01 13:38:22 +000010359 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010360 XP_ERROR(XPATH_EXPR_ERROR);
10361 }
10362 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010363#ifdef DEBUG_EXPR
10364 if (prefix == NULL)
10365 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10366 name);
10367 else
10368 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10369 prefix, name);
10370#endif
10371
Owen Taylor3473f882001-02-23 17:55:21 +000010372 if (CUR != '(') {
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020010373 xmlFree(name);
10374 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010375 XP_ERROR(XPATH_EXPR_ERROR);
10376 }
10377 NEXT;
10378 SKIP_BLANKS;
10379
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010380 /*
10381 * Optimization for count(): we don't need the node-set to be sorted.
10382 */
10383 if ((prefix == NULL) && (name[0] == 'c') &&
10384 xmlStrEqual(name, BAD_CAST "count"))
10385 {
10386 sort = 0;
10387 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010388 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010389 if (CUR != ')') {
10390 while (CUR != 0) {
10391 int op1 = ctxt->comp->last;
10392 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010393 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard074f37e2008-09-01 13:38:22 +000010394 if (ctxt->error != XPATH_EXPRESSION_OK) {
10395 xmlFree(name);
10396 xmlFree(prefix);
10397 return;
10398 }
Daniel Veillard71f9d732003-01-14 16:07:16 +000010399 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10400 nbargs++;
10401 if (CUR == ')') break;
10402 if (CUR != ',') {
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020010403 xmlFree(name);
10404 xmlFree(prefix);
Daniel Veillard71f9d732003-01-14 16:07:16 +000010405 XP_ERROR(XPATH_EXPR_ERROR);
10406 }
10407 NEXT;
10408 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010409 }
Owen Taylor3473f882001-02-23 17:55:21 +000010410 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010411 if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
10412 xmlFree(prefix);
10413 xmlFree(name);
10414 }
Owen Taylor3473f882001-02-23 17:55:21 +000010415 NEXT;
10416 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010417}
10418
10419/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010420 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010421 * @ctxt: the XPath Parser context
10422 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010423 * [15] PrimaryExpr ::= VariableReference
Owen Taylor3473f882001-02-23 17:55:21 +000010424 * | '(' Expr ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010425 * | Literal
10426 * | Number
10427 * | FunctionCall
Owen Taylor3473f882001-02-23 17:55:21 +000010428 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010429 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010430 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010431static void
10432xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010433 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010434 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010435 else if (CUR == '(') {
10436 NEXT;
10437 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010438 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010439 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010440 if (CUR != ')') {
10441 XP_ERROR(XPATH_EXPR_ERROR);
10442 }
10443 NEXT;
10444 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010445 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010446 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010447 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010448 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010449 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010450 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010451 }
10452 SKIP_BLANKS;
10453}
10454
10455/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010456 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010457 * @ctxt: the XPath Parser context
10458 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010459 * [20] FilterExpr ::= PrimaryExpr
10460 * | FilterExpr Predicate
Owen Taylor3473f882001-02-23 17:55:21 +000010461 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010462 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010463 * Square brackets are used to filter expressions in the same way that
10464 * they are used in location paths. It is an error if the expression to
10465 * be filtered does not evaluate to a node-set. The context node list
10466 * used for evaluating the expression in square brackets is the node-set
10467 * to be filtered listed in document order.
10468 */
10469
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010470static void
10471xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10472 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010473 CHECK_ERROR;
10474 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010475
Owen Taylor3473f882001-02-23 17:55:21 +000010476 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010477 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010478 SKIP_BLANKS;
10479 }
10480
Daniel Veillard45490ae2008-07-29 09:13:19 +000010481
Owen Taylor3473f882001-02-23 17:55:21 +000010482}
10483
10484/**
10485 * xmlXPathScanName:
10486 * @ctxt: the XPath Parser context
10487 *
10488 * Trickery: parse an XML name but without consuming the input flow
10489 * Needed to avoid insanity in the parser state.
10490 *
10491 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10492 * CombiningChar | Extender
10493 *
10494 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10495 *
10496 * [6] Names ::= Name (S Name)*
10497 *
10498 * Returns the Name parsed or NULL
10499 */
10500
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010501static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010502xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010503 int len = 0, l;
10504 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010505 const xmlChar *cur;
10506 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010507
Daniel Veillard03226812004-11-01 14:55:21 +000010508 cur = ctxt->cur;
10509
10510 c = CUR_CHAR(l);
10511 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10512 (!IS_LETTER(c) && (c != '_') &&
10513 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010514 return(NULL);
10515 }
10516
Daniel Veillard03226812004-11-01 14:55:21 +000010517 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10518 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10519 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010520 (c == '_') || (c == ':') ||
Daniel Veillard03226812004-11-01 14:55:21 +000010521 (IS_COMBINING(c)) ||
10522 (IS_EXTENDER(c)))) {
10523 len += l;
10524 NEXTL(l);
10525 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010526 }
Daniel Veillard03226812004-11-01 14:55:21 +000010527 ret = xmlStrndup(cur, ctxt->cur - cur);
10528 ctxt->cur = cur;
10529 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010530}
10531
10532/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010533 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010534 * @ctxt: the XPath Parser context
10535 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010536 * [19] PathExpr ::= LocationPath
10537 * | FilterExpr
10538 * | FilterExpr '/' RelativeLocationPath
10539 * | FilterExpr '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000010540 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010541 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010542 * The / operator and // operators combine an arbitrary expression
10543 * and a relative location path. It is an error if the expression
10544 * does not evaluate to a node-set.
10545 * The / operator does composition in the same way as when / is
10546 * used in a location path. As in location paths, // is short for
10547 * /descendant-or-self::node()/.
10548 */
10549
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010550static void
10551xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010552 int lc = 1; /* Should we branch to LocationPath ? */
10553 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10554
10555 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010556 if ((CUR == '$') || (CUR == '(') ||
10557 (IS_ASCII_DIGIT(CUR)) ||
William M. Brackd1757ab2004-10-02 22:07:48 +000010558 (CUR == '\'') || (CUR == '"') ||
10559 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010560 lc = 0;
10561 } else if (CUR == '*') {
10562 /* relative or absolute location path */
10563 lc = 1;
10564 } else if (CUR == '/') {
10565 /* relative or absolute location path */
10566 lc = 1;
10567 } else if (CUR == '@') {
10568 /* relative abbreviated attribute location path */
10569 lc = 1;
10570 } else if (CUR == '.') {
10571 /* relative abbreviated attribute location path */
10572 lc = 1;
10573 } else {
10574 /*
10575 * Problem is finding if we have a name here whether it's:
10576 * - a nodetype
10577 * - a function call in which case it's followed by '('
10578 * - an axis in which case it's followed by ':'
10579 * - a element name
10580 * We do an a priori analysis here rather than having to
10581 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010582 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010583 * read/write/debug.
10584 */
10585 SKIP_BLANKS;
10586 name = xmlXPathScanName(ctxt);
10587 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10588#ifdef DEBUG_STEP
10589 xmlGenericError(xmlGenericErrorContext,
10590 "PathExpr: Axis\n");
10591#endif
10592 lc = 1;
10593 xmlFree(name);
10594 } else if (name != NULL) {
10595 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010596
Daniel Veillard45490ae2008-07-29 09:13:19 +000010597
Owen Taylor3473f882001-02-23 17:55:21 +000010598 while (NXT(len) != 0) {
10599 if (NXT(len) == '/') {
10600 /* element name */
10601#ifdef DEBUG_STEP
10602 xmlGenericError(xmlGenericErrorContext,
10603 "PathExpr: AbbrRelLocation\n");
10604#endif
10605 lc = 1;
10606 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010607 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010608 /* ignore blanks */
10609 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010610 } else if (NXT(len) == ':') {
10611#ifdef DEBUG_STEP
10612 xmlGenericError(xmlGenericErrorContext,
10613 "PathExpr: AbbrRelLocation\n");
10614#endif
10615 lc = 1;
10616 break;
10617 } else if ((NXT(len) == '(')) {
Brian C. Young01c35762017-04-03 12:46:02 -070010618 /* Node Type or Function */
Owen Taylor3473f882001-02-23 17:55:21 +000010619 if (xmlXPathIsNodeType(name)) {
10620#ifdef DEBUG_STEP
10621 xmlGenericError(xmlGenericErrorContext,
10622 "PathExpr: Type search\n");
10623#endif
10624 lc = 1;
Brian C. Young01c35762017-04-03 12:46:02 -070010625#ifdef LIBXML_XPTR_ENABLED
10626 } else if (ctxt->xptr &&
10627 xmlStrEqual(name, BAD_CAST "range-to")) {
10628 lc = 1;
10629#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010630 } else {
10631#ifdef DEBUG_STEP
10632 xmlGenericError(xmlGenericErrorContext,
10633 "PathExpr: function call\n");
10634#endif
10635 lc = 0;
10636 }
10637 break;
10638 } else if ((NXT(len) == '[')) {
10639 /* element name */
10640#ifdef DEBUG_STEP
10641 xmlGenericError(xmlGenericErrorContext,
10642 "PathExpr: AbbrRelLocation\n");
10643#endif
10644 lc = 1;
10645 break;
10646 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10647 (NXT(len) == '=')) {
10648 lc = 1;
10649 break;
10650 } else {
10651 lc = 1;
10652 break;
10653 }
10654 len++;
10655 }
10656 if (NXT(len) == 0) {
10657#ifdef DEBUG_STEP
10658 xmlGenericError(xmlGenericErrorContext,
10659 "PathExpr: AbbrRelLocation\n");
10660#endif
10661 /* element name */
10662 lc = 1;
10663 }
10664 xmlFree(name);
10665 } else {
William M. Brack08171912003-12-29 02:52:11 +000010666 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010667 XP_ERROR(XPATH_EXPR_ERROR);
10668 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000010669 }
Owen Taylor3473f882001-02-23 17:55:21 +000010670
10671 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010672 if (CUR == '/') {
10673 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10674 } else {
10675 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010676 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010677 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010678 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010679 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010680 CHECK_ERROR;
10681 if ((CUR == '/') && (NXT(1) == '/')) {
10682 SKIP(2);
10683 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010684
10685 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10686 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010687
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010688 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010689 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010690 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010691 }
10692 }
10693 SKIP_BLANKS;
10694}
10695
10696/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010697 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010698 * @ctxt: the XPath Parser context
10699 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010700 * [18] UnionExpr ::= PathExpr
10701 * | UnionExpr '|' PathExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010702 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010703 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010704 */
10705
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010706static void
10707xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10708 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010709 CHECK_ERROR;
10710 SKIP_BLANKS;
10711 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010712 int op1 = ctxt->comp->last;
10713 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010714
10715 NEXT;
10716 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010717 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010718
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010719 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10720
Owen Taylor3473f882001-02-23 17:55:21 +000010721 SKIP_BLANKS;
10722 }
Owen Taylor3473f882001-02-23 17:55:21 +000010723}
10724
10725/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010726 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010727 * @ctxt: the XPath Parser context
10728 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010729 * [27] UnaryExpr ::= UnionExpr
10730 * | '-' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010731 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010732 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010733 */
10734
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010735static void
10736xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010737 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010738 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010739
10740 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010741 while (CUR == '-') {
10742 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010743 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010744 NEXT;
10745 SKIP_BLANKS;
10746 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010747
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010748 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010749 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010750 if (found) {
10751 if (minus)
10752 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10753 else
10754 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010755 }
10756}
10757
10758/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010759 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010760 * @ctxt: the XPath Parser context
10761 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010762 * [26] MultiplicativeExpr ::= UnaryExpr
10763 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10764 * | MultiplicativeExpr 'div' UnaryExpr
10765 * | MultiplicativeExpr 'mod' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010766 * [34] MultiplyOperator ::= '*'
10767 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010768 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010769 */
10770
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010771static void
10772xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10773 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010774 CHECK_ERROR;
10775 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010776 while ((CUR == '*') ||
Owen Taylor3473f882001-02-23 17:55:21 +000010777 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10778 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10779 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010780 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010781
10782 if (CUR == '*') {
10783 op = 0;
10784 NEXT;
10785 } else if (CUR == 'd') {
10786 op = 1;
10787 SKIP(3);
10788 } else if (CUR == 'm') {
10789 op = 2;
10790 SKIP(3);
10791 }
10792 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010793 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010794 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010795 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010796 SKIP_BLANKS;
10797 }
10798}
10799
10800/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010801 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010802 * @ctxt: the XPath Parser context
10803 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010804 * [25] AdditiveExpr ::= MultiplicativeExpr
10805 * | AdditiveExpr '+' MultiplicativeExpr
10806 * | AdditiveExpr '-' MultiplicativeExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010807 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010808 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010809 */
10810
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010811static void
10812xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010813
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010814 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010815 CHECK_ERROR;
10816 SKIP_BLANKS;
10817 while ((CUR == '+') || (CUR == '-')) {
10818 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010819 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010820
10821 if (CUR == '+') plus = 1;
10822 else plus = 0;
10823 NEXT;
10824 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010825 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010826 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010827 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010828 SKIP_BLANKS;
10829 }
10830}
10831
10832/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010833 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010834 * @ctxt: the XPath Parser context
10835 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010836 * [24] RelationalExpr ::= AdditiveExpr
10837 * | RelationalExpr '<' AdditiveExpr
10838 * | RelationalExpr '>' AdditiveExpr
10839 * | RelationalExpr '<=' AdditiveExpr
10840 * | RelationalExpr '>=' AdditiveExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010841 *
10842 * A <= B > C is allowed ? Answer from James, yes with
10843 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10844 * which is basically what got implemented.
10845 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010846 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010847 * on the stack
10848 */
10849
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010850static void
10851xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10852 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010853 CHECK_ERROR;
10854 SKIP_BLANKS;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010855 while ((CUR == '<') || (CUR == '>')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010856 int inf, strict;
10857 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010858
10859 if (CUR == '<') inf = 1;
10860 else inf = 0;
10861 if (NXT(1) == '=') strict = 0;
10862 else strict = 1;
10863 NEXT;
10864 if (!strict) NEXT;
10865 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010866 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010867 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010868 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010869 SKIP_BLANKS;
10870 }
10871}
10872
10873/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010874 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010875 * @ctxt: the XPath Parser context
10876 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010877 * [23] EqualityExpr ::= RelationalExpr
10878 * | EqualityExpr '=' RelationalExpr
10879 * | EqualityExpr '!=' RelationalExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010880 *
10881 * A != B != C is allowed ? Answer from James, yes with
10882 * (RelationalExpr = RelationalExpr) = RelationalExpr
10883 * (RelationalExpr != RelationalExpr) != RelationalExpr
10884 * which is basically what got implemented.
10885 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010886 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010887 *
10888 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010889static void
10890xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10891 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010892 CHECK_ERROR;
10893 SKIP_BLANKS;
10894 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010895 int eq;
10896 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010897
10898 if (CUR == '=') eq = 1;
10899 else eq = 0;
10900 NEXT;
10901 if (!eq) NEXT;
10902 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010903 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010904 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010905 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010906 SKIP_BLANKS;
10907 }
10908}
10909
10910/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010911 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010912 * @ctxt: the XPath Parser context
10913 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010914 * [22] AndExpr ::= EqualityExpr
10915 * | AndExpr 'and' EqualityExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010916 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010917 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010918 *
10919 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010920static void
10921xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10922 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010923 CHECK_ERROR;
10924 SKIP_BLANKS;
10925 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010926 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010927 SKIP(3);
10928 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010929 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010930 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010931 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010932 SKIP_BLANKS;
10933 }
10934}
10935
10936/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010937 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010938 * @ctxt: the XPath Parser context
10939 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010940 * [14] Expr ::= OrExpr
10941 * [21] OrExpr ::= AndExpr
10942 * | OrExpr 'or' AndExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010943 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010944 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010945 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010946static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010947xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010948 xmlXPathContextPtr xpctxt = ctxt->context;
10949
10950 if (xpctxt != NULL) {
10951 if (xpctxt->depth >= xpctxt->maxParserDepth)
10952 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10953 xpctxt->depth += 1;
10954 }
10955
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010956 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010957 CHECK_ERROR;
10958 SKIP_BLANKS;
10959 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010960 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010961 SKIP(2);
10962 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010963 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010964 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010965 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010966 SKIP_BLANKS;
10967 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010968 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010969 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010970 /*
10971 * This is the main place to eliminate sorting for
10972 * operations which don't require a sorted node-set.
10973 * E.g. count().
10974 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010975 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10976 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070010977
10978 if (xpctxt != NULL)
10979 xpctxt->depth -= 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010980}
10981
10982/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010983 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000010984 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010985 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000010986 *
10987 * [8] Predicate ::= '[' PredicateExpr ']'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010988 * [9] PredicateExpr ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010989 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010990 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000010991 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010992static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010993xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010994 int op1 = ctxt->comp->last;
10995
10996 SKIP_BLANKS;
10997 if (CUR != '[') {
10998 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10999 }
11000 NEXT;
11001 SKIP_BLANKS;
11002
11003 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011004 /*
11005 * This call to xmlXPathCompileExpr() will deactivate sorting
11006 * of the predicate result.
11007 * TODO: Sorting is still activated for filters, since I'm not
11008 * sure if needed. Normally sorting should not be needed, since
11009 * a filter can only diminish the number of items in a sequence,
11010 * but won't change its order; so if the initial sequence is sorted,
11011 * subsequent sorting is not needed.
11012 */
11013 if (! filter)
11014 xmlXPathCompileExpr(ctxt, 0);
11015 else
11016 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011017 CHECK_ERROR;
11018
11019 if (CUR != ']') {
11020 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11021 }
11022
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011023 if (filter)
11024 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11025 else
11026 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011027
11028 NEXT;
11029 SKIP_BLANKS;
11030}
11031
11032/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011033 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000011034 * @ctxt: the XPath Parser context
11035 * @test: pointer to a xmlXPathTestVal
11036 * @type: pointer to a xmlXPathTypeVal
11037 * @prefix: placeholder for a possible name prefix
11038 *
11039 * [7] NodeTest ::= NameTest
11040 * | NodeType '(' ')'
11041 * | 'processing-instruction' '(' Literal ')'
11042 *
11043 * [37] NameTest ::= '*'
11044 * | NCName ':' '*'
11045 * | QName
11046 * [38] NodeType ::= 'comment'
11047 * | 'text'
11048 * | 'processing-instruction'
11049 * | 'node'
11050 *
William M. Brack08171912003-12-29 02:52:11 +000011051 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000011052 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011053static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011054xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011055 xmlXPathTypeVal *type, xmlChar **prefix,
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011056 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000011057 int blanks;
11058
11059 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11060 STRANGE;
11061 return(NULL);
11062 }
William M. Brack78637da2003-07-31 14:47:38 +000011063 *type = (xmlXPathTypeVal) 0;
11064 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011065 *prefix = NULL;
11066 SKIP_BLANKS;
11067
11068 if ((name == NULL) && (CUR == '*')) {
11069 /*
11070 * All elements
11071 */
11072 NEXT;
11073 *test = NODE_TEST_ALL;
11074 return(NULL);
11075 }
11076
11077 if (name == NULL)
11078 name = xmlXPathParseNCName(ctxt);
11079 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011080 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011081 }
11082
William M. Brack76e95df2003-10-18 16:20:14 +000011083 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000011084 SKIP_BLANKS;
11085 if (CUR == '(') {
11086 NEXT;
11087 /*
11088 * NodeType or PI search
11089 */
11090 if (xmlStrEqual(name, BAD_CAST "comment"))
11091 *type = NODE_TYPE_COMMENT;
11092 else if (xmlStrEqual(name, BAD_CAST "node"))
11093 *type = NODE_TYPE_NODE;
11094 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11095 *type = NODE_TYPE_PI;
11096 else if (xmlStrEqual(name, BAD_CAST "text"))
11097 *type = NODE_TYPE_TEXT;
11098 else {
11099 if (name != NULL)
11100 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011101 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011102 }
11103
11104 *test = NODE_TEST_TYPE;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011105
Owen Taylor3473f882001-02-23 17:55:21 +000011106 SKIP_BLANKS;
11107 if (*type == NODE_TYPE_PI) {
11108 /*
11109 * Specific case: search a PI by name.
11110 */
Owen Taylor3473f882001-02-23 17:55:21 +000011111 if (name != NULL)
11112 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000011113 name = NULL;
11114 if (CUR != ')') {
11115 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000011116 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000011117 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000011118 SKIP_BLANKS;
11119 }
Owen Taylor3473f882001-02-23 17:55:21 +000011120 }
11121 if (CUR != ')') {
11122 if (name != NULL)
11123 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011124 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011125 }
11126 NEXT;
11127 return(name);
11128 }
11129 *test = NODE_TEST_NAME;
11130 if ((!blanks) && (CUR == ':')) {
11131 NEXT;
11132
11133 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011134 * Since currently the parser context don't have a
11135 * namespace list associated:
11136 * The namespace name for this prefix can be computed
11137 * only at evaluation time. The compilation is done
11138 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000011139 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011140#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000011141 *prefix = xmlXPathNsLookup(ctxt->context, name);
11142 if (name != NULL)
11143 xmlFree(name);
11144 if (*prefix == NULL) {
11145 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11146 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011147#else
11148 *prefix = name;
11149#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011150
11151 if (CUR == '*') {
11152 /*
11153 * All elements
11154 */
11155 NEXT;
11156 *test = NODE_TEST_ALL;
11157 return(NULL);
11158 }
11159
11160 name = xmlXPathParseNCName(ctxt);
11161 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011162 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011163 }
11164 }
11165 return(name);
11166}
11167
11168/**
11169 * xmlXPathIsAxisName:
11170 * @name: a preparsed name token
11171 *
11172 * [6] AxisName ::= 'ancestor'
11173 * | 'ancestor-or-self'
11174 * | 'attribute'
11175 * | 'child'
11176 * | 'descendant'
11177 * | 'descendant-or-self'
11178 * | 'following'
11179 * | 'following-sibling'
11180 * | 'namespace'
11181 * | 'parent'
11182 * | 'preceding'
11183 * | 'preceding-sibling'
11184 * | 'self'
11185 *
11186 * Returns the axis or 0
11187 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011188static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011189xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011190 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011191 switch (name[0]) {
11192 case 'a':
11193 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11194 ret = AXIS_ANCESTOR;
11195 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11196 ret = AXIS_ANCESTOR_OR_SELF;
11197 if (xmlStrEqual(name, BAD_CAST "attribute"))
11198 ret = AXIS_ATTRIBUTE;
11199 break;
11200 case 'c':
11201 if (xmlStrEqual(name, BAD_CAST "child"))
11202 ret = AXIS_CHILD;
11203 break;
11204 case 'd':
11205 if (xmlStrEqual(name, BAD_CAST "descendant"))
11206 ret = AXIS_DESCENDANT;
11207 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11208 ret = AXIS_DESCENDANT_OR_SELF;
11209 break;
11210 case 'f':
11211 if (xmlStrEqual(name, BAD_CAST "following"))
11212 ret = AXIS_FOLLOWING;
11213 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11214 ret = AXIS_FOLLOWING_SIBLING;
11215 break;
11216 case 'n':
11217 if (xmlStrEqual(name, BAD_CAST "namespace"))
11218 ret = AXIS_NAMESPACE;
11219 break;
11220 case 'p':
11221 if (xmlStrEqual(name, BAD_CAST "parent"))
11222 ret = AXIS_PARENT;
11223 if (xmlStrEqual(name, BAD_CAST "preceding"))
11224 ret = AXIS_PRECEDING;
11225 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11226 ret = AXIS_PRECEDING_SIBLING;
11227 break;
11228 case 's':
11229 if (xmlStrEqual(name, BAD_CAST "self"))
11230 ret = AXIS_SELF;
11231 break;
11232 }
11233 return(ret);
11234}
11235
11236/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011237 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011238 * @ctxt: the XPath Parser context
11239 *
11240 * [4] Step ::= AxisSpecifier NodeTest Predicate*
Daniel Veillard45490ae2008-07-29 09:13:19 +000011241 * | AbbreviatedStep
Owen Taylor3473f882001-02-23 17:55:21 +000011242 *
11243 * [12] AbbreviatedStep ::= '.' | '..'
11244 *
11245 * [5] AxisSpecifier ::= AxisName '::'
11246 * | AbbreviatedAxisSpecifier
11247 *
11248 * [13] AbbreviatedAxisSpecifier ::= '@'?
11249 *
11250 * Modified for XPtr range support as:
11251 *
11252 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11253 * | AbbreviatedStep
11254 * | 'range-to' '(' Expr ')' Predicate*
11255 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011256 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011257 * A location step of . is short for self::node(). This is
11258 * particularly useful in conjunction with //. For example, the
11259 * location path .//para is short for
11260 * self::node()/descendant-or-self::node()/child::para
11261 * and so will select all para descendant elements of the context
11262 * node.
11263 * Similarly, a location step of .. is short for parent::node().
11264 * For example, ../title is short for parent::node()/child::title
11265 * and so will select the title children of the parent of the context
11266 * node.
11267 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011268static void
11269xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011270#ifdef LIBXML_XPTR_ENABLED
11271 int rangeto = 0;
11272 int op2 = -1;
11273#endif
11274
Owen Taylor3473f882001-02-23 17:55:21 +000011275 SKIP_BLANKS;
11276 if ((CUR == '.') && (NXT(1) == '.')) {
11277 SKIP(2);
11278 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011279 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11280 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011281 } else if (CUR == '.') {
11282 NEXT;
11283 SKIP_BLANKS;
11284 } else {
11285 xmlChar *name = NULL;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011286 xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011287 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011288 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011289 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011290 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011291
11292 /*
11293 * The modification needed for XPointer change to the production
11294 */
11295#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011296 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011297 name = xmlXPathParseNCName(ctxt);
11298 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011299 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011300 xmlFree(name);
11301 SKIP_BLANKS;
11302 if (CUR != '(') {
11303 XP_ERROR(XPATH_EXPR_ERROR);
11304 }
11305 NEXT;
11306 SKIP_BLANKS;
11307
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011308 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011309 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011310 CHECK_ERROR;
11311
11312 SKIP_BLANKS;
11313 if (CUR != ')') {
11314 XP_ERROR(XPATH_EXPR_ERROR);
11315 }
11316 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011317 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011318 goto eval_predicates;
11319 }
11320 }
11321#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011322 if (CUR == '*') {
11323 axis = AXIS_CHILD;
11324 } else {
11325 if (name == NULL)
11326 name = xmlXPathParseNCName(ctxt);
11327 if (name != NULL) {
11328 axis = xmlXPathIsAxisName(name);
11329 if (axis != 0) {
11330 SKIP_BLANKS;
11331 if ((CUR == ':') && (NXT(1) == ':')) {
11332 SKIP(2);
11333 xmlFree(name);
11334 name = NULL;
11335 } else {
11336 /* an element name can conflict with an axis one :-\ */
11337 axis = AXIS_CHILD;
11338 }
Owen Taylor3473f882001-02-23 17:55:21 +000011339 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011340 axis = AXIS_CHILD;
11341 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011342 } else if (CUR == '@') {
11343 NEXT;
11344 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011345 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011346 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011347 }
Owen Taylor3473f882001-02-23 17:55:21 +000011348 }
11349
Daniel Veillard2f3523f2010-10-15 18:30:29 +020011350 if (ctxt->error != XPATH_EXPRESSION_OK) {
11351 xmlFree(name);
11352 return;
11353 }
Owen Taylor3473f882001-02-23 17:55:21 +000011354
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011355 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011356 if (test == 0)
11357 return;
11358
Daniel Veillarded6c5492005-07-23 15:00:22 +000011359 if ((prefix != NULL) && (ctxt->context != NULL) &&
11360 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11361 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11362 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11363 }
11364 }
Owen Taylor3473f882001-02-23 17:55:21 +000011365#ifdef DEBUG_STEP
11366 xmlGenericError(xmlGenericErrorContext,
11367 "Basis : computing new set\n");
11368#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011369
Owen Taylor3473f882001-02-23 17:55:21 +000011370#ifdef DEBUG_STEP
11371 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011372 if (ctxt->value == NULL)
11373 xmlGenericError(xmlGenericErrorContext, "no value\n");
11374 else if (ctxt->value->nodesetval == NULL)
11375 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11376 else
11377 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011378#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011379
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011380#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011381eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011382#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011383 op1 = ctxt->comp->last;
11384 ctxt->comp->last = -1;
11385
Owen Taylor3473f882001-02-23 17:55:21 +000011386 SKIP_BLANKS;
11387 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011388 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011389 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011390
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011391#ifdef LIBXML_XPTR_ENABLED
11392 if (rangeto) {
11393 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11394 } else
11395#endif
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011396 if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11397 test, type, (void *)prefix, (void *)name) == -1) {
11398 xmlFree(prefix);
11399 xmlFree(name);
11400 }
Owen Taylor3473f882001-02-23 17:55:21 +000011401 }
11402#ifdef DEBUG_STEP
11403 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011404 if (ctxt->value == NULL)
11405 xmlGenericError(xmlGenericErrorContext, "no value\n");
11406 else if (ctxt->value->nodesetval == NULL)
11407 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11408 else
11409 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11410 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011411#endif
11412}
11413
11414/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011415 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011416 * @ctxt: the XPath Parser context
11417 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011418 * [3] RelativeLocationPath ::= Step
11419 * | RelativeLocationPath '/' Step
11420 * | AbbreviatedRelativeLocationPath
11421 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
Owen Taylor3473f882001-02-23 17:55:21 +000011422 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011423 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011424 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011425static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011426xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011427(xmlXPathParserContextPtr ctxt) {
11428 SKIP_BLANKS;
11429 if ((CUR == '/') && (NXT(1) == '/')) {
11430 SKIP(2);
11431 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011432 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11433 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011434 } else if (CUR == '/') {
11435 NEXT;
11436 SKIP_BLANKS;
11437 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011438 xmlXPathCompStep(ctxt);
Martin729601f2009-10-12 22:42:26 +020011439 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011440 SKIP_BLANKS;
11441 while (CUR == '/') {
11442 if ((CUR == '/') && (NXT(1) == '/')) {
11443 SKIP(2);
11444 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011445 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011446 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011447 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011448 } else if (CUR == '/') {
11449 NEXT;
11450 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011451 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011452 }
11453 SKIP_BLANKS;
11454 }
11455}
11456
11457/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011458 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011459 * @ctxt: the XPath Parser context
11460 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011461 * [1] LocationPath ::= RelativeLocationPath
11462 * | AbsoluteLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011463 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
Daniel Veillard45490ae2008-07-29 09:13:19 +000011464 * | AbbreviatedAbsoluteLocationPath
11465 * [10] AbbreviatedAbsoluteLocationPath ::=
11466 * '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011467 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011468 * Compile a location path
11469 *
Owen Taylor3473f882001-02-23 17:55:21 +000011470 * // is short for /descendant-or-self::node()/. For example,
11471 * //para is short for /descendant-or-self::node()/child::para and
11472 * so will select any para element in the document (even a para element
11473 * that is a document element will be selected by //para since the
11474 * document element node is a child of the root node); div//para is
11475 * short for div/descendant-or-self::node()/child::para and so will
11476 * select all para descendants of div children.
11477 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011478static void
11479xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011480 SKIP_BLANKS;
11481 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011482 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011483 } else {
11484 while (CUR == '/') {
11485 if ((CUR == '/') && (NXT(1) == '/')) {
11486 SKIP(2);
11487 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011488 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11489 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011490 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011491 } else if (CUR == '/') {
11492 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011493 SKIP_BLANKS;
11494 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011495 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011496 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011497 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011498 }
Martin729601f2009-10-12 22:42:26 +020011499 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011500 }
11501 }
11502}
11503
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011504/************************************************************************
11505 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011506 * XPath precompiled expression evaluation *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011507 * *
11508 ************************************************************************/
11509
Daniel Veillardf06307e2001-07-03 10:35:50 +000011510static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011511xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11512
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011513#ifdef DEBUG_STEP
11514static void
Daniel Veillard074f37e2008-09-01 13:38:22 +000011515xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011516 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011517{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011518 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillard074f37e2008-09-01 13:38:22 +000011519 switch (op->value) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011520 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011521 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011522 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011523 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011524 xmlGenericError(xmlGenericErrorContext,
11525 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011526 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011527 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011528 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011529 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011530 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011531 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011532 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011533 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011534 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011535 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011536 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011537 xmlGenericError(xmlGenericErrorContext,
11538 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011539 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011540 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011541 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011542 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011543 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011544 xmlGenericError(xmlGenericErrorContext,
11545 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011546 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011547 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011548 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011549 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011550 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011551 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011552 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011553 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011554 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011555 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011556 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011557 xmlGenericError(xmlGenericErrorContext,
11558 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011559 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011560 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011561 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011562 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011563 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011564 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011565 " context contains %d nodes\n", nbNodes);
Daniel Veillard074f37e2008-09-01 13:38:22 +000011566 switch (op->value2) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011567 case NODE_TEST_NONE:
11568 xmlGenericError(xmlGenericErrorContext,
11569 " searching for none !!!\n");
11570 break;
11571 case NODE_TEST_TYPE:
11572 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011573 " searching for type %d\n", op->value3);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011574 break;
11575 case NODE_TEST_PI:
11576 xmlGenericError(xmlGenericErrorContext,
11577 " searching for PI !!!\n");
11578 break;
11579 case NODE_TEST_ALL:
11580 xmlGenericError(xmlGenericErrorContext,
11581 " searching for *\n");
11582 break;
11583 case NODE_TEST_NS:
11584 xmlGenericError(xmlGenericErrorContext,
11585 " searching for namespace %s\n",
Daniel Veillard074f37e2008-09-01 13:38:22 +000011586 op->value5);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011587 break;
11588 case NODE_TEST_NAME:
11589 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011590 " searching for name %s\n", op->value5);
11591 if (op->value4)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011592 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011593 " with namespace %s\n", op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011594 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011595 }
11596 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011597}
11598#endif /* DEBUG_STEP */
11599
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011600/**
11601 * xmlXPathNodeSetFilter:
11602 * @ctxt: the XPath Parser context
11603 * @set: the node set to filter
11604 * @filterOpIndex: the index of the predicate/filter op
11605 * @minPos: minimum position in the filtered set (1-based)
11606 * @maxPos: maximum position in the filtered set (1-based)
11607 * @hasNsNodes: true if the node set may contain namespace nodes
11608 *
11609 * Filter a node set, keeping only nodes for which the predicate expression
11610 * matches. Afterwards, keep only nodes between minPos and maxPos in the
11611 * filtered result.
11612 */
11613static void
11614xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11615 xmlNodeSetPtr set,
11616 int filterOpIndex,
11617 int minPos, int maxPos,
11618 int hasNsNodes)
11619{
11620 xmlXPathContextPtr xpctxt;
11621 xmlNodePtr oldnode;
11622 xmlDocPtr olddoc;
11623 xmlXPathStepOpPtr filterOp;
11624 int oldcs, oldpp;
11625 int i, j, pos;
11626
11627 if ((set == NULL) || (set->nodeNr == 0))
11628 return;
11629
11630 /*
11631 * Check if the node set contains a sufficient number of nodes for
11632 * the requested range.
11633 */
11634 if (set->nodeNr < minPos) {
11635 xmlXPathNodeSetClear(set, hasNsNodes);
11636 return;
11637 }
11638
11639 xpctxt = ctxt->context;
11640 oldnode = xpctxt->node;
11641 olddoc = xpctxt->doc;
11642 oldcs = xpctxt->contextSize;
11643 oldpp = xpctxt->proximityPosition;
11644 filterOp = &ctxt->comp->steps[filterOpIndex];
11645
11646 xpctxt->contextSize = set->nodeNr;
11647
11648 for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11649 xmlNodePtr node = set->nodeTab[i];
11650 int res;
11651
11652 xpctxt->node = node;
11653 xpctxt->proximityPosition = i + 1;
11654
11655 /*
11656 * Also set the xpath document in case things like
11657 * key() are evaluated in the predicate.
11658 *
11659 * TODO: Get real doc for namespace nodes.
11660 */
11661 if ((node->type != XML_NAMESPACE_DECL) &&
11662 (node->doc != NULL))
11663 xpctxt->doc = node->doc;
11664
11665 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11666
11667 if (ctxt->error != XPATH_EXPRESSION_OK)
11668 goto exit;
11669 if (res < 0) {
11670 /* Shouldn't happen */
11671 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11672 goto exit;
11673 }
11674
11675 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11676 if (i != j) {
11677 set->nodeTab[j] = node;
11678 set->nodeTab[i] = NULL;
11679 }
11680
11681 j += 1;
11682 } else {
11683 /* Remove the entry from the initial node set. */
11684 set->nodeTab[i] = NULL;
11685 if (node->type == XML_NAMESPACE_DECL)
11686 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11687 }
11688
11689 if (res != 0) {
11690 if (pos == maxPos) {
11691 /* Clear remaining nodes and exit loop. */
11692 if (hasNsNodes) {
11693 for (i++; i < set->nodeNr; i++) {
11694 node = set->nodeTab[i];
11695 if ((node != NULL) &&
11696 (node->type == XML_NAMESPACE_DECL))
11697 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11698 }
11699 }
11700 break;
11701 }
11702
11703 pos += 1;
11704 }
11705 }
11706
11707 set->nodeNr = j;
11708
11709 /* If too many elements were removed, shrink table to preserve memory. */
11710 if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11711 (set->nodeNr < set->nodeMax / 2)) {
11712 xmlNodePtr *tmp;
11713 int nodeMax = set->nodeNr;
11714
11715 if (nodeMax < XML_NODESET_DEFAULT)
11716 nodeMax = XML_NODESET_DEFAULT;
11717 tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11718 nodeMax * sizeof(xmlNodePtr));
11719 if (tmp == NULL) {
11720 xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11721 } else {
11722 set->nodeTab = tmp;
11723 set->nodeMax = nodeMax;
11724 }
11725 }
11726
11727exit:
11728 xpctxt->node = oldnode;
11729 xpctxt->doc = olddoc;
11730 xpctxt->contextSize = oldcs;
11731 xpctxt->proximityPosition = oldpp;
11732}
11733
11734#ifdef LIBXML_XPTR_ENABLED
11735/**
11736 * xmlXPathLocationSetFilter:
11737 * @ctxt: the XPath Parser context
11738 * @locset: the location set to filter
11739 * @filterOpIndex: the index of the predicate/filter op
11740 * @minPos: minimum position in the filtered set (1-based)
11741 * @maxPos: maximum position in the filtered set (1-based)
11742 *
11743 * Filter a location set, keeping only nodes for which the predicate
11744 * expression matches. Afterwards, keep only nodes between minPos and maxPos
11745 * in the filtered result.
11746 */
11747static void
11748xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11749 xmlLocationSetPtr locset,
11750 int filterOpIndex,
11751 int minPos, int maxPos)
11752{
11753 xmlXPathContextPtr xpctxt;
11754 xmlNodePtr oldnode;
11755 xmlDocPtr olddoc;
11756 xmlXPathStepOpPtr filterOp;
11757 int oldcs, oldpp;
11758 int i, j, pos;
11759
11760 if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11761 return;
11762
11763 xpctxt = ctxt->context;
11764 oldnode = xpctxt->node;
11765 olddoc = xpctxt->doc;
11766 oldcs = xpctxt->contextSize;
11767 oldpp = xpctxt->proximityPosition;
11768 filterOp = &ctxt->comp->steps[filterOpIndex];
11769
11770 xpctxt->contextSize = locset->locNr;
11771
11772 for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11773 xmlNodePtr contextNode = locset->locTab[i]->user;
11774 int res;
11775
11776 xpctxt->node = contextNode;
11777 xpctxt->proximityPosition = i + 1;
11778
11779 /*
11780 * Also set the xpath document in case things like
11781 * key() are evaluated in the predicate.
11782 *
11783 * TODO: Get real doc for namespace nodes.
11784 */
11785 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11786 (contextNode->doc != NULL))
11787 xpctxt->doc = contextNode->doc;
11788
11789 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11790
11791 if (ctxt->error != XPATH_EXPRESSION_OK)
11792 goto exit;
11793 if (res < 0) {
11794 /* Shouldn't happen */
11795 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11796 goto exit;
11797 }
11798
11799 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11800 if (i != j) {
11801 locset->locTab[j] = locset->locTab[i];
11802 locset->locTab[i] = NULL;
11803 }
11804
11805 j += 1;
11806 } else {
11807 /* Remove the entry from the initial location set. */
11808 xmlXPathFreeObject(locset->locTab[i]);
11809 locset->locTab[i] = NULL;
11810 }
11811
11812 if (res != 0) {
11813 if (pos == maxPos) {
11814 /* Clear remaining nodes and exit loop. */
11815 for (i++; i < locset->locNr; i++) {
11816 xmlXPathFreeObject(locset->locTab[i]);
11817 }
11818 break;
11819 }
11820
11821 pos += 1;
11822 }
11823 }
11824
11825 locset->locNr = j;
11826
11827 /* If too many elements were removed, shrink table to preserve memory. */
11828 if ((locset->locMax > XML_NODESET_DEFAULT) &&
11829 (locset->locNr < locset->locMax / 2)) {
11830 xmlXPathObjectPtr *tmp;
11831 int locMax = locset->locNr;
11832
11833 if (locMax < XML_NODESET_DEFAULT)
11834 locMax = XML_NODESET_DEFAULT;
11835 tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11836 locMax * sizeof(xmlXPathObjectPtr));
11837 if (tmp == NULL) {
11838 xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11839 } else {
11840 locset->locTab = tmp;
11841 locset->locMax = locMax;
11842 }
11843 }
11844
11845exit:
11846 xpctxt->node = oldnode;
11847 xpctxt->doc = olddoc;
11848 xpctxt->contextSize = oldcs;
11849 xpctxt->proximityPosition = oldpp;
11850}
11851#endif /* LIBXML_XPTR_ENABLED */
11852
11853/**
11854 * xmlXPathCompOpEvalPredicate:
11855 * @ctxt: the XPath Parser context
11856 * @op: the predicate op
11857 * @set: the node set to filter
11858 * @minPos: minimum position in the filtered set (1-based)
11859 * @maxPos: maximum position in the filtered set (1-based)
11860 * @hasNsNodes: true if the node set may contain namespace nodes
11861 *
11862 * Filter a node set, keeping only nodes for which the sequence of predicate
11863 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11864 * in the filtered result.
11865 */
11866static void
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011867xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11868 xmlXPathStepOpPtr op,
11869 xmlNodeSetPtr set,
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011870 int minPos, int maxPos,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011871 int hasNsNodes)
11872{
11873 if (op->ch1 != -1) {
11874 xmlXPathCompExprPtr comp = ctxt->comp;
11875 /*
11876 * Process inner predicates first.
11877 */
11878 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011879 xmlGenericError(xmlGenericErrorContext,
11880 "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11881 XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011882 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011883 if (ctxt->context->depth >= ctxt->context->maxDepth)
11884 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11885 ctxt->context->depth += 1;
11886 xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11887 1, set->nodeNr, hasNsNodes);
11888 ctxt->context->depth -= 1;
11889 CHECK_ERROR;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011890 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011891
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011892 if (op->ch2 != -1)
11893 xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011894}
11895
11896static int
11897xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
Daniel Veillard45490ae2008-07-29 09:13:19 +000011898 xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011899 int *maxPos)
11900{
11901
11902 xmlXPathStepOpPtr exprOp;
11903
11904 /*
11905 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11906 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011907
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011908 /*
11909 * If not -1, then ch1 will point to:
11910 * 1) For predicates (XPATH_OP_PREDICATE):
11911 * - an inner predicate operator
11912 * 2) For filters (XPATH_OP_FILTER):
Haibo Huangcfd91dc2020-07-30 23:01:33 -070011913 * - an inner filter operator OR
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011914 * - an expression selecting the node set.
11915 * E.g. "key('a', 'b')" or "(//foo | //bar)".
Daniel Veillard45490ae2008-07-29 09:13:19 +000011916 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011917 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11918 return(0);
11919
11920 if (op->ch2 != -1) {
11921 exprOp = &ctxt->comp->steps[op->ch2];
Daniel Veillard45490ae2008-07-29 09:13:19 +000011922 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011923 return(0);
11924
11925 if ((exprOp != NULL) &&
11926 (exprOp->op == XPATH_OP_VALUE) &&
11927 (exprOp->value4 != NULL) &&
11928 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11929 {
Nick Wellnhofera58331a2017-05-29 21:02:21 +020011930 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11931
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011932 /*
11933 * We have a "[n]" predicate here.
11934 * TODO: Unfortunately this simplistic test here is not
11935 * able to detect a position() predicate in compound
11936 * expressions like "[@attr = 'a" and position() = 1],
11937 * and even not the usage of position() in
11938 * "[position() = 1]"; thus - obviously - a position-range,
11939 * like it "[position() < 5]", is also not detected.
11940 * Maybe we could rewrite the AST to ease the optimization.
11941 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011942
Nick Wellnhofera58331a2017-05-29 21:02:21 +020011943 if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11944 *maxPos = (int) floatval;
11945 if (floatval == (double) *maxPos)
11946 return(1);
11947 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011948 }
11949 return(0);
11950}
11951
11952static int
11953xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11954 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011955 xmlNodePtr * first, xmlNodePtr * last,
11956 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011957{
11958
11959#define XP_TEST_HIT \
11960 if (hasAxisRange != 0) { \
11961 if (++pos == maxPos) { \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011962 if (addNode(seq, cur) < 0) \
11963 ctxt->error = XPATH_MEMORY_ERROR; \
11964 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011965 } else { \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011966 if (addNode(seq, cur) < 0) \
11967 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011968 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011969
11970#define XP_TEST_HIT_NS \
11971 if (hasAxisRange != 0) { \
11972 if (++pos == maxPos) { \
11973 hasNsNodes = 1; \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011974 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11975 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011976 goto axis_range_end; } \
11977 } else { \
11978 hasNsNodes = 1; \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011979 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11980 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011981 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011982
11983 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11984 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11985 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11986 const xmlChar *prefix = op->value4;
11987 const xmlChar *name = op->value5;
11988 const xmlChar *URI = NULL;
11989
11990#ifdef DEBUG_STEP
11991 int nbMatches = 0, prevMatches = 0;
11992#endif
11993 int total = 0, hasNsNodes = 0;
11994 /* The popped object holding the context nodes */
11995 xmlXPathObjectPtr obj;
11996 /* The set of context nodes for the node tests */
11997 xmlNodeSetPtr contextSeq;
11998 int contextIdx;
11999 xmlNodePtr contextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012000 /* The final resulting node set wrt to all context nodes */
12001 xmlNodeSetPtr outSeq;
12002 /*
12003 * The temporary resulting node set wrt 1 context node.
12004 * Used to feed predicate evaluation.
12005 */
12006 xmlNodeSetPtr seq;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012007 xmlNodePtr cur;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012008 /* First predicate operator */
12009 xmlXPathStepOpPtr predOp;
12010 int maxPos; /* The requested position() (when a "[n]" predicate) */
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012011 int hasPredicateRange, hasAxisRange, pos;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012012 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012013
12014 xmlXPathTraversalFunction next = NULL;
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012015 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012016 xmlXPathNodeSetMergeFunction mergeAndClear;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012017 xmlNodePtr oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012018 xmlXPathContextPtr xpctxt = ctxt->context;
12019
12020
12021 CHECK_TYPE0(XPATH_NODESET);
12022 obj = valuePop(ctxt);
12023 /*
12024 * Setup namespaces.
12025 */
12026 if (prefix != NULL) {
12027 URI = xmlXPathNsLookup(xpctxt, prefix);
12028 if (URI == NULL) {
12029 xmlXPathReleaseObject(xpctxt, obj);
12030 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12031 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012032 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012033 /*
12034 * Setup axis.
12035 *
12036 * MAYBE FUTURE TODO: merging optimizations:
12037 * - If the nodes to be traversed wrt to the initial nodes and
12038 * the current axis cannot overlap, then we could avoid searching
12039 * for duplicates during the merge.
12040 * But the question is how/when to evaluate if they cannot overlap.
12041 * Example: if we know that for two initial nodes, the one is
12042 * not in the ancestor-or-self axis of the other, then we could safely
12043 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12044 * the descendant-or-self axis.
12045 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012046 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12047 switch (axis) {
12048 case AXIS_ANCESTOR:
12049 first = NULL;
12050 next = xmlXPathNextAncestor;
12051 break;
12052 case AXIS_ANCESTOR_OR_SELF:
12053 first = NULL;
12054 next = xmlXPathNextAncestorOrSelf;
12055 break;
12056 case AXIS_ATTRIBUTE:
12057 first = NULL;
12058 last = NULL;
12059 next = xmlXPathNextAttribute;
12060 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12061 break;
12062 case AXIS_CHILD:
12063 last = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012064 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12065 (type == NODE_TYPE_NODE))
12066 {
12067 /*
12068 * Optimization if an element node type is 'element'.
12069 */
12070 next = xmlXPathNextChildElement;
12071 } else
12072 next = xmlXPathNextChild;
12073 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12074 break;
12075 case AXIS_DESCENDANT:
12076 last = NULL;
12077 next = xmlXPathNextDescendant;
12078 break;
12079 case AXIS_DESCENDANT_OR_SELF:
12080 last = NULL;
12081 next = xmlXPathNextDescendantOrSelf;
12082 break;
12083 case AXIS_FOLLOWING:
12084 last = NULL;
12085 next = xmlXPathNextFollowing;
12086 break;
12087 case AXIS_FOLLOWING_SIBLING:
12088 last = NULL;
12089 next = xmlXPathNextFollowingSibling;
12090 break;
12091 case AXIS_NAMESPACE:
12092 first = NULL;
12093 last = NULL;
12094 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12095 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12096 break;
12097 case AXIS_PARENT:
12098 first = NULL;
12099 next = xmlXPathNextParent;
12100 break;
12101 case AXIS_PRECEDING:
12102 first = NULL;
12103 next = xmlXPathNextPrecedingInternal;
12104 break;
12105 case AXIS_PRECEDING_SIBLING:
12106 first = NULL;
12107 next = xmlXPathNextPrecedingSibling;
12108 break;
12109 case AXIS_SELF:
12110 first = NULL;
12111 last = NULL;
12112 next = xmlXPathNextSelf;
12113 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12114 break;
12115 }
12116
12117#ifdef DEBUG_STEP
Daniel Veillard074f37e2008-09-01 13:38:22 +000012118 xmlXPathDebugDumpStepAxis(op,
12119 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012120#endif
12121
12122 if (next == NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000012123 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012124 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012125 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012126 contextSeq = obj->nodesetval;
12127 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12128 xmlXPathReleaseObject(xpctxt, obj);
12129 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12130 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012131 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012132 /*
12133 * Predicate optimization ---------------------------------------------
12134 * If this step has a last predicate, which contains a position(),
12135 * then we'll optimize (although not exactly "position()", but only
12136 * the short-hand form, i.e., "[n]".
12137 *
12138 * Example - expression "/foo[parent::bar][1]":
Daniel Veillard45490ae2008-07-29 09:13:19 +000012139 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012140 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12141 * ROOT -- op->ch1
12142 * PREDICATE -- op->ch2 (predOp)
12143 * PREDICATE -- predOp->ch1 = [parent::bar]
12144 * SORT
12145 * COLLECT 'parent' 'name' 'node' bar
12146 * NODE
12147 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12148 *
12149 */
12150 maxPos = 0;
12151 predOp = NULL;
12152 hasPredicateRange = 0;
12153 hasAxisRange = 0;
12154 if (op->ch2 != -1) {
12155 /*
12156 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12157 */
12158 predOp = &ctxt->comp->steps[op->ch2];
12159 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12160 if (predOp->ch1 != -1) {
12161 /*
12162 * Use the next inner predicate operator.
12163 */
12164 predOp = &ctxt->comp->steps[predOp->ch1];
12165 hasPredicateRange = 1;
12166 } else {
12167 /*
12168 * There's no other predicate than the [n] predicate.
12169 */
12170 predOp = NULL;
12171 hasAxisRange = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012172 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012173 }
12174 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012175 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012176 /*
12177 * Axis traversal -----------------------------------------------------
12178 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012179 /*
12180 * 2.3 Node Tests
Daniel Veillard45490ae2008-07-29 09:13:19 +000012181 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012182 * - For the namespace axis, the principal node type is namespace.
12183 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012184 *
12185 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012186 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012187 * select all element children of the context node
12188 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012189 oldContextNode = xpctxt->node;
12190 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012191 outSeq = NULL;
12192 seq = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012193 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012194 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012195
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012196
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012197 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12198 (ctxt->error == XPATH_EXPRESSION_OK)) {
Nick Wellnhofer62270532012-08-19 19:42:38 +020012199 xpctxt->node = contextSeq->nodeTab[contextIdx++];
Daniel Veillard45490ae2008-07-29 09:13:19 +000012200
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012201 if (seq == NULL) {
12202 seq = xmlXPathNodeSetCreate(NULL);
12203 if (seq == NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012204 /* TODO: Propagate memory error. */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012205 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012206 goto error;
12207 }
12208 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012209 /*
12210 * Traverse the axis and test the nodes.
12211 */
12212 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012213 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012214 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012215 do {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012216 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12217 goto error;
12218
Daniel Veillardf06307e2001-07-03 10:35:50 +000012219 cur = next(ctxt, cur);
12220 if (cur == NULL)
12221 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012222
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012223 /*
12224 * QUESTION TODO: What does the "first" and "last" stuff do?
12225 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012226 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012227 if (*first == cur)
12228 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012229 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012230#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012231 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012232#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012233 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012234#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012235 {
12236 break;
12237 }
12238 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012239 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012240 if (*last == cur)
12241 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012242 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012243#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012244 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012245#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012246 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012247#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012248 {
12249 break;
12250 }
12251 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012252
12253 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012254
Daniel Veillardf06307e2001-07-03 10:35:50 +000012255#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012256 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12257#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012258
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012259 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012260 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012261 total = 0;
12262 STRANGE
12263 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012264 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012265 if (type == NODE_TYPE_NODE) {
12266 switch (cur->type) {
12267 case XML_DOCUMENT_NODE:
12268 case XML_HTML_DOCUMENT_NODE:
12269#ifdef LIBXML_DOCB_ENABLED
12270 case XML_DOCB_DOCUMENT_NODE:
12271#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012272 case XML_ELEMENT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012273 case XML_ATTRIBUTE_NODE:
12274 case XML_PI_NODE:
12275 case XML_COMMENT_NODE:
12276 case XML_CDATA_SECTION_NODE:
12277 case XML_TEXT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012278 XP_TEST_HIT
12279 break;
Nick Wellnhoferf39fd662016-04-27 03:01:16 +020012280 case XML_NAMESPACE_DECL: {
12281 if (axis == AXIS_NAMESPACE) {
12282 XP_TEST_HIT_NS
12283 } else {
Nick Wellnhofer6eb08942016-05-05 16:49:00 +020012284 hasNsNodes = 1;
Nick Wellnhoferf39fd662016-04-27 03:01:16 +020012285 XP_TEST_HIT
12286 }
12287 break;
12288 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012289 default:
12290 break;
12291 }
Nick Wellnhoferb2189572017-11-13 21:23:17 +010012292 } else if (cur->type == (xmlElementType) type) {
Daniel Veillard713434d2012-09-26 10:21:06 +080012293 if (cur->type == XML_NAMESPACE_DECL)
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012294 XP_TEST_HIT_NS
12295 else
12296 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012297 } else if ((type == NODE_TYPE_TEXT) &&
12298 (cur->type == XML_CDATA_SECTION_NODE))
12299 {
12300 XP_TEST_HIT
12301 }
12302 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012303 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012304 if ((cur->type == XML_PI_NODE) &&
12305 ((name == NULL) || xmlStrEqual(name, cur->name)))
12306 {
12307 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012308 }
12309 break;
12310 case NODE_TEST_ALL:
12311 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012312 if (cur->type == XML_ATTRIBUTE_NODE)
12313 {
Nick Wellnhofere8de99f2013-08-05 01:26:25 +020012314 if (prefix == NULL)
12315 {
12316 XP_TEST_HIT
12317 } else if ((cur->ns != NULL) &&
12318 (xmlStrEqual(URI, cur->ns->href)))
12319 {
12320 XP_TEST_HIT
12321 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012322 }
12323 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012324 if (cur->type == XML_NAMESPACE_DECL)
12325 {
12326 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012327 }
12328 } else {
12329 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012330 if (prefix == NULL)
12331 {
12332 XP_TEST_HIT
12333
Daniel Veillardf06307e2001-07-03 10:35:50 +000012334 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012335 (xmlStrEqual(URI, cur->ns->href)))
12336 {
12337 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012338 }
12339 }
12340 }
12341 break;
12342 case NODE_TEST_NS:{
12343 TODO;
12344 break;
12345 }
12346 case NODE_TEST_NAME:
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012347 if (axis == AXIS_ATTRIBUTE) {
12348 if (cur->type != XML_ATTRIBUTE_NODE)
12349 break;
12350 } else if (axis == AXIS_NAMESPACE) {
12351 if (cur->type != XML_NAMESPACE_DECL)
12352 break;
12353 } else {
12354 if (cur->type != XML_ELEMENT_NODE)
12355 break;
12356 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012357 switch (cur->type) {
12358 case XML_ELEMENT_NODE:
12359 if (xmlStrEqual(name, cur->name)) {
12360 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012361 if (cur->ns == NULL)
12362 {
12363 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012364 }
12365 } else {
12366 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012367 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012368 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012369 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012370 }
12371 }
12372 }
12373 break;
12374 case XML_ATTRIBUTE_NODE:{
12375 xmlAttrPtr attr = (xmlAttrPtr) cur;
12376
12377 if (xmlStrEqual(name, attr->name)) {
12378 if (prefix == NULL) {
12379 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012380 (attr->ns->prefix == NULL))
12381 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012382 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012383 }
12384 } else {
12385 if ((attr->ns != NULL) &&
12386 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012387 attr->ns->href)))
12388 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012389 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012390 }
12391 }
12392 }
12393 break;
12394 }
12395 case XML_NAMESPACE_DECL:
12396 if (cur->type == XML_NAMESPACE_DECL) {
12397 xmlNsPtr ns = (xmlNsPtr) cur;
12398
12399 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012400 && (xmlStrEqual(ns->prefix, name)))
12401 {
12402 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012403 }
12404 }
12405 break;
12406 default:
12407 break;
12408 }
12409 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012410 } /* switch(test) */
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012411 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012412
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012413 goto apply_predicates;
12414
Daniel Veillard45490ae2008-07-29 09:13:19 +000012415axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012416 /*
12417 * We have a "/foo[n]", and position() = n was reached.
12418 * Note that we can have as well "/foo/::parent::foo[1]", so
12419 * a duplicate-aware merge is still needed.
12420 * Merge with the result.
12421 */
12422 if (outSeq == NULL) {
12423 outSeq = seq;
12424 seq = NULL;
12425 } else
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012426 /* TODO: Check memory error. */
12427 outSeq = mergeAndClear(outSeq, seq);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012428 /*
12429 * Break if only a true/false result was requested.
12430 */
12431 if (toBool)
12432 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012433 continue;
12434
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012435first_hit: /* ---------------------------------------------------------- */
12436 /*
12437 * Break if only a true/false result was requested and
12438 * no predicates existed and a node test succeeded.
12439 */
12440 if (outSeq == NULL) {
12441 outSeq = seq;
12442 seq = NULL;
12443 } else
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012444 /* TODO: Check memory error. */
12445 outSeq = mergeAndClear(outSeq, seq);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012446 break;
12447
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012448#ifdef DEBUG_STEP
12449 if (seq != NULL)
12450 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012451#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012452
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012453apply_predicates: /* --------------------------------------------------- */
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012454 if (ctxt->error != XPATH_EXPRESSION_OK)
12455 goto error;
12456
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012457 /*
12458 * Apply predicates.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012459 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012460 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12461 /*
12462 * E.g. when we have a "/foo[some expression][n]".
Daniel Veillardf8e3db02012-09-11 13:26:36 +080012463 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012464 /*
12465 * QUESTION TODO: The old predicate evaluation took into
12466 * account location-sets.
12467 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12468 * Do we expect such a set here?
12469 * All what I learned now from the evaluation semantics
12470 * does not indicate that a location-set will be processed
12471 * here, so this looks OK.
Daniel Veillardf8e3db02012-09-11 13:26:36 +080012472 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012473 /*
12474 * Iterate over all predicates, starting with the outermost
12475 * predicate.
12476 * TODO: Problem: we cannot execute the inner predicates first
12477 * since we cannot go back *up* the operator tree!
12478 * Options we have:
12479 * 1) Use of recursive functions (like is it currently done
12480 * via xmlXPathCompOpEval())
12481 * 2) Add a predicate evaluation information stack to the
12482 * context struct
12483 * 3) Change the way the operators are linked; we need a
12484 * "parent" field on xmlXPathStepOp
12485 *
12486 * For the moment, I'll try to solve this with a recursive
12487 * function: xmlXPathCompOpEvalPredicate().
Daniel Veillard45490ae2008-07-29 09:13:19 +000012488 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012489 if (hasPredicateRange != 0)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012490 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12491 hasNsNodes);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012492 else
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012493 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12494 hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012495
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012496 if (ctxt->error != XPATH_EXPRESSION_OK) {
12497 total = 0;
12498 goto error;
12499 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012500 }
12501
12502 if (seq->nodeNr > 0) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012503 /*
12504 * Add to result set.
12505 */
12506 if (outSeq == NULL) {
12507 outSeq = seq;
12508 seq = NULL;
12509 } else {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012510 /* TODO: Check memory error. */
12511 outSeq = mergeAndClear(outSeq, seq);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012512 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012513
12514 if (toBool)
12515 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012516 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012517 }
12518
12519error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012520 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012521 /*
12522 * QUESTION TODO: What does this do and why?
12523 * TODO: Do we have to do this also for the "error"
12524 * cleanup further down?
12525 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012526 ctxt->value->boolval = 1;
12527 ctxt->value->user = obj->user;
12528 obj->user = NULL;
12529 obj->boolval = 0;
12530 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012531 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012532
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012533 /*
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012534 * Ensure we return at least an empty set.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012535 */
12536 if (outSeq == NULL) {
12537 if ((seq != NULL) && (seq->nodeNr == 0))
12538 outSeq = seq;
12539 else
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012540 /* TODO: Check memory error. */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012541 outSeq = xmlXPathNodeSetCreate(NULL);
12542 }
12543 if ((seq != NULL) && (seq != outSeq)) {
12544 xmlXPathFreeNodeSet(seq);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012545 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012546 /*
12547 * Hand over the result. Better to push the set also in
12548 * case of errors.
12549 */
12550 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12551 /*
12552 * Reset the context node.
12553 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012554 xpctxt->node = oldContextNode;
Nick Wellnhofer82b73032016-04-30 17:53:10 +020012555 /*
12556 * When traversing the namespace axis in "toBool" mode, it's
12557 * possible that tmpNsList wasn't freed.
12558 */
12559 if (xpctxt->tmpNsList != NULL) {
12560 xmlFree(xpctxt->tmpNsList);
12561 xpctxt->tmpNsList = NULL;
12562 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012563
12564#ifdef DEBUG_STEP
12565 xmlGenericError(xmlGenericErrorContext,
12566 "\nExamined %d nodes, found %d nodes at that step\n",
12567 total, nbMatches);
12568#endif
12569
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012570 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012571}
12572
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012573static int
12574xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12575 xmlXPathStepOpPtr op, xmlNodePtr * first);
12576
Daniel Veillardf06307e2001-07-03 10:35:50 +000012577/**
12578 * xmlXPathCompOpEvalFirst:
12579 * @ctxt: the XPath parser context with the compiled expression
12580 * @op: an XPath compiled operation
12581 * @first: the first elem found so far
12582 *
12583 * Evaluate the Precompiled XPath operation searching only the first
12584 * element in document order
12585 *
12586 * Returns the number of examined objects.
12587 */
12588static int
12589xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12590 xmlXPathStepOpPtr op, xmlNodePtr * first)
12591{
12592 int total = 0, cur;
12593 xmlXPathCompExprPtr comp;
12594 xmlXPathObjectPtr arg1, arg2;
12595
Daniel Veillard556c6682001-10-06 09:59:51 +000012596 CHECK_ERROR0;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012597 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12598 return(0);
12599 if (ctxt->context->depth >= ctxt->context->maxDepth)
12600 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12601 ctxt->context->depth += 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012602 comp = ctxt->comp;
12603 switch (op->op) {
12604 case XPATH_OP_END:
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012605 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012606 case XPATH_OP_UNION:
12607 total =
12608 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12609 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012610 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012611 if ((ctxt->value != NULL)
12612 && (ctxt->value->type == XPATH_NODESET)
12613 && (ctxt->value->nodesetval != NULL)
12614 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12615 /*
12616 * limit tree traversing to first node in the result
12617 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012618 /*
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012619 * OPTIMIZE TODO: This implicitly sorts
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012620 * the result, even if not needed. E.g. if the argument
12621 * of the count() function, no sorting is needed.
12622 * OPTIMIZE TODO: How do we know if the node-list wasn't
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012623 * already sorted?
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012624 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012625 if (ctxt->value->nodesetval->nodeNr > 1)
12626 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012627 *first = ctxt->value->nodesetval->nodeTab[0];
12628 }
12629 cur =
12630 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12631 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012632 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012633
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012634 arg2 = valuePop(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012635 arg1 = valuePop(ctxt);
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012636 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12637 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12638 xmlXPathReleaseObject(ctxt->context, arg1);
12639 xmlXPathReleaseObject(ctxt->context, arg2);
12640 XP_ERROR0(XPATH_INVALID_TYPE);
12641 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012642 if ((ctxt->context->opLimit != 0) &&
12643 (((arg1->nodesetval != NULL) &&
12644 (xmlXPathCheckOpLimit(ctxt,
12645 arg1->nodesetval->nodeNr) < 0)) ||
12646 ((arg2->nodesetval != NULL) &&
12647 (xmlXPathCheckOpLimit(ctxt,
12648 arg2->nodesetval->nodeNr) < 0)))) {
12649 xmlXPathReleaseObject(ctxt->context, arg1);
12650 xmlXPathReleaseObject(ctxt->context, arg2);
12651 break;
12652 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012653
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012654 /* TODO: Check memory error. */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012655 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12656 arg2->nodesetval);
12657 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012658 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012659 /* optimizer */
12660 if (total > cur)
12661 xmlXPathCompSwap(op);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012662 total += cur;
12663 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012664 case XPATH_OP_ROOT:
12665 xmlXPathRoot(ctxt);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012666 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012667 case XPATH_OP_NODE:
12668 if (op->ch1 != -1)
12669 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012670 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012671 if (op->ch2 != -1)
12672 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012673 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012674 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12675 ctxt->context->node));
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012676 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012677 case XPATH_OP_COLLECT:{
12678 if (op->ch1 == -1)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012679 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012680
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
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012684 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012685 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012686 }
12687 case XPATH_OP_VALUE:
12688 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012689 xmlXPathCacheObjectCopy(ctxt->context,
12690 (xmlXPathObjectPtr) op->value4));
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012691 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012692 case XPATH_OP_SORT:
12693 if (op->ch1 != -1)
12694 total +=
12695 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12696 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012697 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012698 if ((ctxt->value != NULL)
12699 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012700 && (ctxt->value->nodesetval != NULL)
12701 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012702 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012703 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012704#ifdef XP_OPTIMIZED_FILTER_FIRST
12705 case XPATH_OP_FILTER:
Marius Wachtler2ddecc22010-10-12 09:09:07 +020012706 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012707 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012708#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012709 default:
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012710 total += xmlXPathCompOpEval(ctxt, op);
12711 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012712 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012713
12714 ctxt->context->depth -= 1;
12715 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012716}
12717
12718/**
12719 * xmlXPathCompOpEvalLast:
12720 * @ctxt: the XPath parser context with the compiled expression
12721 * @op: an XPath compiled operation
12722 * @last: the last elem found so far
12723 *
12724 * Evaluate the Precompiled XPath operation searching only the last
12725 * element in document order
12726 *
William M. Brack08171912003-12-29 02:52:11 +000012727 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012728 */
12729static int
12730xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12731 xmlNodePtr * last)
12732{
12733 int total = 0, cur;
12734 xmlXPathCompExprPtr comp;
12735 xmlXPathObjectPtr arg1, arg2;
12736
Daniel Veillard556c6682001-10-06 09:59:51 +000012737 CHECK_ERROR0;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012738 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12739 return(0);
12740 if (ctxt->context->depth >= ctxt->context->maxDepth)
12741 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12742 ctxt->context->depth += 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012743 comp = ctxt->comp;
12744 switch (op->op) {
12745 case XPATH_OP_END:
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012746 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012747 case XPATH_OP_UNION:
12748 total =
12749 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012750 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012751 if ((ctxt->value != NULL)
12752 && (ctxt->value->type == XPATH_NODESET)
12753 && (ctxt->value->nodesetval != NULL)
12754 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12755 /*
12756 * limit tree traversing to first node in the result
12757 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012758 if (ctxt->value->nodesetval->nodeNr > 1)
12759 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012760 *last =
12761 ctxt->value->nodesetval->nodeTab[ctxt->value->
12762 nodesetval->nodeNr -
12763 1];
12764 }
12765 cur =
12766 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012767 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012768 if ((ctxt->value != NULL)
12769 && (ctxt->value->type == XPATH_NODESET)
12770 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012771 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012772 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012773
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012774 arg2 = valuePop(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012775 arg1 = valuePop(ctxt);
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012776 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12777 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12778 xmlXPathReleaseObject(ctxt->context, arg1);
12779 xmlXPathReleaseObject(ctxt->context, arg2);
12780 XP_ERROR0(XPATH_INVALID_TYPE);
12781 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012782 if ((ctxt->context->opLimit != 0) &&
12783 (((arg1->nodesetval != NULL) &&
12784 (xmlXPathCheckOpLimit(ctxt,
12785 arg1->nodesetval->nodeNr) < 0)) ||
12786 ((arg2->nodesetval != NULL) &&
12787 (xmlXPathCheckOpLimit(ctxt,
12788 arg2->nodesetval->nodeNr) < 0)))) {
12789 xmlXPathReleaseObject(ctxt->context, arg1);
12790 xmlXPathReleaseObject(ctxt->context, arg2);
12791 break;
12792 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012793
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012794 /* TODO: Check memory error. */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012795 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12796 arg2->nodesetval);
12797 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012798 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012799 /* optimizer */
12800 if (total > cur)
12801 xmlXPathCompSwap(op);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012802 total += cur;
12803 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012804 case XPATH_OP_ROOT:
12805 xmlXPathRoot(ctxt);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012806 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012807 case XPATH_OP_NODE:
12808 if (op->ch1 != -1)
12809 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012810 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012811 if (op->ch2 != -1)
12812 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012813 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012814 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12815 ctxt->context->node));
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012816 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012817 case XPATH_OP_COLLECT:{
12818 if (op->ch1 == -1)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012819 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012820
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
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012824 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012825 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012826 }
12827 case XPATH_OP_VALUE:
12828 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012829 xmlXPathCacheObjectCopy(ctxt->context,
12830 (xmlXPathObjectPtr) op->value4));
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012831 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012832 case XPATH_OP_SORT:
12833 if (op->ch1 != -1)
12834 total +=
12835 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12836 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012837 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012838 if ((ctxt->value != NULL)
12839 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012840 && (ctxt->value->nodesetval != NULL)
12841 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012842 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012843 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012844 default:
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012845 total += xmlXPathCompOpEval(ctxt, op);
12846 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012847 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012848
12849 ctxt->context->depth -= 1;
12850 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012851}
12852
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012853#ifdef XP_OPTIMIZED_FILTER_FIRST
12854static int
12855xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12856 xmlXPathStepOpPtr op, xmlNodePtr * first)
12857{
12858 int total = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012859 xmlXPathCompExprPtr comp;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012860 xmlNodeSetPtr set;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012861
12862 CHECK_ERROR0;
12863 comp = ctxt->comp;
12864 /*
12865 * Optimization for ()[last()] selection i.e. the last elem
12866 */
12867 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12868 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12869 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12870 int f = comp->steps[op->ch2].ch1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012871
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012872 if ((f != -1) &&
12873 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12874 (comp->steps[f].value5 == NULL) &&
12875 (comp->steps[f].value == 0) &&
12876 (comp->steps[f].value4 != NULL) &&
12877 (xmlStrEqual
12878 (comp->steps[f].value4, BAD_CAST "last"))) {
12879 xmlNodePtr last = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012880
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012881 total +=
12882 xmlXPathCompOpEvalLast(ctxt,
12883 &comp->steps[op->ch1],
12884 &last);
12885 CHECK_ERROR0;
12886 /*
12887 * The nodeset should be in document order,
12888 * Keep only the last value
12889 */
12890 if ((ctxt->value != NULL) &&
12891 (ctxt->value->type == XPATH_NODESET) &&
12892 (ctxt->value->nodesetval != NULL) &&
12893 (ctxt->value->nodesetval->nodeTab != NULL) &&
12894 (ctxt->value->nodesetval->nodeNr > 1)) {
Nick Wellnhofer95a92492017-05-21 15:18:58 +020012895 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012896 *first = *(ctxt->value->nodesetval->nodeTab);
12897 }
12898 return (total);
12899 }
12900 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012901
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012902 if (op->ch1 != -1)
12903 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12904 CHECK_ERROR0;
12905 if (op->ch2 == -1)
12906 return (total);
12907 if (ctxt->value == NULL)
12908 return (total);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012909
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012910#ifdef LIBXML_XPTR_ENABLED
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012911 /*
12912 * Hum are we filtering the result of an XPointer expression
12913 */
12914 if (ctxt->value->type == XPATH_LOCATIONSET) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012915 xmlLocationSetPtr locset = ctxt->value->user;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012916
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012917 if (locset != NULL) {
12918 xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12919 if (locset->locNr > 0)
12920 *first = (xmlNodePtr) locset->locTab[0]->user;
12921 }
Elliott Hughes7fbecab2019-01-10 16:42:03 -080012922
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012923 return (total);
12924 }
12925#endif /* LIBXML_XPTR_ENABLED */
Daniel Veillard45490ae2008-07-29 09:13:19 +000012926
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012927 CHECK_TYPE0(XPATH_NODESET);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012928 set = ctxt->value->nodesetval;
12929 if (set != NULL) {
12930 xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12931 if (set->nodeNr > 0)
12932 *first = set->nodeTab[0];
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012933 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012934
12935 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012936}
12937#endif /* XP_OPTIMIZED_FILTER_FIRST */
12938
Owen Taylor3473f882001-02-23 17:55:21 +000012939/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012940 * xmlXPathCompOpEval:
12941 * @ctxt: the XPath parser context with the compiled expression
12942 * @op: an XPath compiled operation
12943 *
12944 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000012945 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012946 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012947static int
12948xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12949{
12950 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012951 int equal, ret;
12952 xmlXPathCompExprPtr comp;
12953 xmlXPathObjectPtr arg1, arg2;
12954
Daniel Veillard556c6682001-10-06 09:59:51 +000012955 CHECK_ERROR0;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012956 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12957 return(0);
12958 if (ctxt->context->depth >= ctxt->context->maxDepth)
12959 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12960 ctxt->context->depth += 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012961 comp = ctxt->comp;
12962 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012963 case XPATH_OP_END:
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012964 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012965 case XPATH_OP_AND:
12966 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012967 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012968 xmlXPathBooleanFunction(ctxt, 1);
12969 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012970 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012971 arg2 = valuePop(ctxt);
12972 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012973 if (ctxt->error) {
12974 xmlXPathFreeObject(arg2);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012975 break;
Daniel Veillard556c6682001-10-06 09:59:51 +000012976 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012977 xmlXPathBooleanFunction(ctxt, 1);
Elliott Hughes7fbecab2019-01-10 16:42:03 -080012978 if (ctxt->value != NULL)
12979 ctxt->value->boolval &= arg2->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012980 xmlXPathReleaseObject(ctxt->context, arg2);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012981 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012982 case XPATH_OP_OR:
12983 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012984 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012985 xmlXPathBooleanFunction(ctxt, 1);
12986 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012987 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012988 arg2 = valuePop(ctxt);
12989 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012990 if (ctxt->error) {
12991 xmlXPathFreeObject(arg2);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012992 break;
Daniel Veillard556c6682001-10-06 09:59:51 +000012993 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012994 xmlXPathBooleanFunction(ctxt, 1);
Elliott Hughes7fbecab2019-01-10 16:42:03 -080012995 if (ctxt->value != NULL)
12996 ctxt->value->boolval |= arg2->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012997 xmlXPathReleaseObject(ctxt->context, arg2);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070012998 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012999 case XPATH_OP_EQUAL:
13000 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013001 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013002 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013003 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013004 if (op->value)
Daniel Veillard45490ae2008-07-29 09:13:19 +000013005 equal = xmlXPathEqualValues(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +000013006 else
13007 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013008 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013009 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013010 case XPATH_OP_CMP:
13011 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013012 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013013 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013014 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013015 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013016 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013017 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013018 case XPATH_OP_PLUS:
13019 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013020 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013021 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013022 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013023 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013024 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013025 if (op->value == 0)
13026 xmlXPathSubValues(ctxt);
13027 else if (op->value == 1)
13028 xmlXPathAddValues(ctxt);
13029 else if (op->value == 2)
13030 xmlXPathValueFlipSign(ctxt);
13031 else if (op->value == 3) {
13032 CAST_TO_NUMBER;
13033 CHECK_TYPE0(XPATH_NUMBER);
13034 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013035 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013036 case XPATH_OP_MULT:
13037 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013038 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013039 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013040 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013041 if (op->value == 0)
13042 xmlXPathMultValues(ctxt);
13043 else if (op->value == 1)
13044 xmlXPathDivValues(ctxt);
13045 else if (op->value == 2)
13046 xmlXPathModValues(ctxt);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013047 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013048 case XPATH_OP_UNION:
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 Veillard9e7160d2001-03-18 23:17:47 +000013053
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020013054 arg2 = valuePop(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013055 arg1 = valuePop(ctxt);
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020013056 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13057 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13058 xmlXPathReleaseObject(ctxt->context, arg1);
13059 xmlXPathReleaseObject(ctxt->context, arg2);
13060 XP_ERROR0(XPATH_INVALID_TYPE);
13061 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013062 if ((ctxt->context->opLimit != 0) &&
13063 (((arg1->nodesetval != NULL) &&
13064 (xmlXPathCheckOpLimit(ctxt,
13065 arg1->nodesetval->nodeNr) < 0)) ||
13066 ((arg2->nodesetval != NULL) &&
13067 (xmlXPathCheckOpLimit(ctxt,
13068 arg2->nodesetval->nodeNr) < 0)))) {
13069 xmlXPathReleaseObject(ctxt->context, arg1);
13070 xmlXPathReleaseObject(ctxt->context, arg2);
13071 break;
13072 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013073
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013074 if ((arg1->nodesetval == NULL) ||
13075 ((arg2->nodesetval != NULL) &&
13076 (arg2->nodesetval->nodeNr != 0)))
13077 {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013078 /* TODO: Check memory error. */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013079 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13080 arg2->nodesetval);
13081 }
13082
Daniel Veillardf06307e2001-07-03 10:35:50 +000013083 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013084 xmlXPathReleaseObject(ctxt->context, arg2);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013085 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013086 case XPATH_OP_ROOT:
13087 xmlXPathRoot(ctxt);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013088 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013089 case XPATH_OP_NODE:
13090 if (op->ch1 != -1)
13091 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013092 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013093 if (op->ch2 != -1)
13094 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013095 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013096 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13097 ctxt->context->node));
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013098 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013099 case XPATH_OP_COLLECT:{
13100 if (op->ch1 == -1)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013101 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013102
Daniel Veillardf06307e2001-07-03 10:35:50 +000013103 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013104 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013105
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013106 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013107 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013108 }
13109 case XPATH_OP_VALUE:
13110 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013111 xmlXPathCacheObjectCopy(ctxt->context,
13112 (xmlXPathObjectPtr) op->value4));
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013113 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013114 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013115 xmlXPathObjectPtr val;
13116
Daniel Veillardf06307e2001-07-03 10:35:50 +000013117 if (op->ch1 != -1)
13118 total +=
13119 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013120 if (op->value5 == NULL) {
13121 val = xmlXPathVariableLookup(ctxt->context, op->value4);
Nick Wellnhofer3157cf42017-09-20 16:13:29 +020013122 if (val == NULL)
13123 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
Daniel Veillard556c6682001-10-06 09:59:51 +000013124 valuePush(ctxt, val);
13125 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013126 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013127
Daniel Veillardf06307e2001-07-03 10:35:50 +000013128 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13129 if (URI == NULL) {
13130 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013131 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13132 (char *) op->value4, (char *)op->value5);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013133 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013134 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013135 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013136 val = xmlXPathVariableLookupNS(ctxt->context,
13137 op->value4, URI);
Nick Wellnhofer3157cf42017-09-20 16:13:29 +020013138 if (val == NULL)
13139 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
Daniel Veillard556c6682001-10-06 09:59:51 +000013140 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013141 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013142 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013143 }
13144 case XPATH_OP_FUNCTION:{
13145 xmlXPathFunction func;
13146 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013147 int i;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013148 int frame;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013149
Daniel Veillardf5048b32011-08-18 17:10:13 +080013150 frame = xmlXPathSetFrame(ctxt);
Nick Wellnhofer03c67232013-12-20 00:01:53 +010013151 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013152 total +=
13153 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhofer03c67232013-12-20 00:01:53 +010013154 if (ctxt->error != XPATH_EXPRESSION_OK) {
13155 xmlXPathPopFrame(ctxt, frame);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013156 break;
Nick Wellnhofer03c67232013-12-20 00:01:53 +010013157 }
13158 }
13159 if (ctxt->valueNr < ctxt->valueFrame + op->value) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013160 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013161 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013162 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013163 xmlXPathPopFrame(ctxt, frame);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013164 break;
Daniel Veillard556c6682001-10-06 09:59:51 +000013165 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013166 for (i = 0; i < op->value; i++) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013167 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13168 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013169 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013170 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013171 xmlXPathPopFrame(ctxt, frame);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013172 break;
Daniel Veillard556c6682001-10-06 09:59:51 +000013173 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013174 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013175 if (op->cache != NULL)
Nick Wellnhofer229d1f92016-08-22 13:21:57 +020013176 func = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013177 else {
13178 const xmlChar *URI = NULL;
13179
13180 if (op->value5 == NULL)
13181 func =
13182 xmlXPathFunctionLookup(ctxt->context,
13183 op->value4);
13184 else {
13185 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13186 if (URI == NULL) {
13187 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013188 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13189 (char *)op->value4, (char *)op->value5);
Daniel Veillardf5048b32011-08-18 17:10:13 +080013190 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013191 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013192 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013193 }
13194 func = xmlXPathFunctionLookupNS(ctxt->context,
13195 op->value4, URI);
13196 }
13197 if (func == NULL) {
13198 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013199 "xmlXPathCompOpEval: function %s not found\n",
13200 (char *)op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013201 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013202 }
Nick Wellnhofer229d1f92016-08-22 13:21:57 +020013203 op->cache = func;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013204 op->cacheURI = (void *) URI;
13205 }
13206 oldFunc = ctxt->context->function;
13207 oldFuncURI = ctxt->context->functionURI;
13208 ctxt->context->function = op->value4;
13209 ctxt->context->functionURI = op->cacheURI;
13210 func(ctxt, op->value);
13211 ctxt->context->function = oldFunc;
13212 ctxt->context->functionURI = oldFuncURI;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013213 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13214 (ctxt->valueNr != ctxt->valueFrame + 1))
13215 XP_ERROR0(XPATH_STACK_ERROR);
Daniel Veillardf5048b32011-08-18 17:10:13 +080013216 xmlXPathPopFrame(ctxt, frame);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013217 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013218 }
13219 case XPATH_OP_ARG:
Nick Wellnhofer07def302014-03-21 19:38:08 +010013220 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013221 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhofer07def302014-03-21 19:38:08 +010013222 CHECK_ERROR0;
13223 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013224 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013225 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013226 CHECK_ERROR0;
13227 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013228 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013229 case XPATH_OP_PREDICATE:
13230 case XPATH_OP_FILTER:{
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013231 xmlNodeSetPtr set;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013232
13233 /*
13234 * Optimization for ()[1] selection i.e. the first elem
13235 */
13236 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013237#ifdef XP_OPTIMIZED_FILTER_FIRST
13238 /*
13239 * FILTER TODO: Can we assume that the inner processing
13240 * will result in an ordered list if we have an
13241 * XPATH_OP_FILTER?
13242 * What about an additional field or flag on
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013243 * xmlXPathObject like @sorted ? This way we wouldn't need
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013244 * to assume anything, so it would be more robust and
13245 * easier to optimize.
13246 */
13247 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13248 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13249#else
13250 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13251#endif
13252 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013253 xmlXPathObjectPtr val;
13254
13255 val = comp->steps[op->ch2].value4;
13256 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13257 (val->floatval == 1.0)) {
13258 xmlNodePtr first = NULL;
13259
13260 total +=
13261 xmlXPathCompOpEvalFirst(ctxt,
13262 &comp->steps[op->ch1],
13263 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013264 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013265 /*
13266 * The nodeset should be in document order,
13267 * Keep only the first value
13268 */
13269 if ((ctxt->value != NULL) &&
13270 (ctxt->value->type == XPATH_NODESET) &&
13271 (ctxt->value->nodesetval != NULL) &&
13272 (ctxt->value->nodesetval->nodeNr > 1))
Nick Wellnhofer95a92492017-05-21 15:18:58 +020013273 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13274 1, 1);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013275 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013276 }
13277 }
13278 /*
13279 * Optimization for ()[last()] selection i.e. the last elem
13280 */
13281 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13282 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13283 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13284 int f = comp->steps[op->ch2].ch1;
13285
13286 if ((f != -1) &&
13287 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13288 (comp->steps[f].value5 == NULL) &&
13289 (comp->steps[f].value == 0) &&
13290 (comp->steps[f].value4 != NULL) &&
13291 (xmlStrEqual
13292 (comp->steps[f].value4, BAD_CAST "last"))) {
13293 xmlNodePtr last = NULL;
13294
13295 total +=
13296 xmlXPathCompOpEvalLast(ctxt,
13297 &comp->steps[op->ch1],
13298 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013299 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013300 /*
13301 * The nodeset should be in document order,
13302 * Keep only the last value
13303 */
13304 if ((ctxt->value != NULL) &&
13305 (ctxt->value->type == XPATH_NODESET) &&
13306 (ctxt->value->nodesetval != NULL) &&
13307 (ctxt->value->nodesetval->nodeTab != NULL) &&
Nick Wellnhofer95a92492017-05-21 15:18:58 +020013308 (ctxt->value->nodesetval->nodeNr > 1))
13309 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013310 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013311 }
13312 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013313 /*
13314 * Process inner predicates first.
13315 * Example "index[parent::book][1]":
13316 * ...
13317 * PREDICATE <-- we are here "[1]"
13318 * PREDICATE <-- process "[parent::book]" first
13319 * SORT
13320 * COLLECT 'parent' 'name' 'node' book
13321 * NODE
13322 * ELEM Object is a number : 1
13323 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013324 if (op->ch1 != -1)
13325 total +=
13326 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013327 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013328 if (op->ch2 == -1)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013329 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013330 if (ctxt->value == NULL)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013331 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013332
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013333#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013334 /*
13335 * Hum are we filtering the result of an XPointer expression
13336 */
13337 if (ctxt->value->type == XPATH_LOCATIONSET) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013338 xmlLocationSetPtr locset = ctxt->value->user;
13339 xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13340 1, locset->locNr);
13341 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013342 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013343#endif /* LIBXML_XPTR_ENABLED */
13344
Daniel Veillardf06307e2001-07-03 10:35:50 +000013345 CHECK_TYPE0(XPATH_NODESET);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013346 set = ctxt->value->nodesetval;
13347 if (set != NULL)
13348 xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13349 1, set->nodeNr, 1);
13350 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013351 }
13352 case XPATH_OP_SORT:
13353 if (op->ch1 != -1)
13354 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013355 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013356 if ((ctxt->value != NULL) &&
13357 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013358 (ctxt->value->nodesetval != NULL) &&
13359 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013360 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013361 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013362 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013363 break;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013364#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013365 case XPATH_OP_RANGETO:{
13366 xmlXPathObjectPtr range;
13367 xmlXPathObjectPtr res, obj;
13368 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013369 xmlLocationSetPtr newlocset = NULL;
13370 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013371 xmlNodeSetPtr oldset;
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013372 xmlNodePtr oldnode = ctxt->context->node;
13373 int oldcs = ctxt->context->contextSize;
13374 int oldpp = ctxt->context->proximityPosition;
William M. Brack72ee48d2003-12-30 08:30:19 +000013375 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013376
Nick Wellnhoferd8083bf2016-06-25 12:35:50 +020013377 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013378 total +=
13379 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhoferd8083bf2016-06-25 12:35:50 +020013380 CHECK_ERROR0;
13381 }
13382 if (ctxt->value == NULL) {
13383 XP_ERROR0(XPATH_INVALID_OPERAND);
13384 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013385 if (op->ch2 == -1)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013386 break;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013387
William M. Brack08171912003-12-29 02:52:11 +000013388 if (ctxt->value->type == XPATH_LOCATIONSET) {
13389 /*
13390 * Extract the old locset, and then evaluate the result of the
13391 * expression for all the element in the locset. use it to grow
13392 * up a new locset.
13393 */
13394 CHECK_TYPE0(XPATH_LOCATIONSET);
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013395
13396 if ((ctxt->value->user == NULL) ||
13397 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013398 break;
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013399
William M. Brack08171912003-12-29 02:52:11 +000013400 obj = valuePop(ctxt);
13401 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013402
William M. Brack08171912003-12-29 02:52:11 +000013403 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013404
William M. Brack08171912003-12-29 02:52:11 +000013405 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013406 /*
William M. Brack08171912003-12-29 02:52:11 +000013407 * Run the evaluation with a node list made of a
13408 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013409 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013410 ctxt->context->node = oldlocset->locTab[i]->user;
13411 ctxt->context->contextSize = oldlocset->locNr;
13412 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013413 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13414 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013415 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013416
Daniel Veillardf06307e2001-07-03 10:35:50 +000013417 if (op->ch2 != -1)
13418 total +=
13419 xmlXPathCompOpEval(ctxt,
13420 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013421 if (ctxt->error != XPATH_EXPRESSION_OK) {
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013422 xmlXPtrFreeLocationSet(newlocset);
13423 goto rangeto_error;
William M. Brack2c19a7b2005-04-10 01:03:23 +000013424 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013425
Daniel Veillardf06307e2001-07-03 10:35:50 +000013426 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013427 if (res->type == XPATH_LOCATIONSET) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000013428 xmlLocationSetPtr rloc =
William M. Brack72ee48d2003-12-30 08:30:19 +000013429 (xmlLocationSetPtr)res->user;
13430 for (j=0; j<rloc->locNr; j++) {
13431 range = xmlXPtrNewRange(
13432 oldlocset->locTab[i]->user,
13433 oldlocset->locTab[i]->index,
13434 rloc->locTab[j]->user2,
13435 rloc->locTab[j]->index2);
13436 if (range != NULL) {
13437 xmlXPtrLocationSetAdd(newlocset, range);
13438 }
13439 }
13440 } else {
13441 range = xmlXPtrNewRangeNodeObject(
13442 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13443 if (range != NULL) {
13444 xmlXPtrLocationSetAdd(newlocset,range);
13445 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013446 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013447
Daniel Veillardf06307e2001-07-03 10:35:50 +000013448 /*
13449 * Cleanup
13450 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013451 if (res != NULL) {
13452 xmlXPathReleaseObject(ctxt->context, res);
13453 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013454 if (ctxt->value == tmp) {
13455 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013456 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013457 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013458 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013459 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000013460 CHECK_TYPE0(XPATH_NODESET);
13461 obj = valuePop(ctxt);
13462 oldset = obj->nodesetval;
William M. Brack08171912003-12-29 02:52:11 +000013463
13464 newlocset = xmlXPtrLocationSetCreate(NULL);
13465
13466 if (oldset != NULL) {
13467 for (i = 0; i < oldset->nodeNr; i++) {
13468 /*
13469 * Run the evaluation with a node list made of a single item
13470 * in the nodeset.
13471 */
13472 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013473 /*
13474 * OPTIMIZE TODO: Avoid recreation for every iteration.
13475 */
13476 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13477 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000013478 valuePush(ctxt, tmp);
13479
13480 if (op->ch2 != -1)
13481 total +=
13482 xmlXPathCompOpEval(ctxt,
13483 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013484 if (ctxt->error != XPATH_EXPRESSION_OK) {
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013485 xmlXPtrFreeLocationSet(newlocset);
13486 goto rangeto_error;
William M. Brack2c19a7b2005-04-10 01:03:23 +000013487 }
William M. Brack08171912003-12-29 02:52:11 +000013488
William M. Brack08171912003-12-29 02:52:11 +000013489 res = valuePop(ctxt);
13490 range =
13491 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13492 res);
13493 if (range != NULL) {
13494 xmlXPtrLocationSetAdd(newlocset, range);
13495 }
13496
13497 /*
13498 * Cleanup
13499 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013500 if (res != NULL) {
13501 xmlXPathReleaseObject(ctxt->context, res);
13502 }
William M. Brack08171912003-12-29 02:52:11 +000013503 if (ctxt->value == tmp) {
13504 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013505 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000013506 }
William M. Brack08171912003-12-29 02:52:11 +000013507 }
13508 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013509 }
13510
13511 /*
13512 * The result is used as the new evaluation set.
13513 */
William M. Brack08171912003-12-29 02:52:11 +000013514 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013515rangeto_error:
13516 xmlXPathReleaseObject(ctxt->context, obj);
13517 ctxt->context->node = oldnode;
13518 ctxt->context->contextSize = oldcs;
13519 ctxt->context->proximityPosition = oldpp;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013520 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013521 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013522#endif /* LIBXML_XPTR_ENABLED */
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013523 default:
13524 xmlGenericError(xmlGenericErrorContext,
13525 "XPath: unknown precompiled operation %d\n", op->op);
13526 ctxt->error = XPATH_INVALID_OPERAND;
13527 break;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013528 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013529
13530 ctxt->context->depth -= 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013531 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013532}
13533
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013534/**
13535 * xmlXPathCompOpEvalToBoolean:
13536 * @ctxt: the XPath parser context
13537 *
13538 * Evaluates if the expression evaluates to true.
13539 *
13540 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13541 */
13542static int
13543xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013544 xmlXPathStepOpPtr op,
13545 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013546{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013547 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013548
13549start:
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013550 if (OP_LIMIT_EXCEEDED(ctxt, 1))
13551 return(0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013552 /* comp = ctxt->comp; */
13553 switch (op->op) {
13554 case XPATH_OP_END:
13555 return (0);
13556 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013557 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000013558 if (isPredicate)
13559 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13560 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013561 case XPATH_OP_SORT:
13562 /*
13563 * We don't need sorting for boolean results. Skip this one.
13564 */
13565 if (op->ch1 != -1) {
13566 op = &ctxt->comp->steps[op->ch1];
13567 goto start;
13568 }
13569 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013570 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013571 if (op->ch1 == -1)
13572 return(0);
13573
13574 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13575 if (ctxt->error != XPATH_EXPRESSION_OK)
13576 return(-1);
13577
13578 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13579 if (ctxt->error != XPATH_EXPRESSION_OK)
13580 return(-1);
13581
13582 resObj = valuePop(ctxt);
13583 if (resObj == NULL)
13584 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013585 break;
13586 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013587 /*
13588 * Fallback to call xmlXPathCompOpEval().
13589 */
13590 xmlXPathCompOpEval(ctxt, op);
13591 if (ctxt->error != XPATH_EXPRESSION_OK)
13592 return(-1);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013593
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013594 resObj = valuePop(ctxt);
13595 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000013596 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013597 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013598 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013599
13600 if (resObj) {
13601 int res;
13602
13603 if (resObj->type == XPATH_BOOLEAN) {
13604 res = resObj->boolval;
13605 } else if (isPredicate) {
13606 /*
13607 * For predicates a result of type "number" is handled
13608 * differently:
13609 * SPEC XPath 1.0:
13610 * "If the result is a number, the result will be converted
13611 * to true if the number is equal to the context position
13612 * and will be converted to false otherwise;"
13613 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013614 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013615 } else {
13616 res = xmlXPathCastToBoolean(resObj);
13617 }
13618 xmlXPathReleaseObject(ctxt->context, resObj);
13619 return(res);
13620 }
13621
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013622 return(0);
13623}
13624
Daniel Veillard56de87e2005-02-16 00:22:29 +000013625#ifdef XPATH_STREAMING
13626/**
13627 * xmlXPathRunStreamEval:
13628 * @ctxt: the XPath parser context with the compiled expression
13629 *
13630 * Evaluate the Precompiled Streamable XPath expression in the given context.
13631 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013632static int
13633xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13634 xmlXPathObjectPtr *resultSeq, int toBool)
13635{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013636 int max_depth, min_depth;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013637 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013638 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013639 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000013640 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000013641 xmlStreamCtxtPtr patstream = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013642
13643 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013644
13645 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013646 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013647 max_depth = xmlPatternMaxDepth(comp);
13648 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013649 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013650 if (max_depth == -2)
13651 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013652 min_depth = xmlPatternMinDepth(comp);
13653 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013654 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013655 from_root = xmlPatternFromRoot(comp);
13656 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013657 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000013658#if 0
13659 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13660#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000013661
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013662 if (! toBool) {
13663 if (resultSeq == NULL)
13664 return(-1);
13665 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13666 if (*resultSeq == NULL)
13667 return(-1);
13668 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000013669
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013670 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000013671 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013672 */
13673 if (min_depth == 0) {
13674 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000013675 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013676 if (toBool)
13677 return(1);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013678 /* TODO: Check memory error. */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013679 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013680 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013681 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000013682 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013683 if (toBool)
13684 return(1);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013685 /* TODO: Check memory error. */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013686 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013687 }
13688 }
13689 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013690 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013691 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013692
Daniel Veillard56de87e2005-02-16 00:22:29 +000013693 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000013694 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013695 } else if (ctxt->node != NULL) {
13696 switch (ctxt->node->type) {
13697 case XML_ELEMENT_NODE:
13698 case XML_DOCUMENT_NODE:
13699 case XML_DOCUMENT_FRAG_NODE:
13700 case XML_HTML_DOCUMENT_NODE:
13701#ifdef LIBXML_DOCB_ENABLED
13702 case XML_DOCB_DOCUMENT_NODE:
13703#endif
13704 cur = ctxt->node;
13705 break;
13706 case XML_ATTRIBUTE_NODE:
13707 case XML_TEXT_NODE:
13708 case XML_CDATA_SECTION_NODE:
13709 case XML_ENTITY_REF_NODE:
13710 case XML_ENTITY_NODE:
13711 case XML_PI_NODE:
13712 case XML_COMMENT_NODE:
13713 case XML_NOTATION_NODE:
13714 case XML_DTD_NODE:
13715 case XML_DOCUMENT_TYPE_NODE:
13716 case XML_ELEMENT_DECL:
13717 case XML_ATTRIBUTE_DECL:
13718 case XML_ENTITY_DECL:
13719 case XML_NAMESPACE_DECL:
13720 case XML_XINCLUDE_START:
13721 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000013722 break;
13723 }
13724 limit = cur;
13725 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013726 if (cur == NULL) {
13727 return(0);
13728 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013729
13730 patstream = xmlPatternGetStreamCtxt(comp);
13731 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013732 /*
13733 * QUESTION TODO: Is this an error?
13734 */
13735 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013736 }
13737
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013738 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013739
Daniel Veillard56de87e2005-02-16 00:22:29 +000013740 if (from_root) {
13741 ret = xmlStreamPush(patstream, NULL, NULL);
13742 if (ret < 0) {
13743 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013744 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000013745 goto return_1;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013746 /* TODO: Check memory error. */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013747 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013748 }
13749 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013750 depth = 0;
13751 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013752next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000013753 do {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013754 if (ctxt->opLimit != 0) {
13755 if (ctxt->opCount >= ctxt->opLimit) {
13756 xmlGenericError(xmlGenericErrorContext,
13757 "XPath operation limit exceeded\n");
13758 xmlFreeStreamCtxt(patstream);
13759 return(-1);
13760 }
13761 ctxt->opCount++;
13762 }
13763
Daniel Veillard56de87e2005-02-16 00:22:29 +000013764 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013765
13766 switch (cur->type) {
13767 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013768 case XML_TEXT_NODE:
13769 case XML_CDATA_SECTION_NODE:
13770 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013771 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013772 if (cur->type == XML_ELEMENT_NODE) {
13773 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000013774 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013775 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013776 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13777 else
13778 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013779
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013780 if (ret < 0) {
13781 /* NOP. */
13782 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013783 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000013784 goto return_1;
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013785 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13786 < 0) {
13787 ctxt->lastError.domain = XML_FROM_XPATH;
13788 ctxt->lastError.code = XML_ERR_NO_MEMORY;
13789 }
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013790 }
13791 if ((cur->children == NULL) || (depth >= max_depth)) {
13792 ret = xmlStreamPop(patstream);
13793 while (cur->next != NULL) {
13794 cur = cur->next;
13795 if ((cur->type != XML_ENTITY_DECL) &&
13796 (cur->type != XML_DTD_NODE))
13797 goto next_node;
13798 }
13799 }
13800 default:
13801 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013802 }
13803
Daniel Veillard56de87e2005-02-16 00:22:29 +000013804scan_children:
Daniel Veillard3e62adb2012-08-09 14:24:02 +080013805 if (cur->type == XML_NAMESPACE_DECL) break;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013806 if ((cur->children != NULL) && (depth < max_depth)) {
13807 /*
Daniel Veillard45490ae2008-07-29 09:13:19 +000013808 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000013809 */
13810 if (cur->children->type != XML_ENTITY_DECL) {
13811 cur = cur->children;
13812 depth++;
13813 /*
13814 * Skip DTDs
13815 */
13816 if (cur->type != XML_DTD_NODE)
13817 continue;
13818 }
13819 }
13820
13821 if (cur == limit)
13822 break;
13823
13824 while (cur->next != NULL) {
13825 cur = cur->next;
13826 if ((cur->type != XML_ENTITY_DECL) &&
13827 (cur->type != XML_DTD_NODE))
13828 goto next_node;
13829 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000013830
Daniel Veillard56de87e2005-02-16 00:22:29 +000013831 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000013832 cur = cur->parent;
13833 depth--;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013834 if ((cur == NULL) || (cur == limit) ||
13835 (cur->type == XML_DOCUMENT_NODE))
Daniel Veillard56de87e2005-02-16 00:22:29 +000013836 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013837 if (cur->type == XML_ELEMENT_NODE) {
13838 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013839 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013840 ((cur->type == XML_TEXT_NODE) ||
13841 (cur->type == XML_CDATA_SECTION_NODE) ||
13842 (cur->type == XML_COMMENT_NODE) ||
13843 (cur->type == XML_PI_NODE)))
13844 {
13845 ret = xmlStreamPop(patstream);
13846 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013847 if (cur->next != NULL) {
13848 cur = cur->next;
13849 break;
13850 }
13851 } while (cur != NULL);
13852
13853 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013854
Daniel Veillard56de87e2005-02-16 00:22:29 +000013855done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013856
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000013857#if 0
13858 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013859 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000013860#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013861
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000013862 if (patstream)
13863 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013864 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000013865
13866return_1:
13867 if (patstream)
13868 xmlFreeStreamCtxt(patstream);
13869 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013870}
13871#endif /* XPATH_STREAMING */
13872
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013873/**
13874 * xmlXPathRunEval:
13875 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013876 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013877 *
13878 * Evaluate the Precompiled XPath expression in the given context.
13879 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013880static int
13881xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13882{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013883 xmlXPathCompExprPtr comp;
13884
13885 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013886 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013887
Haibo Huangcfd91dc2020-07-30 23:01:33 -070013888 ctxt->context->depth = 0;
13889
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013890 if (ctxt->valueTab == NULL) {
13891 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013892 ctxt->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013893 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13894 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000013895 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013896 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013897 }
13898 ctxt->valueNr = 0;
13899 ctxt->valueMax = 10;
13900 ctxt->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013901 ctxt->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013902 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013903#ifdef XPATH_STREAMING
13904 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013905 int res;
13906
13907 if (toBool) {
13908 /*
13909 * Evaluation to boolean result.
13910 */
13911 res = xmlXPathRunStreamEval(ctxt->context,
13912 ctxt->comp->stream, NULL, 1);
13913 if (res != -1)
13914 return(res);
13915 } else {
Daniel Veillard45490ae2008-07-29 09:13:19 +000013916 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013917
13918 /*
13919 * Evaluation to a sequence.
13920 */
13921 res = xmlXPathRunStreamEval(ctxt->context,
13922 ctxt->comp->stream, &resObj, 0);
13923
13924 if ((res != -1) && (resObj != NULL)) {
13925 valuePush(ctxt, resObj);
13926 return(0);
13927 }
13928 if (resObj != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +000013929 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013930 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013931 /*
13932 * QUESTION TODO: This falls back to normal XPath evaluation
13933 * if res == -1. Is this intended?
13934 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000013935 }
13936#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013937 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013938 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000013939 xmlGenericError(xmlGenericErrorContext,
13940 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013941 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000013942 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013943 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013944 return(xmlXPathCompOpEvalToBoolean(ctxt,
13945 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013946 else
13947 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13948
13949 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013950}
13951
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013952/************************************************************************
13953 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000013954 * Public interfaces *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013955 * *
13956 ************************************************************************/
13957
13958/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013959 * xmlXPathEvalPredicate:
13960 * @ctxt: the XPath context
13961 * @res: the Predicate Expression evaluation result
13962 *
13963 * Evaluate a predicate result for the current node.
13964 * A PredicateExpr is evaluated by evaluating the Expr and converting
13965 * the result to a boolean. If the result is a number, the result will
13966 * be converted to true if the number is equal to the position of the
13967 * context node in the context node list (as returned by the position
13968 * function) and will be converted to false otherwise; if the result
13969 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000013970 * to the boolean function.
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013971 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013972 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013973 */
13974int
13975xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000013976 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013977 switch (res->type) {
13978 case XPATH_BOOLEAN:
13979 return(res->boolval);
13980 case XPATH_NUMBER:
13981 return(res->floatval == ctxt->proximityPosition);
13982 case XPATH_NODESET:
13983 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013984 if (res->nodesetval == NULL)
13985 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013986 return(res->nodesetval->nodeNr != 0);
13987 case XPATH_STRING:
13988 return((res->stringval != NULL) &&
13989 (xmlStrlen(res->stringval) != 0));
13990 default:
13991 STRANGE
13992 }
13993 return(0);
13994}
13995
13996/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013997 * xmlXPathEvaluatePredicateResult:
13998 * @ctxt: the XPath Parser context
13999 * @res: the Predicate Expression evaluation result
14000 *
14001 * Evaluate a predicate result for the current node.
14002 * A PredicateExpr is evaluated by evaluating the Expr and converting
14003 * the result to a boolean. If the result is a number, the result will
14004 * be converted to true if the number is equal to the position of the
14005 * context node in the context node list (as returned by the position
14006 * function) and will be converted to false otherwise; if the result
14007 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014008 * to the boolean function.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014009 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014010 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014011 */
14012int
Daniel Veillard45490ae2008-07-29 09:13:19 +000014013xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014014 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014015 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014016 switch (res->type) {
14017 case XPATH_BOOLEAN:
14018 return(res->boolval);
14019 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014020#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014021 return((res->floatval == ctxt->context->proximityPosition) &&
14022 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014023#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014024 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014025#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014026 case XPATH_NODESET:
14027 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014028 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014029 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014030 return(res->nodesetval->nodeNr != 0);
14031 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014032 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014033#ifdef LIBXML_XPTR_ENABLED
14034 case XPATH_LOCATIONSET:{
14035 xmlLocationSetPtr ptr = res->user;
14036 if (ptr == NULL)
14037 return(0);
14038 return (ptr->locNr != 0);
14039 }
14040#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014041 default:
14042 STRANGE
14043 }
14044 return(0);
14045}
14046
Daniel Veillard56de87e2005-02-16 00:22:29 +000014047#ifdef XPATH_STREAMING
14048/**
14049 * xmlXPathTryStreamCompile:
14050 * @ctxt: an XPath context
14051 * @str: the XPath expression
14052 *
14053 * Try to compile the XPath expression as a streamable subset.
14054 *
14055 * Returns the compiled expression or NULL if failed to compile.
14056 */
14057static xmlXPathCompExprPtr
14058xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14059 /*
14060 * Optimization: use streaming patterns when the XPath expression can
14061 * be compiled to a stream lookup
14062 */
14063 xmlPatternPtr stream;
14064 xmlXPathCompExprPtr comp;
14065 xmlDictPtr dict = NULL;
14066 const xmlChar **namespaces = NULL;
14067 xmlNsPtr ns;
14068 int i, j;
14069
14070 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14071 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014072 const xmlChar *tmp;
14073
14074 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014075 * We don't try to handle expressions using the verbose axis
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014076 * specifiers ("::"), just the simplified form at this point.
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014077 * Additionally, if there is no list of namespaces available and
14078 * there's a ":" in the expression, indicating a prefixed QName,
14079 * then we won't try to compile either. xmlPatterncompile() needs
14080 * to have a list of namespaces at compilation time in order to
14081 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014082 */
14083 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014084 if ((tmp != NULL) &&
14085 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
Daniel Veillard45490ae2008-07-29 09:13:19 +000014086 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014087
Daniel Veillard56de87e2005-02-16 00:22:29 +000014088 if (ctxt != NULL) {
14089 dict = ctxt->dict;
14090 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014091 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014092 if (namespaces == NULL) {
14093 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14094 return(NULL);
14095 }
14096 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14097 ns = ctxt->namespaces[j];
14098 namespaces[i++] = ns->href;
14099 namespaces[i++] = ns->prefix;
14100 }
14101 namespaces[i++] = NULL;
Daniel Veillard13cee4e2009-09-05 14:52:55 +020014102 namespaces[i] = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014103 }
14104 }
14105
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014106 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014107 if (namespaces != NULL) {
14108 xmlFree((xmlChar **)namespaces);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014109 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014110 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14111 comp = xmlXPathNewCompExpr();
14112 if (comp == NULL) {
14113 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14114 return(NULL);
14115 }
14116 comp->stream = stream;
14117 comp->dict = dict;
14118 if (comp->dict)
14119 xmlDictReference(comp->dict);
14120 return(comp);
14121 }
14122 xmlFreePattern(stream);
14123 }
14124 return(NULL);
14125}
14126#endif /* XPATH_STREAMING */
14127
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014128static void
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014129xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14130 xmlXPathStepOpPtr op)
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014131{
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014132 xmlXPathCompExprPtr comp = pctxt->comp;
14133 xmlXPathContextPtr ctxt;
14134
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014135 /*
14136 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14137 * internal representation.
14138 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014139
Nick Wellnhoferb4bcba22013-08-05 00:15:11 +020014140 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14141 (op->ch1 != -1) &&
14142 (op->ch2 == -1 /* no predicate */))
Nick Wellnhofer62270532012-08-19 19:42:38 +020014143 {
14144 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14145
14146 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14147 ((xmlXPathAxisVal) prevop->value ==
14148 AXIS_DESCENDANT_OR_SELF) &&
14149 (prevop->ch2 == -1) &&
14150 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14151 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14152 {
14153 /*
14154 * This is a "descendant-or-self::node()" without predicates.
14155 * Try to eliminate it.
14156 */
14157
14158 switch ((xmlXPathAxisVal) op->value) {
14159 case AXIS_CHILD:
14160 case AXIS_DESCENDANT:
14161 /*
14162 * Convert "descendant-or-self::node()/child::" or
14163 * "descendant-or-self::node()/descendant::" to
14164 * "descendant::"
14165 */
14166 op->ch1 = prevop->ch1;
14167 op->value = AXIS_DESCENDANT;
14168 break;
14169 case AXIS_SELF:
14170 case AXIS_DESCENDANT_OR_SELF:
14171 /*
14172 * Convert "descendant-or-self::node()/self::" or
14173 * "descendant-or-self::node()/descendant-or-self::" to
14174 * to "descendant-or-self::"
14175 */
14176 op->ch1 = prevop->ch1;
14177 op->value = AXIS_DESCENDANT_OR_SELF;
14178 break;
14179 default:
14180 break;
14181 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014182 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014183 }
Nick Wellnhofer62270532012-08-19 19:42:38 +020014184
Nick Wellnhofer839689a2016-04-27 18:00:12 +020014185 /* OP_VALUE has invalid ch1. */
14186 if (op->op == XPATH_OP_VALUE)
14187 return;
14188
Nick Wellnhofer62270532012-08-19 19:42:38 +020014189 /* Recurse */
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014190 ctxt = pctxt->context;
14191 if (ctxt != NULL) {
14192 if (ctxt->depth >= ctxt->maxDepth)
14193 return;
14194 ctxt->depth += 1;
14195 }
Nick Wellnhofer62270532012-08-19 19:42:38 +020014196 if (op->ch1 != -1)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014197 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014198 if (op->ch2 != -1)
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014199 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14200 if (ctxt != NULL)
14201 ctxt->depth -= 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014202}
14203
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014204/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014205 * xmlXPathCtxtCompile:
14206 * @ctxt: an XPath context
14207 * @str: the XPath expression
14208 *
14209 * Compile an XPath expression
14210 *
14211 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14212 * the caller has to free the object.
14213 */
14214xmlXPathCompExprPtr
14215xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14216 xmlXPathParserContextPtr pctxt;
14217 xmlXPathCompExprPtr comp;
14218
Daniel Veillard56de87e2005-02-16 00:22:29 +000014219#ifdef XPATH_STREAMING
14220 comp = xmlXPathTryStreamCompile(ctxt, str);
14221 if (comp != NULL)
14222 return(comp);
14223#endif
14224
Daniel Veillard4773df22004-01-23 13:15:13 +000014225 xmlXPathInit();
14226
14227 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014228 if (pctxt == NULL)
14229 return NULL;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014230 if (ctxt != NULL)
14231 ctxt->depth = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014232 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014233
14234 if( pctxt->error != XPATH_EXPRESSION_OK )
14235 {
14236 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014237 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014238 }
14239
14240 if (*pctxt->cur != 0) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014241 /*
Daniel Veillard4773df22004-01-23 13:15:13 +000014242 * aleksey: in some cases this line prints *second* error message
14243 * (see bug #78858) and probably this should be fixed.
14244 * However, we are not sure that all error messages are printed
14245 * out in other places. It's not critical so we leave it as-is for now
14246 */
14247 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14248 comp = NULL;
14249 } else {
14250 comp = pctxt->comp;
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014251 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14252 if (ctxt != NULL)
14253 ctxt->depth = 0;
14254 xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14255 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014256 pctxt->comp = NULL;
14257 }
14258 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014259
Daniel Veillard4773df22004-01-23 13:15:13 +000014260 if (comp != NULL) {
14261 comp->expr = xmlStrdup(str);
14262#ifdef DEBUG_EVAL_COUNTS
14263 comp->string = xmlStrdup(str);
14264 comp->nb = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014265#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014266 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014267 return(comp);
14268}
14269
14270/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014271 * xmlXPathCompile:
14272 * @str: the XPath expression
14273 *
14274 * Compile an XPath expression
14275 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014276 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014277 * the caller has to free the object.
14278 */
14279xmlXPathCompExprPtr
14280xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014281 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014282}
14283
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014284/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014285 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014286 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014287 * @ctxt: the XPath context
14288 * @resObj: the resulting XPath object or NULL
14289 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014290 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014291 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014292 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014293 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014294 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014295 * the caller has to free the object.
14296 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014297static int
14298xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14299 xmlXPathContextPtr ctxt,
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014300 xmlXPathObjectPtr *resObjPtr,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014301 int toBool)
14302{
Daniel Veillard45490ae2008-07-29 09:13:19 +000014303 xmlXPathParserContextPtr pctxt;
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014304 xmlXPathObjectPtr resObj;
Daniel Veillard81463942001-10-16 12:34:39 +000014305#ifndef LIBXML_THREAD_ENABLED
14306 static int reentance = 0;
14307#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014308 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014309
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014310 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014311
14312 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014313 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014314 xmlXPathInit();
14315
Daniel Veillard81463942001-10-16 12:34:39 +000014316#ifndef LIBXML_THREAD_ENABLED
14317 reentance++;
14318 if (reentance > 1)
14319 xmlXPathDisableOptimizer = 1;
14320#endif
14321
Daniel Veillardf06307e2001-07-03 10:35:50 +000014322#ifdef DEBUG_EVAL_COUNTS
14323 comp->nb++;
14324 if ((comp->string != NULL) && (comp->nb > 100)) {
14325 fprintf(stderr, "100 x %s\n", comp->string);
14326 comp->nb = 0;
14327 }
14328#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014329 pctxt = xmlXPathCompParserContext(comp, ctxt);
14330 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014331
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014332 if (pctxt->error != XPATH_EXPRESSION_OK) {
14333 resObj = NULL;
14334 } else {
14335 resObj = valuePop(pctxt);
14336 if (resObj == NULL) {
Nick Wellnhofera07a4e92017-05-27 17:04:12 +020014337 if (!toBool)
14338 xmlGenericError(xmlGenericErrorContext,
14339 "xmlXPathCompiledEval: No result on the stack.\n");
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014340 } else if (pctxt->valueNr > 0) {
14341 xmlGenericError(xmlGenericErrorContext,
14342 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14343 pctxt->valueNr);
14344 }
Owen Taylor3473f882001-02-23 17:55:21 +000014345 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014346
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014347 if (resObjPtr)
14348 *resObjPtr = resObj;
14349 else
14350 xmlXPathReleaseObject(ctxt, resObj);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014351
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014352 pctxt->comp = NULL;
14353 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014354#ifndef LIBXML_THREAD_ENABLED
14355 reentance--;
14356#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014357
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014358 return(res);
14359}
14360
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014361/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014362 * xmlXPathCompiledEval:
14363 * @comp: the compiled XPath expression
14364 * @ctx: the XPath context
14365 *
14366 * Evaluate the Precompiled XPath expression in the given context.
14367 *
14368 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14369 * the caller has to free the object.
14370 */
14371xmlXPathObjectPtr
14372xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14373{
14374 xmlXPathObjectPtr res = NULL;
14375
14376 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14377 return(res);
14378}
14379
14380/**
14381 * xmlXPathCompiledEvalToBoolean:
14382 * @comp: the compiled XPath expression
14383 * @ctxt: the XPath context
14384 *
14385 * Applies the XPath boolean() function on the result of the given
14386 * compiled expression.
14387 *
14388 * Returns 1 if the expression evaluated to true, 0 if to false and
14389 * -1 in API and internal errors.
14390 */
14391int
14392xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14393 xmlXPathContextPtr ctxt)
14394{
14395 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14396}
14397
14398/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014399 * xmlXPathEvalExpr:
14400 * @ctxt: the XPath Parser context
14401 *
14402 * Parse and evaluate an XPath expression in the given context,
14403 * then push the result on the context stack
14404 */
14405void
14406xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014407#ifdef XPATH_STREAMING
14408 xmlXPathCompExprPtr comp;
14409#endif
14410
Daniel Veillarda82b1822004-11-08 16:24:57 +000014411 if (ctxt == NULL) return;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014412
Daniel Veillard56de87e2005-02-16 00:22:29 +000014413#ifdef XPATH_STREAMING
14414 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14415 if (comp != NULL) {
14416 if (ctxt->comp != NULL)
14417 xmlXPathFreeCompExpr(ctxt->comp);
14418 ctxt->comp = comp;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014419 } else
14420#endif
14421 {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014422 if (ctxt->context != NULL)
14423 ctxt->context->depth = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014424 xmlXPathCompileExpr(ctxt, 1);
Nick Wellnhoferaed407c2017-05-25 16:57:14 +020014425 CHECK_ERROR;
14426
14427 /* Check for trailing characters. */
14428 if (*ctxt->cur != 0)
14429 XP_ERROR(XPATH_EXPR_ERROR);
14430
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014431 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14432 if (ctxt->context != NULL)
14433 ctxt->context->depth = 0;
14434 xmlXPathOptimizeExpression(ctxt,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014435 &ctxt->comp->steps[ctxt->comp->last]);
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014436 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014437 }
Nick Wellnhoferaed407c2017-05-25 16:57:14 +020014438
Daniel Veillard45490ae2008-07-29 09:13:19 +000014439 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014440}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014441
14442/**
14443 * xmlXPathEval:
14444 * @str: the XPath expression
14445 * @ctx: the XPath context
14446 *
14447 * Evaluate the XPath Location Path in the given context.
14448 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014449 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014450 * the caller has to free the object.
14451 */
14452xmlXPathObjectPtr
14453xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14454 xmlXPathParserContextPtr ctxt;
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014455 xmlXPathObjectPtr res;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014456
William M. Brackf13f77f2004-11-12 16:03:48 +000014457 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014458
William M. Brackf13f77f2004-11-12 16:03:48 +000014459 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014460
14461 ctxt = xmlXPathNewParserContext(str, ctx);
William M. Brack11be2d02007-01-24 19:17:19 +000014462 if (ctxt == NULL)
14463 return NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014464 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014465
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014466 if (ctxt->error != XPATH_EXPRESSION_OK) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014467 res = NULL;
14468 } else {
14469 res = valuePop(ctxt);
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014470 if (res == NULL) {
14471 xmlGenericError(xmlGenericErrorContext,
14472 "xmlXPathCompiledEval: No result on the stack.\n");
14473 } else if (ctxt->valueNr > 0) {
14474 xmlGenericError(xmlGenericErrorContext,
14475 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14476 ctxt->valueNr);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014477 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014478 }
14479
Owen Taylor3473f882001-02-23 17:55:21 +000014480 xmlXPathFreeParserContext(ctxt);
14481 return(res);
14482}
14483
14484/**
Alex Bligh28876af2013-03-23 17:23:27 +000014485 * xmlXPathSetContextNode:
14486 * @node: the node to to use as the context node
14487 * @ctx: the XPath context
14488 *
14489 * Sets 'node' as the context node. The node must be in the same
14490 * document as that associated with the context.
14491 *
14492 * Returns -1 in case of error or 0 if successful
14493 */
14494int
14495xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14496 if ((node == NULL) || (ctx == NULL))
14497 return(-1);
14498
14499 if (node->doc == ctx->doc) {
14500 ctx->node = node;
14501 return(0);
14502 }
14503 return(-1);
14504}
14505
14506/**
14507 * xmlXPathNodeEval:
14508 * @node: the node to to use as the context node
14509 * @str: the XPath expression
14510 * @ctx: the XPath context
14511 *
14512 * Evaluate the XPath Location Path in the given context. The node 'node'
14513 * is set as the context node. The context node is not restored.
14514 *
14515 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14516 * the caller has to free the object.
14517 */
14518xmlXPathObjectPtr
14519xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14520 if (str == NULL)
14521 return(NULL);
14522 if (xmlXPathSetContextNode(node, ctx) < 0)
14523 return(NULL);
14524 return(xmlXPathEval(str, ctx));
14525}
14526
14527/**
Owen Taylor3473f882001-02-23 17:55:21 +000014528 * xmlXPathEvalExpression:
14529 * @str: the XPath expression
14530 * @ctxt: the XPath context
14531 *
Daniel Veillarddbb828f2017-08-28 20:38:53 +020014532 * Alias for xmlXPathEval().
Owen Taylor3473f882001-02-23 17:55:21 +000014533 *
14534 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14535 * the caller has to free the object.
14536 */
14537xmlXPathObjectPtr
14538xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
Nick Wellnhofer640a3682017-05-27 14:59:49 +020014539 return(xmlXPathEval(str, ctxt));
Owen Taylor3473f882001-02-23 17:55:21 +000014540}
14541
Daniel Veillard42766c02002-08-22 20:52:17 +000014542/************************************************************************
14543 * *
14544 * Extra functions not pertaining to the XPath spec *
14545 * *
14546 ************************************************************************/
14547/**
14548 * xmlXPathEscapeUriFunction:
14549 * @ctxt: the XPath Parser context
14550 * @nargs: the number of arguments
14551 *
14552 * Implement the escape-uri() XPath function
14553 * string escape-uri(string $str, bool $escape-reserved)
14554 *
14555 * This function applies the URI escaping rules defined in section 2 of [RFC
14556 * 2396] to the string supplied as $uri-part, which typically represents all
14557 * or part of a URI. The effect of the function is to replace any special
14558 * character in the string by an escape sequence of the form %xx%yy...,
14559 * where xxyy... is the hexadecimal representation of the octets used to
14560 * represent the character in UTF-8.
14561 *
14562 * The set of characters that are escaped depends on the setting of the
14563 * boolean argument $escape-reserved.
14564 *
14565 * If $escape-reserved is true, all characters are escaped other than lower
14566 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14567 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14568 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14569 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14570 * A-F).
14571 *
14572 * If $escape-reserved is false, the behavior differs in that characters
14573 * referred to in [RFC 2396] as reserved characters are not escaped. These
14574 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
Daniel Veillard45490ae2008-07-29 09:13:19 +000014575 *
Daniel Veillard42766c02002-08-22 20:52:17 +000014576 * [RFC 2396] does not define whether escaped URIs should use lower case or
14577 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14578 * compared using string comparison functions, this function must always use
14579 * the upper-case letters A-F.
Daniel Veillard45490ae2008-07-29 09:13:19 +000014580 *
Daniel Veillard42766c02002-08-22 20:52:17 +000014581 * Generally, $escape-reserved should be set to true when escaping a string
14582 * that is to form a single part of a URI, and to false when escaping an
14583 * entire URI or URI reference.
Daniel Veillard45490ae2008-07-29 09:13:19 +000014584 *
14585 * In the case of non-ascii characters, the string is encoded according to
Daniel Veillard42766c02002-08-22 20:52:17 +000014586 * utf-8 and then converted according to RFC 2396.
14587 *
14588 * Examples
Daniel Veillard45490ae2008-07-29 09:13:19 +000014589 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
Daniel Veillard42766c02002-08-22 20:52:17 +000014590 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14591 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14592 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14593 *
14594 */
Daniel Veillard118aed72002-09-24 14:13:13 +000014595static void
Daniel Veillard42766c02002-08-22 20:52:17 +000014596xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14597 xmlXPathObjectPtr str;
14598 int escape_reserved;
Daniel Veillardade10f22012-07-12 09:43:27 +080014599 xmlBufPtr target;
Daniel Veillard42766c02002-08-22 20:52:17 +000014600 xmlChar *cptr;
14601 xmlChar escape[4];
Daniel Veillard45490ae2008-07-29 09:13:19 +000014602
Daniel Veillard42766c02002-08-22 20:52:17 +000014603 CHECK_ARITY(2);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014604
Daniel Veillard42766c02002-08-22 20:52:17 +000014605 escape_reserved = xmlXPathPopBoolean(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014606
Daniel Veillard42766c02002-08-22 20:52:17 +000014607 CAST_TO_STRING;
14608 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014609
Daniel Veillardade10f22012-07-12 09:43:27 +080014610 target = xmlBufCreate();
Daniel Veillard45490ae2008-07-29 09:13:19 +000014611
Daniel Veillard42766c02002-08-22 20:52:17 +000014612 escape[0] = '%';
14613 escape[3] = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014614
Daniel Veillard42766c02002-08-22 20:52:17 +000014615 if (target) {
14616 for (cptr = str->stringval; *cptr; cptr++) {
14617 if ((*cptr >= 'A' && *cptr <= 'Z') ||
14618 (*cptr >= 'a' && *cptr <= 'z') ||
14619 (*cptr >= '0' && *cptr <= '9') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000014620 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
Daniel Veillard42766c02002-08-22 20:52:17 +000014621 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14622 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000014623 (*cptr == '%' &&
Daniel Veillard42766c02002-08-22 20:52:17 +000014624 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14625 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14626 (cptr[1] >= '0' && cptr[1] <= '9')) &&
14627 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14628 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14629 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14630 (!escape_reserved &&
14631 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14632 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14633 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14634 *cptr == ','))) {
Daniel Veillardade10f22012-07-12 09:43:27 +080014635 xmlBufAdd(target, cptr, 1);
Daniel Veillard42766c02002-08-22 20:52:17 +000014636 } else {
14637 if ((*cptr >> 4) < 10)
14638 escape[1] = '0' + (*cptr >> 4);
14639 else
14640 escape[1] = 'A' - 10 + (*cptr >> 4);
14641 if ((*cptr & 0xF) < 10)
14642 escape[2] = '0' + (*cptr & 0xF);
14643 else
14644 escape[2] = 'A' - 10 + (*cptr & 0xF);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014645
Daniel Veillardade10f22012-07-12 09:43:27 +080014646 xmlBufAdd(target, &escape[0], 3);
Daniel Veillard42766c02002-08-22 20:52:17 +000014647 }
14648 }
14649 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014650 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +080014651 xmlBufContent(target)));
14652 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014653 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000014654}
14655
Owen Taylor3473f882001-02-23 17:55:21 +000014656/**
14657 * xmlXPathRegisterAllFunctions:
14658 * @ctxt: the XPath context
14659 *
14660 * Registers all default XPath functions in this context
14661 */
14662void
14663xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14664{
14665 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14666 xmlXPathBooleanFunction);
14667 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14668 xmlXPathCeilingFunction);
14669 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14670 xmlXPathCountFunction);
14671 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14672 xmlXPathConcatFunction);
14673 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14674 xmlXPathContainsFunction);
14675 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14676 xmlXPathIdFunction);
14677 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14678 xmlXPathFalseFunction);
14679 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14680 xmlXPathFloorFunction);
14681 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14682 xmlXPathLastFunction);
14683 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14684 xmlXPathLangFunction);
14685 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14686 xmlXPathLocalNameFunction);
14687 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14688 xmlXPathNotFunction);
14689 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14690 xmlXPathNameFunction);
14691 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14692 xmlXPathNamespaceURIFunction);
14693 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14694 xmlXPathNormalizeFunction);
14695 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14696 xmlXPathNumberFunction);
14697 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14698 xmlXPathPositionFunction);
14699 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14700 xmlXPathRoundFunction);
14701 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14702 xmlXPathStringFunction);
14703 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14704 xmlXPathStringLengthFunction);
14705 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14706 xmlXPathStartsWithFunction);
14707 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14708 xmlXPathSubstringFunction);
14709 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14710 xmlXPathSubstringBeforeFunction);
14711 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14712 xmlXPathSubstringAfterFunction);
14713 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14714 xmlXPathSumFunction);
14715 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14716 xmlXPathTrueFunction);
14717 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14718 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000014719
14720 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14721 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14722 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000014723}
14724
14725#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000014726#define bottom_xpath
14727#include "elfgcchack.h"