1 /* libxml2 - Library for parsing XML documents
2  * Copyright (C) 2006-2019 Free Software Foundation, Inc.
3  *
4  * This file is not part of the GNU gettext program, but is used with
5  * GNU gettext.
6  *
7  * The original copyright notice is as follows:
8  */
9 
10 /*
11  * Copyright (C) 1998-2012 Daniel Veillard.  All Rights Reserved.
12  *
13  * Permission is hereby granted, free of charge, to any person obtaining a copy
14  * of this software and associated documentation files (the "Software"), to deal
15  * in the Software without restriction, including without limitation the rights
16  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17  * copies of the Software, and to permit persons to whom the Software is fur-
18  * nished to do so, subject to the following conditions:
19  *
20  * The above copyright notice and this permission notice shall be included in
21  * all copies or substantial portions of the Software.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
25  * NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
26  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29  * THE SOFTWARE.
30  *
31  * Author: daniel@veillard.com
32  */
33 
34 /*
35  * xpath.c: XML Path Language implementation
36  *          XPath is a language for addressing parts of an XML document,
37  *          designed to be used by both XSLT and XPointer
38  *
39  * Reference: W3C Recommendation 16 November 1999
40  *     http://www.w3.org/TR/1999/REC-xpath-19991116
41  * Public reference:
42  *     http://www.w3.org/TR/xpath
43  */
44 
45 /* To avoid EBCDIC trouble when parsing on zOS */
46 #if defined(__MVS__)
47 #pragma convert("ISO8859-1")
48 #endif
49 
50 #define IN_LIBXML
51 #include "libxml.h"
52 
53 #include <limits.h>
54 #include <string.h>
55 #include <stddef.h>
56 
57 #ifdef HAVE_SYS_TYPES_H
58 #include <sys/types.h>
59 #endif
60 #ifdef HAVE_MATH_H
61 #include <math.h>
62 #endif
63 #ifdef HAVE_FLOAT_H
64 #include <float.h>
65 #endif
66 #ifdef HAVE_CTYPE_H
67 #include <ctype.h>
68 #endif
69 #ifdef HAVE_SIGNAL_H
70 #include <signal.h>
71 #endif
72 
73 #include <libxml/xmlmemory.h>
74 #include <libxml/tree.h>
75 #include <libxml/valid.h>
76 #include <libxml/xpath.h>
77 #include <libxml/xpathInternals.h>
78 #include <libxml/parserInternals.h>
79 #include <libxml/hash.h>
80 #ifdef LIBXML_XPTR_ENABLED
81 #include <libxml/xpointer.h>
82 #endif
83 #ifdef LIBXML_DEBUG_ENABLED
84 #include <libxml/debugXML.h>
85 #endif
86 #include <libxml/xmlerror.h>
87 #include <libxml/threads.h>
88 #include <libxml/globals.h>
89 #ifdef LIBXML_PATTERN_ENABLED
90 #include <libxml/pattern.h>
91 #endif
92 
93 #include "buf.h"
94 
95 #ifdef LIBXML_PATTERN_ENABLED
96 #define XPATH_STREAMING
97 #endif
98 
99 #define TODO								\
100     xmlGenericError(xmlGenericErrorContext,				\
101 	    "Unimplemented block at %s:%d\n",				\
102             __FILE__, __LINE__);
103 
104 /**
105  * WITH_TIM_SORT:
106  *
107  * Use the Timsort algorithm provided in timsort.h to sort
108  * nodeset as this is a great improvement over the old Shell sort
109  * used in xmlXPathNodeSetSort()
110  */
111 #define WITH_TIM_SORT
112 
113 /*
114 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
115 * If defined, this will use xmlXPathCmpNodesExt() instead of
116 * xmlXPathCmpNodes(). The new function is optimized comparison of
117 * non-element nodes; actually it will speed up comparison only if
118 * xmlXPathOrderDocElems() was called in order to index the elements of
119 * a tree in document order; Libxslt does such an indexing, thus it will
120 * benefit from this optimization.
121 */
122 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
123 
124 /*
125 * XP_OPTIMIZED_FILTER_FIRST:
126 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
127 * in a way, that it stop evaluation at the first node.
128 */
129 #define XP_OPTIMIZED_FILTER_FIRST
130 
131 /*
132 * XP_DEBUG_OBJ_USAGE:
133 * Internal flag to enable tracking of how much XPath objects have been
134 * created.
135 */
136 /* #define XP_DEBUG_OBJ_USAGE */
137 
138 /*
139  * XPATH_MAX_STEPS:
140  * when compiling an XPath expression we arbitrary limit the maximum
141  * number of step operation in the compiled expression. 1000000 is
142  * an insanely large value which should never be reached under normal
143  * circumstances
144  */
145 #define XPATH_MAX_STEPS 1000000
146 
147 /*
148  * XPATH_MAX_STACK_DEPTH:
149  * when evaluating an XPath expression we arbitrary limit the maximum
150  * number of object allowed to be pushed on the stack. 1000000 is
151  * an insanely large value which should never be reached under normal
152  * circumstances
153  */
154 #define XPATH_MAX_STACK_DEPTH 1000000
155 
156 /*
157  * XPATH_MAX_NODESET_LENGTH:
158  * when evaluating an XPath expression nodesets are created and we
159  * arbitrary limit the maximum length of those node set. 10000000 is
160  * an insanely large value which should never be reached under normal
161  * circumstances, one would first need to construct an in memory tree
162  * with more than 10 millions nodes.
163  */
164 #define XPATH_MAX_NODESET_LENGTH 10000000
165 
166 /*
167  * TODO:
168  * There are a few spots where some tests are done which depend upon ascii
169  * data.  These should be enhanced for full UTF8 support (see particularly
170  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
171  */
172 
173 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
174 /**
175  * xmlXPathCmpNodesExt:
176  * @node1:  the first node
177  * @node2:  the second node
178  *
179  * Compare two nodes w.r.t document order.
180  * This one is optimized for handling of non-element nodes.
181  *
182  * Returns -2 in case of error 1 if first point < second point, 0 if
183  *         it's the same node, -1 otherwise
184  */
185 static int
xmlXPathCmpNodesExt(xmlNodePtr node1,xmlNodePtr node2)186 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
187     int depth1, depth2;
188     int misc = 0, precedence1 = 0, precedence2 = 0;
189     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
190     xmlNodePtr cur, root;
191     ptrdiff_t l1, l2;
192 
193     if ((node1 == NULL) || (node2 == NULL))
194 	return(-2);
195 
196     if (node1 == node2)
197 	return(0);
198 
199     /*
200      * a couple of optimizations which will avoid computations in most cases
201      */
202     switch (node1->type) {
203 	case XML_ELEMENT_NODE:
204 	    if (node2->type == XML_ELEMENT_NODE) {
205 		if ((0 > (ptrdiff_t) node1->content) &&
206 		    (0 > (ptrdiff_t) node2->content) &&
207 		    (node1->doc == node2->doc))
208 		{
209 		    l1 = -((ptrdiff_t) node1->content);
210 		    l2 = -((ptrdiff_t) node2->content);
211 		    if (l1 < l2)
212 			return(1);
213 		    if (l1 > l2)
214 			return(-1);
215 		} else
216 		    goto turtle_comparison;
217 	    }
218 	    break;
219 	case XML_ATTRIBUTE_NODE:
220 	    precedence1 = 1; /* element is owner */
221 	    miscNode1 = node1;
222 	    node1 = node1->parent;
223 	    misc = 1;
224 	    break;
225 	case XML_TEXT_NODE:
226 	case XML_CDATA_SECTION_NODE:
227 	case XML_COMMENT_NODE:
228 	case XML_PI_NODE: {
229 	    miscNode1 = node1;
230 	    /*
231 	    * Find nearest element node.
232 	    */
233 	    if (node1->prev != NULL) {
234 		do {
235 		    node1 = node1->prev;
236 		    if (node1->type == XML_ELEMENT_NODE) {
237 			precedence1 = 3; /* element in prev-sibl axis */
238 			break;
239 		    }
240 		    if (node1->prev == NULL) {
241 			precedence1 = 2; /* element is parent */
242 			/*
243 			* URGENT TODO: Are there any cases, where the
244 			* parent of such a node is not an element node?
245 			*/
246 			node1 = node1->parent;
247 			break;
248 		    }
249 		} while (1);
250 	    } else {
251 		precedence1 = 2; /* element is parent */
252 		node1 = node1->parent;
253 	    }
254 	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
255 		(0 <= (ptrdiff_t) node1->content)) {
256 		/*
257 		* Fallback for whatever case.
258 		*/
259 		node1 = miscNode1;
260 		precedence1 = 0;
261 	    } else
262 		misc = 1;
263 	}
264 	    break;
265 	case XML_NAMESPACE_DECL:
266 	    /*
267 	    * TODO: why do we return 1 for namespace nodes?
268 	    */
269 	    return(1);
270 	default:
271 	    break;
272     }
273     switch (node2->type) {
274 	case XML_ELEMENT_NODE:
275 	    break;
276 	case XML_ATTRIBUTE_NODE:
277 	    precedence2 = 1; /* element is owner */
278 	    miscNode2 = node2;
279 	    node2 = node2->parent;
280 	    misc = 1;
281 	    break;
282 	case XML_TEXT_NODE:
283 	case XML_CDATA_SECTION_NODE:
284 	case XML_COMMENT_NODE:
285 	case XML_PI_NODE: {
286 	    miscNode2 = node2;
287 	    if (node2->prev != NULL) {
288 		do {
289 		    node2 = node2->prev;
290 		    if (node2->type == XML_ELEMENT_NODE) {
291 			precedence2 = 3; /* element in prev-sibl axis */
292 			break;
293 		    }
294 		    if (node2->prev == NULL) {
295 			precedence2 = 2; /* element is parent */
296 			node2 = node2->parent;
297 			break;
298 		    }
299 		} while (1);
300 	    } else {
301 		precedence2 = 2; /* element is parent */
302 		node2 = node2->parent;
303 	    }
304 	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
305 		(0 <= (ptrdiff_t) node2->content))
306 	    {
307 		node2 = miscNode2;
308 		precedence2 = 0;
309 	    } else
310 		misc = 1;
311 	}
312 	    break;
313 	case XML_NAMESPACE_DECL:
314 	    return(1);
315 	default:
316 	    break;
317     }
318     if (misc) {
319 	if (node1 == node2) {
320 	    if (precedence1 == precedence2) {
321 		/*
322 		* The ugly case; but normally there aren't many
323 		* adjacent non-element nodes around.
324 		*/
325 		cur = miscNode2->prev;
326 		while (cur != NULL) {
327 		    if (cur == miscNode1)
328 			return(1);
329 		    if (cur->type == XML_ELEMENT_NODE)
330 			return(-1);
331 		    cur = cur->prev;
332 		}
333 		return (-1);
334 	    } else {
335 		/*
336 		* Evaluate based on higher precedence wrt to the element.
337 		* TODO: This assumes attributes are sorted before content.
338 		*   Is this 100% correct?
339 		*/
340 		if (precedence1 < precedence2)
341 		    return(1);
342 		else
343 		    return(-1);
344 	    }
345 	}
346 	/*
347 	* Special case: One of the helper-elements is contained by the other.
348 	* <foo>
349 	*   <node2>
350 	*     <node1>Text-1(precedence1 == 2)</node1>
351 	*   </node2>
352 	*   Text-6(precedence2 == 3)
353 	* </foo>
354 	*/
355 	if ((precedence2 == 3) && (precedence1 > 1)) {
356 	    cur = node1->parent;
357 	    while (cur) {
358 		if (cur == node2)
359 		    return(1);
360 		cur = cur->parent;
361 	    }
362 	}
363 	if ((precedence1 == 3) && (precedence2 > 1)) {
364 	    cur = node2->parent;
365 	    while (cur) {
366 		if (cur == node1)
367 		    return(-1);
368 		cur = cur->parent;
369 	    }
370 	}
371     }
372 
373     /*
374      * Speedup using document order if availble.
375      */
376     if ((node1->type == XML_ELEMENT_NODE) &&
377 	(node2->type == XML_ELEMENT_NODE) &&
378 	(0 > (ptrdiff_t) node1->content) &&
379 	(0 > (ptrdiff_t) node2->content) &&
380 	(node1->doc == node2->doc)) {
381 
382 	l1 = -((ptrdiff_t) node1->content);
383 	l2 = -((ptrdiff_t) node2->content);
384 	if (l1 < l2)
385 	    return(1);
386 	if (l1 > l2)
387 	    return(-1);
388     }
389 
390 turtle_comparison:
391 
392     if (node1 == node2->prev)
393 	return(1);
394     if (node1 == node2->next)
395 	return(-1);
396     /*
397      * compute depth to root
398      */
399     for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
400 	if (cur->parent == node1)
401 	    return(1);
402 	depth2++;
403     }
404     root = cur;
405     for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
406 	if (cur->parent == node2)
407 	    return(-1);
408 	depth1++;
409     }
410     /*
411      * Distinct document (or distinct entities :-( ) case.
412      */
413     if (root != cur) {
414 	return(-2);
415     }
416     /*
417      * get the nearest common ancestor.
418      */
419     while (depth1 > depth2) {
420 	depth1--;
421 	node1 = node1->parent;
422     }
423     while (depth2 > depth1) {
424 	depth2--;
425 	node2 = node2->parent;
426     }
427     while (node1->parent != node2->parent) {
428 	node1 = node1->parent;
429 	node2 = node2->parent;
430 	/* should not happen but just in case ... */
431 	if ((node1 == NULL) || (node2 == NULL))
432 	    return(-2);
433     }
434     /*
435      * Find who's first.
436      */
437     if (node1 == node2->prev)
438 	return(1);
439     if (node1 == node2->next)
440 	return(-1);
441     /*
442      * Speedup using document order if availble.
443      */
444     if ((node1->type == XML_ELEMENT_NODE) &&
445 	(node2->type == XML_ELEMENT_NODE) &&
446 	(0 > (ptrdiff_t) node1->content) &&
447 	(0 > (ptrdiff_t) node2->content) &&
448 	(node1->doc == node2->doc)) {
449 
450 	l1 = -((ptrdiff_t) node1->content);
451 	l2 = -((ptrdiff_t) node2->content);
452 	if (l1 < l2)
453 	    return(1);
454 	if (l1 > l2)
455 	    return(-1);
456     }
457 
458     for (cur = node1->next;cur != NULL;cur = cur->next)
459 	if (cur == node2)
460 	    return(1);
461     return(-1); /* assume there is no sibling list corruption */
462 }
463 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
464 
465 /*
466  * Wrapper for the Timsort argorithm from timsort.h
467  */
468 #ifdef WITH_TIM_SORT
469 #define SORT_NAME libxml_domnode
470 #define SORT_TYPE xmlNodePtr
471 /**
472  * wrap_cmp:
473  * @x: a node
474  * @y: another node
475  *
476  * Comparison function for the Timsort implementation
477  *
478  * Returns -2 in case of error -1 if first point < second point, 0 if
479  *         it's the same node, +1 otherwise
480  */
481 static
482 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
483 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
wrap_cmp(xmlNodePtr x,xmlNodePtr y)484     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
485     {
486         int res = xmlXPathCmpNodesExt(x, y);
487         return res == -2 ? res : -res;
488     }
489 #else
wrap_cmp(xmlNodePtr x,xmlNodePtr y)490     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
491     {
492         int res = xmlXPathCmpNodes(x, y);
493         return res == -2 ? res : -res;
494     }
495 #endif
496 #define SORT_CMP(x, y)  (wrap_cmp(x, y))
497 #include "timsort.h"
498 #endif /* WITH_TIM_SORT */
499 
500 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
501 
502 /************************************************************************
503  *									*
504  *			Floating point stuff				*
505  *									*
506  ************************************************************************/
507 
508 #ifndef INFINITY
509 #define INFINITY (DBL_MAX * DBL_MAX)
510 #endif
511 
512 #ifndef NAN
513 #define NAN (INFINITY / INFINITY)
514 #endif
515 
516 double xmlXPathNAN;
517 double xmlXPathPINF;
518 double xmlXPathNINF;
519 
520 /**
521  * xmlXPathInit:
522  *
523  * Initialize the XPath environment
524  */
525 void
xmlXPathInit(void)526 xmlXPathInit(void) {
527     xmlXPathNAN = NAN;
528     xmlXPathPINF = INFINITY;
529     xmlXPathNINF = -INFINITY;
530 }
531 
532 /**
533  * xmlXPathIsNaN:
534  * @val:  a double value
535  *
536  * Returns 1 if the value is a NaN, 0 otherwise
537  */
538 int
xmlXPathIsNaN(double val)539 xmlXPathIsNaN(double val) {
540 #ifdef isnan
541     return isnan(val);
542 #else
543     return !(val == val);
544 #endif
545 }
546 
547 /**
548  * xmlXPathIsInf:
549  * @val:  a double value
550  *
551  * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
552  */
553 int
xmlXPathIsInf(double val)554 xmlXPathIsInf(double val) {
555 #ifdef isinf
556     return isinf(val) ? (val > 0 ? 1 : -1) : 0;
557 #else
558     if (val >= INFINITY)
559         return 1;
560     if (val <= -INFINITY)
561         return -1;
562     return 0;
563 #endif
564 }
565 
566 #endif /* SCHEMAS or XPATH */
567 
568 #ifdef LIBXML_XPATH_ENABLED
569 
570 /*
571  * TODO: when compatibility allows remove all "fake node libxslt" strings
572  *       the test should just be name[0] = ' '
573  */
574 #ifdef DEBUG_XPATH_EXPRESSION
575 #define DEBUG_STEP
576 #define DEBUG_EXPR
577 #define DEBUG_EVAL_COUNTS
578 #endif
579 
580 static xmlNs xmlXPathXMLNamespaceStruct = {
581     NULL,
582     XML_NAMESPACE_DECL,
583     XML_XML_NAMESPACE,
584     BAD_CAST "xml",
585     NULL,
586     NULL
587 };
588 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
589 #ifndef LIBXML_THREAD_ENABLED
590 /*
591  * Optimizer is disabled only when threaded apps are detected while
592  * the library ain't compiled for thread safety.
593  */
594 static int xmlXPathDisableOptimizer = 0;
595 #endif
596 
597 /************************************************************************
598  *									*
599  *			Error handling routines				*
600  *									*
601  ************************************************************************/
602 
603 /**
604  * XP_ERRORNULL:
605  * @X:  the error code
606  *
607  * Macro to raise an XPath error and return NULL.
608  */
609 #define XP_ERRORNULL(X)							\
610     { xmlXPathErr(ctxt, X); return(NULL); }
611 
612 /*
613  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
614  */
615 static const char *xmlXPathErrorMessages[] = {
616     "Ok\n",
617     "Number encoding\n",
618     "Unfinished literal\n",
619     "Start of literal\n",
620     "Expected $ for variable reference\n",
621     "Undefined variable\n",
622     "Invalid predicate\n",
623     "Invalid expression\n",
624     "Missing closing curly brace\n",
625     "Unregistered function\n",
626     "Invalid operand\n",
627     "Invalid type\n",
628     "Invalid number of arguments\n",
629     "Invalid context size\n",
630     "Invalid context position\n",
631     "Memory allocation error\n",
632     "Syntax error\n",
633     "Resource error\n",
634     "Sub resource error\n",
635     "Undefined namespace prefix\n",
636     "Encoding error\n",
637     "Char out of XML range\n",
638     "Invalid or incomplete context\n",
639     "Stack usage error\n",
640     "Forbidden variable\n",
641     "?? Unknown error ??\n"	/* Must be last in the list! */
642 };
643 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
644 		   sizeof(xmlXPathErrorMessages[0])) - 1)
645 /**
646  * xmlXPathErrMemory:
647  * @ctxt:  an XPath context
648  * @extra:  extra informations
649  *
650  * Handle a redefinition of attribute error
651  */
652 static void
xmlXPathErrMemory(xmlXPathContextPtr ctxt,const char * extra)653 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
654 {
655     if (ctxt != NULL) {
656         if (extra) {
657             xmlChar buf[200];
658 
659             xmlStrPrintf(buf, 200,
660                          "Memory allocation failed : %s\n",
661                          extra);
662             ctxt->lastError.message = (char *) xmlStrdup(buf);
663         } else {
664             ctxt->lastError.message = (char *)
665 	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
666         }
667         ctxt->lastError.domain = XML_FROM_XPATH;
668         ctxt->lastError.code = XML_ERR_NO_MEMORY;
669 	if (ctxt->error != NULL)
670 	    ctxt->error(ctxt->userData, &ctxt->lastError);
671     } else {
672         if (extra)
673             __xmlRaiseError(NULL, NULL, NULL,
674                             NULL, NULL, XML_FROM_XPATH,
675                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
676                             extra, NULL, NULL, 0, 0,
677                             "Memory allocation failed : %s\n", extra);
678         else
679             __xmlRaiseError(NULL, NULL, NULL,
680                             NULL, NULL, XML_FROM_XPATH,
681                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
682                             NULL, NULL, NULL, 0, 0,
683                             "Memory allocation failed\n");
684     }
685 }
686 
687 /**
688  * xmlXPathPErrMemory:
689  * @ctxt:  an XPath parser context
690  * @extra:  extra informations
691  *
692  * Handle a redefinition of attribute error
693  */
694 static void
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt,const char * extra)695 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
696 {
697     if (ctxt == NULL)
698 	xmlXPathErrMemory(NULL, extra);
699     else {
700 	ctxt->error = XPATH_MEMORY_ERROR;
701 	xmlXPathErrMemory(ctxt->context, extra);
702     }
703 }
704 
705 /**
706  * xmlXPathErr:
707  * @ctxt:  a XPath parser context
708  * @error:  the error code
709  *
710  * Handle an XPath error
711  */
712 void
xmlXPathErr(xmlXPathParserContextPtr ctxt,int error)713 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
714 {
715     if ((error < 0) || (error > MAXERRNO))
716 	error = MAXERRNO;
717     if (ctxt == NULL) {
718 	__xmlRaiseError(NULL, NULL, NULL,
719 			NULL, NULL, XML_FROM_XPATH,
720 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
721 			XML_ERR_ERROR, NULL, 0,
722 			NULL, NULL, NULL, 0, 0,
723 			"%s", xmlXPathErrorMessages[error]);
724 	return;
725     }
726     ctxt->error = error;
727     if (ctxt->context == NULL) {
728 	__xmlRaiseError(NULL, NULL, NULL,
729 			NULL, NULL, XML_FROM_XPATH,
730 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
731 			XML_ERR_ERROR, NULL, 0,
732 			(const char *) ctxt->base, NULL, NULL,
733 			ctxt->cur - ctxt->base, 0,
734 			"%s", xmlXPathErrorMessages[error]);
735 	return;
736     }
737 
738     /* cleanup current last error */
739     xmlResetError(&ctxt->context->lastError);
740 
741     ctxt->context->lastError.domain = XML_FROM_XPATH;
742     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
743                            XPATH_EXPRESSION_OK;
744     ctxt->context->lastError.level = XML_ERR_ERROR;
745     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
746     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
747     ctxt->context->lastError.node = ctxt->context->debugNode;
748     if (ctxt->context->error != NULL) {
749 	ctxt->context->error(ctxt->context->userData,
750 	                     &ctxt->context->lastError);
751     } else {
752 	__xmlRaiseError(NULL, NULL, NULL,
753 			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
754 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
755 			XML_ERR_ERROR, NULL, 0,
756 			(const char *) ctxt->base, NULL, NULL,
757 			ctxt->cur - ctxt->base, 0,
758 			"%s", xmlXPathErrorMessages[error]);
759     }
760 
761 }
762 
763 /**
764  * xmlXPatherror:
765  * @ctxt:  the XPath Parser context
766  * @file:  the file name
767  * @line:  the line number
768  * @no:  the error number
769  *
770  * Formats an error message.
771  */
772 void
xmlXPatherror(xmlXPathParserContextPtr ctxt,const char * file ATTRIBUTE_UNUSED,int line ATTRIBUTE_UNUSED,int no)773 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
774               int line ATTRIBUTE_UNUSED, int no) {
775     xmlXPathErr(ctxt, no);
776 }
777 
778 /************************************************************************
779  *									*
780  *			Utilities					*
781  *									*
782  ************************************************************************/
783 
784 /**
785  * xsltPointerList:
786  *
787  * Pointer-list for various purposes.
788  */
789 typedef struct _xmlPointerList xmlPointerList;
790 typedef xmlPointerList *xmlPointerListPtr;
791 struct _xmlPointerList {
792     void **items;
793     int number;
794     int size;
795 };
796 /*
797 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
798 * and here, we should make the functions public.
799 */
800 static int
xmlPointerListAddSize(xmlPointerListPtr list,void * item,int initialSize)801 xmlPointerListAddSize(xmlPointerListPtr list,
802 		       void *item,
803 		       int initialSize)
804 {
805     if (list->items == NULL) {
806 	if (initialSize <= 0)
807 	    initialSize = 1;
808 	list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
809 	if (list->items == NULL) {
810 	    xmlXPathErrMemory(NULL,
811 		"xmlPointerListCreate: allocating item\n");
812 	    return(-1);
813 	}
814 	list->number = 0;
815 	list->size = initialSize;
816     } else if (list->size <= list->number) {
817         if (list->size > 50000000) {
818 	    xmlXPathErrMemory(NULL,
819 		"xmlPointerListAddSize: re-allocating item\n");
820             return(-1);
821         }
822 	list->size *= 2;
823 	list->items = (void **) xmlRealloc(list->items,
824 	    list->size * sizeof(void *));
825 	if (list->items == NULL) {
826 	    xmlXPathErrMemory(NULL,
827 		"xmlPointerListAddSize: re-allocating item\n");
828 	    list->size = 0;
829 	    return(-1);
830 	}
831     }
832     list->items[list->number++] = item;
833     return(0);
834 }
835 
836 /**
837  * xsltPointerListCreate:
838  *
839  * Creates an xsltPointerList structure.
840  *
841  * Returns a xsltPointerList structure or NULL in case of an error.
842  */
843 static xmlPointerListPtr
xmlPointerListCreate(int initialSize)844 xmlPointerListCreate(int initialSize)
845 {
846     xmlPointerListPtr ret;
847 
848     ret = xmlMalloc(sizeof(xmlPointerList));
849     if (ret == NULL) {
850 	xmlXPathErrMemory(NULL,
851 	    "xmlPointerListCreate: allocating item\n");
852 	return (NULL);
853     }
854     memset(ret, 0, sizeof(xmlPointerList));
855     if (initialSize > 0) {
856 	xmlPointerListAddSize(ret, NULL, initialSize);
857 	ret->number = 0;
858     }
859     return (ret);
860 }
861 
862 /**
863  * xsltPointerListFree:
864  *
865  * Frees the xsltPointerList structure. This does not free
866  * the content of the list.
867  */
868 static void
xmlPointerListFree(xmlPointerListPtr list)869 xmlPointerListFree(xmlPointerListPtr list)
870 {
871     if (list == NULL)
872 	return;
873     if (list->items != NULL)
874 	xmlFree(list->items);
875     xmlFree(list);
876 }
877 
878 /************************************************************************
879  *									*
880  *			Parser Types					*
881  *									*
882  ************************************************************************/
883 
884 /*
885  * Types are private:
886  */
887 
888 typedef enum {
889     XPATH_OP_END=0,
890     XPATH_OP_AND,
891     XPATH_OP_OR,
892     XPATH_OP_EQUAL,
893     XPATH_OP_CMP,
894     XPATH_OP_PLUS,
895     XPATH_OP_MULT,
896     XPATH_OP_UNION,
897     XPATH_OP_ROOT,
898     XPATH_OP_NODE,
899     XPATH_OP_COLLECT,
900     XPATH_OP_VALUE, /* 11 */
901     XPATH_OP_VARIABLE,
902     XPATH_OP_FUNCTION,
903     XPATH_OP_ARG,
904     XPATH_OP_PREDICATE,
905     XPATH_OP_FILTER, /* 16 */
906     XPATH_OP_SORT /* 17 */
907 #ifdef LIBXML_XPTR_ENABLED
908     ,XPATH_OP_RANGETO
909 #endif
910 } xmlXPathOp;
911 
912 typedef enum {
913     AXIS_ANCESTOR = 1,
914     AXIS_ANCESTOR_OR_SELF,
915     AXIS_ATTRIBUTE,
916     AXIS_CHILD,
917     AXIS_DESCENDANT,
918     AXIS_DESCENDANT_OR_SELF,
919     AXIS_FOLLOWING,
920     AXIS_FOLLOWING_SIBLING,
921     AXIS_NAMESPACE,
922     AXIS_PARENT,
923     AXIS_PRECEDING,
924     AXIS_PRECEDING_SIBLING,
925     AXIS_SELF
926 } xmlXPathAxisVal;
927 
928 typedef enum {
929     NODE_TEST_NONE = 0,
930     NODE_TEST_TYPE = 1,
931     NODE_TEST_PI = 2,
932     NODE_TEST_ALL = 3,
933     NODE_TEST_NS = 4,
934     NODE_TEST_NAME = 5
935 } xmlXPathTestVal;
936 
937 typedef enum {
938     NODE_TYPE_NODE = 0,
939     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
940     NODE_TYPE_TEXT = XML_TEXT_NODE,
941     NODE_TYPE_PI = XML_PI_NODE
942 } xmlXPathTypeVal;
943 
944 typedef struct _xmlXPathStepOp xmlXPathStepOp;
945 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
946 struct _xmlXPathStepOp {
947     xmlXPathOp op;		/* The identifier of the operation */
948     int ch1;			/* First child */
949     int ch2;			/* Second child */
950     int value;
951     int value2;
952     int value3;
953     void *value4;
954     void *value5;
955     xmlXPathFunction cache;
956     void *cacheURI;
957 };
958 
959 struct _xmlXPathCompExpr {
960     int nbStep;			/* Number of steps in this expression */
961     int maxStep;		/* Maximum number of steps allocated */
962     xmlXPathStepOp *steps;	/* ops for computation of this expression */
963     int last;			/* index of last step in expression */
964     xmlChar *expr;		/* the expression being computed */
965     xmlDictPtr dict;		/* the dictionary to use if any */
966 #ifdef DEBUG_EVAL_COUNTS
967     int nb;
968     xmlChar *string;
969 #endif
970 #ifdef XPATH_STREAMING
971     xmlPatternPtr stream;
972 #endif
973 };
974 
975 /************************************************************************
976  *									*
977  *			Forward declarations				*
978  *									*
979  ************************************************************************/
980 static void
981 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
982 static void
983 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
984 static int
985 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
986                         xmlXPathStepOpPtr op, xmlNodePtr *first);
987 static int
988 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
989 			    xmlXPathStepOpPtr op,
990 			    int isPredicate);
991 static void
992 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
993 
994 /************************************************************************
995  *									*
996  *			Parser Type functions				*
997  *									*
998  ************************************************************************/
999 
1000 /**
1001  * xmlXPathNewCompExpr:
1002  *
1003  * Create a new Xpath component
1004  *
1005  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1006  */
1007 static xmlXPathCompExprPtr
xmlXPathNewCompExpr(void)1008 xmlXPathNewCompExpr(void) {
1009     xmlXPathCompExprPtr cur;
1010 
1011     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1012     if (cur == NULL) {
1013         xmlXPathErrMemory(NULL, "allocating component\n");
1014 	return(NULL);
1015     }
1016     memset(cur, 0, sizeof(xmlXPathCompExpr));
1017     cur->maxStep = 10;
1018     cur->nbStep = 0;
1019     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1020 	                                   sizeof(xmlXPathStepOp));
1021     if (cur->steps == NULL) {
1022         xmlXPathErrMemory(NULL, "allocating steps\n");
1023 	xmlFree(cur);
1024 	return(NULL);
1025     }
1026     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1027     cur->last = -1;
1028 #ifdef DEBUG_EVAL_COUNTS
1029     cur->nb = 0;
1030 #endif
1031     return(cur);
1032 }
1033 
1034 /**
1035  * xmlXPathFreeCompExpr:
1036  * @comp:  an XPATH comp
1037  *
1038  * Free up the memory allocated by @comp
1039  */
1040 void
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)1041 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1042 {
1043     xmlXPathStepOpPtr op;
1044     int i;
1045 
1046     if (comp == NULL)
1047         return;
1048     if (comp->dict == NULL) {
1049 	for (i = 0; i < comp->nbStep; i++) {
1050 	    op = &comp->steps[i];
1051 	    if (op->value4 != NULL) {
1052 		if (op->op == XPATH_OP_VALUE)
1053 		    xmlXPathFreeObject(op->value4);
1054 		else
1055 		    xmlFree(op->value4);
1056 	    }
1057 	    if (op->value5 != NULL)
1058 		xmlFree(op->value5);
1059 	}
1060     } else {
1061 	for (i = 0; i < comp->nbStep; i++) {
1062 	    op = &comp->steps[i];
1063 	    if (op->value4 != NULL) {
1064 		if (op->op == XPATH_OP_VALUE)
1065 		    xmlXPathFreeObject(op->value4);
1066 	    }
1067 	}
1068         xmlDictFree(comp->dict);
1069     }
1070     if (comp->steps != NULL) {
1071         xmlFree(comp->steps);
1072     }
1073 #ifdef DEBUG_EVAL_COUNTS
1074     if (comp->string != NULL) {
1075         xmlFree(comp->string);
1076     }
1077 #endif
1078 #ifdef XPATH_STREAMING
1079     if (comp->stream != NULL) {
1080         xmlFreePatternList(comp->stream);
1081     }
1082 #endif
1083     if (comp->expr != NULL) {
1084         xmlFree(comp->expr);
1085     }
1086 
1087     xmlFree(comp);
1088 }
1089 
1090 /**
1091  * xmlXPathCompExprAdd:
1092  * @comp:  the compiled expression
1093  * @ch1: first child index
1094  * @ch2: second child index
1095  * @op:  an op
1096  * @value:  the first int value
1097  * @value2:  the second int value
1098  * @value3:  the third int value
1099  * @value4:  the first string value
1100  * @value5:  the second string value
1101  *
1102  * Add a step to an XPath Compiled Expression
1103  *
1104  * Returns -1 in case of failure, the index otherwise
1105  */
1106 static int
xmlXPathCompExprAdd(xmlXPathCompExprPtr comp,int ch1,int ch2,xmlXPathOp op,int value,int value2,int value3,void * value4,void * value5)1107 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
1108    xmlXPathOp op, int value,
1109    int value2, int value3, void *value4, void *value5) {
1110     if (comp->nbStep >= comp->maxStep) {
1111 	xmlXPathStepOp *real;
1112 
1113         if (comp->maxStep >= XPATH_MAX_STEPS) {
1114 	    xmlXPathErrMemory(NULL, "adding step\n");
1115 	    return(-1);
1116         }
1117 	comp->maxStep *= 2;
1118 	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1119 		                      comp->maxStep * sizeof(xmlXPathStepOp));
1120 	if (real == NULL) {
1121 	    comp->maxStep /= 2;
1122 	    xmlXPathErrMemory(NULL, "adding step\n");
1123 	    return(-1);
1124 	}
1125 	comp->steps = real;
1126     }
1127     comp->last = comp->nbStep;
1128     comp->steps[comp->nbStep].ch1 = ch1;
1129     comp->steps[comp->nbStep].ch2 = ch2;
1130     comp->steps[comp->nbStep].op = op;
1131     comp->steps[comp->nbStep].value = value;
1132     comp->steps[comp->nbStep].value2 = value2;
1133     comp->steps[comp->nbStep].value3 = value3;
1134     if ((comp->dict != NULL) &&
1135         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1136 	 (op == XPATH_OP_COLLECT))) {
1137         if (value4 != NULL) {
1138 	    comp->steps[comp->nbStep].value4 = (xmlChar *)
1139 	        (void *)xmlDictLookup(comp->dict, value4, -1);
1140 	    xmlFree(value4);
1141 	} else
1142 	    comp->steps[comp->nbStep].value4 = NULL;
1143         if (value5 != NULL) {
1144 	    comp->steps[comp->nbStep].value5 = (xmlChar *)
1145 	        (void *)xmlDictLookup(comp->dict, value5, -1);
1146 	    xmlFree(value5);
1147 	} else
1148 	    comp->steps[comp->nbStep].value5 = NULL;
1149     } else {
1150 	comp->steps[comp->nbStep].value4 = value4;
1151 	comp->steps[comp->nbStep].value5 = value5;
1152     }
1153     comp->steps[comp->nbStep].cache = NULL;
1154     return(comp->nbStep++);
1155 }
1156 
1157 /**
1158  * xmlXPathCompSwap:
1159  * @comp:  the compiled expression
1160  * @op: operation index
1161  *
1162  * Swaps 2 operations in the compiled expression
1163  */
1164 static void
xmlXPathCompSwap(xmlXPathStepOpPtr op)1165 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1166     int tmp;
1167 
1168 #ifndef LIBXML_THREAD_ENABLED
1169     /*
1170      * Since this manipulates possibly shared variables, this is
1171      * disabled if one detects that the library is used in a multithreaded
1172      * application
1173      */
1174     if (xmlXPathDisableOptimizer)
1175 	return;
1176 #endif
1177 
1178     tmp = op->ch1;
1179     op->ch1 = op->ch2;
1180     op->ch2 = tmp;
1181 }
1182 
1183 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
1184     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\
1185 	                (op), (val), (val2), (val3), (val4), (val5))
1186 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
1187     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\
1188 	                (op), (val), (val2), (val3), (val4), (val5))
1189 
1190 #define PUSH_LEAVE_EXPR(op, val, val2)					\
1191 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1192 
1193 #define PUSH_UNARY_EXPR(op, ch, val, val2)				\
1194 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1195 
1196 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
1197 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\
1198 			(val), (val2), 0 ,NULL ,NULL)
1199 
1200 /************************************************************************
1201  *									*
1202  *		XPath object cache structures				*
1203  *									*
1204  ************************************************************************/
1205 
1206 /* #define XP_DEFAULT_CACHE_ON */
1207 
1208 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1209 
1210 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1211 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1212 struct _xmlXPathContextCache {
1213     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1214     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1215     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1216     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1217     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1218     int maxNodeset;
1219     int maxString;
1220     int maxBoolean;
1221     int maxNumber;
1222     int maxMisc;
1223 #ifdef XP_DEBUG_OBJ_USAGE
1224     int dbgCachedAll;
1225     int dbgCachedNodeset;
1226     int dbgCachedString;
1227     int dbgCachedBool;
1228     int dbgCachedNumber;
1229     int dbgCachedPoint;
1230     int dbgCachedRange;
1231     int dbgCachedLocset;
1232     int dbgCachedUsers;
1233     int dbgCachedXSLTTree;
1234     int dbgCachedUndefined;
1235 
1236 
1237     int dbgReusedAll;
1238     int dbgReusedNodeset;
1239     int dbgReusedString;
1240     int dbgReusedBool;
1241     int dbgReusedNumber;
1242     int dbgReusedPoint;
1243     int dbgReusedRange;
1244     int dbgReusedLocset;
1245     int dbgReusedUsers;
1246     int dbgReusedXSLTTree;
1247     int dbgReusedUndefined;
1248 
1249 #endif
1250 };
1251 
1252 /************************************************************************
1253  *									*
1254  *		Debugging related functions				*
1255  *									*
1256  ************************************************************************/
1257 
1258 #define STRANGE							\
1259     xmlGenericError(xmlGenericErrorContext,				\
1260 	    "Internal error at %s:%d\n",				\
1261             __FILE__, __LINE__);
1262 
1263 #ifdef LIBXML_DEBUG_ENABLED
1264 static void
xmlXPathDebugDumpNode(FILE * output,xmlNodePtr cur,int depth)1265 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1266     int i;
1267     char shift[100];
1268 
1269     for (i = 0;((i < depth) && (i < 25));i++)
1270         shift[2 * i] = shift[2 * i + 1] = ' ';
1271     shift[2 * i] = shift[2 * i + 1] = 0;
1272     if (cur == NULL) {
1273 	fprintf(output, "%s", shift);
1274 	fprintf(output, "Node is NULL !\n");
1275 	return;
1276 
1277     }
1278 
1279     if ((cur->type == XML_DOCUMENT_NODE) ||
1280 	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
1281 	fprintf(output, "%s", shift);
1282 	fprintf(output, " /\n");
1283     } else if (cur->type == XML_ATTRIBUTE_NODE)
1284 	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1285     else
1286 	xmlDebugDumpOneNode(output, cur, depth);
1287 }
1288 static void
xmlXPathDebugDumpNodeList(FILE * output,xmlNodePtr cur,int depth)1289 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1290     xmlNodePtr tmp;
1291     int i;
1292     char shift[100];
1293 
1294     for (i = 0;((i < depth) && (i < 25));i++)
1295         shift[2 * i] = shift[2 * i + 1] = ' ';
1296     shift[2 * i] = shift[2 * i + 1] = 0;
1297     if (cur == NULL) {
1298 	fprintf(output, "%s", shift);
1299 	fprintf(output, "Node is NULL !\n");
1300 	return;
1301 
1302     }
1303 
1304     while (cur != NULL) {
1305 	tmp = cur;
1306 	cur = cur->next;
1307 	xmlDebugDumpOneNode(output, tmp, depth);
1308     }
1309 }
1310 
1311 static void
xmlXPathDebugDumpNodeSet(FILE * output,xmlNodeSetPtr cur,int depth)1312 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1313     int i;
1314     char shift[100];
1315 
1316     for (i = 0;((i < depth) && (i < 25));i++)
1317         shift[2 * i] = shift[2 * i + 1] = ' ';
1318     shift[2 * i] = shift[2 * i + 1] = 0;
1319 
1320     if (cur == NULL) {
1321 	fprintf(output, "%s", shift);
1322 	fprintf(output, "NodeSet is NULL !\n");
1323 	return;
1324 
1325     }
1326 
1327     if (cur != NULL) {
1328 	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1329 	for (i = 0;i < cur->nodeNr;i++) {
1330 	    fprintf(output, "%s", shift);
1331 	    fprintf(output, "%d", i + 1);
1332 	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1333 	}
1334     }
1335 }
1336 
1337 static void
xmlXPathDebugDumpValueTree(FILE * output,xmlNodeSetPtr cur,int depth)1338 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1339     int i;
1340     char shift[100];
1341 
1342     for (i = 0;((i < depth) && (i < 25));i++)
1343         shift[2 * i] = shift[2 * i + 1] = ' ';
1344     shift[2 * i] = shift[2 * i + 1] = 0;
1345 
1346     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1347 	fprintf(output, "%s", shift);
1348 	fprintf(output, "Value Tree is NULL !\n");
1349 	return;
1350 
1351     }
1352 
1353     fprintf(output, "%s", shift);
1354     fprintf(output, "%d", i + 1);
1355     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1356 }
1357 #if defined(LIBXML_XPTR_ENABLED)
1358 static void
xmlXPathDebugDumpLocationSet(FILE * output,xmlLocationSetPtr cur,int depth)1359 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1360     int i;
1361     char shift[100];
1362 
1363     for (i = 0;((i < depth) && (i < 25));i++)
1364         shift[2 * i] = shift[2 * i + 1] = ' ';
1365     shift[2 * i] = shift[2 * i + 1] = 0;
1366 
1367     if (cur == NULL) {
1368 	fprintf(output, "%s", shift);
1369 	fprintf(output, "LocationSet is NULL !\n");
1370 	return;
1371 
1372     }
1373 
1374     for (i = 0;i < cur->locNr;i++) {
1375 	fprintf(output, "%s", shift);
1376         fprintf(output, "%d : ", i + 1);
1377 	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1378     }
1379 }
1380 #endif /* LIBXML_XPTR_ENABLED */
1381 
1382 /**
1383  * xmlXPathDebugDumpObject:
1384  * @output:  the FILE * to dump the output
1385  * @cur:  the object to inspect
1386  * @depth:  indentation level
1387  *
1388  * Dump the content of the object for debugging purposes
1389  */
1390 void
xmlXPathDebugDumpObject(FILE * output,xmlXPathObjectPtr cur,int depth)1391 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1392     int i;
1393     char shift[100];
1394 
1395     if (output == NULL) return;
1396 
1397     for (i = 0;((i < depth) && (i < 25));i++)
1398         shift[2 * i] = shift[2 * i + 1] = ' ';
1399     shift[2 * i] = shift[2 * i + 1] = 0;
1400 
1401 
1402     fprintf(output, "%s", shift);
1403 
1404     if (cur == NULL) {
1405         fprintf(output, "Object is empty (NULL)\n");
1406 	return;
1407     }
1408     switch(cur->type) {
1409         case XPATH_UNDEFINED:
1410 	    fprintf(output, "Object is uninitialized\n");
1411 	    break;
1412         case XPATH_NODESET:
1413 	    fprintf(output, "Object is a Node Set :\n");
1414 	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1415 	    break;
1416 	case XPATH_XSLT_TREE:
1417 	    fprintf(output, "Object is an XSLT value tree :\n");
1418 	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1419 	    break;
1420         case XPATH_BOOLEAN:
1421 	    fprintf(output, "Object is a Boolean : ");
1422 	    if (cur->boolval) fprintf(output, "true\n");
1423 	    else fprintf(output, "false\n");
1424 	    break;
1425         case XPATH_NUMBER:
1426 	    switch (xmlXPathIsInf(cur->floatval)) {
1427 	    case 1:
1428 		fprintf(output, "Object is a number : Infinity\n");
1429 		break;
1430 	    case -1:
1431 		fprintf(output, "Object is a number : -Infinity\n");
1432 		break;
1433 	    default:
1434 		if (xmlXPathIsNaN(cur->floatval)) {
1435 		    fprintf(output, "Object is a number : NaN\n");
1436 		} else if (cur->floatval == 0) {
1437                     /* Omit sign for negative zero. */
1438 		    fprintf(output, "Object is a number : 0\n");
1439 		} else {
1440 		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
1441 		}
1442 	    }
1443 	    break;
1444         case XPATH_STRING:
1445 	    fprintf(output, "Object is a string : ");
1446 	    xmlDebugDumpString(output, cur->stringval);
1447 	    fprintf(output, "\n");
1448 	    break;
1449 	case XPATH_POINT:
1450 	    fprintf(output, "Object is a point : index %d in node", cur->index);
1451 	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1452 	    fprintf(output, "\n");
1453 	    break;
1454 	case XPATH_RANGE:
1455 	    if ((cur->user2 == NULL) ||
1456 		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1457 		fprintf(output, "Object is a collapsed range :\n");
1458 		fprintf(output, "%s", shift);
1459 		if (cur->index >= 0)
1460 		    fprintf(output, "index %d in ", cur->index);
1461 		fprintf(output, "node\n");
1462 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1463 			              depth + 1);
1464 	    } else  {
1465 		fprintf(output, "Object is a range :\n");
1466 		fprintf(output, "%s", shift);
1467 		fprintf(output, "From ");
1468 		if (cur->index >= 0)
1469 		    fprintf(output, "index %d in ", cur->index);
1470 		fprintf(output, "node\n");
1471 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1472 			              depth + 1);
1473 		fprintf(output, "%s", shift);
1474 		fprintf(output, "To ");
1475 		if (cur->index2 >= 0)
1476 		    fprintf(output, "index %d in ", cur->index2);
1477 		fprintf(output, "node\n");
1478 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1479 			              depth + 1);
1480 		fprintf(output, "\n");
1481 	    }
1482 	    break;
1483 	case XPATH_LOCATIONSET:
1484 #if defined(LIBXML_XPTR_ENABLED)
1485 	    fprintf(output, "Object is a Location Set:\n");
1486 	    xmlXPathDebugDumpLocationSet(output,
1487 		    (xmlLocationSetPtr) cur->user, depth);
1488 #endif
1489 	    break;
1490 	case XPATH_USERS:
1491 	    fprintf(output, "Object is user defined\n");
1492 	    break;
1493     }
1494 }
1495 
1496 static void
xmlXPathDebugDumpStepOp(FILE * output,xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op,int depth)1497 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1498 	                     xmlXPathStepOpPtr op, int depth) {
1499     int i;
1500     char shift[100];
1501 
1502     for (i = 0;((i < depth) && (i < 25));i++)
1503         shift[2 * i] = shift[2 * i + 1] = ' ';
1504     shift[2 * i] = shift[2 * i + 1] = 0;
1505 
1506     fprintf(output, "%s", shift);
1507     if (op == NULL) {
1508 	fprintf(output, "Step is NULL\n");
1509 	return;
1510     }
1511     switch (op->op) {
1512         case XPATH_OP_END:
1513 	    fprintf(output, "END"); break;
1514         case XPATH_OP_AND:
1515 	    fprintf(output, "AND"); break;
1516         case XPATH_OP_OR:
1517 	    fprintf(output, "OR"); break;
1518         case XPATH_OP_EQUAL:
1519 	     if (op->value)
1520 		 fprintf(output, "EQUAL =");
1521 	     else
1522 		 fprintf(output, "EQUAL !=");
1523 	     break;
1524         case XPATH_OP_CMP:
1525 	     if (op->value)
1526 		 fprintf(output, "CMP <");
1527 	     else
1528 		 fprintf(output, "CMP >");
1529 	     if (!op->value2)
1530 		 fprintf(output, "=");
1531 	     break;
1532         case XPATH_OP_PLUS:
1533 	     if (op->value == 0)
1534 		 fprintf(output, "PLUS -");
1535 	     else if (op->value == 1)
1536 		 fprintf(output, "PLUS +");
1537 	     else if (op->value == 2)
1538 		 fprintf(output, "PLUS unary -");
1539 	     else if (op->value == 3)
1540 		 fprintf(output, "PLUS unary - -");
1541 	     break;
1542         case XPATH_OP_MULT:
1543 	     if (op->value == 0)
1544 		 fprintf(output, "MULT *");
1545 	     else if (op->value == 1)
1546 		 fprintf(output, "MULT div");
1547 	     else
1548 		 fprintf(output, "MULT mod");
1549 	     break;
1550         case XPATH_OP_UNION:
1551 	     fprintf(output, "UNION"); break;
1552         case XPATH_OP_ROOT:
1553 	     fprintf(output, "ROOT"); break;
1554         case XPATH_OP_NODE:
1555 	     fprintf(output, "NODE"); break;
1556         case XPATH_OP_SORT:
1557 	     fprintf(output, "SORT"); break;
1558         case XPATH_OP_COLLECT: {
1559 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1560 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1561 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1562 	    const xmlChar *prefix = op->value4;
1563 	    const xmlChar *name = op->value5;
1564 
1565 	    fprintf(output, "COLLECT ");
1566 	    switch (axis) {
1567 		case AXIS_ANCESTOR:
1568 		    fprintf(output, " 'ancestors' "); break;
1569 		case AXIS_ANCESTOR_OR_SELF:
1570 		    fprintf(output, " 'ancestors-or-self' "); break;
1571 		case AXIS_ATTRIBUTE:
1572 		    fprintf(output, " 'attributes' "); break;
1573 		case AXIS_CHILD:
1574 		    fprintf(output, " 'child' "); break;
1575 		case AXIS_DESCENDANT:
1576 		    fprintf(output, " 'descendant' "); break;
1577 		case AXIS_DESCENDANT_OR_SELF:
1578 		    fprintf(output, " 'descendant-or-self' "); break;
1579 		case AXIS_FOLLOWING:
1580 		    fprintf(output, " 'following' "); break;
1581 		case AXIS_FOLLOWING_SIBLING:
1582 		    fprintf(output, " 'following-siblings' "); break;
1583 		case AXIS_NAMESPACE:
1584 		    fprintf(output, " 'namespace' "); break;
1585 		case AXIS_PARENT:
1586 		    fprintf(output, " 'parent' "); break;
1587 		case AXIS_PRECEDING:
1588 		    fprintf(output, " 'preceding' "); break;
1589 		case AXIS_PRECEDING_SIBLING:
1590 		    fprintf(output, " 'preceding-sibling' "); break;
1591 		case AXIS_SELF:
1592 		    fprintf(output, " 'self' "); break;
1593 	    }
1594 	    switch (test) {
1595                 case NODE_TEST_NONE:
1596 		    fprintf(output, "'none' "); break;
1597                 case NODE_TEST_TYPE:
1598 		    fprintf(output, "'type' "); break;
1599                 case NODE_TEST_PI:
1600 		    fprintf(output, "'PI' "); break;
1601                 case NODE_TEST_ALL:
1602 		    fprintf(output, "'all' "); break;
1603                 case NODE_TEST_NS:
1604 		    fprintf(output, "'namespace' "); break;
1605                 case NODE_TEST_NAME:
1606 		    fprintf(output, "'name' "); break;
1607 	    }
1608 	    switch (type) {
1609                 case NODE_TYPE_NODE:
1610 		    fprintf(output, "'node' "); break;
1611                 case NODE_TYPE_COMMENT:
1612 		    fprintf(output, "'comment' "); break;
1613                 case NODE_TYPE_TEXT:
1614 		    fprintf(output, "'text' "); break;
1615                 case NODE_TYPE_PI:
1616 		    fprintf(output, "'PI' "); break;
1617 	    }
1618 	    if (prefix != NULL)
1619 		fprintf(output, "%s:", prefix);
1620 	    if (name != NULL)
1621 		fprintf(output, "%s", (const char *) name);
1622 	    break;
1623 
1624         }
1625 	case XPATH_OP_VALUE: {
1626 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1627 
1628 	    fprintf(output, "ELEM ");
1629 	    xmlXPathDebugDumpObject(output, object, 0);
1630 	    goto finish;
1631 	}
1632 	case XPATH_OP_VARIABLE: {
1633 	    const xmlChar *prefix = op->value5;
1634 	    const xmlChar *name = op->value4;
1635 
1636 	    if (prefix != NULL)
1637 		fprintf(output, "VARIABLE %s:%s", prefix, name);
1638 	    else
1639 		fprintf(output, "VARIABLE %s", name);
1640 	    break;
1641 	}
1642 	case XPATH_OP_FUNCTION: {
1643 	    int nbargs = op->value;
1644 	    const xmlChar *prefix = op->value5;
1645 	    const xmlChar *name = op->value4;
1646 
1647 	    if (prefix != NULL)
1648 		fprintf(output, "FUNCTION %s:%s(%d args)",
1649 			prefix, name, nbargs);
1650 	    else
1651 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1652 	    break;
1653 	}
1654         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1655         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1656         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1657 #ifdef LIBXML_XPTR_ENABLED
1658         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1659 #endif
1660 	default:
1661         fprintf(output, "UNKNOWN %d\n", op->op); return;
1662     }
1663     fprintf(output, "\n");
1664 finish:
1665     if (op->ch1 >= 0)
1666 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1667     if (op->ch2 >= 0)
1668 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1669 }
1670 
1671 /**
1672  * xmlXPathDebugDumpCompExpr:
1673  * @output:  the FILE * for the output
1674  * @comp:  the precompiled XPath expression
1675  * @depth:  the indentation level.
1676  *
1677  * Dumps the tree of the compiled XPath expression.
1678  */
1679 void
xmlXPathDebugDumpCompExpr(FILE * output,xmlXPathCompExprPtr comp,int depth)1680 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1681 	                  int depth) {
1682     int i;
1683     char shift[100];
1684 
1685     if ((output == NULL) || (comp == NULL)) return;
1686 
1687     for (i = 0;((i < depth) && (i < 25));i++)
1688         shift[2 * i] = shift[2 * i + 1] = ' ';
1689     shift[2 * i] = shift[2 * i + 1] = 0;
1690 
1691     fprintf(output, "%s", shift);
1692 
1693 #ifdef XPATH_STREAMING
1694     if (comp->stream) {
1695         fprintf(output, "Streaming Expression\n");
1696     } else
1697 #endif
1698     {
1699         fprintf(output, "Compiled Expression : %d elements\n",
1700                 comp->nbStep);
1701         i = comp->last;
1702         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1703     }
1704 }
1705 
1706 #ifdef XP_DEBUG_OBJ_USAGE
1707 
1708 /*
1709 * XPath object usage related debugging variables.
1710 */
1711 static int xmlXPathDebugObjCounterUndefined = 0;
1712 static int xmlXPathDebugObjCounterNodeset = 0;
1713 static int xmlXPathDebugObjCounterBool = 0;
1714 static int xmlXPathDebugObjCounterNumber = 0;
1715 static int xmlXPathDebugObjCounterString = 0;
1716 static int xmlXPathDebugObjCounterPoint = 0;
1717 static int xmlXPathDebugObjCounterRange = 0;
1718 static int xmlXPathDebugObjCounterLocset = 0;
1719 static int xmlXPathDebugObjCounterUsers = 0;
1720 static int xmlXPathDebugObjCounterXSLTTree = 0;
1721 static int xmlXPathDebugObjCounterAll = 0;
1722 
1723 static int xmlXPathDebugObjTotalUndefined = 0;
1724 static int xmlXPathDebugObjTotalNodeset = 0;
1725 static int xmlXPathDebugObjTotalBool = 0;
1726 static int xmlXPathDebugObjTotalNumber = 0;
1727 static int xmlXPathDebugObjTotalString = 0;
1728 static int xmlXPathDebugObjTotalPoint = 0;
1729 static int xmlXPathDebugObjTotalRange = 0;
1730 static int xmlXPathDebugObjTotalLocset = 0;
1731 static int xmlXPathDebugObjTotalUsers = 0;
1732 static int xmlXPathDebugObjTotalXSLTTree = 0;
1733 static int xmlXPathDebugObjTotalAll = 0;
1734 
1735 static int xmlXPathDebugObjMaxUndefined = 0;
1736 static int xmlXPathDebugObjMaxNodeset = 0;
1737 static int xmlXPathDebugObjMaxBool = 0;
1738 static int xmlXPathDebugObjMaxNumber = 0;
1739 static int xmlXPathDebugObjMaxString = 0;
1740 static int xmlXPathDebugObjMaxPoint = 0;
1741 static int xmlXPathDebugObjMaxRange = 0;
1742 static int xmlXPathDebugObjMaxLocset = 0;
1743 static int xmlXPathDebugObjMaxUsers = 0;
1744 static int xmlXPathDebugObjMaxXSLTTree = 0;
1745 static int xmlXPathDebugObjMaxAll = 0;
1746 
1747 /* REVISIT TODO: Make this static when committing */
1748 static void
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)1749 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1750 {
1751     if (ctxt != NULL) {
1752 	if (ctxt->cache != NULL) {
1753 	    xmlXPathContextCachePtr cache =
1754 		(xmlXPathContextCachePtr) ctxt->cache;
1755 
1756 	    cache->dbgCachedAll = 0;
1757 	    cache->dbgCachedNodeset = 0;
1758 	    cache->dbgCachedString = 0;
1759 	    cache->dbgCachedBool = 0;
1760 	    cache->dbgCachedNumber = 0;
1761 	    cache->dbgCachedPoint = 0;
1762 	    cache->dbgCachedRange = 0;
1763 	    cache->dbgCachedLocset = 0;
1764 	    cache->dbgCachedUsers = 0;
1765 	    cache->dbgCachedXSLTTree = 0;
1766 	    cache->dbgCachedUndefined = 0;
1767 
1768 	    cache->dbgReusedAll = 0;
1769 	    cache->dbgReusedNodeset = 0;
1770 	    cache->dbgReusedString = 0;
1771 	    cache->dbgReusedBool = 0;
1772 	    cache->dbgReusedNumber = 0;
1773 	    cache->dbgReusedPoint = 0;
1774 	    cache->dbgReusedRange = 0;
1775 	    cache->dbgReusedLocset = 0;
1776 	    cache->dbgReusedUsers = 0;
1777 	    cache->dbgReusedXSLTTree = 0;
1778 	    cache->dbgReusedUndefined = 0;
1779 	}
1780     }
1781 
1782     xmlXPathDebugObjCounterUndefined = 0;
1783     xmlXPathDebugObjCounterNodeset = 0;
1784     xmlXPathDebugObjCounterBool = 0;
1785     xmlXPathDebugObjCounterNumber = 0;
1786     xmlXPathDebugObjCounterString = 0;
1787     xmlXPathDebugObjCounterPoint = 0;
1788     xmlXPathDebugObjCounterRange = 0;
1789     xmlXPathDebugObjCounterLocset = 0;
1790     xmlXPathDebugObjCounterUsers = 0;
1791     xmlXPathDebugObjCounterXSLTTree = 0;
1792     xmlXPathDebugObjCounterAll = 0;
1793 
1794     xmlXPathDebugObjTotalUndefined = 0;
1795     xmlXPathDebugObjTotalNodeset = 0;
1796     xmlXPathDebugObjTotalBool = 0;
1797     xmlXPathDebugObjTotalNumber = 0;
1798     xmlXPathDebugObjTotalString = 0;
1799     xmlXPathDebugObjTotalPoint = 0;
1800     xmlXPathDebugObjTotalRange = 0;
1801     xmlXPathDebugObjTotalLocset = 0;
1802     xmlXPathDebugObjTotalUsers = 0;
1803     xmlXPathDebugObjTotalXSLTTree = 0;
1804     xmlXPathDebugObjTotalAll = 0;
1805 
1806     xmlXPathDebugObjMaxUndefined = 0;
1807     xmlXPathDebugObjMaxNodeset = 0;
1808     xmlXPathDebugObjMaxBool = 0;
1809     xmlXPathDebugObjMaxNumber = 0;
1810     xmlXPathDebugObjMaxString = 0;
1811     xmlXPathDebugObjMaxPoint = 0;
1812     xmlXPathDebugObjMaxRange = 0;
1813     xmlXPathDebugObjMaxLocset = 0;
1814     xmlXPathDebugObjMaxUsers = 0;
1815     xmlXPathDebugObjMaxXSLTTree = 0;
1816     xmlXPathDebugObjMaxAll = 0;
1817 
1818 }
1819 
1820 static void
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,xmlXPathObjectType objType)1821 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1822 			      xmlXPathObjectType objType)
1823 {
1824     int isCached = 0;
1825 
1826     if (ctxt != NULL) {
1827 	if (ctxt->cache != NULL) {
1828 	    xmlXPathContextCachePtr cache =
1829 		(xmlXPathContextCachePtr) ctxt->cache;
1830 
1831 	    isCached = 1;
1832 
1833 	    cache->dbgReusedAll++;
1834 	    switch (objType) {
1835 		case XPATH_UNDEFINED:
1836 		    cache->dbgReusedUndefined++;
1837 		    break;
1838 		case XPATH_NODESET:
1839 		    cache->dbgReusedNodeset++;
1840 		    break;
1841 		case XPATH_BOOLEAN:
1842 		    cache->dbgReusedBool++;
1843 		    break;
1844 		case XPATH_NUMBER:
1845 		    cache->dbgReusedNumber++;
1846 		    break;
1847 		case XPATH_STRING:
1848 		    cache->dbgReusedString++;
1849 		    break;
1850 		case XPATH_POINT:
1851 		    cache->dbgReusedPoint++;
1852 		    break;
1853 		case XPATH_RANGE:
1854 		    cache->dbgReusedRange++;
1855 		    break;
1856 		case XPATH_LOCATIONSET:
1857 		    cache->dbgReusedLocset++;
1858 		    break;
1859 		case XPATH_USERS:
1860 		    cache->dbgReusedUsers++;
1861 		    break;
1862 		case XPATH_XSLT_TREE:
1863 		    cache->dbgReusedXSLTTree++;
1864 		    break;
1865 		default:
1866 		    break;
1867 	    }
1868 	}
1869     }
1870 
1871     switch (objType) {
1872 	case XPATH_UNDEFINED:
1873 	    if (! isCached)
1874 		xmlXPathDebugObjTotalUndefined++;
1875 	    xmlXPathDebugObjCounterUndefined++;
1876 	    if (xmlXPathDebugObjCounterUndefined >
1877 		xmlXPathDebugObjMaxUndefined)
1878 		xmlXPathDebugObjMaxUndefined =
1879 		    xmlXPathDebugObjCounterUndefined;
1880 	    break;
1881 	case XPATH_NODESET:
1882 	    if (! isCached)
1883 		xmlXPathDebugObjTotalNodeset++;
1884 	    xmlXPathDebugObjCounterNodeset++;
1885 	    if (xmlXPathDebugObjCounterNodeset >
1886 		xmlXPathDebugObjMaxNodeset)
1887 		xmlXPathDebugObjMaxNodeset =
1888 		    xmlXPathDebugObjCounterNodeset;
1889 	    break;
1890 	case XPATH_BOOLEAN:
1891 	    if (! isCached)
1892 		xmlXPathDebugObjTotalBool++;
1893 	    xmlXPathDebugObjCounterBool++;
1894 	    if (xmlXPathDebugObjCounterBool >
1895 		xmlXPathDebugObjMaxBool)
1896 		xmlXPathDebugObjMaxBool =
1897 		    xmlXPathDebugObjCounterBool;
1898 	    break;
1899 	case XPATH_NUMBER:
1900 	    if (! isCached)
1901 		xmlXPathDebugObjTotalNumber++;
1902 	    xmlXPathDebugObjCounterNumber++;
1903 	    if (xmlXPathDebugObjCounterNumber >
1904 		xmlXPathDebugObjMaxNumber)
1905 		xmlXPathDebugObjMaxNumber =
1906 		    xmlXPathDebugObjCounterNumber;
1907 	    break;
1908 	case XPATH_STRING:
1909 	    if (! isCached)
1910 		xmlXPathDebugObjTotalString++;
1911 	    xmlXPathDebugObjCounterString++;
1912 	    if (xmlXPathDebugObjCounterString >
1913 		xmlXPathDebugObjMaxString)
1914 		xmlXPathDebugObjMaxString =
1915 		    xmlXPathDebugObjCounterString;
1916 	    break;
1917 	case XPATH_POINT:
1918 	    if (! isCached)
1919 		xmlXPathDebugObjTotalPoint++;
1920 	    xmlXPathDebugObjCounterPoint++;
1921 	    if (xmlXPathDebugObjCounterPoint >
1922 		xmlXPathDebugObjMaxPoint)
1923 		xmlXPathDebugObjMaxPoint =
1924 		    xmlXPathDebugObjCounterPoint;
1925 	    break;
1926 	case XPATH_RANGE:
1927 	    if (! isCached)
1928 		xmlXPathDebugObjTotalRange++;
1929 	    xmlXPathDebugObjCounterRange++;
1930 	    if (xmlXPathDebugObjCounterRange >
1931 		xmlXPathDebugObjMaxRange)
1932 		xmlXPathDebugObjMaxRange =
1933 		    xmlXPathDebugObjCounterRange;
1934 	    break;
1935 	case XPATH_LOCATIONSET:
1936 	    if (! isCached)
1937 		xmlXPathDebugObjTotalLocset++;
1938 	    xmlXPathDebugObjCounterLocset++;
1939 	    if (xmlXPathDebugObjCounterLocset >
1940 		xmlXPathDebugObjMaxLocset)
1941 		xmlXPathDebugObjMaxLocset =
1942 		    xmlXPathDebugObjCounterLocset;
1943 	    break;
1944 	case XPATH_USERS:
1945 	    if (! isCached)
1946 		xmlXPathDebugObjTotalUsers++;
1947 	    xmlXPathDebugObjCounterUsers++;
1948 	    if (xmlXPathDebugObjCounterUsers >
1949 		xmlXPathDebugObjMaxUsers)
1950 		xmlXPathDebugObjMaxUsers =
1951 		    xmlXPathDebugObjCounterUsers;
1952 	    break;
1953 	case XPATH_XSLT_TREE:
1954 	    if (! isCached)
1955 		xmlXPathDebugObjTotalXSLTTree++;
1956 	    xmlXPathDebugObjCounterXSLTTree++;
1957 	    if (xmlXPathDebugObjCounterXSLTTree >
1958 		xmlXPathDebugObjMaxXSLTTree)
1959 		xmlXPathDebugObjMaxXSLTTree =
1960 		    xmlXPathDebugObjCounterXSLTTree;
1961 	    break;
1962 	default:
1963 	    break;
1964     }
1965     if (! isCached)
1966 	xmlXPathDebugObjTotalAll++;
1967     xmlXPathDebugObjCounterAll++;
1968     if (xmlXPathDebugObjCounterAll >
1969 	xmlXPathDebugObjMaxAll)
1970 	xmlXPathDebugObjMaxAll =
1971 	    xmlXPathDebugObjCounterAll;
1972 }
1973 
1974 static void
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,xmlXPathObjectType objType)1975 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1976 			      xmlXPathObjectType objType)
1977 {
1978     int isCached = 0;
1979 
1980     if (ctxt != NULL) {
1981 	if (ctxt->cache != NULL) {
1982 	    xmlXPathContextCachePtr cache =
1983 		(xmlXPathContextCachePtr) ctxt->cache;
1984 
1985 	    isCached = 1;
1986 
1987 	    cache->dbgCachedAll++;
1988 	    switch (objType) {
1989 		case XPATH_UNDEFINED:
1990 		    cache->dbgCachedUndefined++;
1991 		    break;
1992 		case XPATH_NODESET:
1993 		    cache->dbgCachedNodeset++;
1994 		    break;
1995 		case XPATH_BOOLEAN:
1996 		    cache->dbgCachedBool++;
1997 		    break;
1998 		case XPATH_NUMBER:
1999 		    cache->dbgCachedNumber++;
2000 		    break;
2001 		case XPATH_STRING:
2002 		    cache->dbgCachedString++;
2003 		    break;
2004 		case XPATH_POINT:
2005 		    cache->dbgCachedPoint++;
2006 		    break;
2007 		case XPATH_RANGE:
2008 		    cache->dbgCachedRange++;
2009 		    break;
2010 		case XPATH_LOCATIONSET:
2011 		    cache->dbgCachedLocset++;
2012 		    break;
2013 		case XPATH_USERS:
2014 		    cache->dbgCachedUsers++;
2015 		    break;
2016 		case XPATH_XSLT_TREE:
2017 		    cache->dbgCachedXSLTTree++;
2018 		    break;
2019 		default:
2020 		    break;
2021 	    }
2022 
2023 	}
2024     }
2025     switch (objType) {
2026 	case XPATH_UNDEFINED:
2027 	    xmlXPathDebugObjCounterUndefined--;
2028 	    break;
2029 	case XPATH_NODESET:
2030 	    xmlXPathDebugObjCounterNodeset--;
2031 	    break;
2032 	case XPATH_BOOLEAN:
2033 	    xmlXPathDebugObjCounterBool--;
2034 	    break;
2035 	case XPATH_NUMBER:
2036 	    xmlXPathDebugObjCounterNumber--;
2037 	    break;
2038 	case XPATH_STRING:
2039 	    xmlXPathDebugObjCounterString--;
2040 	    break;
2041 	case XPATH_POINT:
2042 	    xmlXPathDebugObjCounterPoint--;
2043 	    break;
2044 	case XPATH_RANGE:
2045 	    xmlXPathDebugObjCounterRange--;
2046 	    break;
2047 	case XPATH_LOCATIONSET:
2048 	    xmlXPathDebugObjCounterLocset--;
2049 	    break;
2050 	case XPATH_USERS:
2051 	    xmlXPathDebugObjCounterUsers--;
2052 	    break;
2053 	case XPATH_XSLT_TREE:
2054 	    xmlXPathDebugObjCounterXSLTTree--;
2055 	    break;
2056 	default:
2057 	    break;
2058     }
2059     xmlXPathDebugObjCounterAll--;
2060 }
2061 
2062 /* REVISIT TODO: Make this static when committing */
2063 static void
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)2064 xmlXPathDebugObjUsageDisplay(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;
2081 
2082     printf("# XPath object usage:\n");
2083 
2084     if (ctxt != NULL) {
2085 	if (ctxt->cache != NULL) {
2086 	    xmlXPathContextCachePtr cache =
2087 		(xmlXPathContextCachePtr) ctxt->cache;
2088 
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;
2103 
2104 	    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;
2111 
2112 	    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     }
2124 
2125     printf("# all\n");
2126     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 
2172 #endif /* LIBXML_DEBUG_ENABLED */
2173 
2174 /************************************************************************
2175  *									*
2176  *			XPath object caching				*
2177  *									*
2178  ************************************************************************/
2179 
2180 /**
2181  * xmlXPathNewCache:
2182  *
2183  * Create a new object cache
2184  *
2185  * Returns the xmlXPathCache just allocated.
2186  */
2187 static xmlXPathContextCachePtr
xmlXPathNewCache(void)2188 xmlXPathNewCache(void)
2189 {
2190     xmlXPathContextCachePtr ret;
2191 
2192     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2193     if (ret == NULL) {
2194         xmlXPathErrMemory(NULL, "creating object cache\n");
2195 	return(NULL);
2196     }
2197     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2198     ret->maxNodeset = 100;
2199     ret->maxString = 100;
2200     ret->maxBoolean = 100;
2201     ret->maxNumber = 100;
2202     ret->maxMisc = 100;
2203     return(ret);
2204 }
2205 
2206 static void
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)2207 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2208 {
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 
2234 static void
xmlXPathFreeCache(xmlXPathContextCachePtr cache)2235 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2236 {
2237     if (cache == NULL)
2238 	return;
2239     if (cache->nodesetObjs)
2240 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2241     if (cache->stringObjs)
2242 	xmlXPathCacheFreeObjectList(cache->stringObjs);
2243     if (cache->booleanObjs)
2244 	xmlXPathCacheFreeObjectList(cache->booleanObjs);
2245     if (cache->numberObjs)
2246 	xmlXPathCacheFreeObjectList(cache->numberObjs);
2247     if (cache->miscObjs)
2248 	xmlXPathCacheFreeObjectList(cache->miscObjs);
2249     xmlFree(cache);
2250 }
2251 
2252 /**
2253  * xmlXPathContextSetCache:
2254  *
2255  * @ctxt:  the XPath context
2256  * @active: enables/disables (creates/frees) the cache
2257  * @value: a value with semantics dependant on @options
2258  * @options: options (currently only the value 0 is used)
2259  *
2260  * Creates/frees an object cache on the XPath context.
2261  * If activates XPath objects (xmlXPathObject) will be cached internally
2262  * 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
2267  *        to be cached per slot
2268  *        There are 5 slots for: node-set, string, number, boolean, and
2269  *        misc objects. Use <0 for the default number (100).
2270  *   Other values for @options have currently no effect.
2271  *
2272  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2273  */
2274 int
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,int active,int value,int options)2275 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2276 			int active,
2277 			int value,
2278 			int options)
2279 {
2280     if (ctxt == NULL)
2281 	return(-1);
2282     if (active) {
2283 	xmlXPathContextCachePtr cache;
2284 
2285 	if (ctxt->cache == NULL) {
2286 	    ctxt->cache = xmlXPathNewCache();
2287 	    if (ctxt->cache == NULL)
2288 		return(-1);
2289 	}
2290 	cache = (xmlXPathContextCachePtr) ctxt->cache;
2291 	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;
2298 	    cache->maxMisc = value;
2299 	}
2300     } else if (ctxt->cache != NULL) {
2301 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2302 	ctxt->cache = NULL;
2303     }
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  */
2317 static xmlXPathObjectPtr
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt,xmlNodeSetPtr val)2318 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2319 {
2320     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2321 	xmlXPathContextCachePtr cache =
2322 	    (xmlXPathContextCachePtr) ctxt->cache;
2323 
2324 	if ((cache->miscObjs != NULL) &&
2325 	    (cache->miscObjs->number != 0))
2326 	{
2327 	    xmlXPathObjectPtr ret;
2328 
2329 	    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
2336 	    return(ret);
2337 	}
2338     }
2339 
2340     return(xmlXPathWrapNodeSet(val));
2341 
2342 }
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  */
2354 static xmlXPathObjectPtr
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt,xmlChar * val)2355 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2356 {
2357     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2358 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2359 
2360 	if ((cache->stringObjs != NULL) &&
2361 	    (cache->stringObjs->number != 0))
2362 	{
2363 
2364 	    xmlXPathObjectPtr ret;
2365 
2366 	    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  */
2406 static xmlXPathObjectPtr
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt,xmlNodePtr val)2407 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2408 {
2409     if ((ctxt != NULL) && (ctxt->cache)) {
2410 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2411 
2412 	if ((cache->nodesetObjs != NULL) &&
2413 	    (cache->nodesetObjs->number != 0))
2414 	{
2415 	    xmlXPathObjectPtr ret;
2416 	    /*
2417 	    * Use the nodset-cache.
2418 	    */
2419 	    ret = (xmlXPathObjectPtr)
2420 		cache->nodesetObjs->items[--cache->nodesetObjs->number];
2421 	    ret->type = XPATH_NODESET;
2422 	    ret->boolval = 0;
2423 	    if (val) {
2424 		if ((ret->nodesetval->nodeMax == 0) ||
2425 		    (val->type == XML_NAMESPACE_DECL))
2426 		{
2427 		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2428 		} else {
2429 		    ret->nodesetval->nodeTab[0] = val;
2430 		    ret->nodesetval->nodeNr = 1;
2431 		}
2432 	    }
2433 #ifdef XP_DEBUG_OBJ_USAGE
2434 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2435 #endif
2436 	    return(ret);
2437 	} else if ((cache->miscObjs != NULL) &&
2438 	    (cache->miscObjs->number != 0))
2439 	{
2440 	    xmlXPathObjectPtr ret;
2441 	    /*
2442 	    * Fallback to misc-cache.
2443 	    */
2444 
2445 	    ret = (xmlXPathObjectPtr)
2446 		cache->miscObjs->items[--cache->miscObjs->number];
2447 
2448 	    ret->type = XPATH_NODESET;
2449 	    ret->boolval = 0;
2450 	    ret->nodesetval = xmlXPathNodeSetCreate(val);
2451 	    if (ret->nodesetval == NULL) {
2452 		ctxt->lastError.domain = XML_FROM_XPATH;
2453 		ctxt->lastError.code = XML_ERR_NO_MEMORY;
2454 		return(NULL);
2455 	    }
2456 #ifdef XP_DEBUG_OBJ_USAGE
2457 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2458 #endif
2459 	    return(ret);
2460 	}
2461     }
2462     return(xmlXPathNewNodeSet(val));
2463 }
2464 
2465 /**
2466  * xmlXPathCacheNewCString:
2467  * @ctxt: the XPath context
2468  * @val:  the char * value
2469  *
2470  * This is the cached version of xmlXPathNewCString().
2471  * Acquire an xmlXPathObjectPtr of type string and of value @val
2472  *
2473  * Returns the created or reused object.
2474  */
2475 static xmlXPathObjectPtr
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt,const char * val)2476 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2477 {
2478     if ((ctxt != NULL) && (ctxt->cache)) {
2479 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2480 
2481 	if ((cache->stringObjs != NULL) &&
2482 	    (cache->stringObjs->number != 0))
2483 	{
2484 	    xmlXPathObjectPtr ret;
2485 
2486 	    ret = (xmlXPathObjectPtr)
2487 		cache->stringObjs->items[--cache->stringObjs->number];
2488 
2489 	    ret->type = XPATH_STRING;
2490 	    ret->stringval = xmlStrdup(BAD_CAST val);
2491 #ifdef XP_DEBUG_OBJ_USAGE
2492 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2493 #endif
2494 	    return(ret);
2495 	} else if ((cache->miscObjs != NULL) &&
2496 	    (cache->miscObjs->number != 0))
2497 	{
2498 	    xmlXPathObjectPtr ret;
2499 
2500 	    ret = (xmlXPathObjectPtr)
2501 		cache->miscObjs->items[--cache->miscObjs->number];
2502 
2503 	    ret->type = XPATH_STRING;
2504 	    ret->stringval = xmlStrdup(BAD_CAST val);
2505 #ifdef XP_DEBUG_OBJ_USAGE
2506 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2507 #endif
2508 	    return(ret);
2509 	}
2510     }
2511     return(xmlXPathNewCString(val));
2512 }
2513 
2514 /**
2515  * xmlXPathCacheNewString:
2516  * @ctxt: the XPath context
2517  * @val:  the xmlChar * value
2518  *
2519  * This is the cached version of xmlXPathNewString().
2520  * Acquire an xmlXPathObjectPtr of type string and of value @val
2521  *
2522  * Returns the created or reused object.
2523  */
2524 static xmlXPathObjectPtr
xmlXPathCacheNewString(xmlXPathContextPtr ctxt,const xmlChar * val)2525 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2526 {
2527     if ((ctxt != NULL) && (ctxt->cache)) {
2528 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2529 
2530 	if ((cache->stringObjs != NULL) &&
2531 	    (cache->stringObjs->number != 0))
2532 	{
2533 	    xmlXPathObjectPtr ret;
2534 
2535 	    ret = (xmlXPathObjectPtr)
2536 		cache->stringObjs->items[--cache->stringObjs->number];
2537 	    ret->type = XPATH_STRING;
2538 	    if (val != NULL)
2539 		ret->stringval = xmlStrdup(val);
2540 	    else
2541 		ret->stringval = xmlStrdup((const xmlChar *)"");
2542 #ifdef XP_DEBUG_OBJ_USAGE
2543 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2544 #endif
2545 	    return(ret);
2546 	} else if ((cache->miscObjs != NULL) &&
2547 	    (cache->miscObjs->number != 0))
2548 	{
2549 	    xmlXPathObjectPtr ret;
2550 
2551 	    ret = (xmlXPathObjectPtr)
2552 		cache->miscObjs->items[--cache->miscObjs->number];
2553 
2554 	    ret->type = XPATH_STRING;
2555 	    if (val != NULL)
2556 		ret->stringval = xmlStrdup(val);
2557 	    else
2558 		ret->stringval = xmlStrdup((const xmlChar *)"");
2559 #ifdef XP_DEBUG_OBJ_USAGE
2560 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2561 #endif
2562 	    return(ret);
2563 	}
2564     }
2565     return(xmlXPathNewString(val));
2566 }
2567 
2568 /**
2569  * xmlXPathCacheNewBoolean:
2570  * @ctxt: the XPath context
2571  * @val:  the boolean value
2572  *
2573  * This is the cached version of xmlXPathNewBoolean().
2574  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2575  *
2576  * Returns the created or reused object.
2577  */
2578 static xmlXPathObjectPtr
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt,int val)2579 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2580 {
2581     if ((ctxt != NULL) && (ctxt->cache)) {
2582 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2583 
2584 	if ((cache->booleanObjs != NULL) &&
2585 	    (cache->booleanObjs->number != 0))
2586 	{
2587 	    xmlXPathObjectPtr ret;
2588 
2589 	    ret = (xmlXPathObjectPtr)
2590 		cache->booleanObjs->items[--cache->booleanObjs->number];
2591 	    ret->type = XPATH_BOOLEAN;
2592 	    ret->boolval = (val != 0);
2593 #ifdef XP_DEBUG_OBJ_USAGE
2594 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2595 #endif
2596 	    return(ret);
2597 	} else if ((cache->miscObjs != NULL) &&
2598 	    (cache->miscObjs->number != 0))
2599 	{
2600 	    xmlXPathObjectPtr ret;
2601 
2602 	    ret = (xmlXPathObjectPtr)
2603 		cache->miscObjs->items[--cache->miscObjs->number];
2604 
2605 	    ret->type = XPATH_BOOLEAN;
2606 	    ret->boolval = (val != 0);
2607 #ifdef XP_DEBUG_OBJ_USAGE
2608 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2609 #endif
2610 	    return(ret);
2611 	}
2612     }
2613     return(xmlXPathNewBoolean(val));
2614 }
2615 
2616 /**
2617  * xmlXPathCacheNewFloat:
2618  * @ctxt: the XPath context
2619  * @val:  the double value
2620  *
2621  * This is the cached version of xmlXPathNewFloat().
2622  * Acquires an xmlXPathObjectPtr of type double and of value @val
2623  *
2624  * Returns the created or reused object.
2625  */
2626 static xmlXPathObjectPtr
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt,double val)2627 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2628 {
2629      if ((ctxt != NULL) && (ctxt->cache)) {
2630 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2631 
2632 	if ((cache->numberObjs != NULL) &&
2633 	    (cache->numberObjs->number != 0))
2634 	{
2635 	    xmlXPathObjectPtr ret;
2636 
2637 	    ret = (xmlXPathObjectPtr)
2638 		cache->numberObjs->items[--cache->numberObjs->number];
2639 	    ret->type = XPATH_NUMBER;
2640 	    ret->floatval = val;
2641 #ifdef XP_DEBUG_OBJ_USAGE
2642 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2643 #endif
2644 	    return(ret);
2645 	} else if ((cache->miscObjs != NULL) &&
2646 	    (cache->miscObjs->number != 0))
2647 	{
2648 	    xmlXPathObjectPtr ret;
2649 
2650 	    ret = (xmlXPathObjectPtr)
2651 		cache->miscObjs->items[--cache->miscObjs->number];
2652 
2653 	    ret->type = XPATH_NUMBER;
2654 	    ret->floatval = val;
2655 #ifdef XP_DEBUG_OBJ_USAGE
2656 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2657 #endif
2658 	    return(ret);
2659 	}
2660     }
2661     return(xmlXPathNewFloat(val));
2662 }
2663 
2664 /**
2665  * xmlXPathCacheConvertString:
2666  * @ctxt: the XPath context
2667  * @val:  an XPath object
2668  *
2669  * This is the cached version of xmlXPathConvertString().
2670  * Converts an existing object to its string() equivalent
2671  *
2672  * Returns a created or reused object, the old one is freed (cached)
2673  *         (or the operation is done directly on @val)
2674  */
2675 
2676 static xmlXPathObjectPtr
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2677 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2678     xmlChar *res = NULL;
2679 
2680     if (val == NULL)
2681 	return(xmlXPathCacheNewCString(ctxt, ""));
2682 
2683     switch (val->type) {
2684     case XPATH_UNDEFINED:
2685 #ifdef DEBUG_EXPR
2686 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2687 #endif
2688 	break;
2689     case XPATH_NODESET:
2690     case XPATH_XSLT_TREE:
2691 	res = xmlXPathCastNodeSetToString(val->nodesetval);
2692 	break;
2693     case XPATH_STRING:
2694 	return(val);
2695     case XPATH_BOOLEAN:
2696 	res = xmlXPathCastBooleanToString(val->boolval);
2697 	break;
2698     case XPATH_NUMBER:
2699 	res = xmlXPathCastNumberToString(val->floatval);
2700 	break;
2701     case XPATH_USERS:
2702     case XPATH_POINT:
2703     case XPATH_RANGE:
2704     case XPATH_LOCATIONSET:
2705 	TODO;
2706 	break;
2707     }
2708     xmlXPathReleaseObject(ctxt, val);
2709     if (res == NULL)
2710 	return(xmlXPathCacheNewCString(ctxt, ""));
2711     return(xmlXPathCacheWrapString(ctxt, res));
2712 }
2713 
2714 /**
2715  * xmlXPathCacheObjectCopy:
2716  * @ctxt: the XPath context
2717  * @val:  the original object
2718  *
2719  * This is the cached version of xmlXPathObjectCopy().
2720  * Acquire a copy of a given object
2721  *
2722  * Returns a created or reused created object.
2723  */
2724 static xmlXPathObjectPtr
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2725 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2726 {
2727     if (val == NULL)
2728 	return(NULL);
2729 
2730     if (XP_HAS_CACHE(ctxt)) {
2731 	switch (val->type) {
2732 	    case XPATH_NODESET:
2733 		return(xmlXPathCacheWrapNodeSet(ctxt,
2734 		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2735 	    case XPATH_STRING:
2736 		return(xmlXPathCacheNewString(ctxt, val->stringval));
2737 	    case XPATH_BOOLEAN:
2738 		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2739 	    case XPATH_NUMBER:
2740 		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2741 	    default:
2742 		break;
2743 	}
2744     }
2745     return(xmlXPathObjectCopy(val));
2746 }
2747 
2748 /**
2749  * xmlXPathCacheConvertBoolean:
2750  * @ctxt: the XPath context
2751  * @val:  an XPath object
2752  *
2753  * This is the cached version of xmlXPathConvertBoolean().
2754  * Converts an existing object to its boolean() equivalent
2755  *
2756  * Returns a created or reused object, the old one is freed (or the operation
2757  *         is done directly on @val)
2758  */
2759 static xmlXPathObjectPtr
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2760 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2761     xmlXPathObjectPtr ret;
2762 
2763     if (val == NULL)
2764 	return(xmlXPathCacheNewBoolean(ctxt, 0));
2765     if (val->type == XPATH_BOOLEAN)
2766 	return(val);
2767     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2768     xmlXPathReleaseObject(ctxt, val);
2769     return(ret);
2770 }
2771 
2772 /**
2773  * xmlXPathCacheConvertNumber:
2774  * @ctxt: the XPath context
2775  * @val:  an XPath object
2776  *
2777  * This is the cached version of xmlXPathConvertNumber().
2778  * Converts an existing object to its number() equivalent
2779  *
2780  * Returns a created or reused object, the old one is freed (or the operation
2781  *         is done directly on @val)
2782  */
2783 static xmlXPathObjectPtr
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2784 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2785     xmlXPathObjectPtr ret;
2786 
2787     if (val == NULL)
2788 	return(xmlXPathCacheNewFloat(ctxt, 0.0));
2789     if (val->type == XPATH_NUMBER)
2790 	return(val);
2791     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2792     xmlXPathReleaseObject(ctxt, val);
2793     return(ret);
2794 }
2795 
2796 /************************************************************************
2797  *									*
2798  *		Parser stacks related functions and macros		*
2799  *									*
2800  ************************************************************************/
2801 
2802 /**
2803  * xmlXPathSetFrame:
2804  * @ctxt: an XPath parser context
2805  *
2806  * Set the callee evaluation frame
2807  *
2808  * Returns the previous frame value to be restored once done
2809  */
2810 static int
xmlXPathSetFrame(xmlXPathParserContextPtr ctxt)2811 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2812     int ret;
2813 
2814     if (ctxt == NULL)
2815         return(0);
2816     ret = ctxt->valueFrame;
2817     ctxt->valueFrame = ctxt->valueNr;
2818     return(ret);
2819 }
2820 
2821 /**
2822  * xmlXPathPopFrame:
2823  * @ctxt: an XPath parser context
2824  * @frame: the previous frame value
2825  *
2826  * Remove the callee evaluation frame
2827  */
2828 static void
xmlXPathPopFrame(xmlXPathParserContextPtr ctxt,int frame)2829 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2830     if (ctxt == NULL)
2831         return;
2832     if (ctxt->valueNr < ctxt->valueFrame) {
2833         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2834     }
2835     ctxt->valueFrame = frame;
2836 }
2837 
2838 /**
2839  * valuePop:
2840  * @ctxt: an XPath evaluation context
2841  *
2842  * Pops the top XPath object from the value stack
2843  *
2844  * Returns the XPath object just removed
2845  */
2846 xmlXPathObjectPtr
valuePop(xmlXPathParserContextPtr ctxt)2847 valuePop(xmlXPathParserContextPtr ctxt)
2848 {
2849     xmlXPathObjectPtr ret;
2850 
2851     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2852         return (NULL);
2853 
2854     if (ctxt->valueNr <= ctxt->valueFrame) {
2855         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2856         return (NULL);
2857     }
2858 
2859     ctxt->valueNr--;
2860     if (ctxt->valueNr > 0)
2861         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2862     else
2863         ctxt->value = NULL;
2864     ret = ctxt->valueTab[ctxt->valueNr];
2865     ctxt->valueTab[ctxt->valueNr] = NULL;
2866     return (ret);
2867 }
2868 /**
2869  * valuePush:
2870  * @ctxt:  an XPath evaluation context
2871  * @value:  the XPath object
2872  *
2873  * Pushes a new XPath object on top of the value stack
2874  *
2875  * returns the number of items on the value stack
2876  */
2877 int
valuePush(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr value)2878 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2879 {
2880     if ((ctxt == NULL) || (value == NULL)) return(-1);
2881     if (ctxt->valueNr >= ctxt->valueMax) {
2882         xmlXPathObjectPtr *tmp;
2883 
2884         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2885             xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2886             ctxt->error = XPATH_MEMORY_ERROR;
2887             return (0);
2888         }
2889         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2890                                              2 * ctxt->valueMax *
2891                                              sizeof(ctxt->valueTab[0]));
2892         if (tmp == NULL) {
2893             xmlXPathErrMemory(NULL, "pushing value\n");
2894             ctxt->error = XPATH_MEMORY_ERROR;
2895             return (0);
2896         }
2897         ctxt->valueMax *= 2;
2898 	ctxt->valueTab = tmp;
2899     }
2900     ctxt->valueTab[ctxt->valueNr] = value;
2901     ctxt->value = value;
2902     return (ctxt->valueNr++);
2903 }
2904 
2905 /**
2906  * xmlXPathPopBoolean:
2907  * @ctxt:  an XPath parser context
2908  *
2909  * Pops a boolean from the stack, handling conversion if needed.
2910  * Check error with #xmlXPathCheckError.
2911  *
2912  * Returns the boolean
2913  */
2914 int
xmlXPathPopBoolean(xmlXPathParserContextPtr ctxt)2915 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2916     xmlXPathObjectPtr obj;
2917     int ret;
2918 
2919     obj = valuePop(ctxt);
2920     if (obj == NULL) {
2921 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2922 	return(0);
2923     }
2924     if (obj->type != XPATH_BOOLEAN)
2925 	ret = xmlXPathCastToBoolean(obj);
2926     else
2927         ret = obj->boolval;
2928     xmlXPathReleaseObject(ctxt->context, obj);
2929     return(ret);
2930 }
2931 
2932 /**
2933  * xmlXPathPopNumber:
2934  * @ctxt:  an XPath parser context
2935  *
2936  * Pops a number from the stack, handling conversion if needed.
2937  * Check error with #xmlXPathCheckError.
2938  *
2939  * Returns the number
2940  */
2941 double
xmlXPathPopNumber(xmlXPathParserContextPtr ctxt)2942 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2943     xmlXPathObjectPtr obj;
2944     double ret;
2945 
2946     obj = valuePop(ctxt);
2947     if (obj == NULL) {
2948 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2949 	return(0);
2950     }
2951     if (obj->type != XPATH_NUMBER)
2952 	ret = xmlXPathCastToNumber(obj);
2953     else
2954         ret = obj->floatval;
2955     xmlXPathReleaseObject(ctxt->context, obj);
2956     return(ret);
2957 }
2958 
2959 /**
2960  * xmlXPathPopString:
2961  * @ctxt:  an XPath parser context
2962  *
2963  * Pops a string from the stack, handling conversion if needed.
2964  * Check error with #xmlXPathCheckError.
2965  *
2966  * Returns the string
2967  */
2968 xmlChar *
xmlXPathPopString(xmlXPathParserContextPtr ctxt)2969 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2970     xmlXPathObjectPtr obj;
2971     xmlChar * ret;
2972 
2973     obj = valuePop(ctxt);
2974     if (obj == NULL) {
2975 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2976 	return(NULL);
2977     }
2978     ret = xmlXPathCastToString(obj);	/* this does required strdup */
2979     /* TODO: needs refactoring somewhere else */
2980     if (obj->stringval == ret)
2981 	obj->stringval = NULL;
2982     xmlXPathReleaseObject(ctxt->context, obj);
2983     return(ret);
2984 }
2985 
2986 /**
2987  * xmlXPathPopNodeSet:
2988  * @ctxt:  an XPath parser context
2989  *
2990  * Pops a node-set from the stack, handling conversion if needed.
2991  * Check error with #xmlXPathCheckError.
2992  *
2993  * Returns the node-set
2994  */
2995 xmlNodeSetPtr
xmlXPathPopNodeSet(xmlXPathParserContextPtr ctxt)2996 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2997     xmlXPathObjectPtr obj;
2998     xmlNodeSetPtr ret;
2999 
3000     if (ctxt == NULL) return(NULL);
3001     if (ctxt->value == NULL) {
3002 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3003 	return(NULL);
3004     }
3005     if (!xmlXPathStackIsNodeSet(ctxt)) {
3006 	xmlXPathSetTypeError(ctxt);
3007 	return(NULL);
3008     }
3009     obj = valuePop(ctxt);
3010     ret = obj->nodesetval;
3011 #if 0
3012     /* to fix memory leak of not clearing obj->user */
3013     if (obj->boolval && obj->user != NULL)
3014         xmlFreeNodeList((xmlNodePtr) obj->user);
3015 #endif
3016     obj->nodesetval = NULL;
3017     xmlXPathReleaseObject(ctxt->context, obj);
3018     return(ret);
3019 }
3020 
3021 /**
3022  * xmlXPathPopExternal:
3023  * @ctxt:  an XPath parser context
3024  *
3025  * Pops an external object from the stack, handling conversion if needed.
3026  * Check error with #xmlXPathCheckError.
3027  *
3028  * Returns the object
3029  */
3030 void *
xmlXPathPopExternal(xmlXPathParserContextPtr ctxt)3031 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3032     xmlXPathObjectPtr obj;
3033     void * ret;
3034 
3035     if ((ctxt == NULL) || (ctxt->value == NULL)) {
3036 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3037 	return(NULL);
3038     }
3039     if (ctxt->value->type != XPATH_USERS) {
3040 	xmlXPathSetTypeError(ctxt);
3041 	return(NULL);
3042     }
3043     obj = valuePop(ctxt);
3044     ret = obj->user;
3045     obj->user = NULL;
3046     xmlXPathReleaseObject(ctxt->context, obj);
3047     return(ret);
3048 }
3049 
3050 /*
3051  * Macros for accessing the content. Those should be used only by the parser,
3052  * and not exported.
3053  *
3054  * Dirty macros, i.e. one need to make assumption on the context to use them
3055  *
3056  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3057  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3058  *           in ISO-Latin or UTF-8.
3059  *           This should be used internally by the parser
3060  *           only to compare to ASCII values otherwise it would break when
3061  *           running with UTF-8 encoding.
3062  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3063  *           to compare on ASCII based substring.
3064  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3065  *           strings within the parser.
3066  *   CURRENT Returns the current char value, with the full decoding of
3067  *           UTF-8 if we are using this mode. It returns an int.
3068  *   NEXT    Skip to the next character, this does the proper decoding
3069  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3070  *           It returns the pointer to the current xmlChar.
3071  */
3072 
3073 #define CUR (*ctxt->cur)
3074 #define SKIP(val) ctxt->cur += (val)
3075 #define NXT(val) ctxt->cur[(val)]
3076 #define CUR_PTR ctxt->cur
3077 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3078 
3079 #define COPY_BUF(l,b,i,v)                                              \
3080     if (l == 1) b[i++] = (xmlChar) v;                                  \
3081     else i += xmlCopyChar(l,&b[i],v)
3082 
3083 #define NEXTL(l)  ctxt->cur += l
3084 
3085 #define SKIP_BLANKS							\
3086     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3087 
3088 #define CURRENT (*ctxt->cur)
3089 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3090 
3091 
3092 #ifndef DBL_DIG
3093 #define DBL_DIG 16
3094 #endif
3095 #ifndef DBL_EPSILON
3096 #define DBL_EPSILON 1E-9
3097 #endif
3098 
3099 #define UPPER_DOUBLE 1E9
3100 #define LOWER_DOUBLE 1E-5
3101 #define	LOWER_DOUBLE_EXP 5
3102 
3103 #define INTEGER_DIGITS DBL_DIG
3104 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3105 #define EXPONENT_DIGITS (3 + 2)
3106 
3107 /**
3108  * xmlXPathFormatNumber:
3109  * @number:     number to format
3110  * @buffer:     output buffer
3111  * @buffersize: size of output buffer
3112  *
3113  * Convert the number into a string representation.
3114  */
3115 static void
xmlXPathFormatNumber(double number,char buffer[],int buffersize)3116 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3117 {
3118     switch (xmlXPathIsInf(number)) {
3119     case 1:
3120 	if (buffersize > (int)sizeof("Infinity"))
3121 	    snprintf(buffer, buffersize, "Infinity");
3122 	break;
3123     case -1:
3124 	if (buffersize > (int)sizeof("-Infinity"))
3125 	    snprintf(buffer, buffersize, "-Infinity");
3126 	break;
3127     default:
3128 	if (xmlXPathIsNaN(number)) {
3129 	    if (buffersize > (int)sizeof("NaN"))
3130 		snprintf(buffer, buffersize, "NaN");
3131 	} else if (number == 0) {
3132             /* Omit sign for negative zero. */
3133 	    snprintf(buffer, buffersize, "0");
3134 	} else if ((number > INT_MIN) && (number < INT_MAX) &&
3135                    (number == (int) number)) {
3136 	    char work[30];
3137 	    char *ptr, *cur;
3138 	    int value = (int) number;
3139 
3140             ptr = &buffer[0];
3141 	    if (value == 0) {
3142 		*ptr++ = '0';
3143 	    } else {
3144 		snprintf(work, 29, "%d", value);
3145 		cur = &work[0];
3146 		while ((*cur) && (ptr - buffer < buffersize)) {
3147 		    *ptr++ = *cur++;
3148 		}
3149 	    }
3150 	    if (ptr - buffer < buffersize) {
3151 		*ptr = 0;
3152 	    } else if (buffersize > 0) {
3153 		ptr--;
3154 		*ptr = 0;
3155 	    }
3156 	} else {
3157 	    /*
3158 	      For the dimension of work,
3159 	          DBL_DIG is number of significant digits
3160 		  EXPONENT is only needed for "scientific notation"
3161 	          3 is sign, decimal point, and terminating zero
3162 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3163 	      Note that this dimension is slightly (a few characters)
3164 	      larger than actually necessary.
3165 	    */
3166 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3167 	    int integer_place, fraction_place;
3168 	    char *ptr;
3169 	    char *after_fraction;
3170 	    double absolute_value;
3171 	    int size;
3172 
3173 	    absolute_value = fabs(number);
3174 
3175 	    /*
3176 	     * First choose format - scientific or regular floating point.
3177 	     * In either case, result is in work, and after_fraction points
3178 	     * just past the fractional part.
3179 	    */
3180 	    if ( ((absolute_value > UPPER_DOUBLE) ||
3181 		  (absolute_value < LOWER_DOUBLE)) &&
3182 		 (absolute_value != 0.0) ) {
3183 		/* Use scientific notation */
3184 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3185 		fraction_place = DBL_DIG - 1;
3186 		size = snprintf(work, sizeof(work),"%*.*e",
3187 			 integer_place, fraction_place, number);
3188 		while ((size > 0) && (work[size] != 'e')) size--;
3189 
3190 	    }
3191 	    else {
3192 		/* Use regular notation */
3193 		if (absolute_value > 0.0) {
3194 		    integer_place = (int)log10(absolute_value);
3195 		    if (integer_place > 0)
3196 		        fraction_place = DBL_DIG - integer_place - 1;
3197 		    else
3198 		        fraction_place = DBL_DIG - integer_place;
3199 		} else {
3200 		    fraction_place = 1;
3201 		}
3202 		size = snprintf(work, sizeof(work), "%0.*f",
3203 				fraction_place, number);
3204 	    }
3205 
3206 	    /* Remove leading spaces sometimes inserted by snprintf */
3207 	    while (work[0] == ' ') {
3208 	        for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3209 		size--;
3210 	    }
3211 
3212 	    /* Remove fractional trailing zeroes */
3213 	    after_fraction = work + size;
3214 	    ptr = after_fraction;
3215 	    while (*(--ptr) == '0')
3216 		;
3217 	    if (*ptr != '.')
3218 	        ptr++;
3219 	    while ((*ptr++ = *after_fraction++) != 0);
3220 
3221 	    /* Finally copy result back to caller */
3222 	    size = strlen(work) + 1;
3223 	    if (size > buffersize) {
3224 		work[buffersize - 1] = 0;
3225 		size = buffersize;
3226 	    }
3227 	    memmove(buffer, work, size);
3228 	}
3229 	break;
3230     }
3231 }
3232 
3233 
3234 /************************************************************************
3235  *									*
3236  *			Routines to handle NodeSets			*
3237  *									*
3238  ************************************************************************/
3239 
3240 /**
3241  * xmlXPathOrderDocElems:
3242  * @doc:  an input document
3243  *
3244  * Call this routine to speed up XPath computation on static documents.
3245  * This stamps all the element nodes with the document order
3246  * Like for line information, the order is kept in the element->content
3247  * field, the value stored is actually - the node number (starting at -1)
3248  * to be able to differentiate from line numbers.
3249  *
3250  * Returns the number of elements found in the document or -1 in case
3251  *    of error.
3252  */
3253 long
xmlXPathOrderDocElems(xmlDocPtr doc)3254 xmlXPathOrderDocElems(xmlDocPtr doc) {
3255     ptrdiff_t count = 0;
3256     xmlNodePtr cur;
3257 
3258     if (doc == NULL)
3259 	return(-1);
3260     cur = doc->children;
3261     while (cur != NULL) {
3262 	if (cur->type == XML_ELEMENT_NODE) {
3263 	    cur->content = (void *) (-(++count));
3264 	    if (cur->children != NULL) {
3265 		cur = cur->children;
3266 		continue;
3267 	    }
3268 	}
3269 	if (cur->next != NULL) {
3270 	    cur = cur->next;
3271 	    continue;
3272 	}
3273 	do {
3274 	    cur = cur->parent;
3275 	    if (cur == NULL)
3276 		break;
3277 	    if (cur == (xmlNodePtr) doc) {
3278 		cur = NULL;
3279 		break;
3280 	    }
3281 	    if (cur->next != NULL) {
3282 		cur = cur->next;
3283 		break;
3284 	    }
3285 	} while (cur != NULL);
3286     }
3287     return((long) count);
3288 }
3289 
3290 /**
3291  * xmlXPathCmpNodes:
3292  * @node1:  the first node
3293  * @node2:  the second node
3294  *
3295  * Compare two nodes w.r.t document order
3296  *
3297  * Returns -2 in case of error 1 if first point < second point, 0 if
3298  *         it's the same node, -1 otherwise
3299  */
3300 int
xmlXPathCmpNodes(xmlNodePtr node1,xmlNodePtr node2)3301 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3302     int depth1, depth2;
3303     int attr1 = 0, attr2 = 0;
3304     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3305     xmlNodePtr cur, root;
3306 
3307     if ((node1 == NULL) || (node2 == NULL))
3308 	return(-2);
3309     /*
3310      * a couple of optimizations which will avoid computations in most cases
3311      */
3312     if (node1 == node2)		/* trivial case */
3313 	return(0);
3314     if (node1->type == XML_ATTRIBUTE_NODE) {
3315 	attr1 = 1;
3316 	attrNode1 = node1;
3317 	node1 = node1->parent;
3318     }
3319     if (node2->type == XML_ATTRIBUTE_NODE) {
3320 	attr2 = 1;
3321 	attrNode2 = node2;
3322 	node2 = node2->parent;
3323     }
3324     if (node1 == node2) {
3325 	if (attr1 == attr2) {
3326 	    /* not required, but we keep attributes in order */
3327 	    if (attr1 != 0) {
3328 	        cur = attrNode2->prev;
3329 		while (cur != NULL) {
3330 		    if (cur == attrNode1)
3331 		        return (1);
3332 		    cur = cur->prev;
3333 		}
3334 		return (-1);
3335 	    }
3336 	    return(0);
3337 	}
3338 	if (attr2 == 1)
3339 	    return(1);
3340 	return(-1);
3341     }
3342     if ((node1->type == XML_NAMESPACE_DECL) ||
3343         (node2->type == XML_NAMESPACE_DECL))
3344 	return(1);
3345     if (node1 == node2->prev)
3346 	return(1);
3347     if (node1 == node2->next)
3348 	return(-1);
3349 
3350     /*
3351      * Speedup using document order if availble.
3352      */
3353     if ((node1->type == XML_ELEMENT_NODE) &&
3354 	(node2->type == XML_ELEMENT_NODE) &&
3355 	(0 > (ptrdiff_t) node1->content) &&
3356 	(0 > (ptrdiff_t) node2->content) &&
3357 	(node1->doc == node2->doc)) {
3358 	ptrdiff_t l1, l2;
3359 
3360 	l1 = -((ptrdiff_t) node1->content);
3361 	l2 = -((ptrdiff_t) node2->content);
3362 	if (l1 < l2)
3363 	    return(1);
3364 	if (l1 > l2)
3365 	    return(-1);
3366     }
3367 
3368     /*
3369      * compute depth to root
3370      */
3371     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3372 	if (cur->parent == node1)
3373 	    return(1);
3374 	depth2++;
3375     }
3376     root = cur;
3377     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3378 	if (cur->parent == node2)
3379 	    return(-1);
3380 	depth1++;
3381     }
3382     /*
3383      * Distinct document (or distinct entities :-( ) case.
3384      */
3385     if (root != cur) {
3386 	return(-2);
3387     }
3388     /*
3389      * get the nearest common ancestor.
3390      */
3391     while (depth1 > depth2) {
3392 	depth1--;
3393 	node1 = node1->parent;
3394     }
3395     while (depth2 > depth1) {
3396 	depth2--;
3397 	node2 = node2->parent;
3398     }
3399     while (node1->parent != node2->parent) {
3400 	node1 = node1->parent;
3401 	node2 = node2->parent;
3402 	/* should not happen but just in case ... */
3403 	if ((node1 == NULL) || (node2 == NULL))
3404 	    return(-2);
3405     }
3406     /*
3407      * Find who's first.
3408      */
3409     if (node1 == node2->prev)
3410 	return(1);
3411     if (node1 == node2->next)
3412 	return(-1);
3413     /*
3414      * Speedup using document order if availble.
3415      */
3416     if ((node1->type == XML_ELEMENT_NODE) &&
3417 	(node2->type == XML_ELEMENT_NODE) &&
3418 	(0 > (ptrdiff_t) node1->content) &&
3419 	(0 > (ptrdiff_t) node2->content) &&
3420 	(node1->doc == node2->doc)) {
3421 	ptrdiff_t l1, l2;
3422 
3423 	l1 = -((ptrdiff_t) node1->content);
3424 	l2 = -((ptrdiff_t) node2->content);
3425 	if (l1 < l2)
3426 	    return(1);
3427 	if (l1 > l2)
3428 	    return(-1);
3429     }
3430 
3431     for (cur = node1->next;cur != NULL;cur = cur->next)
3432 	if (cur == node2)
3433 	    return(1);
3434     return(-1); /* assume there is no sibling list corruption */
3435 }
3436 
3437 /**
3438  * xmlXPathNodeSetSort:
3439  * @set:  the node set
3440  *
3441  * Sort the node set in document order
3442  */
3443 void
xmlXPathNodeSetSort(xmlNodeSetPtr set)3444 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3445 #ifndef WITH_TIM_SORT
3446     int i, j, incr, len;
3447     xmlNodePtr tmp;
3448 #endif
3449 
3450     if (set == NULL)
3451 	return;
3452 
3453 #ifndef WITH_TIM_SORT
3454     /*
3455      * Use the old Shell's sort implementation to sort the node-set
3456      * Timsort ought to be quite faster
3457      */
3458     len = set->nodeNr;
3459     for (incr = len / 2; incr > 0; incr /= 2) {
3460 	for (i = incr; i < len; i++) {
3461 	    j = i - incr;
3462 	    while (j >= 0) {
3463 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3464 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
3465 			set->nodeTab[j + incr]) == -1)
3466 #else
3467 		if (xmlXPathCmpNodes(set->nodeTab[j],
3468 			set->nodeTab[j + incr]) == -1)
3469 #endif
3470 		{
3471 		    tmp = set->nodeTab[j];
3472 		    set->nodeTab[j] = set->nodeTab[j + incr];
3473 		    set->nodeTab[j + incr] = tmp;
3474 		    j -= incr;
3475 		} else
3476 		    break;
3477 	    }
3478 	}
3479     }
3480 #else /* WITH_TIM_SORT */
3481     libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3482 #endif /* WITH_TIM_SORT */
3483 }
3484 
3485 #define XML_NODESET_DEFAULT	10
3486 /**
3487  * xmlXPathNodeSetDupNs:
3488  * @node:  the parent node of the namespace XPath node
3489  * @ns:  the libxml namespace declaration node.
3490  *
3491  * Namespace node in libxml don't match the XPath semantic. In a node set
3492  * the namespace nodes are duplicated and the next pointer is set to the
3493  * parent node in the XPath semantic.
3494  *
3495  * Returns the newly created object.
3496  */
3497 static xmlNodePtr
xmlXPathNodeSetDupNs(xmlNodePtr node,xmlNsPtr ns)3498 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3499     xmlNsPtr cur;
3500 
3501     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3502 	return(NULL);
3503     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3504 	return((xmlNodePtr) ns);
3505 
3506     /*
3507      * Allocate a new Namespace and fill the fields.
3508      */
3509     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3510     if (cur == NULL) {
3511         xmlXPathErrMemory(NULL, "duplicating namespace\n");
3512 	return(NULL);
3513     }
3514     memset(cur, 0, sizeof(xmlNs));
3515     cur->type = XML_NAMESPACE_DECL;
3516     if (ns->href != NULL)
3517 	cur->href = xmlStrdup(ns->href);
3518     if (ns->prefix != NULL)
3519 	cur->prefix = xmlStrdup(ns->prefix);
3520     cur->next = (xmlNsPtr) node;
3521     return((xmlNodePtr) cur);
3522 }
3523 
3524 /**
3525  * xmlXPathNodeSetFreeNs:
3526  * @ns:  the XPath namespace node found in a nodeset.
3527  *
3528  * Namespace nodes in libxml don't match the XPath semantic. In a node set
3529  * the namespace nodes are duplicated and the next pointer is set to the
3530  * parent node in the XPath semantic. Check if such a node needs to be freed
3531  */
3532 void
xmlXPathNodeSetFreeNs(xmlNsPtr ns)3533 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3534     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3535 	return;
3536 
3537     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3538 	if (ns->href != NULL)
3539 	    xmlFree((xmlChar *)ns->href);
3540 	if (ns->prefix != NULL)
3541 	    xmlFree((xmlChar *)ns->prefix);
3542 	xmlFree(ns);
3543     }
3544 }
3545 
3546 /**
3547  * xmlXPathNodeSetCreate:
3548  * @val:  an initial xmlNodePtr, or NULL
3549  *
3550  * Create a new xmlNodeSetPtr of type double and of value @val
3551  *
3552  * Returns the newly created object.
3553  */
3554 xmlNodeSetPtr
xmlXPathNodeSetCreate(xmlNodePtr val)3555 xmlXPathNodeSetCreate(xmlNodePtr val) {
3556     xmlNodeSetPtr ret;
3557 
3558     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3559     if (ret == NULL) {
3560         xmlXPathErrMemory(NULL, "creating nodeset\n");
3561 	return(NULL);
3562     }
3563     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3564     if (val != NULL) {
3565         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3566 					     sizeof(xmlNodePtr));
3567 	if (ret->nodeTab == NULL) {
3568 	    xmlXPathErrMemory(NULL, "creating nodeset\n");
3569 	    xmlFree(ret);
3570 	    return(NULL);
3571 	}
3572 	memset(ret->nodeTab, 0 ,
3573 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3574         ret->nodeMax = XML_NODESET_DEFAULT;
3575 	if (val->type == XML_NAMESPACE_DECL) {
3576 	    xmlNsPtr ns = (xmlNsPtr) val;
3577 
3578 	    ret->nodeTab[ret->nodeNr++] =
3579 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3580 	} else
3581 	    ret->nodeTab[ret->nodeNr++] = val;
3582     }
3583     return(ret);
3584 }
3585 
3586 /**
3587  * xmlXPathNodeSetCreateSize:
3588  * @size:  the initial size of the set
3589  *
3590  * Create a new xmlNodeSetPtr of type double and of value @val
3591  *
3592  * Returns the newly created object.
3593  */
3594 static xmlNodeSetPtr
xmlXPathNodeSetCreateSize(int size)3595 xmlXPathNodeSetCreateSize(int size) {
3596     xmlNodeSetPtr ret;
3597 
3598     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3599     if (ret == NULL) {
3600         xmlXPathErrMemory(NULL, "creating nodeset\n");
3601 	return(NULL);
3602     }
3603     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3604     if (size < XML_NODESET_DEFAULT)
3605 	size = XML_NODESET_DEFAULT;
3606     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3607     if (ret->nodeTab == NULL) {
3608 	xmlXPathErrMemory(NULL, "creating nodeset\n");
3609 	xmlFree(ret);
3610 	return(NULL);
3611     }
3612     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3613     ret->nodeMax = size;
3614     return(ret);
3615 }
3616 
3617 /**
3618  * xmlXPathNodeSetContains:
3619  * @cur:  the node-set
3620  * @val:  the node
3621  *
3622  * checks whether @cur contains @val
3623  *
3624  * Returns true (1) if @cur contains @val, false (0) otherwise
3625  */
3626 int
xmlXPathNodeSetContains(xmlNodeSetPtr cur,xmlNodePtr val)3627 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3628     int i;
3629 
3630     if ((cur == NULL) || (val == NULL)) return(0);
3631     if (val->type == XML_NAMESPACE_DECL) {
3632 	for (i = 0; i < cur->nodeNr; i++) {
3633 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3634 		xmlNsPtr ns1, ns2;
3635 
3636 		ns1 = (xmlNsPtr) val;
3637 		ns2 = (xmlNsPtr) cur->nodeTab[i];
3638 		if (ns1 == ns2)
3639 		    return(1);
3640 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3641 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
3642 		    return(1);
3643 	    }
3644 	}
3645     } else {
3646 	for (i = 0; i < cur->nodeNr; i++) {
3647 	    if (cur->nodeTab[i] == val)
3648 		return(1);
3649 	}
3650     }
3651     return(0);
3652 }
3653 
3654 /**
3655  * xmlXPathNodeSetAddNs:
3656  * @cur:  the initial node set
3657  * @node:  the hosting node
3658  * @ns:  a the namespace node
3659  *
3660  * add a new namespace node to an existing NodeSet
3661  *
3662  * Returns 0 in case of success and -1 in case of error
3663  */
3664 int
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur,xmlNodePtr node,xmlNsPtr ns)3665 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3666     int i;
3667 
3668 
3669     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3670         (ns->type != XML_NAMESPACE_DECL) ||
3671 	(node->type != XML_ELEMENT_NODE))
3672 	return(-1);
3673 
3674     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3675     /*
3676      * prevent duplicates
3677      */
3678     for (i = 0;i < cur->nodeNr;i++) {
3679         if ((cur->nodeTab[i] != NULL) &&
3680 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3681 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3682 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3683 	    return(0);
3684     }
3685 
3686     /*
3687      * grow the nodeTab if needed
3688      */
3689     if (cur->nodeMax == 0) {
3690         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3691 					     sizeof(xmlNodePtr));
3692 	if (cur->nodeTab == NULL) {
3693 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3694 	    return(-1);
3695 	}
3696 	memset(cur->nodeTab, 0 ,
3697 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3698         cur->nodeMax = XML_NODESET_DEFAULT;
3699     } else if (cur->nodeNr == cur->nodeMax) {
3700         xmlNodePtr *temp;
3701 
3702         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3703             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3704             return(-1);
3705         }
3706 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3707 				      sizeof(xmlNodePtr));
3708 	if (temp == NULL) {
3709 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3710 	    return(-1);
3711 	}
3712         cur->nodeMax *= 2;
3713 	cur->nodeTab = temp;
3714     }
3715     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3716     return(0);
3717 }
3718 
3719 /**
3720  * xmlXPathNodeSetAdd:
3721  * @cur:  the initial node set
3722  * @val:  a new xmlNodePtr
3723  *
3724  * add a new xmlNodePtr to an existing NodeSet
3725  *
3726  * Returns 0 in case of success, and -1 in case of error
3727  */
3728 int
xmlXPathNodeSetAdd(xmlNodeSetPtr cur,xmlNodePtr val)3729 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3730     int i;
3731 
3732     if ((cur == NULL) || (val == NULL)) return(-1);
3733 
3734     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3735     /*
3736      * prevent duplicates
3737      */
3738     for (i = 0;i < cur->nodeNr;i++)
3739         if (cur->nodeTab[i] == val) return(0);
3740 
3741     /*
3742      * grow the nodeTab if needed
3743      */
3744     if (cur->nodeMax == 0) {
3745         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3746 					     sizeof(xmlNodePtr));
3747 	if (cur->nodeTab == NULL) {
3748 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3749 	    return(-1);
3750 	}
3751 	memset(cur->nodeTab, 0 ,
3752 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3753         cur->nodeMax = XML_NODESET_DEFAULT;
3754     } else if (cur->nodeNr == cur->nodeMax) {
3755         xmlNodePtr *temp;
3756 
3757         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3758             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3759             return(-1);
3760         }
3761 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3762 				      sizeof(xmlNodePtr));
3763 	if (temp == NULL) {
3764 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3765 	    return(-1);
3766 	}
3767         cur->nodeMax *= 2;
3768 	cur->nodeTab = temp;
3769     }
3770     if (val->type == XML_NAMESPACE_DECL) {
3771 	xmlNsPtr ns = (xmlNsPtr) val;
3772 
3773 	cur->nodeTab[cur->nodeNr++] =
3774 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3775     } else
3776 	cur->nodeTab[cur->nodeNr++] = val;
3777     return(0);
3778 }
3779 
3780 /**
3781  * xmlXPathNodeSetAddUnique:
3782  * @cur:  the initial node set
3783  * @val:  a new xmlNodePtr
3784  *
3785  * add a new xmlNodePtr to an existing NodeSet, optimized version
3786  * when we are sure the node is not already in the set.
3787  *
3788  * Returns 0 in case of success and -1 in case of failure
3789  */
3790 int
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur,xmlNodePtr val)3791 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3792     if ((cur == NULL) || (val == NULL)) return(-1);
3793 
3794     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3795     /*
3796      * grow the nodeTab if needed
3797      */
3798     if (cur->nodeMax == 0) {
3799         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3800 					     sizeof(xmlNodePtr));
3801 	if (cur->nodeTab == NULL) {
3802 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3803 	    return(-1);
3804 	}
3805 	memset(cur->nodeTab, 0 ,
3806 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3807         cur->nodeMax = XML_NODESET_DEFAULT;
3808     } else if (cur->nodeNr == cur->nodeMax) {
3809         xmlNodePtr *temp;
3810 
3811         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3812             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3813             return(-1);
3814         }
3815 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3816 				      sizeof(xmlNodePtr));
3817 	if (temp == NULL) {
3818 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3819 	    return(-1);
3820 	}
3821 	cur->nodeTab = temp;
3822         cur->nodeMax *= 2;
3823     }
3824     if (val->type == XML_NAMESPACE_DECL) {
3825 	xmlNsPtr ns = (xmlNsPtr) val;
3826 
3827 	cur->nodeTab[cur->nodeNr++] =
3828 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3829     } else
3830 	cur->nodeTab[cur->nodeNr++] = val;
3831     return(0);
3832 }
3833 
3834 /**
3835  * xmlXPathNodeSetMerge:
3836  * @val1:  the first NodeSet or NULL
3837  * @val2:  the second NodeSet
3838  *
3839  * Merges two nodesets, all nodes from @val2 are added to @val1
3840  * if @val1 is NULL, a new set is created and copied from @val2
3841  *
3842  * Returns @val1 once extended or NULL in case of error.
3843  */
3844 xmlNodeSetPtr
xmlXPathNodeSetMerge(xmlNodeSetPtr val1,xmlNodeSetPtr val2)3845 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3846     int i, j, initNr, skip;
3847     xmlNodePtr n1, n2;
3848 
3849     if (val2 == NULL) return(val1);
3850     if (val1 == NULL) {
3851 	val1 = xmlXPathNodeSetCreate(NULL);
3852     if (val1 == NULL)
3853         return (NULL);
3854 #if 0
3855 	/*
3856 	* TODO: The optimization won't work in every case, since
3857 	*  those nasty namespace nodes need to be added with
3858 	*  xmlXPathNodeSetDupNs() to the set; thus a pure
3859 	*  memcpy is not possible.
3860 	*  If there was a flag on the nodesetval, indicating that
3861 	*  some temporary nodes are in, that would be helpfull.
3862 	*/
3863 	/*
3864 	* Optimization: Create an equally sized node-set
3865 	* and memcpy the content.
3866 	*/
3867 	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3868 	if (val1 == NULL)
3869 	    return(NULL);
3870 	if (val2->nodeNr != 0) {
3871 	    if (val2->nodeNr == 1)
3872 		*(val1->nodeTab) = *(val2->nodeTab);
3873 	    else {
3874 		memcpy(val1->nodeTab, val2->nodeTab,
3875 		    val2->nodeNr * sizeof(xmlNodePtr));
3876 	    }
3877 	    val1->nodeNr = val2->nodeNr;
3878 	}
3879 	return(val1);
3880 #endif
3881     }
3882 
3883     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3884     initNr = val1->nodeNr;
3885 
3886     for (i = 0;i < val2->nodeNr;i++) {
3887 	n2 = val2->nodeTab[i];
3888 	/*
3889 	 * check against duplicates
3890 	 */
3891 	skip = 0;
3892 	for (j = 0; j < initNr; j++) {
3893 	    n1 = val1->nodeTab[j];
3894 	    if (n1 == n2) {
3895 		skip = 1;
3896 		break;
3897 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3898 		       (n2->type == XML_NAMESPACE_DECL)) {
3899 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3900 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3901 			((xmlNsPtr) n2)->prefix)))
3902 		{
3903 		    skip = 1;
3904 		    break;
3905 		}
3906 	    }
3907 	}
3908 	if (skip)
3909 	    continue;
3910 
3911 	/*
3912 	 * grow the nodeTab if needed
3913 	 */
3914 	if (val1->nodeMax == 0) {
3915 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3916 						    sizeof(xmlNodePtr));
3917 	    if (val1->nodeTab == NULL) {
3918 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3919 		return(NULL);
3920 	    }
3921 	    memset(val1->nodeTab, 0 ,
3922 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3923 	    val1->nodeMax = XML_NODESET_DEFAULT;
3924 	} else if (val1->nodeNr == val1->nodeMax) {
3925 	    xmlNodePtr *temp;
3926 
3927             if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3928                 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3929                 return(NULL);
3930             }
3931 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3932 					     sizeof(xmlNodePtr));
3933 	    if (temp == NULL) {
3934 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3935 		return(NULL);
3936 	    }
3937 	    val1->nodeTab = temp;
3938 	    val1->nodeMax *= 2;
3939 	}
3940 	if (n2->type == XML_NAMESPACE_DECL) {
3941 	    xmlNsPtr ns = (xmlNsPtr) n2;
3942 
3943 	    val1->nodeTab[val1->nodeNr++] =
3944 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3945 	} else
3946 	    val1->nodeTab[val1->nodeNr++] = n2;
3947     }
3948 
3949     return(val1);
3950 }
3951 
3952 
3953 /**
3954  * xmlXPathNodeSetMergeAndClear:
3955  * @set1:  the first NodeSet or NULL
3956  * @set2:  the second NodeSet
3957  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3958  *
3959  * Merges two nodesets, all nodes from @set2 are added to @set1
3960  * if @set1 is NULL, a new set is created and copied from @set2.
3961  * Checks for duplicate nodes. Clears set2.
3962  *
3963  * Returns @set1 once extended or NULL in case of error.
3964  */
3965 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1,xmlNodeSetPtr set2,int hasNullEntries)3966 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3967 			     int hasNullEntries)
3968 {
3969     if ((set1 == NULL) && (hasNullEntries == 0)) {
3970 	/*
3971 	* Note that doing a memcpy of the list, namespace nodes are
3972 	* just assigned to set1, since set2 is cleared anyway.
3973 	*/
3974 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3975 	if (set1 == NULL)
3976 	    return(NULL);
3977 	if (set2->nodeNr != 0) {
3978 	    memcpy(set1->nodeTab, set2->nodeTab,
3979 		set2->nodeNr * sizeof(xmlNodePtr));
3980 	    set1->nodeNr = set2->nodeNr;
3981 	}
3982     } else {
3983 	int i, j, initNbSet1;
3984 	xmlNodePtr n1, n2;
3985 
3986 	if (set1 == NULL)
3987             set1 = xmlXPathNodeSetCreate(NULL);
3988         if (set1 == NULL)
3989             return (NULL);
3990 
3991 	initNbSet1 = set1->nodeNr;
3992 	for (i = 0;i < set2->nodeNr;i++) {
3993 	    n2 = set2->nodeTab[i];
3994 	    /*
3995 	    * Skip NULLed entries.
3996 	    */
3997 	    if (n2 == NULL)
3998 		continue;
3999 	    /*
4000 	    * Skip duplicates.
4001 	    */
4002 	    for (j = 0; j < initNbSet1; j++) {
4003 		n1 = set1->nodeTab[j];
4004 		if (n1 == n2) {
4005 		    goto skip_node;
4006 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
4007 		    (n2->type == XML_NAMESPACE_DECL))
4008 		{
4009 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
4010 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
4011 			((xmlNsPtr) n2)->prefix)))
4012 		    {
4013 			/*
4014 			* Free the namespace node.
4015 			*/
4016 			set2->nodeTab[i] = NULL;
4017 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
4018 			goto skip_node;
4019 		    }
4020 		}
4021 	    }
4022 	    /*
4023 	    * grow the nodeTab if needed
4024 	    */
4025 	    if (set1->nodeMax == 0) {
4026 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4027 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4028 		if (set1->nodeTab == NULL) {
4029 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4030 		    return(NULL);
4031 		}
4032 		memset(set1->nodeTab, 0,
4033 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4034 		set1->nodeMax = XML_NODESET_DEFAULT;
4035 	    } else if (set1->nodeNr >= set1->nodeMax) {
4036 		xmlNodePtr *temp;
4037 
4038                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4039                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4040                     return(NULL);
4041                 }
4042 		temp = (xmlNodePtr *) xmlRealloc(
4043 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4044 		if (temp == NULL) {
4045 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4046 		    return(NULL);
4047 		}
4048 		set1->nodeTab = temp;
4049 		set1->nodeMax *= 2;
4050 	    }
4051 	    set1->nodeTab[set1->nodeNr++] = n2;
4052 skip_node:
4053 	    {}
4054 	}
4055     }
4056     set2->nodeNr = 0;
4057     return(set1);
4058 }
4059 
4060 /**
4061  * xmlXPathNodeSetMergeAndClearNoDupls:
4062  * @set1:  the first NodeSet or NULL
4063  * @set2:  the second NodeSet
4064  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4065  *
4066  * Merges two nodesets, all nodes from @set2 are added to @set1
4067  * if @set1 is NULL, a new set is created and copied from @set2.
4068  * Doesn't chack for duplicate nodes. Clears set2.
4069  *
4070  * Returns @set1 once extended or NULL in case of error.
4071  */
4072 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1,xmlNodeSetPtr set2,int hasNullEntries)4073 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4074 				    int hasNullEntries)
4075 {
4076     if (set2 == NULL)
4077 	return(set1);
4078     if ((set1 == NULL) && (hasNullEntries == 0)) {
4079 	/*
4080 	* Note that doing a memcpy of the list, namespace nodes are
4081 	* just assigned to set1, since set2 is cleared anyway.
4082 	*/
4083 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4084 	if (set1 == NULL)
4085 	    return(NULL);
4086 	if (set2->nodeNr != 0) {
4087 	    memcpy(set1->nodeTab, set2->nodeTab,
4088 		set2->nodeNr * sizeof(xmlNodePtr));
4089 	    set1->nodeNr = set2->nodeNr;
4090 	}
4091     } else {
4092 	int i;
4093 	xmlNodePtr n2;
4094 
4095 	if (set1 == NULL)
4096 	    set1 = xmlXPathNodeSetCreate(NULL);
4097         if (set1 == NULL)
4098             return (NULL);
4099 
4100 	for (i = 0;i < set2->nodeNr;i++) {
4101 	    n2 = set2->nodeTab[i];
4102 	    /*
4103 	    * Skip NULLed entries.
4104 	    */
4105 	    if (n2 == NULL)
4106 		continue;
4107 	    if (set1->nodeMax == 0) {
4108 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4109 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4110 		if (set1->nodeTab == NULL) {
4111 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4112 		    return(NULL);
4113 		}
4114 		memset(set1->nodeTab, 0,
4115 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4116 		set1->nodeMax = XML_NODESET_DEFAULT;
4117 	    } else if (set1->nodeNr >= set1->nodeMax) {
4118 		xmlNodePtr *temp;
4119 
4120                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4121                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4122                     return(NULL);
4123                 }
4124 		temp = (xmlNodePtr *) xmlRealloc(
4125 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4126 		if (temp == NULL) {
4127 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4128 		    return(NULL);
4129 		}
4130 		set1->nodeTab = temp;
4131 		set1->nodeMax *= 2;
4132 	    }
4133 	    set1->nodeTab[set1->nodeNr++] = n2;
4134 	}
4135     }
4136     set2->nodeNr = 0;
4137     return(set1);
4138 }
4139 
4140 /**
4141  * xmlXPathNodeSetDel:
4142  * @cur:  the initial node set
4143  * @val:  an xmlNodePtr
4144  *
4145  * Removes an xmlNodePtr from an existing NodeSet
4146  */
4147 void
xmlXPathNodeSetDel(xmlNodeSetPtr cur,xmlNodePtr val)4148 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4149     int i;
4150 
4151     if (cur == NULL) return;
4152     if (val == NULL) return;
4153 
4154     /*
4155      * find node in nodeTab
4156      */
4157     for (i = 0;i < cur->nodeNr;i++)
4158         if (cur->nodeTab[i] == val) break;
4159 
4160     if (i >= cur->nodeNr) {	/* not found */
4161 #ifdef DEBUG
4162         xmlGenericError(xmlGenericErrorContext,
4163 	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4164 		val->name);
4165 #endif
4166         return;
4167     }
4168     if ((cur->nodeTab[i] != NULL) &&
4169 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4170 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4171     cur->nodeNr--;
4172     for (;i < cur->nodeNr;i++)
4173         cur->nodeTab[i] = cur->nodeTab[i + 1];
4174     cur->nodeTab[cur->nodeNr] = NULL;
4175 }
4176 
4177 /**
4178  * xmlXPathNodeSetRemove:
4179  * @cur:  the initial node set
4180  * @val:  the index to remove
4181  *
4182  * Removes an entry from an existing NodeSet list.
4183  */
4184 void
xmlXPathNodeSetRemove(xmlNodeSetPtr cur,int val)4185 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4186     if (cur == NULL) return;
4187     if (val >= cur->nodeNr) return;
4188     if ((cur->nodeTab[val] != NULL) &&
4189 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4190 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4191     cur->nodeNr--;
4192     for (;val < cur->nodeNr;val++)
4193         cur->nodeTab[val] = cur->nodeTab[val + 1];
4194     cur->nodeTab[cur->nodeNr] = NULL;
4195 }
4196 
4197 /**
4198  * xmlXPathFreeNodeSet:
4199  * @obj:  the xmlNodeSetPtr to free
4200  *
4201  * Free the NodeSet compound (not the actual nodes !).
4202  */
4203 void
xmlXPathFreeNodeSet(xmlNodeSetPtr obj)4204 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4205     if (obj == NULL) return;
4206     if (obj->nodeTab != NULL) {
4207 	int i;
4208 
4209 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
4210 	for (i = 0;i < obj->nodeNr;i++)
4211 	    if ((obj->nodeTab[i] != NULL) &&
4212 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4213 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4214 	xmlFree(obj->nodeTab);
4215     }
4216     xmlFree(obj);
4217 }
4218 
4219 /**
4220  * xmlXPathNodeSetClearFromPos:
4221  * @set: the node set to be cleared
4222  * @pos: the start position to clear from
4223  *
4224  * Clears the list from temporary XPath objects (e.g. namespace nodes
4225  * are feed) starting with the entry at @pos, but does *not* free the list
4226  * itself. Sets the length of the list to @pos.
4227  */
4228 static void
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set,int pos,int hasNsNodes)4229 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4230 {
4231     if ((set == NULL) || (pos >= set->nodeNr))
4232 	return;
4233     else if ((hasNsNodes)) {
4234 	int i;
4235 	xmlNodePtr node;
4236 
4237 	for (i = pos; i < set->nodeNr; i++) {
4238 	    node = set->nodeTab[i];
4239 	    if ((node != NULL) &&
4240 		(node->type == XML_NAMESPACE_DECL))
4241 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4242 	}
4243     }
4244     set->nodeNr = pos;
4245 }
4246 
4247 /**
4248  * xmlXPathNodeSetClear:
4249  * @set:  the node set to clear
4250  *
4251  * Clears the list from all temporary XPath objects (e.g. namespace nodes
4252  * are feed), but does *not* free the list itself. Sets the length of the
4253  * list to 0.
4254  */
4255 static void
xmlXPathNodeSetClear(xmlNodeSetPtr set,int hasNsNodes)4256 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4257 {
4258     xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4259 }
4260 
4261 /**
4262  * xmlXPathNodeSetKeepLast:
4263  * @set: the node set to be cleared
4264  *
4265  * Move the last node to the first position and clear temporary XPath objects
4266  * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4267  * to 1.
4268  */
4269 static void
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)4270 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4271 {
4272     int i;
4273     xmlNodePtr node;
4274 
4275     if ((set == NULL) || (set->nodeNr <= 1))
4276 	return;
4277     for (i = 0; i < set->nodeNr - 1; i++) {
4278         node = set->nodeTab[i];
4279         if ((node != NULL) &&
4280             (node->type == XML_NAMESPACE_DECL))
4281             xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4282     }
4283     set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4284     set->nodeNr = 1;
4285 }
4286 
4287 /**
4288  * xmlXPathFreeValueTree:
4289  * @obj:  the xmlNodeSetPtr to free
4290  *
4291  * Free the NodeSet compound and the actual tree, this is different
4292  * from xmlXPathFreeNodeSet()
4293  */
4294 static void
xmlXPathFreeValueTree(xmlNodeSetPtr obj)4295 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4296     int i;
4297 
4298     if (obj == NULL) return;
4299 
4300     if (obj->nodeTab != NULL) {
4301 	for (i = 0;i < obj->nodeNr;i++) {
4302 	    if (obj->nodeTab[i] != NULL) {
4303 		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4304 		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4305 		} else {
4306 		    xmlFreeNodeList(obj->nodeTab[i]);
4307 		}
4308 	    }
4309 	}
4310 	xmlFree(obj->nodeTab);
4311     }
4312     xmlFree(obj);
4313 }
4314 
4315 #if defined(DEBUG) || defined(DEBUG_STEP)
4316 /**
4317  * xmlGenericErrorContextNodeSet:
4318  * @output:  a FILE * for the output
4319  * @obj:  the xmlNodeSetPtr to display
4320  *
4321  * Quick display of a NodeSet
4322  */
4323 void
xmlGenericErrorContextNodeSet(FILE * output,xmlNodeSetPtr obj)4324 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4325     int i;
4326 
4327     if (output == NULL) output = xmlGenericErrorContext;
4328     if (obj == NULL)  {
4329         fprintf(output, "NodeSet == NULL !\n");
4330 	return;
4331     }
4332     if (obj->nodeNr == 0) {
4333         fprintf(output, "NodeSet is empty\n");
4334 	return;
4335     }
4336     if (obj->nodeTab == NULL) {
4337 	fprintf(output, " nodeTab == NULL !\n");
4338 	return;
4339     }
4340     for (i = 0; i < obj->nodeNr; i++) {
4341         if (obj->nodeTab[i] == NULL) {
4342 	    fprintf(output, " NULL !\n");
4343 	    return;
4344         }
4345 	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4346 	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4347 	    fprintf(output, " /");
4348 	else if (obj->nodeTab[i]->name == NULL)
4349 	    fprintf(output, " noname!");
4350 	else fprintf(output, " %s", obj->nodeTab[i]->name);
4351     }
4352     fprintf(output, "\n");
4353 }
4354 #endif
4355 
4356 /**
4357  * xmlXPathNewNodeSet:
4358  * @val:  the NodePtr value
4359  *
4360  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4361  * it with the single Node @val
4362  *
4363  * Returns the newly created object.
4364  */
4365 xmlXPathObjectPtr
xmlXPathNewNodeSet(xmlNodePtr val)4366 xmlXPathNewNodeSet(xmlNodePtr val) {
4367     xmlXPathObjectPtr ret;
4368 
4369     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4370     if (ret == NULL) {
4371         xmlXPathErrMemory(NULL, "creating nodeset\n");
4372 	return(NULL);
4373     }
4374     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4375     ret->type = XPATH_NODESET;
4376     ret->boolval = 0;
4377     ret->nodesetval = xmlXPathNodeSetCreate(val);
4378     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4379 #ifdef XP_DEBUG_OBJ_USAGE
4380     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4381 #endif
4382     return(ret);
4383 }
4384 
4385 /**
4386  * xmlXPathNewValueTree:
4387  * @val:  the NodePtr value
4388  *
4389  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4390  * it with the tree root @val
4391  *
4392  * Returns the newly created object.
4393  */
4394 xmlXPathObjectPtr
xmlXPathNewValueTree(xmlNodePtr val)4395 xmlXPathNewValueTree(xmlNodePtr val) {
4396     xmlXPathObjectPtr ret;
4397 
4398     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4399     if (ret == NULL) {
4400         xmlXPathErrMemory(NULL, "creating result value tree\n");
4401 	return(NULL);
4402     }
4403     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4404     ret->type = XPATH_XSLT_TREE;
4405     ret->boolval = 1;
4406     ret->user = (void *) val;
4407     ret->nodesetval = xmlXPathNodeSetCreate(val);
4408 #ifdef XP_DEBUG_OBJ_USAGE
4409     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4410 #endif
4411     return(ret);
4412 }
4413 
4414 /**
4415  * xmlXPathNewNodeSetList:
4416  * @val:  an existing NodeSet
4417  *
4418  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4419  * it with the Nodeset @val
4420  *
4421  * Returns the newly created object.
4422  */
4423 xmlXPathObjectPtr
xmlXPathNewNodeSetList(xmlNodeSetPtr val)4424 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4425 {
4426     xmlXPathObjectPtr ret;
4427     int i;
4428 
4429     if (val == NULL)
4430         ret = NULL;
4431     else if (val->nodeTab == NULL)
4432         ret = xmlXPathNewNodeSet(NULL);
4433     else {
4434         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4435         if (ret) {
4436             for (i = 1; i < val->nodeNr; ++i) {
4437                 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4438 		    < 0) break;
4439 	    }
4440 	}
4441     }
4442 
4443     return (ret);
4444 }
4445 
4446 /**
4447  * xmlXPathWrapNodeSet:
4448  * @val:  the NodePtr value
4449  *
4450  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4451  *
4452  * Returns the newly created object.
4453  */
4454 xmlXPathObjectPtr
xmlXPathWrapNodeSet(xmlNodeSetPtr val)4455 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4456     xmlXPathObjectPtr ret;
4457 
4458     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4459     if (ret == NULL) {
4460         xmlXPathErrMemory(NULL, "creating node set object\n");
4461 	return(NULL);
4462     }
4463     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4464     ret->type = XPATH_NODESET;
4465     ret->nodesetval = val;
4466 #ifdef XP_DEBUG_OBJ_USAGE
4467     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4468 #endif
4469     return(ret);
4470 }
4471 
4472 /**
4473  * xmlXPathFreeNodeSetList:
4474  * @obj:  an existing NodeSetList object
4475  *
4476  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4477  * the list contrary to xmlXPathFreeObject().
4478  */
4479 void
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj)4480 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4481     if (obj == NULL) return;
4482 #ifdef XP_DEBUG_OBJ_USAGE
4483     xmlXPathDebugObjUsageReleased(NULL, obj->type);
4484 #endif
4485     xmlFree(obj);
4486 }
4487 
4488 /**
4489  * xmlXPathDifference:
4490  * @nodes1:  a node-set
4491  * @nodes2:  a node-set
4492  *
4493  * Implements the EXSLT - Sets difference() function:
4494  *    node-set set:difference (node-set, node-set)
4495  *
4496  * Returns the difference between the two node sets, or nodes1 if
4497  *         nodes2 is empty
4498  */
4499 xmlNodeSetPtr
xmlXPathDifference(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4500 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4501     xmlNodeSetPtr ret;
4502     int i, l1;
4503     xmlNodePtr cur;
4504 
4505     if (xmlXPathNodeSetIsEmpty(nodes2))
4506 	return(nodes1);
4507 
4508     ret = xmlXPathNodeSetCreate(NULL);
4509     if (xmlXPathNodeSetIsEmpty(nodes1))
4510 	return(ret);
4511 
4512     l1 = xmlXPathNodeSetGetLength(nodes1);
4513 
4514     for (i = 0; i < l1; i++) {
4515 	cur = xmlXPathNodeSetItem(nodes1, i);
4516 	if (!xmlXPathNodeSetContains(nodes2, cur)) {
4517 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4518 	        break;
4519 	}
4520     }
4521     return(ret);
4522 }
4523 
4524 /**
4525  * xmlXPathIntersection:
4526  * @nodes1:  a node-set
4527  * @nodes2:  a node-set
4528  *
4529  * Implements the EXSLT - Sets intersection() function:
4530  *    node-set set:intersection (node-set, node-set)
4531  *
4532  * Returns a node set comprising the nodes that are within both the
4533  *         node sets passed as arguments
4534  */
4535 xmlNodeSetPtr
xmlXPathIntersection(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4536 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4537     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4538     int i, l1;
4539     xmlNodePtr cur;
4540 
4541     if (ret == NULL)
4542         return(ret);
4543     if (xmlXPathNodeSetIsEmpty(nodes1))
4544 	return(ret);
4545     if (xmlXPathNodeSetIsEmpty(nodes2))
4546 	return(ret);
4547 
4548     l1 = xmlXPathNodeSetGetLength(nodes1);
4549 
4550     for (i = 0; i < l1; i++) {
4551 	cur = xmlXPathNodeSetItem(nodes1, i);
4552 	if (xmlXPathNodeSetContains(nodes2, cur)) {
4553 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4554 	        break;
4555 	}
4556     }
4557     return(ret);
4558 }
4559 
4560 /**
4561  * xmlXPathDistinctSorted:
4562  * @nodes:  a node-set, sorted by document order
4563  *
4564  * Implements the EXSLT - Sets distinct() function:
4565  *    node-set set:distinct (node-set)
4566  *
4567  * Returns a subset of the nodes contained in @nodes, or @nodes if
4568  *         it is empty
4569  */
4570 xmlNodeSetPtr
xmlXPathDistinctSorted(xmlNodeSetPtr nodes)4571 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4572     xmlNodeSetPtr ret;
4573     xmlHashTablePtr hash;
4574     int i, l;
4575     xmlChar * strval;
4576     xmlNodePtr cur;
4577 
4578     if (xmlXPathNodeSetIsEmpty(nodes))
4579 	return(nodes);
4580 
4581     ret = xmlXPathNodeSetCreate(NULL);
4582     if (ret == NULL)
4583         return(ret);
4584     l = xmlXPathNodeSetGetLength(nodes);
4585     hash = xmlHashCreate (l);
4586     for (i = 0; i < l; i++) {
4587 	cur = xmlXPathNodeSetItem(nodes, i);
4588 	strval = xmlXPathCastNodeToString(cur);
4589 	if (xmlHashLookup(hash, strval) == NULL) {
4590 	    xmlHashAddEntry(hash, strval, strval);
4591 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4592 	        break;
4593 	} else {
4594 	    xmlFree(strval);
4595 	}
4596     }
4597     xmlHashFree(hash, xmlHashDefaultDeallocator);
4598     return(ret);
4599 }
4600 
4601 /**
4602  * xmlXPathDistinct:
4603  * @nodes:  a node-set
4604  *
4605  * Implements the EXSLT - Sets distinct() function:
4606  *    node-set set:distinct (node-set)
4607  * @nodes is sorted by document order, then #exslSetsDistinctSorted
4608  * is called with the sorted node-set
4609  *
4610  * Returns a subset of the nodes contained in @nodes, or @nodes if
4611  *         it is empty
4612  */
4613 xmlNodeSetPtr
xmlXPathDistinct(xmlNodeSetPtr nodes)4614 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4615     if (xmlXPathNodeSetIsEmpty(nodes))
4616 	return(nodes);
4617 
4618     xmlXPathNodeSetSort(nodes);
4619     return(xmlXPathDistinctSorted(nodes));
4620 }
4621 
4622 /**
4623  * xmlXPathHasSameNodes:
4624  * @nodes1:  a node-set
4625  * @nodes2:  a node-set
4626  *
4627  * Implements the EXSLT - Sets has-same-nodes function:
4628  *    boolean set:has-same-node(node-set, node-set)
4629  *
4630  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4631  *         otherwise
4632  */
4633 int
xmlXPathHasSameNodes(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4634 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4635     int i, l;
4636     xmlNodePtr cur;
4637 
4638     if (xmlXPathNodeSetIsEmpty(nodes1) ||
4639 	xmlXPathNodeSetIsEmpty(nodes2))
4640 	return(0);
4641 
4642     l = xmlXPathNodeSetGetLength(nodes1);
4643     for (i = 0; i < l; i++) {
4644 	cur = xmlXPathNodeSetItem(nodes1, i);
4645 	if (xmlXPathNodeSetContains(nodes2, cur))
4646 	    return(1);
4647     }
4648     return(0);
4649 }
4650 
4651 /**
4652  * xmlXPathNodeLeadingSorted:
4653  * @nodes: a node-set, sorted by document order
4654  * @node: a node
4655  *
4656  * Implements the EXSLT - Sets leading() function:
4657  *    node-set set:leading (node-set, node-set)
4658  *
4659  * Returns the nodes in @nodes that precede @node in document order,
4660  *         @nodes if @node is NULL or an empty node-set if @nodes
4661  *         doesn't contain @node
4662  */
4663 xmlNodeSetPtr
xmlXPathNodeLeadingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4664 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4665     int i, l;
4666     xmlNodePtr cur;
4667     xmlNodeSetPtr ret;
4668 
4669     if (node == NULL)
4670 	return(nodes);
4671 
4672     ret = xmlXPathNodeSetCreate(NULL);
4673     if (ret == NULL)
4674         return(ret);
4675     if (xmlXPathNodeSetIsEmpty(nodes) ||
4676 	(!xmlXPathNodeSetContains(nodes, node)))
4677 	return(ret);
4678 
4679     l = xmlXPathNodeSetGetLength(nodes);
4680     for (i = 0; i < l; i++) {
4681 	cur = xmlXPathNodeSetItem(nodes, i);
4682 	if (cur == node)
4683 	    break;
4684 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4685 	    break;
4686     }
4687     return(ret);
4688 }
4689 
4690 /**
4691  * xmlXPathNodeLeading:
4692  * @nodes:  a node-set
4693  * @node:  a node
4694  *
4695  * Implements the EXSLT - Sets leading() function:
4696  *    node-set set:leading (node-set, node-set)
4697  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4698  * is called.
4699  *
4700  * Returns the nodes in @nodes that precede @node in document order,
4701  *         @nodes if @node is NULL or an empty node-set if @nodes
4702  *         doesn't contain @node
4703  */
4704 xmlNodeSetPtr
xmlXPathNodeLeading(xmlNodeSetPtr nodes,xmlNodePtr node)4705 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4706     xmlXPathNodeSetSort(nodes);
4707     return(xmlXPathNodeLeadingSorted(nodes, node));
4708 }
4709 
4710 /**
4711  * xmlXPathLeadingSorted:
4712  * @nodes1:  a node-set, sorted by document order
4713  * @nodes2:  a node-set, sorted by document order
4714  *
4715  * Implements the EXSLT - Sets leading() function:
4716  *    node-set set:leading (node-set, node-set)
4717  *
4718  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4719  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4720  *         an empty node-set if @nodes1 doesn't contain @nodes2
4721  */
4722 xmlNodeSetPtr
xmlXPathLeadingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4723 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4724     if (xmlXPathNodeSetIsEmpty(nodes2))
4725 	return(nodes1);
4726     return(xmlXPathNodeLeadingSorted(nodes1,
4727 				     xmlXPathNodeSetItem(nodes2, 1)));
4728 }
4729 
4730 /**
4731  * xmlXPathLeading:
4732  * @nodes1:  a node-set
4733  * @nodes2:  a node-set
4734  *
4735  * Implements the EXSLT - Sets leading() function:
4736  *    node-set set:leading (node-set, node-set)
4737  * @nodes1 and @nodes2 are sorted by document order, then
4738  * #exslSetsLeadingSorted is called.
4739  *
4740  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4741  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4742  *         an empty node-set if @nodes1 doesn't contain @nodes2
4743  */
4744 xmlNodeSetPtr
xmlXPathLeading(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4745 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4746     if (xmlXPathNodeSetIsEmpty(nodes2))
4747 	return(nodes1);
4748     if (xmlXPathNodeSetIsEmpty(nodes1))
4749 	return(xmlXPathNodeSetCreate(NULL));
4750     xmlXPathNodeSetSort(nodes1);
4751     xmlXPathNodeSetSort(nodes2);
4752     return(xmlXPathNodeLeadingSorted(nodes1,
4753 				     xmlXPathNodeSetItem(nodes2, 1)));
4754 }
4755 
4756 /**
4757  * xmlXPathNodeTrailingSorted:
4758  * @nodes: a node-set, sorted by document order
4759  * @node: a node
4760  *
4761  * Implements the EXSLT - Sets trailing() function:
4762  *    node-set set:trailing (node-set, node-set)
4763  *
4764  * Returns the nodes in @nodes that follow @node in document order,
4765  *         @nodes if @node is NULL or an empty node-set if @nodes
4766  *         doesn't contain @node
4767  */
4768 xmlNodeSetPtr
xmlXPathNodeTrailingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4769 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4770     int i, l;
4771     xmlNodePtr cur;
4772     xmlNodeSetPtr ret;
4773 
4774     if (node == NULL)
4775 	return(nodes);
4776 
4777     ret = xmlXPathNodeSetCreate(NULL);
4778     if (ret == NULL)
4779         return(ret);
4780     if (xmlXPathNodeSetIsEmpty(nodes) ||
4781 	(!xmlXPathNodeSetContains(nodes, node)))
4782 	return(ret);
4783 
4784     l = xmlXPathNodeSetGetLength(nodes);
4785     for (i = l - 1; i >= 0; i--) {
4786 	cur = xmlXPathNodeSetItem(nodes, i);
4787 	if (cur == node)
4788 	    break;
4789 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4790 	    break;
4791     }
4792     xmlXPathNodeSetSort(ret);	/* bug 413451 */
4793     return(ret);
4794 }
4795 
4796 /**
4797  * xmlXPathNodeTrailing:
4798  * @nodes:  a node-set
4799  * @node:  a node
4800  *
4801  * Implements the EXSLT - Sets trailing() function:
4802  *    node-set set:trailing (node-set, node-set)
4803  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4804  * is called.
4805  *
4806  * Returns the nodes in @nodes that follow @node in document order,
4807  *         @nodes if @node is NULL or an empty node-set if @nodes
4808  *         doesn't contain @node
4809  */
4810 xmlNodeSetPtr
xmlXPathNodeTrailing(xmlNodeSetPtr nodes,xmlNodePtr node)4811 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4812     xmlXPathNodeSetSort(nodes);
4813     return(xmlXPathNodeTrailingSorted(nodes, node));
4814 }
4815 
4816 /**
4817  * xmlXPathTrailingSorted:
4818  * @nodes1:  a node-set, sorted by document order
4819  * @nodes2:  a node-set, sorted by document order
4820  *
4821  * Implements the EXSLT - Sets trailing() function:
4822  *    node-set set:trailing (node-set, node-set)
4823  *
4824  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4825  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4826  *         an empty node-set if @nodes1 doesn't contain @nodes2
4827  */
4828 xmlNodeSetPtr
xmlXPathTrailingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4829 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4830     if (xmlXPathNodeSetIsEmpty(nodes2))
4831 	return(nodes1);
4832     return(xmlXPathNodeTrailingSorted(nodes1,
4833 				      xmlXPathNodeSetItem(nodes2, 0)));
4834 }
4835 
4836 /**
4837  * xmlXPathTrailing:
4838  * @nodes1:  a node-set
4839  * @nodes2:  a node-set
4840  *
4841  * Implements the EXSLT - Sets trailing() function:
4842  *    node-set set:trailing (node-set, node-set)
4843  * @nodes1 and @nodes2 are sorted by document order, then
4844  * #xmlXPathTrailingSorted is called.
4845  *
4846  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4847  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4848  *         an empty node-set if @nodes1 doesn't contain @nodes2
4849  */
4850 xmlNodeSetPtr
xmlXPathTrailing(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4851 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4852     if (xmlXPathNodeSetIsEmpty(nodes2))
4853 	return(nodes1);
4854     if (xmlXPathNodeSetIsEmpty(nodes1))
4855 	return(xmlXPathNodeSetCreate(NULL));
4856     xmlXPathNodeSetSort(nodes1);
4857     xmlXPathNodeSetSort(nodes2);
4858     return(xmlXPathNodeTrailingSorted(nodes1,
4859 				      xmlXPathNodeSetItem(nodes2, 0)));
4860 }
4861 
4862 /************************************************************************
4863  *									*
4864  *		Routines to handle extra functions			*
4865  *									*
4866  ************************************************************************/
4867 
4868 /**
4869  * xmlXPathRegisterFunc:
4870  * @ctxt:  the XPath context
4871  * @name:  the function name
4872  * @f:  the function implementation or NULL
4873  *
4874  * Register a new function. If @f is NULL it unregisters the function
4875  *
4876  * Returns 0 in case of success, -1 in case of error
4877  */
4878 int
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathFunction f)4879 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4880 		     xmlXPathFunction f) {
4881     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4882 }
4883 
4884 /**
4885  * xmlXPathRegisterFuncNS:
4886  * @ctxt:  the XPath context
4887  * @name:  the function name
4888  * @ns_uri:  the function namespace URI
4889  * @f:  the function implementation or NULL
4890  *
4891  * Register a new function. If @f is NULL it unregisters the function
4892  *
4893  * Returns 0 in case of success, -1 in case of error
4894  */
4895 int
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathFunction f)4896 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4897 		       const xmlChar *ns_uri, xmlXPathFunction f) {
4898     if (ctxt == NULL)
4899 	return(-1);
4900     if (name == NULL)
4901 	return(-1);
4902 
4903     if (ctxt->funcHash == NULL)
4904 	ctxt->funcHash = xmlHashCreate(0);
4905     if (ctxt->funcHash == NULL)
4906 	return(-1);
4907     if (f == NULL)
4908         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4909 XML_IGNORE_PEDANTIC_WARNINGS
4910     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4911 XML_POP_WARNINGS
4912 }
4913 
4914 /**
4915  * xmlXPathRegisterFuncLookup:
4916  * @ctxt:  the XPath context
4917  * @f:  the lookup function
4918  * @funcCtxt:  the lookup data
4919  *
4920  * Registers an external mechanism to do function lookup.
4921  */
4922 void
xmlXPathRegisterFuncLookup(xmlXPathContextPtr ctxt,xmlXPathFuncLookupFunc f,void * funcCtxt)4923 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4924 			    xmlXPathFuncLookupFunc f,
4925 			    void *funcCtxt) {
4926     if (ctxt == NULL)
4927 	return;
4928     ctxt->funcLookupFunc = f;
4929     ctxt->funcLookupData = funcCtxt;
4930 }
4931 
4932 /**
4933  * xmlXPathFunctionLookup:
4934  * @ctxt:  the XPath context
4935  * @name:  the function name
4936  *
4937  * Search in the Function array of the context for the given
4938  * function.
4939  *
4940  * Returns the xmlXPathFunction or NULL if not found
4941  */
4942 xmlXPathFunction
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt,const xmlChar * name)4943 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4944     if (ctxt == NULL)
4945 	return (NULL);
4946 
4947     if (ctxt->funcLookupFunc != NULL) {
4948 	xmlXPathFunction ret;
4949 	xmlXPathFuncLookupFunc f;
4950 
4951 	f = ctxt->funcLookupFunc;
4952 	ret = f(ctxt->funcLookupData, name, NULL);
4953 	if (ret != NULL)
4954 	    return(ret);
4955     }
4956     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4957 }
4958 
4959 /**
4960  * xmlXPathFunctionLookupNS:
4961  * @ctxt:  the XPath context
4962  * @name:  the function name
4963  * @ns_uri:  the function namespace URI
4964  *
4965  * Search in the Function array of the context for the given
4966  * function.
4967  *
4968  * Returns the xmlXPathFunction or NULL if not found
4969  */
4970 xmlXPathFunction
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4971 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4972 			 const xmlChar *ns_uri) {
4973     xmlXPathFunction ret;
4974 
4975     if (ctxt == NULL)
4976 	return(NULL);
4977     if (name == NULL)
4978 	return(NULL);
4979 
4980     if (ctxt->funcLookupFunc != NULL) {
4981 	xmlXPathFuncLookupFunc f;
4982 
4983 	f = ctxt->funcLookupFunc;
4984 	ret = f(ctxt->funcLookupData, name, ns_uri);
4985 	if (ret != NULL)
4986 	    return(ret);
4987     }
4988 
4989     if (ctxt->funcHash == NULL)
4990 	return(NULL);
4991 
4992 XML_IGNORE_PEDANTIC_WARNINGS
4993     ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4994 XML_POP_WARNINGS
4995     return(ret);
4996 }
4997 
4998 /**
4999  * xmlXPathRegisteredFuncsCleanup:
5000  * @ctxt:  the XPath context
5001  *
5002  * Cleanup the XPath context data associated to registered functions
5003  */
5004 void
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt)5005 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
5006     if (ctxt == NULL)
5007 	return;
5008 
5009     xmlHashFree(ctxt->funcHash, NULL);
5010     ctxt->funcHash = NULL;
5011 }
5012 
5013 /************************************************************************
5014  *									*
5015  *			Routines to handle Variables			*
5016  *									*
5017  ************************************************************************/
5018 
5019 /**
5020  * xmlXPathRegisterVariable:
5021  * @ctxt:  the XPath context
5022  * @name:  the variable name
5023  * @value:  the variable value or NULL
5024  *
5025  * Register a new variable value. If @value is NULL it unregisters
5026  * the variable
5027  *
5028  * Returns 0 in case of success, -1 in case of error
5029  */
5030 int
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathObjectPtr value)5031 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
5032 			 xmlXPathObjectPtr value) {
5033     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
5034 }
5035 
5036 /**
5037  * xmlXPathRegisterVariableNS:
5038  * @ctxt:  the XPath context
5039  * @name:  the variable name
5040  * @ns_uri:  the variable namespace URI
5041  * @value:  the variable value or NULL
5042  *
5043  * Register a new variable value. If @value is NULL it unregisters
5044  * the variable
5045  *
5046  * Returns 0 in case of success, -1 in case of error
5047  */
5048 int
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathObjectPtr value)5049 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5050 			   const xmlChar *ns_uri,
5051 			   xmlXPathObjectPtr value) {
5052     if (ctxt == NULL)
5053 	return(-1);
5054     if (name == NULL)
5055 	return(-1);
5056 
5057     if (ctxt->varHash == NULL)
5058 	ctxt->varHash = xmlHashCreate(0);
5059     if (ctxt->varHash == NULL)
5060 	return(-1);
5061     if (value == NULL)
5062         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5063 	                           xmlXPathFreeObjectEntry));
5064     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5065 			       (void *) value, xmlXPathFreeObjectEntry));
5066 }
5067 
5068 /**
5069  * xmlXPathRegisterVariableLookup:
5070  * @ctxt:  the XPath context
5071  * @f:  the lookup function
5072  * @data:  the lookup data
5073  *
5074  * register an external mechanism to do variable lookup
5075  */
5076 void
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,xmlXPathVariableLookupFunc f,void * data)5077 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5078 	 xmlXPathVariableLookupFunc f, void *data) {
5079     if (ctxt == NULL)
5080 	return;
5081     ctxt->varLookupFunc = f;
5082     ctxt->varLookupData = data;
5083 }
5084 
5085 /**
5086  * xmlXPathVariableLookup:
5087  * @ctxt:  the XPath context
5088  * @name:  the variable name
5089  *
5090  * Search in the Variable array of the context for the given
5091  * variable value.
5092  *
5093  * Returns a copy of the value or NULL if not found
5094  */
5095 xmlXPathObjectPtr
xmlXPathVariableLookup(xmlXPathContextPtr ctxt,const xmlChar * name)5096 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5097     if (ctxt == NULL)
5098 	return(NULL);
5099 
5100     if (ctxt->varLookupFunc != NULL) {
5101 	xmlXPathObjectPtr ret;
5102 
5103 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5104 	        (ctxt->varLookupData, name, NULL);
5105 	return(ret);
5106     }
5107     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5108 }
5109 
5110 /**
5111  * xmlXPathVariableLookupNS:
5112  * @ctxt:  the XPath context
5113  * @name:  the variable name
5114  * @ns_uri:  the variable namespace URI
5115  *
5116  * Search in the Variable array of the context for the given
5117  * variable value.
5118  *
5119  * Returns the a copy of the value or NULL if not found
5120  */
5121 xmlXPathObjectPtr
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)5122 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5123 			 const xmlChar *ns_uri) {
5124     if (ctxt == NULL)
5125 	return(NULL);
5126 
5127     if (ctxt->varLookupFunc != NULL) {
5128 	xmlXPathObjectPtr ret;
5129 
5130 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5131 	        (ctxt->varLookupData, name, ns_uri);
5132 	if (ret != NULL) return(ret);
5133     }
5134 
5135     if (ctxt->varHash == NULL)
5136 	return(NULL);
5137     if (name == NULL)
5138 	return(NULL);
5139 
5140     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5141 		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5142 }
5143 
5144 /**
5145  * xmlXPathRegisteredVariablesCleanup:
5146  * @ctxt:  the XPath context
5147  *
5148  * Cleanup the XPath context data associated to registered variables
5149  */
5150 void
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt)5151 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5152     if (ctxt == NULL)
5153 	return;
5154 
5155     xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5156     ctxt->varHash = NULL;
5157 }
5158 
5159 /**
5160  * xmlXPathRegisterNs:
5161  * @ctxt:  the XPath context
5162  * @prefix:  the namespace prefix cannot be NULL or empty string
5163  * @ns_uri:  the namespace name
5164  *
5165  * Register a new namespace. If @ns_uri is NULL it unregisters
5166  * the namespace
5167  *
5168  * Returns 0 in case of success, -1 in case of error
5169  */
5170 int
xmlXPathRegisterNs(xmlXPathContextPtr ctxt,const xmlChar * prefix,const xmlChar * ns_uri)5171 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5172 			   const xmlChar *ns_uri) {
5173     if (ctxt == NULL)
5174 	return(-1);
5175     if (prefix == NULL)
5176 	return(-1);
5177     if (prefix[0] == 0)
5178 	return(-1);
5179 
5180     if (ctxt->nsHash == NULL)
5181 	ctxt->nsHash = xmlHashCreate(10);
5182     if (ctxt->nsHash == NULL)
5183 	return(-1);
5184     if (ns_uri == NULL)
5185         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5186 	                          xmlHashDefaultDeallocator));
5187     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5188 			      xmlHashDefaultDeallocator));
5189 }
5190 
5191 /**
5192  * xmlXPathNsLookup:
5193  * @ctxt:  the XPath context
5194  * @prefix:  the namespace prefix value
5195  *
5196  * Search in the namespace declaration array of the context for the given
5197  * namespace name associated to the given prefix
5198  *
5199  * Returns the value or NULL if not found
5200  */
5201 const xmlChar *
xmlXPathNsLookup(xmlXPathContextPtr ctxt,const xmlChar * prefix)5202 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5203     if (ctxt == NULL)
5204 	return(NULL);
5205     if (prefix == NULL)
5206 	return(NULL);
5207 
5208 #ifdef XML_XML_NAMESPACE
5209     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5210 	return(XML_XML_NAMESPACE);
5211 #endif
5212 
5213     if (ctxt->namespaces != NULL) {
5214 	int i;
5215 
5216 	for (i = 0;i < ctxt->nsNr;i++) {
5217 	    if ((ctxt->namespaces[i] != NULL) &&
5218 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5219 		return(ctxt->namespaces[i]->href);
5220 	}
5221     }
5222 
5223     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5224 }
5225 
5226 /**
5227  * xmlXPathRegisteredNsCleanup:
5228  * @ctxt:  the XPath context
5229  *
5230  * Cleanup the XPath context data associated to registered variables
5231  */
5232 void
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt)5233 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5234     if (ctxt == NULL)
5235 	return;
5236 
5237     xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5238     ctxt->nsHash = NULL;
5239 }
5240 
5241 /************************************************************************
5242  *									*
5243  *			Routines to handle Values			*
5244  *									*
5245  ************************************************************************/
5246 
5247 /* Allocations are terrible, one needs to optimize all this !!! */
5248 
5249 /**
5250  * xmlXPathNewFloat:
5251  * @val:  the double value
5252  *
5253  * Create a new xmlXPathObjectPtr of type double and of value @val
5254  *
5255  * Returns the newly created object.
5256  */
5257 xmlXPathObjectPtr
xmlXPathNewFloat(double val)5258 xmlXPathNewFloat(double val) {
5259     xmlXPathObjectPtr ret;
5260 
5261     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5262     if (ret == NULL) {
5263         xmlXPathErrMemory(NULL, "creating float object\n");
5264 	return(NULL);
5265     }
5266     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5267     ret->type = XPATH_NUMBER;
5268     ret->floatval = val;
5269 #ifdef XP_DEBUG_OBJ_USAGE
5270     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5271 #endif
5272     return(ret);
5273 }
5274 
5275 /**
5276  * xmlXPathNewBoolean:
5277  * @val:  the boolean value
5278  *
5279  * Create a new xmlXPathObjectPtr of type boolean and of value @val
5280  *
5281  * Returns the newly created object.
5282  */
5283 xmlXPathObjectPtr
xmlXPathNewBoolean(int val)5284 xmlXPathNewBoolean(int val) {
5285     xmlXPathObjectPtr ret;
5286 
5287     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5288     if (ret == NULL) {
5289         xmlXPathErrMemory(NULL, "creating boolean object\n");
5290 	return(NULL);
5291     }
5292     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5293     ret->type = XPATH_BOOLEAN;
5294     ret->boolval = (val != 0);
5295 #ifdef XP_DEBUG_OBJ_USAGE
5296     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5297 #endif
5298     return(ret);
5299 }
5300 
5301 /**
5302  * xmlXPathNewString:
5303  * @val:  the xmlChar * value
5304  *
5305  * Create a new xmlXPathObjectPtr of type string and of value @val
5306  *
5307  * Returns the newly created object.
5308  */
5309 xmlXPathObjectPtr
xmlXPathNewString(const xmlChar * val)5310 xmlXPathNewString(const xmlChar *val) {
5311     xmlXPathObjectPtr ret;
5312 
5313     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5314     if (ret == NULL) {
5315         xmlXPathErrMemory(NULL, "creating string object\n");
5316 	return(NULL);
5317     }
5318     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5319     ret->type = XPATH_STRING;
5320     if (val != NULL)
5321 	ret->stringval = xmlStrdup(val);
5322     else
5323 	ret->stringval = xmlStrdup((const xmlChar *)"");
5324 #ifdef XP_DEBUG_OBJ_USAGE
5325     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5326 #endif
5327     return(ret);
5328 }
5329 
5330 /**
5331  * xmlXPathWrapString:
5332  * @val:  the xmlChar * value
5333  *
5334  * Wraps the @val string into an XPath object.
5335  *
5336  * Returns the newly created object.
5337  */
5338 xmlXPathObjectPtr
xmlXPathWrapString(xmlChar * val)5339 xmlXPathWrapString (xmlChar *val) {
5340     xmlXPathObjectPtr ret;
5341 
5342     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5343     if (ret == NULL) {
5344         xmlXPathErrMemory(NULL, "creating string object\n");
5345 	return(NULL);
5346     }
5347     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5348     ret->type = XPATH_STRING;
5349     ret->stringval = val;
5350 #ifdef XP_DEBUG_OBJ_USAGE
5351     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5352 #endif
5353     return(ret);
5354 }
5355 
5356 /**
5357  * xmlXPathNewCString:
5358  * @val:  the char * value
5359  *
5360  * Create a new xmlXPathObjectPtr of type string and of value @val
5361  *
5362  * Returns the newly created object.
5363  */
5364 xmlXPathObjectPtr
xmlXPathNewCString(const char * val)5365 xmlXPathNewCString(const char *val) {
5366     xmlXPathObjectPtr ret;
5367 
5368     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5369     if (ret == NULL) {
5370         xmlXPathErrMemory(NULL, "creating string object\n");
5371 	return(NULL);
5372     }
5373     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5374     ret->type = XPATH_STRING;
5375     ret->stringval = xmlStrdup(BAD_CAST val);
5376 #ifdef XP_DEBUG_OBJ_USAGE
5377     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5378 #endif
5379     return(ret);
5380 }
5381 
5382 /**
5383  * xmlXPathWrapCString:
5384  * @val:  the char * value
5385  *
5386  * Wraps a string into an XPath object.
5387  *
5388  * Returns the newly created object.
5389  */
5390 xmlXPathObjectPtr
xmlXPathWrapCString(char * val)5391 xmlXPathWrapCString (char * val) {
5392     return(xmlXPathWrapString((xmlChar *)(val)));
5393 }
5394 
5395 /**
5396  * xmlXPathWrapExternal:
5397  * @val:  the user data
5398  *
5399  * Wraps the @val data into an XPath object.
5400  *
5401  * Returns the newly created object.
5402  */
5403 xmlXPathObjectPtr
xmlXPathWrapExternal(void * val)5404 xmlXPathWrapExternal (void *val) {
5405     xmlXPathObjectPtr ret;
5406 
5407     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5408     if (ret == NULL) {
5409         xmlXPathErrMemory(NULL, "creating user object\n");
5410 	return(NULL);
5411     }
5412     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5413     ret->type = XPATH_USERS;
5414     ret->user = val;
5415 #ifdef XP_DEBUG_OBJ_USAGE
5416     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5417 #endif
5418     return(ret);
5419 }
5420 
5421 /**
5422  * xmlXPathObjectCopy:
5423  * @val:  the original object
5424  *
5425  * allocate a new copy of a given object
5426  *
5427  * Returns the newly created object.
5428  */
5429 xmlXPathObjectPtr
xmlXPathObjectCopy(xmlXPathObjectPtr val)5430 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5431     xmlXPathObjectPtr ret;
5432 
5433     if (val == NULL)
5434 	return(NULL);
5435 
5436     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5437     if (ret == NULL) {
5438         xmlXPathErrMemory(NULL, "copying object\n");
5439 	return(NULL);
5440     }
5441     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5442 #ifdef XP_DEBUG_OBJ_USAGE
5443     xmlXPathDebugObjUsageRequested(NULL, val->type);
5444 #endif
5445     switch (val->type) {
5446 	case XPATH_BOOLEAN:
5447 	case XPATH_NUMBER:
5448 	case XPATH_POINT:
5449 	case XPATH_RANGE:
5450 	    break;
5451 	case XPATH_STRING:
5452 	    ret->stringval = xmlStrdup(val->stringval);
5453 	    break;
5454 	case XPATH_XSLT_TREE:
5455 #if 0
5456 /*
5457   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5458   this previous handling is no longer correct, and can cause some serious
5459   problems (ref. bug 145547)
5460 */
5461 	    if ((val->nodesetval != NULL) &&
5462 		(val->nodesetval->nodeTab != NULL)) {
5463 		xmlNodePtr cur, tmp;
5464 		xmlDocPtr top;
5465 
5466 		ret->boolval = 1;
5467 		top =  xmlNewDoc(NULL);
5468 		top->name = (char *)
5469 		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
5470 		ret->user = top;
5471 		if (top != NULL) {
5472 		    top->doc = top;
5473 		    cur = val->nodesetval->nodeTab[0]->children;
5474 		    while (cur != NULL) {
5475 			tmp = xmlDocCopyNode(cur, top, 1);
5476 			xmlAddChild((xmlNodePtr) top, tmp);
5477 			cur = cur->next;
5478 		    }
5479 		}
5480 
5481 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5482 	    } else
5483 		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5484 	    /* Deallocate the copied tree value */
5485 	    break;
5486 #endif
5487 	case XPATH_NODESET:
5488 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5489 	    /* Do not deallocate the copied tree value */
5490 	    ret->boolval = 0;
5491 	    break;
5492 	case XPATH_LOCATIONSET:
5493 #ifdef LIBXML_XPTR_ENABLED
5494 	{
5495 	    xmlLocationSetPtr loc = val->user;
5496 	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5497 	    break;
5498 	}
5499 #endif
5500         case XPATH_USERS:
5501 	    ret->user = val->user;
5502 	    break;
5503         case XPATH_UNDEFINED:
5504 	    xmlGenericError(xmlGenericErrorContext,
5505 		    "xmlXPathObjectCopy: unsupported type %d\n",
5506 		    val->type);
5507 	    break;
5508     }
5509     return(ret);
5510 }
5511 
5512 /**
5513  * xmlXPathFreeObject:
5514  * @obj:  the object to free
5515  *
5516  * Free up an xmlXPathObjectPtr object.
5517  */
5518 void
xmlXPathFreeObject(xmlXPathObjectPtr obj)5519 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5520     if (obj == NULL) return;
5521     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5522 	if (obj->boolval) {
5523 #if 0
5524 	    if (obj->user != NULL) {
5525                 xmlXPathFreeNodeSet(obj->nodesetval);
5526 		xmlFreeNodeList((xmlNodePtr) obj->user);
5527 	    } else
5528 #endif
5529 	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5530 	    if (obj->nodesetval != NULL)
5531 		xmlXPathFreeValueTree(obj->nodesetval);
5532 	} else {
5533 	    if (obj->nodesetval != NULL)
5534 		xmlXPathFreeNodeSet(obj->nodesetval);
5535 	}
5536 #ifdef LIBXML_XPTR_ENABLED
5537     } else if (obj->type == XPATH_LOCATIONSET) {
5538 	if (obj->user != NULL)
5539 	    xmlXPtrFreeLocationSet(obj->user);
5540 #endif
5541     } else if (obj->type == XPATH_STRING) {
5542 	if (obj->stringval != NULL)
5543 	    xmlFree(obj->stringval);
5544     }
5545 #ifdef XP_DEBUG_OBJ_USAGE
5546     xmlXPathDebugObjUsageReleased(NULL, obj->type);
5547 #endif
5548     xmlFree(obj);
5549 }
5550 
5551 static void
xmlXPathFreeObjectEntry(void * obj,const xmlChar * name ATTRIBUTE_UNUSED)5552 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5553     xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5554 }
5555 
5556 /**
5557  * xmlXPathReleaseObject:
5558  * @obj:  the xmlXPathObjectPtr to free or to cache
5559  *
5560  * Depending on the state of the cache this frees the given
5561  * XPath object or stores it in the cache.
5562  */
5563 static void
xmlXPathReleaseObject(xmlXPathContextPtr ctxt,xmlXPathObjectPtr obj)5564 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5565 {
5566 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5567 	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5568     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5569 
5570 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5571 
5572     if (obj == NULL)
5573 	return;
5574     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5575 	 xmlXPathFreeObject(obj);
5576     } else {
5577 	xmlXPathContextCachePtr cache =
5578 	    (xmlXPathContextCachePtr) ctxt->cache;
5579 
5580 	switch (obj->type) {
5581 	    case XPATH_NODESET:
5582 	    case XPATH_XSLT_TREE:
5583 		if (obj->nodesetval != NULL) {
5584 		    if (obj->boolval) {
5585 			/*
5586 			* It looks like the @boolval is used for
5587 			* evaluation if this an XSLT Result Tree Fragment.
5588 			* TODO: Check if this assumption is correct.
5589 			*/
5590 			obj->type = XPATH_XSLT_TREE; /* just for debugging */
5591 			xmlXPathFreeValueTree(obj->nodesetval);
5592 			obj->nodesetval = NULL;
5593 		    } else if ((obj->nodesetval->nodeMax <= 40) &&
5594 			(XP_CACHE_WANTS(cache->nodesetObjs,
5595 					cache->maxNodeset)))
5596 		    {
5597 			XP_CACHE_ADD(cache->nodesetObjs, obj);
5598 			goto obj_cached;
5599 		    } else {
5600 			xmlXPathFreeNodeSet(obj->nodesetval);
5601 			obj->nodesetval = NULL;
5602 		    }
5603 		}
5604 		break;
5605 	    case XPATH_STRING:
5606 		if (obj->stringval != NULL)
5607 		    xmlFree(obj->stringval);
5608 
5609 		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5610 		    XP_CACHE_ADD(cache->stringObjs, obj);
5611 		    goto obj_cached;
5612 		}
5613 		break;
5614 	    case XPATH_BOOLEAN:
5615 		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5616 		    XP_CACHE_ADD(cache->booleanObjs, obj);
5617 		    goto obj_cached;
5618 		}
5619 		break;
5620 	    case XPATH_NUMBER:
5621 		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5622 		    XP_CACHE_ADD(cache->numberObjs, obj);
5623 		    goto obj_cached;
5624 		}
5625 		break;
5626 #ifdef LIBXML_XPTR_ENABLED
5627 	    case XPATH_LOCATIONSET:
5628 		if (obj->user != NULL) {
5629 		    xmlXPtrFreeLocationSet(obj->user);
5630 		}
5631 		goto free_obj;
5632 #endif
5633 	    default:
5634 		goto free_obj;
5635 	}
5636 
5637 	/*
5638 	* Fallback to adding to the misc-objects slot.
5639 	*/
5640 	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5641 	    XP_CACHE_ADD(cache->miscObjs, obj);
5642 	} else
5643 	    goto free_obj;
5644 
5645 obj_cached:
5646 
5647 #ifdef XP_DEBUG_OBJ_USAGE
5648 	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5649 #endif
5650 
5651 	if (obj->nodesetval != NULL) {
5652 	    xmlNodeSetPtr tmpset = obj->nodesetval;
5653 
5654 	    /*
5655 	    * TODO: Due to those nasty ns-nodes, we need to traverse
5656 	    *  the list and free the ns-nodes.
5657 	    * URGENT TODO: Check if it's actually slowing things down.
5658 	    *  Maybe we shouldn't try to preserve the list.
5659 	    */
5660 	    if (tmpset->nodeNr > 1) {
5661 		int i;
5662 		xmlNodePtr node;
5663 
5664 		for (i = 0; i < tmpset->nodeNr; i++) {
5665 		    node = tmpset->nodeTab[i];
5666 		    if ((node != NULL) &&
5667 			(node->type == XML_NAMESPACE_DECL))
5668 		    {
5669 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5670 		    }
5671 		}
5672 	    } else if (tmpset->nodeNr == 1) {
5673 		if ((tmpset->nodeTab[0] != NULL) &&
5674 		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5675 		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5676 	    }
5677 	    tmpset->nodeNr = 0;
5678 	    memset(obj, 0, sizeof(xmlXPathObject));
5679 	    obj->nodesetval = tmpset;
5680 	} else
5681 	    memset(obj, 0, sizeof(xmlXPathObject));
5682 
5683 	return;
5684 
5685 free_obj:
5686 	/*
5687 	* Cache is full; free the object.
5688 	*/
5689 	if (obj->nodesetval != NULL)
5690 	    xmlXPathFreeNodeSet(obj->nodesetval);
5691 #ifdef XP_DEBUG_OBJ_USAGE
5692 	xmlXPathDebugObjUsageReleased(NULL, obj->type);
5693 #endif
5694 	xmlFree(obj);
5695     }
5696     return;
5697 }
5698 
5699 
5700 /************************************************************************
5701  *									*
5702  *			Type Casting Routines				*
5703  *									*
5704  ************************************************************************/
5705 
5706 /**
5707  * xmlXPathCastBooleanToString:
5708  * @val:  a boolean
5709  *
5710  * Converts a boolean to its string value.
5711  *
5712  * Returns a newly allocated string.
5713  */
5714 xmlChar *
xmlXPathCastBooleanToString(int val)5715 xmlXPathCastBooleanToString (int val) {
5716     xmlChar *ret;
5717     if (val)
5718 	ret = xmlStrdup((const xmlChar *) "true");
5719     else
5720 	ret = xmlStrdup((const xmlChar *) "false");
5721     return(ret);
5722 }
5723 
5724 /**
5725  * xmlXPathCastNumberToString:
5726  * @val:  a number
5727  *
5728  * Converts a number to its string value.
5729  *
5730  * Returns a newly allocated string.
5731  */
5732 xmlChar *
xmlXPathCastNumberToString(double val)5733 xmlXPathCastNumberToString (double val) {
5734     xmlChar *ret;
5735     switch (xmlXPathIsInf(val)) {
5736     case 1:
5737 	ret = xmlStrdup((const xmlChar *) "Infinity");
5738 	break;
5739     case -1:
5740 	ret = xmlStrdup((const xmlChar *) "-Infinity");
5741 	break;
5742     default:
5743 	if (xmlXPathIsNaN(val)) {
5744 	    ret = xmlStrdup((const xmlChar *) "NaN");
5745 	} else if (val == 0) {
5746             /* Omit sign for negative zero. */
5747 	    ret = xmlStrdup((const xmlChar *) "0");
5748 	} else {
5749 	    /* could be improved */
5750 	    char buf[100];
5751 	    xmlXPathFormatNumber(val, buf, 99);
5752 	    buf[99] = 0;
5753 	    ret = xmlStrdup((const xmlChar *) buf);
5754 	}
5755     }
5756     return(ret);
5757 }
5758 
5759 /**
5760  * xmlXPathCastNodeToString:
5761  * @node:  a node
5762  *
5763  * Converts a node to its string value.
5764  *
5765  * Returns a newly allocated string.
5766  */
5767 xmlChar *
xmlXPathCastNodeToString(xmlNodePtr node)5768 xmlXPathCastNodeToString (xmlNodePtr node) {
5769 xmlChar *ret;
5770     if ((ret = xmlNodeGetContent(node)) == NULL)
5771 	ret = xmlStrdup((const xmlChar *) "");
5772     return(ret);
5773 }
5774 
5775 /**
5776  * xmlXPathCastNodeSetToString:
5777  * @ns:  a node-set
5778  *
5779  * Converts a node-set to its string value.
5780  *
5781  * Returns a newly allocated string.
5782  */
5783 xmlChar *
xmlXPathCastNodeSetToString(xmlNodeSetPtr ns)5784 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5785     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5786 	return(xmlStrdup((const xmlChar *) ""));
5787 
5788     if (ns->nodeNr > 1)
5789 	xmlXPathNodeSetSort(ns);
5790     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5791 }
5792 
5793 /**
5794  * xmlXPathCastToString:
5795  * @val:  an XPath object
5796  *
5797  * Converts an existing object to its string() equivalent
5798  *
5799  * Returns the allocated string value of the object, NULL in case of error.
5800  *         It's up to the caller to free the string memory with xmlFree().
5801  */
5802 xmlChar *
xmlXPathCastToString(xmlXPathObjectPtr val)5803 xmlXPathCastToString(xmlXPathObjectPtr val) {
5804     xmlChar *ret = NULL;
5805 
5806     if (val == NULL)
5807 	return(xmlStrdup((const xmlChar *) ""));
5808     switch (val->type) {
5809 	case XPATH_UNDEFINED:
5810 #ifdef DEBUG_EXPR
5811 	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5812 #endif
5813 	    ret = xmlStrdup((const xmlChar *) "");
5814 	    break;
5815         case XPATH_NODESET:
5816         case XPATH_XSLT_TREE:
5817 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
5818 	    break;
5819 	case XPATH_STRING:
5820 	    return(xmlStrdup(val->stringval));
5821         case XPATH_BOOLEAN:
5822 	    ret = xmlXPathCastBooleanToString(val->boolval);
5823 	    break;
5824 	case XPATH_NUMBER: {
5825 	    ret = xmlXPathCastNumberToString(val->floatval);
5826 	    break;
5827 	}
5828 	case XPATH_USERS:
5829 	case XPATH_POINT:
5830 	case XPATH_RANGE:
5831 	case XPATH_LOCATIONSET:
5832 	    TODO
5833 	    ret = xmlStrdup((const xmlChar *) "");
5834 	    break;
5835     }
5836     return(ret);
5837 }
5838 
5839 /**
5840  * xmlXPathConvertString:
5841  * @val:  an XPath object
5842  *
5843  * Converts an existing object to its string() equivalent
5844  *
5845  * Returns the new object, the old one is freed (or the operation
5846  *         is done directly on @val)
5847  */
5848 xmlXPathObjectPtr
xmlXPathConvertString(xmlXPathObjectPtr val)5849 xmlXPathConvertString(xmlXPathObjectPtr val) {
5850     xmlChar *res = NULL;
5851 
5852     if (val == NULL)
5853 	return(xmlXPathNewCString(""));
5854 
5855     switch (val->type) {
5856     case XPATH_UNDEFINED:
5857 #ifdef DEBUG_EXPR
5858 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5859 #endif
5860 	break;
5861     case XPATH_NODESET:
5862     case XPATH_XSLT_TREE:
5863 	res = xmlXPathCastNodeSetToString(val->nodesetval);
5864 	break;
5865     case XPATH_STRING:
5866 	return(val);
5867     case XPATH_BOOLEAN:
5868 	res = xmlXPathCastBooleanToString(val->boolval);
5869 	break;
5870     case XPATH_NUMBER:
5871 	res = xmlXPathCastNumberToString(val->floatval);
5872 	break;
5873     case XPATH_USERS:
5874     case XPATH_POINT:
5875     case XPATH_RANGE:
5876     case XPATH_LOCATIONSET:
5877 	TODO;
5878 	break;
5879     }
5880     xmlXPathFreeObject(val);
5881     if (res == NULL)
5882 	return(xmlXPathNewCString(""));
5883     return(xmlXPathWrapString(res));
5884 }
5885 
5886 /**
5887  * xmlXPathCastBooleanToNumber:
5888  * @val:  a boolean
5889  *
5890  * Converts a boolean to its number value
5891  *
5892  * Returns the number value
5893  */
5894 double
xmlXPathCastBooleanToNumber(int val)5895 xmlXPathCastBooleanToNumber(int val) {
5896     if (val)
5897 	return(1.0);
5898     return(0.0);
5899 }
5900 
5901 /**
5902  * xmlXPathCastStringToNumber:
5903  * @val:  a string
5904  *
5905  * Converts a string to its number value
5906  *
5907  * Returns the number value
5908  */
5909 double
xmlXPathCastStringToNumber(const xmlChar * val)5910 xmlXPathCastStringToNumber(const xmlChar * val) {
5911     return(xmlXPathStringEvalNumber(val));
5912 }
5913 
5914 /**
5915  * xmlXPathCastNodeToNumber:
5916  * @node:  a node
5917  *
5918  * Converts a node to its number value
5919  *
5920  * Returns the number value
5921  */
5922 double
xmlXPathCastNodeToNumber(xmlNodePtr node)5923 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5924     xmlChar *strval;
5925     double ret;
5926 
5927     if (node == NULL)
5928 	return(NAN);
5929     strval = xmlXPathCastNodeToString(node);
5930     if (strval == NULL)
5931 	return(NAN);
5932     ret = xmlXPathCastStringToNumber(strval);
5933     xmlFree(strval);
5934 
5935     return(ret);
5936 }
5937 
5938 /**
5939  * xmlXPathCastNodeSetToNumber:
5940  * @ns:  a node-set
5941  *
5942  * Converts a node-set to its number value
5943  *
5944  * Returns the number value
5945  */
5946 double
xmlXPathCastNodeSetToNumber(xmlNodeSetPtr ns)5947 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5948     xmlChar *str;
5949     double ret;
5950 
5951     if (ns == NULL)
5952 	return(NAN);
5953     str = xmlXPathCastNodeSetToString(ns);
5954     ret = xmlXPathCastStringToNumber(str);
5955     xmlFree(str);
5956     return(ret);
5957 }
5958 
5959 /**
5960  * xmlXPathCastToNumber:
5961  * @val:  an XPath object
5962  *
5963  * Converts an XPath object to its number value
5964  *
5965  * Returns the number value
5966  */
5967 double
xmlXPathCastToNumber(xmlXPathObjectPtr val)5968 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5969     double ret = 0.0;
5970 
5971     if (val == NULL)
5972 	return(NAN);
5973     switch (val->type) {
5974     case XPATH_UNDEFINED:
5975 #ifdef DEGUB_EXPR
5976 	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5977 #endif
5978 	ret = NAN;
5979 	break;
5980     case XPATH_NODESET:
5981     case XPATH_XSLT_TREE:
5982 	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5983 	break;
5984     case XPATH_STRING:
5985 	ret = xmlXPathCastStringToNumber(val->stringval);
5986 	break;
5987     case XPATH_NUMBER:
5988 	ret = val->floatval;
5989 	break;
5990     case XPATH_BOOLEAN:
5991 	ret = xmlXPathCastBooleanToNumber(val->boolval);
5992 	break;
5993     case XPATH_USERS:
5994     case XPATH_POINT:
5995     case XPATH_RANGE:
5996     case XPATH_LOCATIONSET:
5997 	TODO;
5998 	ret = NAN;
5999 	break;
6000     }
6001     return(ret);
6002 }
6003 
6004 /**
6005  * xmlXPathConvertNumber:
6006  * @val:  an XPath object
6007  *
6008  * Converts an existing object to its number() equivalent
6009  *
6010  * Returns the new object, the old one is freed (or the operation
6011  *         is done directly on @val)
6012  */
6013 xmlXPathObjectPtr
xmlXPathConvertNumber(xmlXPathObjectPtr val)6014 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
6015     xmlXPathObjectPtr ret;
6016 
6017     if (val == NULL)
6018 	return(xmlXPathNewFloat(0.0));
6019     if (val->type == XPATH_NUMBER)
6020 	return(val);
6021     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
6022     xmlXPathFreeObject(val);
6023     return(ret);
6024 }
6025 
6026 /**
6027  * xmlXPathCastNumberToBoolean:
6028  * @val:  a number
6029  *
6030  * Converts a number to its boolean value
6031  *
6032  * Returns the boolean value
6033  */
6034 int
xmlXPathCastNumberToBoolean(double val)6035 xmlXPathCastNumberToBoolean (double val) {
6036      if (xmlXPathIsNaN(val) || (val == 0.0))
6037 	 return(0);
6038      return(1);
6039 }
6040 
6041 /**
6042  * xmlXPathCastStringToBoolean:
6043  * @val:  a string
6044  *
6045  * Converts a string to its boolean value
6046  *
6047  * Returns the boolean value
6048  */
6049 int
xmlXPathCastStringToBoolean(const xmlChar * val)6050 xmlXPathCastStringToBoolean (const xmlChar *val) {
6051     if ((val == NULL) || (xmlStrlen(val) == 0))
6052 	return(0);
6053     return(1);
6054 }
6055 
6056 /**
6057  * xmlXPathCastNodeSetToBoolean:
6058  * @ns:  a node-set
6059  *
6060  * Converts a node-set to its boolean value
6061  *
6062  * Returns the boolean value
6063  */
6064 int
xmlXPathCastNodeSetToBoolean(xmlNodeSetPtr ns)6065 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6066     if ((ns == NULL) || (ns->nodeNr == 0))
6067 	return(0);
6068     return(1);
6069 }
6070 
6071 /**
6072  * xmlXPathCastToBoolean:
6073  * @val:  an XPath object
6074  *
6075  * Converts an XPath object to its boolean value
6076  *
6077  * Returns the boolean value
6078  */
6079 int
xmlXPathCastToBoolean(xmlXPathObjectPtr val)6080 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6081     int ret = 0;
6082 
6083     if (val == NULL)
6084 	return(0);
6085     switch (val->type) {
6086     case XPATH_UNDEFINED:
6087 #ifdef DEBUG_EXPR
6088 	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6089 #endif
6090 	ret = 0;
6091 	break;
6092     case XPATH_NODESET:
6093     case XPATH_XSLT_TREE:
6094 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6095 	break;
6096     case XPATH_STRING:
6097 	ret = xmlXPathCastStringToBoolean(val->stringval);
6098 	break;
6099     case XPATH_NUMBER:
6100 	ret = xmlXPathCastNumberToBoolean(val->floatval);
6101 	break;
6102     case XPATH_BOOLEAN:
6103 	ret = val->boolval;
6104 	break;
6105     case XPATH_USERS:
6106     case XPATH_POINT:
6107     case XPATH_RANGE:
6108     case XPATH_LOCATIONSET:
6109 	TODO;
6110 	ret = 0;
6111 	break;
6112     }
6113     return(ret);
6114 }
6115 
6116 
6117 /**
6118  * xmlXPathConvertBoolean:
6119  * @val:  an XPath object
6120  *
6121  * Converts an existing object to its boolean() equivalent
6122  *
6123  * Returns the new object, the old one is freed (or the operation
6124  *         is done directly on @val)
6125  */
6126 xmlXPathObjectPtr
xmlXPathConvertBoolean(xmlXPathObjectPtr val)6127 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6128     xmlXPathObjectPtr ret;
6129 
6130     if (val == NULL)
6131 	return(xmlXPathNewBoolean(0));
6132     if (val->type == XPATH_BOOLEAN)
6133 	return(val);
6134     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6135     xmlXPathFreeObject(val);
6136     return(ret);
6137 }
6138 
6139 /************************************************************************
6140  *									*
6141  *		Routines to handle XPath contexts			*
6142  *									*
6143  ************************************************************************/
6144 
6145 /**
6146  * xmlXPathNewContext:
6147  * @doc:  the XML document
6148  *
6149  * Create a new xmlXPathContext
6150  *
6151  * Returns the xmlXPathContext just allocated. The caller will need to free it.
6152  */
6153 xmlXPathContextPtr
xmlXPathNewContext(xmlDocPtr doc)6154 xmlXPathNewContext(xmlDocPtr doc) {
6155     xmlXPathContextPtr ret;
6156 
6157     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6158     if (ret == NULL) {
6159         xmlXPathErrMemory(NULL, "creating context\n");
6160 	return(NULL);
6161     }
6162     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6163     ret->doc = doc;
6164     ret->node = NULL;
6165 
6166     ret->varHash = NULL;
6167 
6168     ret->nb_types = 0;
6169     ret->max_types = 0;
6170     ret->types = NULL;
6171 
6172     ret->funcHash = xmlHashCreate(0);
6173 
6174     ret->nb_axis = 0;
6175     ret->max_axis = 0;
6176     ret->axis = NULL;
6177 
6178     ret->nsHash = NULL;
6179     ret->user = NULL;
6180 
6181     ret->contextSize = -1;
6182     ret->proximityPosition = -1;
6183 
6184 #ifdef XP_DEFAULT_CACHE_ON
6185     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6186 	xmlXPathFreeContext(ret);
6187 	return(NULL);
6188     }
6189 #endif
6190 
6191     xmlXPathRegisterAllFunctions(ret);
6192 
6193     return(ret);
6194 }
6195 
6196 /**
6197  * xmlXPathFreeContext:
6198  * @ctxt:  the context to free
6199  *
6200  * Free up an xmlXPathContext
6201  */
6202 void
xmlXPathFreeContext(xmlXPathContextPtr ctxt)6203 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6204     if (ctxt == NULL) return;
6205 
6206     if (ctxt->cache != NULL)
6207 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6208     xmlXPathRegisteredNsCleanup(ctxt);
6209     xmlXPathRegisteredFuncsCleanup(ctxt);
6210     xmlXPathRegisteredVariablesCleanup(ctxt);
6211     xmlResetError(&ctxt->lastError);
6212     xmlFree(ctxt);
6213 }
6214 
6215 /************************************************************************
6216  *									*
6217  *		Routines to handle XPath parser contexts		*
6218  *									*
6219  ************************************************************************/
6220 
6221 #define CHECK_CTXT(ctxt)						\
6222     if (ctxt == NULL) {						\
6223 	__xmlRaiseError(NULL, NULL, NULL,				\
6224 		NULL, NULL, XML_FROM_XPATH,				\
6225 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6226 		__FILE__, __LINE__,					\
6227 		NULL, NULL, NULL, 0, 0,					\
6228 		"NULL context pointer\n");				\
6229 	return(NULL);							\
6230     }									\
6231 
6232 #define CHECK_CTXT_NEG(ctxt)						\
6233     if (ctxt == NULL) {						\
6234 	__xmlRaiseError(NULL, NULL, NULL,				\
6235 		NULL, NULL, XML_FROM_XPATH,				\
6236 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6237 		__FILE__, __LINE__,					\
6238 		NULL, NULL, NULL, 0, 0,					\
6239 		"NULL context pointer\n");				\
6240 	return(-1);							\
6241     }									\
6242 
6243 
6244 #define CHECK_CONTEXT(ctxt)						\
6245     if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
6246         (ctxt->doc->children == NULL)) {				\
6247 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
6248 	return(NULL);							\
6249     }
6250 
6251 
6252 /**
6253  * xmlXPathNewParserContext:
6254  * @str:  the XPath expression
6255  * @ctxt:  the XPath context
6256  *
6257  * Create a new xmlXPathParserContext
6258  *
6259  * Returns the xmlXPathParserContext just allocated.
6260  */
6261 xmlXPathParserContextPtr
xmlXPathNewParserContext(const xmlChar * str,xmlXPathContextPtr ctxt)6262 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6263     xmlXPathParserContextPtr ret;
6264 
6265     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6266     if (ret == NULL) {
6267         xmlXPathErrMemory(ctxt, "creating parser context\n");
6268 	return(NULL);
6269     }
6270     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6271     ret->cur = ret->base = str;
6272     ret->context = ctxt;
6273 
6274     ret->comp = xmlXPathNewCompExpr();
6275     if (ret->comp == NULL) {
6276 	xmlFree(ret->valueTab);
6277 	xmlFree(ret);
6278 	return(NULL);
6279     }
6280     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6281         ret->comp->dict = ctxt->dict;
6282 	xmlDictReference(ret->comp->dict);
6283     }
6284 
6285     return(ret);
6286 }
6287 
6288 /**
6289  * xmlXPathCompParserContext:
6290  * @comp:  the XPath compiled expression
6291  * @ctxt:  the XPath context
6292  *
6293  * Create a new xmlXPathParserContext when processing a compiled expression
6294  *
6295  * Returns the xmlXPathParserContext just allocated.
6296  */
6297 static xmlXPathParserContextPtr
xmlXPathCompParserContext(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)6298 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6299     xmlXPathParserContextPtr ret;
6300 
6301     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6302     if (ret == NULL) {
6303         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6304 	return(NULL);
6305     }
6306     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6307 
6308     /* Allocate the value stack */
6309     ret->valueTab = (xmlXPathObjectPtr *)
6310                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6311     if (ret->valueTab == NULL) {
6312 	xmlFree(ret);
6313 	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6314 	return(NULL);
6315     }
6316     ret->valueNr = 0;
6317     ret->valueMax = 10;
6318     ret->value = NULL;
6319     ret->valueFrame = 0;
6320 
6321     ret->context = ctxt;
6322     ret->comp = comp;
6323 
6324     return(ret);
6325 }
6326 
6327 /**
6328  * xmlXPathFreeParserContext:
6329  * @ctxt:  the context to free
6330  *
6331  * Free up an xmlXPathParserContext
6332  */
6333 void
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt)6334 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6335     int i;
6336 
6337     if (ctxt->valueTab != NULL) {
6338         for (i = 0; i < ctxt->valueNr; i++) {
6339             if (ctxt->context)
6340                 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6341             else
6342                 xmlXPathFreeObject(ctxt->valueTab[i]);
6343         }
6344         xmlFree(ctxt->valueTab);
6345     }
6346     if (ctxt->comp != NULL) {
6347 #ifdef XPATH_STREAMING
6348 	if (ctxt->comp->stream != NULL) {
6349 	    xmlFreePatternList(ctxt->comp->stream);
6350 	    ctxt->comp->stream = NULL;
6351 	}
6352 #endif
6353 	xmlXPathFreeCompExpr(ctxt->comp);
6354     }
6355     xmlFree(ctxt);
6356 }
6357 
6358 /************************************************************************
6359  *									*
6360  *		The implicit core function library			*
6361  *									*
6362  ************************************************************************/
6363 
6364 /**
6365  * xmlXPathNodeValHash:
6366  * @node:  a node pointer
6367  *
6368  * Function computing the beginning of the string value of the node,
6369  * used to speed up comparisons
6370  *
6371  * Returns an int usable as a hash
6372  */
6373 static unsigned int
xmlXPathNodeValHash(xmlNodePtr node)6374 xmlXPathNodeValHash(xmlNodePtr node) {
6375     int len = 2;
6376     const xmlChar * string = NULL;
6377     xmlNodePtr tmp = NULL;
6378     unsigned int ret = 0;
6379 
6380     if (node == NULL)
6381 	return(0);
6382 
6383     if (node->type == XML_DOCUMENT_NODE) {
6384 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
6385 	if (tmp == NULL)
6386 	    node = node->children;
6387 	else
6388 	    node = tmp;
6389 
6390 	if (node == NULL)
6391 	    return(0);
6392     }
6393 
6394     switch (node->type) {
6395 	case XML_COMMENT_NODE:
6396 	case XML_PI_NODE:
6397 	case XML_CDATA_SECTION_NODE:
6398 	case XML_TEXT_NODE:
6399 	    string = node->content;
6400 	    if (string == NULL)
6401 		return(0);
6402 	    if (string[0] == 0)
6403 		return(0);
6404 	    return(((unsigned int) string[0]) +
6405 		   (((unsigned int) string[1]) << 8));
6406 	case XML_NAMESPACE_DECL:
6407 	    string = ((xmlNsPtr)node)->href;
6408 	    if (string == NULL)
6409 		return(0);
6410 	    if (string[0] == 0)
6411 		return(0);
6412 	    return(((unsigned int) string[0]) +
6413 		   (((unsigned int) string[1]) << 8));
6414 	case XML_ATTRIBUTE_NODE:
6415 	    tmp = ((xmlAttrPtr) node)->children;
6416 	    break;
6417 	case XML_ELEMENT_NODE:
6418 	    tmp = node->children;
6419 	    break;
6420 	default:
6421 	    return(0);
6422     }
6423     while (tmp != NULL) {
6424 	switch (tmp->type) {
6425 	    case XML_CDATA_SECTION_NODE:
6426 	    case XML_TEXT_NODE:
6427 		string = tmp->content;
6428 		break;
6429 	    default:
6430                 string = NULL;
6431 		break;
6432 	}
6433 	if ((string != NULL) && (string[0] != 0)) {
6434 	    if (len == 1) {
6435 		return(ret + (((unsigned int) string[0]) << 8));
6436 	    }
6437 	    if (string[1] == 0) {
6438 		len = 1;
6439 		ret = (unsigned int) string[0];
6440 	    } else {
6441 		return(((unsigned int) string[0]) +
6442 		       (((unsigned int) string[1]) << 8));
6443 	    }
6444 	}
6445 	/*
6446 	 * Skip to next node
6447 	 */
6448 	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6449 	    if (tmp->children->type != XML_ENTITY_DECL) {
6450 		tmp = tmp->children;
6451 		continue;
6452 	    }
6453 	}
6454 	if (tmp == node)
6455 	    break;
6456 
6457 	if (tmp->next != NULL) {
6458 	    tmp = tmp->next;
6459 	    continue;
6460 	}
6461 
6462 	do {
6463 	    tmp = tmp->parent;
6464 	    if (tmp == NULL)
6465 		break;
6466 	    if (tmp == node) {
6467 		tmp = NULL;
6468 		break;
6469 	    }
6470 	    if (tmp->next != NULL) {
6471 		tmp = tmp->next;
6472 		break;
6473 	    }
6474 	} while (tmp != NULL);
6475     }
6476     return(ret);
6477 }
6478 
6479 /**
6480  * xmlXPathStringHash:
6481  * @string:  a string
6482  *
6483  * Function computing the beginning of the string value of the node,
6484  * used to speed up comparisons
6485  *
6486  * Returns an int usable as a hash
6487  */
6488 static unsigned int
xmlXPathStringHash(const xmlChar * string)6489 xmlXPathStringHash(const xmlChar * string) {
6490     if (string == NULL)
6491 	return((unsigned int) 0);
6492     if (string[0] == 0)
6493 	return(0);
6494     return(((unsigned int) string[0]) +
6495 	   (((unsigned int) string[1]) << 8));
6496 }
6497 
6498 /**
6499  * xmlXPathCompareNodeSetFloat:
6500  * @ctxt:  the XPath Parser context
6501  * @inf:  less than (1) or greater than (0)
6502  * @strict:  is the comparison strict
6503  * @arg:  the node set
6504  * @f:  the value
6505  *
6506  * Implement the compare operation between a nodeset and a number
6507  *     @ns < @val    (1, 1, ...
6508  *     @ns <= @val   (1, 0, ...
6509  *     @ns > @val    (0, 1, ...
6510  *     @ns >= @val   (0, 0, ...
6511  *
6512  * If one object to be compared is a node-set and the other is a number,
6513  * then the comparison will be true if and only if there is a node in the
6514  * node-set such that the result of performing the comparison on the number
6515  * to be compared and on the result of converting the string-value of that
6516  * node to a number using the number function is true.
6517  *
6518  * Returns 0 or 1 depending on the results of the test.
6519  */
6520 static int
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr f)6521 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6522 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6523     int i, ret = 0;
6524     xmlNodeSetPtr ns;
6525     xmlChar *str2;
6526 
6527     if ((f == NULL) || (arg == NULL) ||
6528 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6529 	xmlXPathReleaseObject(ctxt->context, arg);
6530 	xmlXPathReleaseObject(ctxt->context, f);
6531         return(0);
6532     }
6533     ns = arg->nodesetval;
6534     if (ns != NULL) {
6535 	for (i = 0;i < ns->nodeNr;i++) {
6536 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6537 	     if (str2 != NULL) {
6538 		 valuePush(ctxt,
6539 			   xmlXPathCacheNewString(ctxt->context, str2));
6540 		 xmlFree(str2);
6541 		 xmlXPathNumberFunction(ctxt, 1);
6542 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6543 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6544 		 if (ret)
6545 		     break;
6546 	     }
6547 	}
6548     }
6549     xmlXPathReleaseObject(ctxt->context, arg);
6550     xmlXPathReleaseObject(ctxt->context, f);
6551     return(ret);
6552 }
6553 
6554 /**
6555  * xmlXPathCompareNodeSetString:
6556  * @ctxt:  the XPath Parser context
6557  * @inf:  less than (1) or greater than (0)
6558  * @strict:  is the comparison strict
6559  * @arg:  the node set
6560  * @s:  the value
6561  *
6562  * Implement the compare operation between a nodeset and a string
6563  *     @ns < @val    (1, 1, ...
6564  *     @ns <= @val   (1, 0, ...
6565  *     @ns > @val    (0, 1, ...
6566  *     @ns >= @val   (0, 0, ...
6567  *
6568  * If one object to be compared is a node-set and the other is a string,
6569  * then the comparison will be true if and only if there is a node in
6570  * the node-set such that the result of performing the comparison on the
6571  * string-value of the node and the other string is true.
6572  *
6573  * Returns 0 or 1 depending on the results of the test.
6574  */
6575 static int
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr s)6576 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6577 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6578     int i, ret = 0;
6579     xmlNodeSetPtr ns;
6580     xmlChar *str2;
6581 
6582     if ((s == NULL) || (arg == NULL) ||
6583 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6584 	xmlXPathReleaseObject(ctxt->context, arg);
6585 	xmlXPathReleaseObject(ctxt->context, s);
6586         return(0);
6587     }
6588     ns = arg->nodesetval;
6589     if (ns != NULL) {
6590 	for (i = 0;i < ns->nodeNr;i++) {
6591 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6592 	     if (str2 != NULL) {
6593 		 valuePush(ctxt,
6594 			   xmlXPathCacheNewString(ctxt->context, str2));
6595 		 xmlFree(str2);
6596 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6597 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6598 		 if (ret)
6599 		     break;
6600 	     }
6601 	}
6602     }
6603     xmlXPathReleaseObject(ctxt->context, arg);
6604     xmlXPathReleaseObject(ctxt->context, s);
6605     return(ret);
6606 }
6607 
6608 /**
6609  * xmlXPathCompareNodeSets:
6610  * @inf:  less than (1) or greater than (0)
6611  * @strict:  is the comparison strict
6612  * @arg1:  the first node set object
6613  * @arg2:  the second node set object
6614  *
6615  * Implement the compare operation on nodesets:
6616  *
6617  * If both objects to be compared are node-sets, then the comparison
6618  * will be true if and only if there is a node in the first node-set
6619  * and a node in the second node-set such that the result of performing
6620  * the comparison on the string-values of the two nodes is true.
6621  * ....
6622  * When neither object to be compared is a node-set and the operator
6623  * is <=, <, >= or >, then the objects are compared by converting both
6624  * objects to numbers and comparing the numbers according to IEEE 754.
6625  * ....
6626  * The number function converts its argument to a number as follows:
6627  *  - a string that consists of optional whitespace followed by an
6628  *    optional minus sign followed by a Number followed by whitespace
6629  *    is converted to the IEEE 754 number that is nearest (according
6630  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6631  *    represented by the string; any other string is converted to NaN
6632  *
6633  * Conclusion all nodes need to be converted first to their string value
6634  * and then the comparison must be done when possible
6635  */
6636 static int
xmlXPathCompareNodeSets(int inf,int strict,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6637 xmlXPathCompareNodeSets(int inf, int strict,
6638 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6639     int i, j, init = 0;
6640     double val1;
6641     double *values2;
6642     int ret = 0;
6643     xmlNodeSetPtr ns1;
6644     xmlNodeSetPtr ns2;
6645 
6646     if ((arg1 == NULL) ||
6647 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6648 	xmlXPathFreeObject(arg2);
6649         return(0);
6650     }
6651     if ((arg2 == NULL) ||
6652 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6653 	xmlXPathFreeObject(arg1);
6654 	xmlXPathFreeObject(arg2);
6655         return(0);
6656     }
6657 
6658     ns1 = arg1->nodesetval;
6659     ns2 = arg2->nodesetval;
6660 
6661     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6662 	xmlXPathFreeObject(arg1);
6663 	xmlXPathFreeObject(arg2);
6664 	return(0);
6665     }
6666     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6667 	xmlXPathFreeObject(arg1);
6668 	xmlXPathFreeObject(arg2);
6669 	return(0);
6670     }
6671 
6672     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6673     if (values2 == NULL) {
6674         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6675 	xmlXPathFreeObject(arg1);
6676 	xmlXPathFreeObject(arg2);
6677 	return(0);
6678     }
6679     for (i = 0;i < ns1->nodeNr;i++) {
6680 	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6681 	if (xmlXPathIsNaN(val1))
6682 	    continue;
6683 	for (j = 0;j < ns2->nodeNr;j++) {
6684 	    if (init == 0) {
6685 		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6686 	    }
6687 	    if (xmlXPathIsNaN(values2[j]))
6688 		continue;
6689 	    if (inf && strict)
6690 		ret = (val1 < values2[j]);
6691 	    else if (inf && !strict)
6692 		ret = (val1 <= values2[j]);
6693 	    else if (!inf && strict)
6694 		ret = (val1 > values2[j]);
6695 	    else if (!inf && !strict)
6696 		ret = (val1 >= values2[j]);
6697 	    if (ret)
6698 		break;
6699 	}
6700 	if (ret)
6701 	    break;
6702 	init = 1;
6703     }
6704     xmlFree(values2);
6705     xmlXPathFreeObject(arg1);
6706     xmlXPathFreeObject(arg2);
6707     return(ret);
6708 }
6709 
6710 /**
6711  * xmlXPathCompareNodeSetValue:
6712  * @ctxt:  the XPath Parser context
6713  * @inf:  less than (1) or greater than (0)
6714  * @strict:  is the comparison strict
6715  * @arg:  the node set
6716  * @val:  the value
6717  *
6718  * Implement the compare operation between a nodeset and a value
6719  *     @ns < @val    (1, 1, ...
6720  *     @ns <= @val   (1, 0, ...
6721  *     @ns > @val    (0, 1, ...
6722  *     @ns >= @val   (0, 0, ...
6723  *
6724  * If one object to be compared is a node-set and the other is a boolean,
6725  * then the comparison will be true if and only if the result of performing
6726  * the comparison on the boolean and on the result of converting
6727  * the node-set to a boolean using the boolean function is true.
6728  *
6729  * Returns 0 or 1 depending on the results of the test.
6730  */
6731 static int
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr val)6732 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6733 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6734     if ((val == NULL) || (arg == NULL) ||
6735 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6736         return(0);
6737 
6738     switch(val->type) {
6739         case XPATH_NUMBER:
6740 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6741         case XPATH_NODESET:
6742         case XPATH_XSLT_TREE:
6743 	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6744         case XPATH_STRING:
6745 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6746         case XPATH_BOOLEAN:
6747 	    valuePush(ctxt, arg);
6748 	    xmlXPathBooleanFunction(ctxt, 1);
6749 	    valuePush(ctxt, val);
6750 	    return(xmlXPathCompareValues(ctxt, inf, strict));
6751 	default:
6752             xmlGenericError(xmlGenericErrorContext,
6753                     "xmlXPathCompareNodeSetValue: Can't compare node set "
6754                     "and object of type %d\n",
6755                     val->type);
6756             xmlXPathReleaseObject(ctxt->context, arg);
6757             xmlXPathReleaseObject(ctxt->context, val);
6758             XP_ERROR0(XPATH_INVALID_TYPE);
6759     }
6760     return(0);
6761 }
6762 
6763 /**
6764  * xmlXPathEqualNodeSetString:
6765  * @arg:  the nodeset object argument
6766  * @str:  the string to compare to.
6767  * @neq:  flag to show whether for '=' (0) or '!=' (1)
6768  *
6769  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6770  * If one object to be compared is a node-set and the other is a string,
6771  * then the comparison will be true if and only if there is a node in
6772  * the node-set such that the result of performing the comparison on the
6773  * string-value of the node and the other string is true.
6774  *
6775  * Returns 0 or 1 depending on the results of the test.
6776  */
6777 static int
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg,const xmlChar * str,int neq)6778 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6779 {
6780     int i;
6781     xmlNodeSetPtr ns;
6782     xmlChar *str2;
6783     unsigned int hash;
6784 
6785     if ((str == NULL) || (arg == NULL) ||
6786         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6787         return (0);
6788     ns = arg->nodesetval;
6789     /*
6790      * A NULL nodeset compared with a string is always false
6791      * (since there is no node equal, and no node not equal)
6792      */
6793     if ((ns == NULL) || (ns->nodeNr <= 0) )
6794         return (0);
6795     hash = xmlXPathStringHash(str);
6796     for (i = 0; i < ns->nodeNr; i++) {
6797         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6798             str2 = xmlNodeGetContent(ns->nodeTab[i]);
6799             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6800                 xmlFree(str2);
6801 		if (neq)
6802 		    continue;
6803                 return (1);
6804 	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6805 		if (neq)
6806 		    continue;
6807                 return (1);
6808             } else if (neq) {
6809 		if (str2 != NULL)
6810 		    xmlFree(str2);
6811 		return (1);
6812 	    }
6813             if (str2 != NULL)
6814                 xmlFree(str2);
6815         } else if (neq)
6816 	    return (1);
6817     }
6818     return (0);
6819 }
6820 
6821 /**
6822  * xmlXPathEqualNodeSetFloat:
6823  * @arg:  the nodeset object argument
6824  * @f:  the float to compare to
6825  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6826  *
6827  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6828  * If one object to be compared is a node-set and the other is a number,
6829  * then the comparison will be true if and only if there is a node in
6830  * the node-set such that the result of performing the comparison on the
6831  * number to be compared and on the result of converting the string-value
6832  * of that node to a number using the number function is true.
6833  *
6834  * Returns 0 or 1 depending on the results of the test.
6835  */
6836 static int
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,double f,int neq)6837 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6838     xmlXPathObjectPtr arg, double f, int neq) {
6839   int i, ret=0;
6840   xmlNodeSetPtr ns;
6841   xmlChar *str2;
6842   xmlXPathObjectPtr val;
6843   double v;
6844 
6845     if ((arg == NULL) ||
6846 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6847         return(0);
6848 
6849     ns = arg->nodesetval;
6850     if (ns != NULL) {
6851 	for (i=0;i<ns->nodeNr;i++) {
6852 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6853 	    if (str2 != NULL) {
6854 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6855 		xmlFree(str2);
6856 		xmlXPathNumberFunction(ctxt, 1);
6857 		val = valuePop(ctxt);
6858 		v = val->floatval;
6859 		xmlXPathReleaseObject(ctxt->context, val);
6860 		if (!xmlXPathIsNaN(v)) {
6861 		    if ((!neq) && (v==f)) {
6862 			ret = 1;
6863 			break;
6864 		    } else if ((neq) && (v!=f)) {
6865 			ret = 1;
6866 			break;
6867 		    }
6868 		} else {	/* NaN is unequal to any value */
6869 		    if (neq)
6870 			ret = 1;
6871 		}
6872 	    }
6873 	}
6874     }
6875 
6876     return(ret);
6877 }
6878 
6879 
6880 /**
6881  * xmlXPathEqualNodeSets:
6882  * @arg1:  first nodeset object argument
6883  * @arg2:  second nodeset object argument
6884  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6885  *
6886  * Implement the equal / not equal operation on XPath nodesets:
6887  * @arg1 == @arg2  or  @arg1 != @arg2
6888  * If both objects to be compared are node-sets, then the comparison
6889  * will be true if and only if there is a node in the first node-set and
6890  * a node in the second node-set such that the result of performing the
6891  * comparison on the string-values of the two nodes is true.
6892  *
6893  * (needless to say, this is a costly operation)
6894  *
6895  * Returns 0 or 1 depending on the results of the test.
6896  */
6897 static int
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2,int neq)6898 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6899     int i, j;
6900     unsigned int *hashs1;
6901     unsigned int *hashs2;
6902     xmlChar **values1;
6903     xmlChar **values2;
6904     int ret = 0;
6905     xmlNodeSetPtr ns1;
6906     xmlNodeSetPtr ns2;
6907 
6908     if ((arg1 == NULL) ||
6909 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6910         return(0);
6911     if ((arg2 == NULL) ||
6912 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6913         return(0);
6914 
6915     ns1 = arg1->nodesetval;
6916     ns2 = arg2->nodesetval;
6917 
6918     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6919 	return(0);
6920     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6921 	return(0);
6922 
6923     /*
6924      * for equal, check if there is a node pertaining to both sets
6925      */
6926     if (neq == 0)
6927 	for (i = 0;i < ns1->nodeNr;i++)
6928 	    for (j = 0;j < ns2->nodeNr;j++)
6929 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
6930 		    return(1);
6931 
6932     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6933     if (values1 == NULL) {
6934         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6935 	return(0);
6936     }
6937     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6938     if (hashs1 == NULL) {
6939         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6940 	xmlFree(values1);
6941 	return(0);
6942     }
6943     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6944     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6945     if (values2 == NULL) {
6946         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6947 	xmlFree(hashs1);
6948 	xmlFree(values1);
6949 	return(0);
6950     }
6951     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6952     if (hashs2 == NULL) {
6953         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6954 	xmlFree(hashs1);
6955 	xmlFree(values1);
6956 	xmlFree(values2);
6957 	return(0);
6958     }
6959     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6960     for (i = 0;i < ns1->nodeNr;i++) {
6961 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6962 	for (j = 0;j < ns2->nodeNr;j++) {
6963 	    if (i == 0)
6964 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6965 	    if (hashs1[i] != hashs2[j]) {
6966 		if (neq) {
6967 		    ret = 1;
6968 		    break;
6969 		}
6970 	    }
6971 	    else {
6972 		if (values1[i] == NULL)
6973 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6974 		if (values2[j] == NULL)
6975 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6976 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6977 		if (ret)
6978 		    break;
6979 	    }
6980 	}
6981 	if (ret)
6982 	    break;
6983     }
6984     for (i = 0;i < ns1->nodeNr;i++)
6985 	if (values1[i] != NULL)
6986 	    xmlFree(values1[i]);
6987     for (j = 0;j < ns2->nodeNr;j++)
6988 	if (values2[j] != NULL)
6989 	    xmlFree(values2[j]);
6990     xmlFree(values1);
6991     xmlFree(values2);
6992     xmlFree(hashs1);
6993     xmlFree(hashs2);
6994     return(ret);
6995 }
6996 
6997 static int
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6998 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6999   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
7000     int ret = 0;
7001     /*
7002      *At this point we are assured neither arg1 nor arg2
7003      *is a nodeset, so we can just pick the appropriate routine.
7004      */
7005     switch (arg1->type) {
7006         case XPATH_UNDEFINED:
7007 #ifdef DEBUG_EXPR
7008 	    xmlGenericError(xmlGenericErrorContext,
7009 		    "Equal: undefined\n");
7010 #endif
7011 	    break;
7012         case XPATH_BOOLEAN:
7013 	    switch (arg2->type) {
7014 	        case XPATH_UNDEFINED:
7015 #ifdef DEBUG_EXPR
7016 		    xmlGenericError(xmlGenericErrorContext,
7017 			    "Equal: undefined\n");
7018 #endif
7019 		    break;
7020 		case XPATH_BOOLEAN:
7021 #ifdef DEBUG_EXPR
7022 		    xmlGenericError(xmlGenericErrorContext,
7023 			    "Equal: %d boolean %d \n",
7024 			    arg1->boolval, arg2->boolval);
7025 #endif
7026 		    ret = (arg1->boolval == arg2->boolval);
7027 		    break;
7028 		case XPATH_NUMBER:
7029 		    ret = (arg1->boolval ==
7030 			   xmlXPathCastNumberToBoolean(arg2->floatval));
7031 		    break;
7032 		case XPATH_STRING:
7033 		    if ((arg2->stringval == NULL) ||
7034 			(arg2->stringval[0] == 0)) ret = 0;
7035 		    else
7036 			ret = 1;
7037 		    ret = (arg1->boolval == ret);
7038 		    break;
7039 		case XPATH_USERS:
7040 		case XPATH_POINT:
7041 		case XPATH_RANGE:
7042 		case XPATH_LOCATIONSET:
7043 		    TODO
7044 		    break;
7045 		case XPATH_NODESET:
7046 		case XPATH_XSLT_TREE:
7047 		    break;
7048 	    }
7049 	    break;
7050         case XPATH_NUMBER:
7051 	    switch (arg2->type) {
7052 	        case XPATH_UNDEFINED:
7053 #ifdef DEBUG_EXPR
7054 		    xmlGenericError(xmlGenericErrorContext,
7055 			    "Equal: undefined\n");
7056 #endif
7057 		    break;
7058 		case XPATH_BOOLEAN:
7059 		    ret = (arg2->boolval==
7060 			   xmlXPathCastNumberToBoolean(arg1->floatval));
7061 		    break;
7062 		case XPATH_STRING:
7063 		    valuePush(ctxt, arg2);
7064 		    xmlXPathNumberFunction(ctxt, 1);
7065 		    arg2 = valuePop(ctxt);
7066                     /* Falls through. */
7067 		case XPATH_NUMBER:
7068 		    /* Hand check NaN and Infinity equalities */
7069 		    if (xmlXPathIsNaN(arg1->floatval) ||
7070 			    xmlXPathIsNaN(arg2->floatval)) {
7071 		        ret = 0;
7072 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7073 		        if (xmlXPathIsInf(arg2->floatval) == 1)
7074 			    ret = 1;
7075 			else
7076 			    ret = 0;
7077 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7078 			if (xmlXPathIsInf(arg2->floatval) == -1)
7079 			    ret = 1;
7080 			else
7081 			    ret = 0;
7082 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7083 			if (xmlXPathIsInf(arg1->floatval) == 1)
7084 			    ret = 1;
7085 			else
7086 			    ret = 0;
7087 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7088 			if (xmlXPathIsInf(arg1->floatval) == -1)
7089 			    ret = 1;
7090 			else
7091 			    ret = 0;
7092 		    } else {
7093 		        ret = (arg1->floatval == arg2->floatval);
7094 		    }
7095 		    break;
7096 		case XPATH_USERS:
7097 		case XPATH_POINT:
7098 		case XPATH_RANGE:
7099 		case XPATH_LOCATIONSET:
7100 		    TODO
7101 		    break;
7102 		case XPATH_NODESET:
7103 		case XPATH_XSLT_TREE:
7104 		    break;
7105 	    }
7106 	    break;
7107         case XPATH_STRING:
7108 	    switch (arg2->type) {
7109 	        case XPATH_UNDEFINED:
7110 #ifdef DEBUG_EXPR
7111 		    xmlGenericError(xmlGenericErrorContext,
7112 			    "Equal: undefined\n");
7113 #endif
7114 		    break;
7115 		case XPATH_BOOLEAN:
7116 		    if ((arg1->stringval == NULL) ||
7117 			(arg1->stringval[0] == 0)) ret = 0;
7118 		    else
7119 			ret = 1;
7120 		    ret = (arg2->boolval == ret);
7121 		    break;
7122 		case XPATH_STRING:
7123 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7124 		    break;
7125 		case XPATH_NUMBER:
7126 		    valuePush(ctxt, arg1);
7127 		    xmlXPathNumberFunction(ctxt, 1);
7128 		    arg1 = valuePop(ctxt);
7129 		    /* Hand check NaN and Infinity equalities */
7130 		    if (xmlXPathIsNaN(arg1->floatval) ||
7131 			    xmlXPathIsNaN(arg2->floatval)) {
7132 		        ret = 0;
7133 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7134 			if (xmlXPathIsInf(arg2->floatval) == 1)
7135 			    ret = 1;
7136 			else
7137 			    ret = 0;
7138 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7139 			if (xmlXPathIsInf(arg2->floatval) == -1)
7140 			    ret = 1;
7141 			else
7142 			    ret = 0;
7143 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7144 			if (xmlXPathIsInf(arg1->floatval) == 1)
7145 			    ret = 1;
7146 			else
7147 			    ret = 0;
7148 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7149 			if (xmlXPathIsInf(arg1->floatval) == -1)
7150 			    ret = 1;
7151 			else
7152 			    ret = 0;
7153 		    } else {
7154 		        ret = (arg1->floatval == arg2->floatval);
7155 		    }
7156 		    break;
7157 		case XPATH_USERS:
7158 		case XPATH_POINT:
7159 		case XPATH_RANGE:
7160 		case XPATH_LOCATIONSET:
7161 		    TODO
7162 		    break;
7163 		case XPATH_NODESET:
7164 		case XPATH_XSLT_TREE:
7165 		    break;
7166 	    }
7167 	    break;
7168         case XPATH_USERS:
7169 	case XPATH_POINT:
7170 	case XPATH_RANGE:
7171 	case XPATH_LOCATIONSET:
7172 	    TODO
7173 	    break;
7174 	case XPATH_NODESET:
7175 	case XPATH_XSLT_TREE:
7176 	    break;
7177     }
7178     xmlXPathReleaseObject(ctxt->context, arg1);
7179     xmlXPathReleaseObject(ctxt->context, arg2);
7180     return(ret);
7181 }
7182 
7183 /**
7184  * xmlXPathEqualValues:
7185  * @ctxt:  the XPath Parser context
7186  *
7187  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7188  *
7189  * Returns 0 or 1 depending on the results of the test.
7190  */
7191 int
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt)7192 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7193     xmlXPathObjectPtr arg1, arg2, argtmp;
7194     int ret = 0;
7195 
7196     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7197     arg2 = valuePop(ctxt);
7198     arg1 = valuePop(ctxt);
7199     if ((arg1 == NULL) || (arg2 == NULL)) {
7200 	if (arg1 != NULL)
7201 	    xmlXPathReleaseObject(ctxt->context, arg1);
7202 	else
7203 	    xmlXPathReleaseObject(ctxt->context, arg2);
7204 	XP_ERROR0(XPATH_INVALID_OPERAND);
7205     }
7206 
7207     if (arg1 == arg2) {
7208 #ifdef DEBUG_EXPR
7209         xmlGenericError(xmlGenericErrorContext,
7210 		"Equal: by pointer\n");
7211 #endif
7212 	xmlXPathFreeObject(arg1);
7213         return(1);
7214     }
7215 
7216     /*
7217      *If either argument is a nodeset, it's a 'special case'
7218      */
7219     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7220       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7221 	/*
7222 	 *Hack it to assure arg1 is the nodeset
7223 	 */
7224 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7225 		argtmp = arg2;
7226 		arg2 = arg1;
7227 		arg1 = argtmp;
7228 	}
7229 	switch (arg2->type) {
7230 	    case XPATH_UNDEFINED:
7231 #ifdef DEBUG_EXPR
7232 		xmlGenericError(xmlGenericErrorContext,
7233 			"Equal: undefined\n");
7234 #endif
7235 		break;
7236 	    case XPATH_NODESET:
7237 	    case XPATH_XSLT_TREE:
7238 		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7239 		break;
7240 	    case XPATH_BOOLEAN:
7241 		if ((arg1->nodesetval == NULL) ||
7242 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7243 		else
7244 		    ret = 1;
7245 		ret = (ret == arg2->boolval);
7246 		break;
7247 	    case XPATH_NUMBER:
7248 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7249 		break;
7250 	    case XPATH_STRING:
7251 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7252 		break;
7253 	    case XPATH_USERS:
7254 	    case XPATH_POINT:
7255 	    case XPATH_RANGE:
7256 	    case XPATH_LOCATIONSET:
7257 		TODO
7258 		break;
7259 	}
7260 	xmlXPathReleaseObject(ctxt->context, arg1);
7261 	xmlXPathReleaseObject(ctxt->context, arg2);
7262 	return(ret);
7263     }
7264 
7265     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7266 }
7267 
7268 /**
7269  * xmlXPathNotEqualValues:
7270  * @ctxt:  the XPath Parser context
7271  *
7272  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7273  *
7274  * Returns 0 or 1 depending on the results of the test.
7275  */
7276 int
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt)7277 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7278     xmlXPathObjectPtr arg1, arg2, argtmp;
7279     int ret = 0;
7280 
7281     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7282     arg2 = valuePop(ctxt);
7283     arg1 = valuePop(ctxt);
7284     if ((arg1 == NULL) || (arg2 == NULL)) {
7285 	if (arg1 != NULL)
7286 	    xmlXPathReleaseObject(ctxt->context, arg1);
7287 	else
7288 	    xmlXPathReleaseObject(ctxt->context, arg2);
7289 	XP_ERROR0(XPATH_INVALID_OPERAND);
7290     }
7291 
7292     if (arg1 == arg2) {
7293 #ifdef DEBUG_EXPR
7294         xmlGenericError(xmlGenericErrorContext,
7295 		"NotEqual: by pointer\n");
7296 #endif
7297 	xmlXPathReleaseObject(ctxt->context, arg1);
7298         return(0);
7299     }
7300 
7301     /*
7302      *If either argument is a nodeset, it's a 'special case'
7303      */
7304     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7305       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7306 	/*
7307 	 *Hack it to assure arg1 is the nodeset
7308 	 */
7309 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7310 		argtmp = arg2;
7311 		arg2 = arg1;
7312 		arg1 = argtmp;
7313 	}
7314 	switch (arg2->type) {
7315 	    case XPATH_UNDEFINED:
7316 #ifdef DEBUG_EXPR
7317 		xmlGenericError(xmlGenericErrorContext,
7318 			"NotEqual: undefined\n");
7319 #endif
7320 		break;
7321 	    case XPATH_NODESET:
7322 	    case XPATH_XSLT_TREE:
7323 		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7324 		break;
7325 	    case XPATH_BOOLEAN:
7326 		if ((arg1->nodesetval == NULL) ||
7327 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7328 		else
7329 		    ret = 1;
7330 		ret = (ret != arg2->boolval);
7331 		break;
7332 	    case XPATH_NUMBER:
7333 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7334 		break;
7335 	    case XPATH_STRING:
7336 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7337 		break;
7338 	    case XPATH_USERS:
7339 	    case XPATH_POINT:
7340 	    case XPATH_RANGE:
7341 	    case XPATH_LOCATIONSET:
7342 		TODO
7343 		break;
7344 	}
7345 	xmlXPathReleaseObject(ctxt->context, arg1);
7346 	xmlXPathReleaseObject(ctxt->context, arg2);
7347 	return(ret);
7348     }
7349 
7350     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7351 }
7352 
7353 /**
7354  * xmlXPathCompareValues:
7355  * @ctxt:  the XPath Parser context
7356  * @inf:  less than (1) or greater than (0)
7357  * @strict:  is the comparison strict
7358  *
7359  * Implement the compare operation on XPath objects:
7360  *     @arg1 < @arg2    (1, 1, ...
7361  *     @arg1 <= @arg2   (1, 0, ...
7362  *     @arg1 > @arg2    (0, 1, ...
7363  *     @arg1 >= @arg2   (0, 0, ...
7364  *
7365  * When neither object to be compared is a node-set and the operator is
7366  * <=, <, >=, >, then the objects are compared by converted both objects
7367  * to numbers and comparing the numbers according to IEEE 754. The <
7368  * comparison will be true if and only if the first number is less than the
7369  * second number. The <= comparison will be true if and only if the first
7370  * number is less than or equal to the second number. The > comparison
7371  * will be true if and only if the first number is greater than the second
7372  * number. The >= comparison will be true if and only if the first number
7373  * is greater than or equal to the second number.
7374  *
7375  * Returns 1 if the comparison succeeded, 0 if it failed
7376  */
7377 int
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt,int inf,int strict)7378 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7379     int ret = 0, arg1i = 0, arg2i = 0;
7380     xmlXPathObjectPtr arg1, arg2;
7381 
7382     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7383     arg2 = valuePop(ctxt);
7384     arg1 = valuePop(ctxt);
7385     if ((arg1 == NULL) || (arg2 == NULL)) {
7386 	if (arg1 != NULL)
7387 	    xmlXPathReleaseObject(ctxt->context, arg1);
7388 	else
7389 	    xmlXPathReleaseObject(ctxt->context, arg2);
7390 	XP_ERROR0(XPATH_INVALID_OPERAND);
7391     }
7392 
7393     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7394       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7395 	/*
7396 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7397 	 * are not freed from within this routine; they will be freed from the
7398 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7399 	 */
7400 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7401 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7402 	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7403 	} else {
7404 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7405 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7406 			                          arg1, arg2);
7407 	    } else {
7408 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7409 			                          arg2, arg1);
7410 	    }
7411 	}
7412 	return(ret);
7413     }
7414 
7415     if (arg1->type != XPATH_NUMBER) {
7416 	valuePush(ctxt, arg1);
7417 	xmlXPathNumberFunction(ctxt, 1);
7418 	arg1 = valuePop(ctxt);
7419     }
7420     if (arg1->type != XPATH_NUMBER) {
7421 	xmlXPathFreeObject(arg1);
7422 	xmlXPathFreeObject(arg2);
7423 	XP_ERROR0(XPATH_INVALID_OPERAND);
7424     }
7425     if (arg2->type != XPATH_NUMBER) {
7426 	valuePush(ctxt, arg2);
7427 	xmlXPathNumberFunction(ctxt, 1);
7428 	arg2 = valuePop(ctxt);
7429     }
7430     if (arg2->type != XPATH_NUMBER) {
7431 	xmlXPathReleaseObject(ctxt->context, arg1);
7432 	xmlXPathReleaseObject(ctxt->context, arg2);
7433 	XP_ERROR0(XPATH_INVALID_OPERAND);
7434     }
7435     /*
7436      * Add tests for infinity and nan
7437      * => feedback on 3.4 for Inf and NaN
7438      */
7439     /* Hand check NaN and Infinity comparisons */
7440     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7441 	ret=0;
7442     } else {
7443 	arg1i=xmlXPathIsInf(arg1->floatval);
7444 	arg2i=xmlXPathIsInf(arg2->floatval);
7445 	if (inf && strict) {
7446 	    if ((arg1i == -1 && arg2i != -1) ||
7447 		(arg2i == 1 && arg1i != 1)) {
7448 		ret = 1;
7449 	    } else if (arg1i == 0 && arg2i == 0) {
7450 		ret = (arg1->floatval < arg2->floatval);
7451 	    } else {
7452 		ret = 0;
7453 	    }
7454 	}
7455 	else if (inf && !strict) {
7456 	    if (arg1i == -1 || arg2i == 1) {
7457 		ret = 1;
7458 	    } else if (arg1i == 0 && arg2i == 0) {
7459 		ret = (arg1->floatval <= arg2->floatval);
7460 	    } else {
7461 		ret = 0;
7462 	    }
7463 	}
7464 	else if (!inf && strict) {
7465 	    if ((arg1i == 1 && arg2i != 1) ||
7466 		(arg2i == -1 && arg1i != -1)) {
7467 		ret = 1;
7468 	    } else if (arg1i == 0 && arg2i == 0) {
7469 		ret = (arg1->floatval > arg2->floatval);
7470 	    } else {
7471 		ret = 0;
7472 	    }
7473 	}
7474 	else if (!inf && !strict) {
7475 	    if (arg1i == 1 || arg2i == -1) {
7476 		ret = 1;
7477 	    } else if (arg1i == 0 && arg2i == 0) {
7478 		ret = (arg1->floatval >= arg2->floatval);
7479 	    } else {
7480 		ret = 0;
7481 	    }
7482 	}
7483     }
7484     xmlXPathReleaseObject(ctxt->context, arg1);
7485     xmlXPathReleaseObject(ctxt->context, arg2);
7486     return(ret);
7487 }
7488 
7489 /**
7490  * xmlXPathValueFlipSign:
7491  * @ctxt:  the XPath Parser context
7492  *
7493  * Implement the unary - operation on an XPath object
7494  * The numeric operators convert their operands to numbers as if
7495  * by calling the number function.
7496  */
7497 void
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt)7498 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7499     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7500     CAST_TO_NUMBER;
7501     CHECK_TYPE(XPATH_NUMBER);
7502     ctxt->value->floatval = -ctxt->value->floatval;
7503 }
7504 
7505 /**
7506  * xmlXPathAddValues:
7507  * @ctxt:  the XPath Parser context
7508  *
7509  * Implement the add operation on XPath objects:
7510  * The numeric operators convert their operands to numbers as if
7511  * by calling the number function.
7512  */
7513 void
xmlXPathAddValues(xmlXPathParserContextPtr ctxt)7514 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7515     xmlXPathObjectPtr arg;
7516     double val;
7517 
7518     arg = valuePop(ctxt);
7519     if (arg == NULL)
7520 	XP_ERROR(XPATH_INVALID_OPERAND);
7521     val = xmlXPathCastToNumber(arg);
7522     xmlXPathReleaseObject(ctxt->context, arg);
7523     CAST_TO_NUMBER;
7524     CHECK_TYPE(XPATH_NUMBER);
7525     ctxt->value->floatval += val;
7526 }
7527 
7528 /**
7529  * xmlXPathSubValues:
7530  * @ctxt:  the XPath Parser context
7531  *
7532  * Implement the subtraction operation on XPath objects:
7533  * The numeric operators convert their operands to numbers as if
7534  * by calling the number function.
7535  */
7536 void
xmlXPathSubValues(xmlXPathParserContextPtr ctxt)7537 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7538     xmlXPathObjectPtr arg;
7539     double val;
7540 
7541     arg = valuePop(ctxt);
7542     if (arg == NULL)
7543 	XP_ERROR(XPATH_INVALID_OPERAND);
7544     val = xmlXPathCastToNumber(arg);
7545     xmlXPathReleaseObject(ctxt->context, arg);
7546     CAST_TO_NUMBER;
7547     CHECK_TYPE(XPATH_NUMBER);
7548     ctxt->value->floatval -= val;
7549 }
7550 
7551 /**
7552  * xmlXPathMultValues:
7553  * @ctxt:  the XPath Parser context
7554  *
7555  * Implement the multiply operation on XPath objects:
7556  * The numeric operators convert their operands to numbers as if
7557  * by calling the number function.
7558  */
7559 void
xmlXPathMultValues(xmlXPathParserContextPtr ctxt)7560 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7561     xmlXPathObjectPtr arg;
7562     double val;
7563 
7564     arg = valuePop(ctxt);
7565     if (arg == NULL)
7566 	XP_ERROR(XPATH_INVALID_OPERAND);
7567     val = xmlXPathCastToNumber(arg);
7568     xmlXPathReleaseObject(ctxt->context, arg);
7569     CAST_TO_NUMBER;
7570     CHECK_TYPE(XPATH_NUMBER);
7571     ctxt->value->floatval *= val;
7572 }
7573 
7574 /**
7575  * xmlXPathDivValues:
7576  * @ctxt:  the XPath Parser context
7577  *
7578  * Implement the div operation on XPath objects @arg1 / @arg2:
7579  * The numeric operators convert their operands to numbers as if
7580  * by calling the number function.
7581  */
7582 void
xmlXPathDivValues(xmlXPathParserContextPtr ctxt)7583 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7584     xmlXPathObjectPtr arg;
7585     double val;
7586 
7587     arg = valuePop(ctxt);
7588     if (arg == NULL)
7589 	XP_ERROR(XPATH_INVALID_OPERAND);
7590     val = xmlXPathCastToNumber(arg);
7591     xmlXPathReleaseObject(ctxt->context, arg);
7592     CAST_TO_NUMBER;
7593     CHECK_TYPE(XPATH_NUMBER);
7594     ctxt->value->floatval /= val;
7595 }
7596 
7597 /**
7598  * xmlXPathModValues:
7599  * @ctxt:  the XPath Parser context
7600  *
7601  * Implement the mod operation on XPath objects: @arg1 / @arg2
7602  * The numeric operators convert their operands to numbers as if
7603  * by calling the number function.
7604  */
7605 void
xmlXPathModValues(xmlXPathParserContextPtr ctxt)7606 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7607     xmlXPathObjectPtr arg;
7608     double arg1, arg2;
7609 
7610     arg = valuePop(ctxt);
7611     if (arg == NULL)
7612 	XP_ERROR(XPATH_INVALID_OPERAND);
7613     arg2 = xmlXPathCastToNumber(arg);
7614     xmlXPathReleaseObject(ctxt->context, arg);
7615     CAST_TO_NUMBER;
7616     CHECK_TYPE(XPATH_NUMBER);
7617     arg1 = ctxt->value->floatval;
7618     if (arg2 == 0)
7619 	ctxt->value->floatval = NAN;
7620     else {
7621 	ctxt->value->floatval = fmod(arg1, arg2);
7622     }
7623 }
7624 
7625 /************************************************************************
7626  *									*
7627  *		The traversal functions					*
7628  *									*
7629  ************************************************************************/
7630 
7631 /*
7632  * A traversal function enumerates nodes along an axis.
7633  * Initially it must be called with NULL, and it indicates
7634  * termination on the axis by returning NULL.
7635  */
7636 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7637                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7638 
7639 /*
7640  * xmlXPathTraversalFunctionExt:
7641  * A traversal function enumerates nodes along an axis.
7642  * Initially it must be called with NULL, and it indicates
7643  * termination on the axis by returning NULL.
7644  * The context node of the traversal is specified via @contextNode.
7645  */
7646 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7647                     (xmlNodePtr cur, xmlNodePtr contextNode);
7648 
7649 /*
7650  * xmlXPathNodeSetMergeFunction:
7651  * Used for merging node sets in xmlXPathCollectAndTest().
7652  */
7653 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7654 		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
7655 
7656 
7657 /**
7658  * xmlXPathNextSelf:
7659  * @ctxt:  the XPath Parser context
7660  * @cur:  the current node in the traversal
7661  *
7662  * Traversal function for the "self" direction
7663  * The self axis contains just the context node itself
7664  *
7665  * Returns the next element following that axis
7666  */
7667 xmlNodePtr
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7668 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7669     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7670     if (cur == NULL)
7671         return(ctxt->context->node);
7672     return(NULL);
7673 }
7674 
7675 /**
7676  * xmlXPathNextChild:
7677  * @ctxt:  the XPath Parser context
7678  * @cur:  the current node in the traversal
7679  *
7680  * Traversal function for the "child" direction
7681  * The child axis contains the children of the context node in document order.
7682  *
7683  * Returns the next element following that axis
7684  */
7685 xmlNodePtr
xmlXPathNextChild(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7686 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7687     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7688     if (cur == NULL) {
7689 	if (ctxt->context->node == NULL) return(NULL);
7690 	switch (ctxt->context->node->type) {
7691             case XML_ELEMENT_NODE:
7692             case XML_TEXT_NODE:
7693             case XML_CDATA_SECTION_NODE:
7694             case XML_ENTITY_REF_NODE:
7695             case XML_ENTITY_NODE:
7696             case XML_PI_NODE:
7697             case XML_COMMENT_NODE:
7698             case XML_NOTATION_NODE:
7699             case XML_DTD_NODE:
7700 		return(ctxt->context->node->children);
7701             case XML_DOCUMENT_NODE:
7702             case XML_DOCUMENT_TYPE_NODE:
7703             case XML_DOCUMENT_FRAG_NODE:
7704             case XML_HTML_DOCUMENT_NODE:
7705 #ifdef LIBXML_DOCB_ENABLED
7706 	    case XML_DOCB_DOCUMENT_NODE:
7707 #endif
7708 		return(((xmlDocPtr) ctxt->context->node)->children);
7709 	    case XML_ELEMENT_DECL:
7710 	    case XML_ATTRIBUTE_DECL:
7711 	    case XML_ENTITY_DECL:
7712             case XML_ATTRIBUTE_NODE:
7713 	    case XML_NAMESPACE_DECL:
7714 	    case XML_XINCLUDE_START:
7715 	    case XML_XINCLUDE_END:
7716 		return(NULL);
7717 	}
7718 	return(NULL);
7719     }
7720     if ((cur->type == XML_DOCUMENT_NODE) ||
7721         (cur->type == XML_HTML_DOCUMENT_NODE))
7722 	return(NULL);
7723     return(cur->next);
7724 }
7725 
7726 /**
7727  * xmlXPathNextChildElement:
7728  * @ctxt:  the XPath Parser context
7729  * @cur:  the current node in the traversal
7730  *
7731  * Traversal function for the "child" direction and nodes of type element.
7732  * The child axis contains the children of the context node in document order.
7733  *
7734  * Returns the next element following that axis
7735  */
7736 static xmlNodePtr
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7737 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7738     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7739     if (cur == NULL) {
7740 	cur = ctxt->context->node;
7741 	if (cur == NULL) return(NULL);
7742 	/*
7743 	* Get the first element child.
7744 	*/
7745 	switch (cur->type) {
7746             case XML_ELEMENT_NODE:
7747 	    case XML_DOCUMENT_FRAG_NODE:
7748 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7749             case XML_ENTITY_NODE:
7750 		cur = cur->children;
7751 		if (cur != NULL) {
7752 		    if (cur->type == XML_ELEMENT_NODE)
7753 			return(cur);
7754 		    do {
7755 			cur = cur->next;
7756 		    } while ((cur != NULL) &&
7757 			(cur->type != XML_ELEMENT_NODE));
7758 		    return(cur);
7759 		}
7760 		return(NULL);
7761             case XML_DOCUMENT_NODE:
7762             case XML_HTML_DOCUMENT_NODE:
7763 #ifdef LIBXML_DOCB_ENABLED
7764 	    case XML_DOCB_DOCUMENT_NODE:
7765 #endif
7766 		return(xmlDocGetRootElement((xmlDocPtr) cur));
7767 	    default:
7768 		return(NULL);
7769 	}
7770 	return(NULL);
7771     }
7772     /*
7773     * Get the next sibling element node.
7774     */
7775     switch (cur->type) {
7776 	case XML_ELEMENT_NODE:
7777 	case XML_TEXT_NODE:
7778 	case XML_ENTITY_REF_NODE:
7779 	case XML_ENTITY_NODE:
7780 	case XML_CDATA_SECTION_NODE:
7781 	case XML_PI_NODE:
7782 	case XML_COMMENT_NODE:
7783 	case XML_XINCLUDE_END:
7784 	    break;
7785 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7786 	default:
7787 	    return(NULL);
7788     }
7789     if (cur->next != NULL) {
7790 	if (cur->next->type == XML_ELEMENT_NODE)
7791 	    return(cur->next);
7792 	cur = cur->next;
7793 	do {
7794 	    cur = cur->next;
7795 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7796 	return(cur);
7797     }
7798     return(NULL);
7799 }
7800 
7801 #if 0
7802 /**
7803  * xmlXPathNextDescendantOrSelfElemParent:
7804  * @ctxt:  the XPath Parser context
7805  * @cur:  the current node in the traversal
7806  *
7807  * Traversal function for the "descendant-or-self" axis.
7808  * Additionally it returns only nodes which can be parents of
7809  * element nodes.
7810  *
7811  *
7812  * Returns the next element following that axis
7813  */
7814 static xmlNodePtr
7815 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7816 				       xmlNodePtr contextNode)
7817 {
7818     if (cur == NULL) {
7819 	if (contextNode == NULL)
7820 	    return(NULL);
7821 	switch (contextNode->type) {
7822 	    case XML_ELEMENT_NODE:
7823 	    case XML_XINCLUDE_START:
7824 	    case XML_DOCUMENT_FRAG_NODE:
7825 	    case XML_DOCUMENT_NODE:
7826 #ifdef LIBXML_DOCB_ENABLED
7827 	    case XML_DOCB_DOCUMENT_NODE:
7828 #endif
7829 	    case XML_HTML_DOCUMENT_NODE:
7830 		return(contextNode);
7831 	    default:
7832 		return(NULL);
7833 	}
7834 	return(NULL);
7835     } else {
7836 	xmlNodePtr start = cur;
7837 
7838 	while (cur != NULL) {
7839 	    switch (cur->type) {
7840 		case XML_ELEMENT_NODE:
7841 		/* TODO: OK to have XInclude here? */
7842 		case XML_XINCLUDE_START:
7843 		case XML_DOCUMENT_FRAG_NODE:
7844 		    if (cur != start)
7845 			return(cur);
7846 		    if (cur->children != NULL) {
7847 			cur = cur->children;
7848 			continue;
7849 		    }
7850 		    break;
7851 		/* Not sure if we need those here. */
7852 		case XML_DOCUMENT_NODE:
7853 #ifdef LIBXML_DOCB_ENABLED
7854 		case XML_DOCB_DOCUMENT_NODE:
7855 #endif
7856 		case XML_HTML_DOCUMENT_NODE:
7857 		    if (cur != start)
7858 			return(cur);
7859 		    return(xmlDocGetRootElement((xmlDocPtr) cur));
7860 		default:
7861 		    break;
7862 	    }
7863 
7864 next_sibling:
7865 	    if ((cur == NULL) || (cur == contextNode))
7866 		return(NULL);
7867 	    if (cur->next != NULL) {
7868 		cur = cur->next;
7869 	    } else {
7870 		cur = cur->parent;
7871 		goto next_sibling;
7872 	    }
7873 	}
7874     }
7875     return(NULL);
7876 }
7877 #endif
7878 
7879 /**
7880  * xmlXPathNextDescendant:
7881  * @ctxt:  the XPath Parser context
7882  * @cur:  the current node in the traversal
7883  *
7884  * Traversal function for the "descendant" direction
7885  * the descendant axis contains the descendants of the context node in document
7886  * order; a descendant is a child or a child of a child and so on.
7887  *
7888  * Returns the next element following that axis
7889  */
7890 xmlNodePtr
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7891 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7892     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7893     if (cur == NULL) {
7894 	if (ctxt->context->node == NULL)
7895 	    return(NULL);
7896 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7897 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7898 	    return(NULL);
7899 
7900         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7901 	    return(ctxt->context->doc->children);
7902         return(ctxt->context->node->children);
7903     }
7904 
7905     if (cur->type == XML_NAMESPACE_DECL)
7906         return(NULL);
7907     if (cur->children != NULL) {
7908 	/*
7909 	 * Do not descend on entities declarations
7910 	 */
7911 	if (cur->children->type != XML_ENTITY_DECL) {
7912 	    cur = cur->children;
7913 	    /*
7914 	     * Skip DTDs
7915 	     */
7916 	    if (cur->type != XML_DTD_NODE)
7917 		return(cur);
7918 	}
7919     }
7920 
7921     if (cur == ctxt->context->node) return(NULL);
7922 
7923     while (cur->next != NULL) {
7924 	cur = cur->next;
7925 	if ((cur->type != XML_ENTITY_DECL) &&
7926 	    (cur->type != XML_DTD_NODE))
7927 	    return(cur);
7928     }
7929 
7930     do {
7931         cur = cur->parent;
7932 	if (cur == NULL) break;
7933 	if (cur == ctxt->context->node) return(NULL);
7934 	if (cur->next != NULL) {
7935 	    cur = cur->next;
7936 	    return(cur);
7937 	}
7938     } while (cur != NULL);
7939     return(cur);
7940 }
7941 
7942 /**
7943  * xmlXPathNextDescendantOrSelf:
7944  * @ctxt:  the XPath Parser context
7945  * @cur:  the current node in the traversal
7946  *
7947  * Traversal function for the "descendant-or-self" direction
7948  * the descendant-or-self axis contains the context node and the descendants
7949  * of the context node in document order; thus the context node is the first
7950  * node on the axis, and the first child of the context node is the second node
7951  * on the axis
7952  *
7953  * Returns the next element following that axis
7954  */
7955 xmlNodePtr
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7956 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7957     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7958     if (cur == NULL)
7959         return(ctxt->context->node);
7960 
7961     if (ctxt->context->node == NULL)
7962         return(NULL);
7963     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7964         (ctxt->context->node->type == XML_NAMESPACE_DECL))
7965         return(NULL);
7966 
7967     return(xmlXPathNextDescendant(ctxt, cur));
7968 }
7969 
7970 /**
7971  * xmlXPathNextParent:
7972  * @ctxt:  the XPath Parser context
7973  * @cur:  the current node in the traversal
7974  *
7975  * Traversal function for the "parent" direction
7976  * The parent axis contains the parent of the context node, if there is one.
7977  *
7978  * Returns the next element following that axis
7979  */
7980 xmlNodePtr
xmlXPathNextParent(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7981 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7982     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7983     /*
7984      * the parent of an attribute or namespace node is the element
7985      * to which the attribute or namespace node is attached
7986      * Namespace handling !!!
7987      */
7988     if (cur == NULL) {
7989 	if (ctxt->context->node == NULL) return(NULL);
7990 	switch (ctxt->context->node->type) {
7991             case XML_ELEMENT_NODE:
7992             case XML_TEXT_NODE:
7993             case XML_CDATA_SECTION_NODE:
7994             case XML_ENTITY_REF_NODE:
7995             case XML_ENTITY_NODE:
7996             case XML_PI_NODE:
7997             case XML_COMMENT_NODE:
7998             case XML_NOTATION_NODE:
7999             case XML_DTD_NODE:
8000 	    case XML_ELEMENT_DECL:
8001 	    case XML_ATTRIBUTE_DECL:
8002 	    case XML_XINCLUDE_START:
8003 	    case XML_XINCLUDE_END:
8004 	    case XML_ENTITY_DECL:
8005 		if (ctxt->context->node->parent == NULL)
8006 		    return((xmlNodePtr) ctxt->context->doc);
8007 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8008 		    ((ctxt->context->node->parent->name[0] == ' ') ||
8009 		     (xmlStrEqual(ctxt->context->node->parent->name,
8010 				 BAD_CAST "fake node libxslt"))))
8011 		    return(NULL);
8012 		return(ctxt->context->node->parent);
8013             case XML_ATTRIBUTE_NODE: {
8014 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8015 
8016 		return(att->parent);
8017 	    }
8018             case XML_DOCUMENT_NODE:
8019             case XML_DOCUMENT_TYPE_NODE:
8020             case XML_DOCUMENT_FRAG_NODE:
8021             case XML_HTML_DOCUMENT_NODE:
8022 #ifdef LIBXML_DOCB_ENABLED
8023 	    case XML_DOCB_DOCUMENT_NODE:
8024 #endif
8025                 return(NULL);
8026 	    case XML_NAMESPACE_DECL: {
8027 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8028 
8029 		if ((ns->next != NULL) &&
8030 		    (ns->next->type != XML_NAMESPACE_DECL))
8031 		    return((xmlNodePtr) ns->next);
8032                 return(NULL);
8033 	    }
8034 	}
8035     }
8036     return(NULL);
8037 }
8038 
8039 /**
8040  * xmlXPathNextAncestor:
8041  * @ctxt:  the XPath Parser context
8042  * @cur:  the current node in the traversal
8043  *
8044  * Traversal function for the "ancestor" direction
8045  * the ancestor axis contains the ancestors of the context node; the ancestors
8046  * of the context node consist of the parent of context node and the parent's
8047  * parent and so on; the nodes are ordered in reverse document order; thus the
8048  * parent is the first node on the axis, and the parent's parent is the second
8049  * node on the axis
8050  *
8051  * Returns the next element following that axis
8052  */
8053 xmlNodePtr
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8054 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8055     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8056     /*
8057      * the parent of an attribute or namespace node is the element
8058      * to which the attribute or namespace node is attached
8059      * !!!!!!!!!!!!!
8060      */
8061     if (cur == NULL) {
8062 	if (ctxt->context->node == NULL) return(NULL);
8063 	switch (ctxt->context->node->type) {
8064             case XML_ELEMENT_NODE:
8065             case XML_TEXT_NODE:
8066             case XML_CDATA_SECTION_NODE:
8067             case XML_ENTITY_REF_NODE:
8068             case XML_ENTITY_NODE:
8069             case XML_PI_NODE:
8070             case XML_COMMENT_NODE:
8071 	    case XML_DTD_NODE:
8072 	    case XML_ELEMENT_DECL:
8073 	    case XML_ATTRIBUTE_DECL:
8074 	    case XML_ENTITY_DECL:
8075             case XML_NOTATION_NODE:
8076 	    case XML_XINCLUDE_START:
8077 	    case XML_XINCLUDE_END:
8078 		if (ctxt->context->node->parent == NULL)
8079 		    return((xmlNodePtr) ctxt->context->doc);
8080 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8081 		    ((ctxt->context->node->parent->name[0] == ' ') ||
8082 		     (xmlStrEqual(ctxt->context->node->parent->name,
8083 				 BAD_CAST "fake node libxslt"))))
8084 		    return(NULL);
8085 		return(ctxt->context->node->parent);
8086             case XML_ATTRIBUTE_NODE: {
8087 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8088 
8089 		return(tmp->parent);
8090 	    }
8091             case XML_DOCUMENT_NODE:
8092             case XML_DOCUMENT_TYPE_NODE:
8093             case XML_DOCUMENT_FRAG_NODE:
8094             case XML_HTML_DOCUMENT_NODE:
8095 #ifdef LIBXML_DOCB_ENABLED
8096 	    case XML_DOCB_DOCUMENT_NODE:
8097 #endif
8098                 return(NULL);
8099 	    case XML_NAMESPACE_DECL: {
8100 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8101 
8102 		if ((ns->next != NULL) &&
8103 		    (ns->next->type != XML_NAMESPACE_DECL))
8104 		    return((xmlNodePtr) ns->next);
8105 		/* Bad, how did that namespace end up here ? */
8106                 return(NULL);
8107 	    }
8108 	}
8109 	return(NULL);
8110     }
8111     if (cur == ctxt->context->doc->children)
8112 	return((xmlNodePtr) ctxt->context->doc);
8113     if (cur == (xmlNodePtr) ctxt->context->doc)
8114 	return(NULL);
8115     switch (cur->type) {
8116 	case XML_ELEMENT_NODE:
8117 	case XML_TEXT_NODE:
8118 	case XML_CDATA_SECTION_NODE:
8119 	case XML_ENTITY_REF_NODE:
8120 	case XML_ENTITY_NODE:
8121 	case XML_PI_NODE:
8122 	case XML_COMMENT_NODE:
8123 	case XML_NOTATION_NODE:
8124 	case XML_DTD_NODE:
8125         case XML_ELEMENT_DECL:
8126         case XML_ATTRIBUTE_DECL:
8127         case XML_ENTITY_DECL:
8128 	case XML_XINCLUDE_START:
8129 	case XML_XINCLUDE_END:
8130 	    if (cur->parent == NULL)
8131 		return(NULL);
8132 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
8133 		((cur->parent->name[0] == ' ') ||
8134 		 (xmlStrEqual(cur->parent->name,
8135 			      BAD_CAST "fake node libxslt"))))
8136 		return(NULL);
8137 	    return(cur->parent);
8138 	case XML_ATTRIBUTE_NODE: {
8139 	    xmlAttrPtr att = (xmlAttrPtr) cur;
8140 
8141 	    return(att->parent);
8142 	}
8143 	case XML_NAMESPACE_DECL: {
8144 	    xmlNsPtr ns = (xmlNsPtr) cur;
8145 
8146 	    if ((ns->next != NULL) &&
8147 	        (ns->next->type != XML_NAMESPACE_DECL))
8148 	        return((xmlNodePtr) ns->next);
8149 	    /* Bad, how did that namespace end up here ? */
8150             return(NULL);
8151 	}
8152 	case XML_DOCUMENT_NODE:
8153 	case XML_DOCUMENT_TYPE_NODE:
8154 	case XML_DOCUMENT_FRAG_NODE:
8155 	case XML_HTML_DOCUMENT_NODE:
8156 #ifdef LIBXML_DOCB_ENABLED
8157 	case XML_DOCB_DOCUMENT_NODE:
8158 #endif
8159 	    return(NULL);
8160     }
8161     return(NULL);
8162 }
8163 
8164 /**
8165  * xmlXPathNextAncestorOrSelf:
8166  * @ctxt:  the XPath Parser context
8167  * @cur:  the current node in the traversal
8168  *
8169  * Traversal function for the "ancestor-or-self" direction
8170  * he ancestor-or-self axis contains the context node and ancestors of
8171  * the context node in reverse document order; thus the context node is
8172  * the first node on the axis, and the context node's parent the second;
8173  * parent here is defined the same as with the parent axis.
8174  *
8175  * Returns the next element following that axis
8176  */
8177 xmlNodePtr
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8178 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8179     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8180     if (cur == NULL)
8181         return(ctxt->context->node);
8182     return(xmlXPathNextAncestor(ctxt, cur));
8183 }
8184 
8185 /**
8186  * xmlXPathNextFollowingSibling:
8187  * @ctxt:  the XPath Parser context
8188  * @cur:  the current node in the traversal
8189  *
8190  * Traversal function for the "following-sibling" direction
8191  * The following-sibling axis contains the following siblings of the context
8192  * node in document order.
8193  *
8194  * Returns the next element following that axis
8195  */
8196 xmlNodePtr
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8197 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8198     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8199     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8200 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8201 	return(NULL);
8202     if (cur == (xmlNodePtr) ctxt->context->doc)
8203         return(NULL);
8204     if (cur == NULL)
8205         return(ctxt->context->node->next);
8206     return(cur->next);
8207 }
8208 
8209 /**
8210  * xmlXPathNextPrecedingSibling:
8211  * @ctxt:  the XPath Parser context
8212  * @cur:  the current node in the traversal
8213  *
8214  * Traversal function for the "preceding-sibling" direction
8215  * The preceding-sibling axis contains the preceding siblings of the context
8216  * node in reverse document order; the first preceding sibling is first on the
8217  * axis; the sibling preceding that node is the second on the axis and so on.
8218  *
8219  * Returns the next element following that axis
8220  */
8221 xmlNodePtr
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8222 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8223     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8224     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8225 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8226 	return(NULL);
8227     if (cur == (xmlNodePtr) ctxt->context->doc)
8228         return(NULL);
8229     if (cur == NULL)
8230         return(ctxt->context->node->prev);
8231     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8232 	cur = cur->prev;
8233 	if (cur == NULL)
8234 	    return(ctxt->context->node->prev);
8235     }
8236     return(cur->prev);
8237 }
8238 
8239 /**
8240  * xmlXPathNextFollowing:
8241  * @ctxt:  the XPath Parser context
8242  * @cur:  the current node in the traversal
8243  *
8244  * Traversal function for the "following" direction
8245  * The following axis contains all nodes in the same document as the context
8246  * node that are after the context node in document order, excluding any
8247  * descendants and excluding attribute nodes and namespace nodes; the nodes
8248  * are ordered in document order
8249  *
8250  * Returns the next element following that axis
8251  */
8252 xmlNodePtr
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8253 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8254     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8255     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8256         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8257         return(cur->children);
8258 
8259     if (cur == NULL) {
8260         cur = ctxt->context->node;
8261         if (cur->type == XML_ATTRIBUTE_NODE) {
8262             cur = cur->parent;
8263         } else if (cur->type == XML_NAMESPACE_DECL) {
8264             xmlNsPtr ns = (xmlNsPtr) cur;
8265 
8266             if ((ns->next == NULL) ||
8267                 (ns->next->type == XML_NAMESPACE_DECL))
8268                 return (NULL);
8269             cur = (xmlNodePtr) ns->next;
8270         }
8271     }
8272     if (cur == NULL) return(NULL) ; /* ERROR */
8273     if (cur->next != NULL) return(cur->next) ;
8274     do {
8275         cur = cur->parent;
8276         if (cur == NULL) break;
8277         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8278         if (cur->next != NULL) return(cur->next);
8279     } while (cur != NULL);
8280     return(cur);
8281 }
8282 
8283 /*
8284  * xmlXPathIsAncestor:
8285  * @ancestor:  the ancestor node
8286  * @node:  the current node
8287  *
8288  * Check that @ancestor is a @node's ancestor
8289  *
8290  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8291  */
8292 static int
xmlXPathIsAncestor(xmlNodePtr ancestor,xmlNodePtr node)8293 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8294     if ((ancestor == NULL) || (node == NULL)) return(0);
8295     if (node->type == XML_NAMESPACE_DECL)
8296         return(0);
8297     if (ancestor->type == XML_NAMESPACE_DECL)
8298         return(0);
8299     /* nodes need to be in the same document */
8300     if (ancestor->doc != node->doc) return(0);
8301     /* avoid searching if ancestor or node is the root node */
8302     if (ancestor == (xmlNodePtr) node->doc) return(1);
8303     if (node == (xmlNodePtr) ancestor->doc) return(0);
8304     while (node->parent != NULL) {
8305         if (node->parent == ancestor)
8306             return(1);
8307 	node = node->parent;
8308     }
8309     return(0);
8310 }
8311 
8312 /**
8313  * xmlXPathNextPreceding:
8314  * @ctxt:  the XPath Parser context
8315  * @cur:  the current node in the traversal
8316  *
8317  * Traversal function for the "preceding" direction
8318  * the preceding axis contains all nodes in the same document as the context
8319  * node that are before the context node in document order, excluding any
8320  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8321  * ordered in reverse document order
8322  *
8323  * Returns the next element following that axis
8324  */
8325 xmlNodePtr
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8326 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8327 {
8328     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8329     if (cur == NULL) {
8330         cur = ctxt->context->node;
8331         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         }
8341     }
8342     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8343 	return (NULL);
8344     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8345 	cur = cur->prev;
8346     do {
8347         if (cur->prev != NULL) {
8348             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8349             return (cur);
8350         }
8351 
8352         cur = cur->parent;
8353         if (cur == NULL)
8354             return (NULL);
8355         if (cur == ctxt->context->doc->children)
8356             return (NULL);
8357     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8358     return (cur);
8359 }
8360 
8361 /**
8362  * xmlXPathNextPrecedingInternal:
8363  * @ctxt:  the XPath Parser context
8364  * @cur:  the current node in the traversal
8365  *
8366  * Traversal function for the "preceding" direction
8367  * the preceding axis contains all nodes in the same document as the context
8368  * node that are before the context node in document order, excluding any
8369  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8370  * ordered in reverse document order
8371  * This is a faster implementation but internal only since it requires a
8372  * state kept in the parser context: ctxt->ancestor.
8373  *
8374  * Returns the next element following that axis
8375  */
8376 static xmlNodePtr
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8377 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8378                               xmlNodePtr cur)
8379 {
8380     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8381     if (cur == NULL) {
8382         cur = ctxt->context->node;
8383         if (cur == NULL)
8384             return (NULL);
8385         if (cur->type == XML_ATTRIBUTE_NODE) {
8386             cur = cur->parent;
8387         } else if (cur->type == XML_NAMESPACE_DECL) {
8388             xmlNsPtr ns = (xmlNsPtr) cur;
8389 
8390             if ((ns->next == NULL) ||
8391                 (ns->next->type == XML_NAMESPACE_DECL))
8392                 return (NULL);
8393             cur = (xmlNodePtr) ns->next;
8394         }
8395         ctxt->ancestor = cur->parent;
8396     }
8397     if (cur->type == XML_NAMESPACE_DECL)
8398         return(NULL);
8399     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8400 	cur = cur->prev;
8401     while (cur->prev == NULL) {
8402         cur = cur->parent;
8403         if (cur == NULL)
8404             return (NULL);
8405         if (cur == ctxt->context->doc->children)
8406             return (NULL);
8407         if (cur != ctxt->ancestor)
8408             return (cur);
8409         ctxt->ancestor = cur->parent;
8410     }
8411     cur = cur->prev;
8412     while (cur->last != NULL)
8413         cur = cur->last;
8414     return (cur);
8415 }
8416 
8417 /**
8418  * xmlXPathNextNamespace:
8419  * @ctxt:  the XPath Parser context
8420  * @cur:  the current attribute in the traversal
8421  *
8422  * Traversal function for the "namespace" direction
8423  * the namespace axis contains the namespace nodes of the context node;
8424  * the order of nodes on this axis is implementation-defined; the axis will
8425  * be empty unless the context node is an element
8426  *
8427  * We keep the XML namespace node at the end of the list.
8428  *
8429  * Returns the next element following that axis
8430  */
8431 xmlNodePtr
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8432 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8433     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8434     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8435     if (cur == NULL) {
8436         if (ctxt->context->tmpNsList != NULL)
8437 	    xmlFree(ctxt->context->tmpNsList);
8438 	ctxt->context->tmpNsList =
8439 	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8440 	ctxt->context->tmpNsNr = 0;
8441 	if (ctxt->context->tmpNsList != NULL) {
8442 	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8443 		ctxt->context->tmpNsNr++;
8444 	    }
8445 	}
8446 	return((xmlNodePtr) xmlXPathXMLNamespace);
8447     }
8448     if (ctxt->context->tmpNsNr > 0) {
8449 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8450     } else {
8451 	if (ctxt->context->tmpNsList != NULL)
8452 	    xmlFree(ctxt->context->tmpNsList);
8453 	ctxt->context->tmpNsList = NULL;
8454 	return(NULL);
8455     }
8456 }
8457 
8458 /**
8459  * xmlXPathNextAttribute:
8460  * @ctxt:  the XPath Parser context
8461  * @cur:  the current attribute in the traversal
8462  *
8463  * Traversal function for the "attribute" direction
8464  * TODO: support DTD inherited default attributes
8465  *
8466  * Returns the next element following that axis
8467  */
8468 xmlNodePtr
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8469 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8470     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8471     if (ctxt->context->node == NULL)
8472 	return(NULL);
8473     if (ctxt->context->node->type != XML_ELEMENT_NODE)
8474 	return(NULL);
8475     if (cur == NULL) {
8476         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8477 	    return(NULL);
8478         return((xmlNodePtr)ctxt->context->node->properties);
8479     }
8480     return((xmlNodePtr)cur->next);
8481 }
8482 
8483 /************************************************************************
8484  *									*
8485  *		NodeTest Functions					*
8486  *									*
8487  ************************************************************************/
8488 
8489 #define IS_FUNCTION			200
8490 
8491 
8492 /************************************************************************
8493  *									*
8494  *		Implicit tree core function library			*
8495  *									*
8496  ************************************************************************/
8497 
8498 /**
8499  * xmlXPathRoot:
8500  * @ctxt:  the XPath Parser context
8501  *
8502  * Initialize the context to the root of the document
8503  */
8504 void
xmlXPathRoot(xmlXPathParserContextPtr ctxt)8505 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8506     if ((ctxt == NULL) || (ctxt->context == NULL))
8507 	return;
8508     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8509 	(xmlNodePtr) ctxt->context->doc));
8510 }
8511 
8512 /************************************************************************
8513  *									*
8514  *		The explicit core function library			*
8515  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
8516  *									*
8517  ************************************************************************/
8518 
8519 
8520 /**
8521  * xmlXPathLastFunction:
8522  * @ctxt:  the XPath Parser context
8523  * @nargs:  the number of arguments
8524  *
8525  * Implement the last() XPath function
8526  *    number last()
8527  * The last function returns the number of nodes in the context node list.
8528  */
8529 void
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt,int nargs)8530 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8531     CHECK_ARITY(0);
8532     if (ctxt->context->contextSize >= 0) {
8533 	valuePush(ctxt,
8534 	    xmlXPathCacheNewFloat(ctxt->context,
8535 		(double) ctxt->context->contextSize));
8536 #ifdef DEBUG_EXPR
8537 	xmlGenericError(xmlGenericErrorContext,
8538 		"last() : %d\n", ctxt->context->contextSize);
8539 #endif
8540     } else {
8541 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8542     }
8543 }
8544 
8545 /**
8546  * xmlXPathPositionFunction:
8547  * @ctxt:  the XPath Parser context
8548  * @nargs:  the number of arguments
8549  *
8550  * Implement the position() XPath function
8551  *    number position()
8552  * The position function returns the position of the context node in the
8553  * context node list. The first position is 1, and so the last position
8554  * will be equal to last().
8555  */
8556 void
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt,int nargs)8557 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8558     CHECK_ARITY(0);
8559     if (ctxt->context->proximityPosition >= 0) {
8560 	valuePush(ctxt,
8561 	      xmlXPathCacheNewFloat(ctxt->context,
8562 		(double) ctxt->context->proximityPosition));
8563 #ifdef DEBUG_EXPR
8564 	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8565 		ctxt->context->proximityPosition);
8566 #endif
8567     } else {
8568 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8569     }
8570 }
8571 
8572 /**
8573  * xmlXPathCountFunction:
8574  * @ctxt:  the XPath Parser context
8575  * @nargs:  the number of arguments
8576  *
8577  * Implement the count() XPath function
8578  *    number count(node-set)
8579  */
8580 void
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt,int nargs)8581 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8582     xmlXPathObjectPtr cur;
8583 
8584     CHECK_ARITY(1);
8585     if ((ctxt->value == NULL) ||
8586 	((ctxt->value->type != XPATH_NODESET) &&
8587 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8588 	XP_ERROR(XPATH_INVALID_TYPE);
8589     cur = valuePop(ctxt);
8590 
8591     if ((cur == NULL) || (cur->nodesetval == NULL))
8592 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8593     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8594 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8595 	    (double) cur->nodesetval->nodeNr));
8596     } else {
8597 	if ((cur->nodesetval->nodeNr != 1) ||
8598 	    (cur->nodesetval->nodeTab == NULL)) {
8599 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8600 	} else {
8601 	    xmlNodePtr tmp;
8602 	    int i = 0;
8603 
8604 	    tmp = cur->nodesetval->nodeTab[0];
8605 	    if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
8606 		tmp = tmp->children;
8607 		while (tmp != NULL) {
8608 		    tmp = tmp->next;
8609 		    i++;
8610 		}
8611 	    }
8612 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8613 	}
8614     }
8615     xmlXPathReleaseObject(ctxt->context, cur);
8616 }
8617 
8618 /**
8619  * xmlXPathGetElementsByIds:
8620  * @doc:  the document
8621  * @ids:  a whitespace separated list of IDs
8622  *
8623  * Selects elements by their unique ID.
8624  *
8625  * Returns a node-set of selected elements.
8626  */
8627 static xmlNodeSetPtr
xmlXPathGetElementsByIds(xmlDocPtr doc,const xmlChar * ids)8628 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8629     xmlNodeSetPtr ret;
8630     const xmlChar *cur = ids;
8631     xmlChar *ID;
8632     xmlAttrPtr attr;
8633     xmlNodePtr elem = NULL;
8634 
8635     if (ids == NULL) return(NULL);
8636 
8637     ret = xmlXPathNodeSetCreate(NULL);
8638     if (ret == NULL)
8639         return(ret);
8640 
8641     while (IS_BLANK_CH(*cur)) cur++;
8642     while (*cur != 0) {
8643 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8644 	    cur++;
8645 
8646         ID = xmlStrndup(ids, cur - ids);
8647 	if (ID != NULL) {
8648 	    /*
8649 	     * We used to check the fact that the value passed
8650 	     * was an NCName, but this generated much troubles for
8651 	     * me and Aleksey Sanin, people blatantly violated that
8652 	     * constaint, like Visa3D spec.
8653 	     * if (xmlValidateNCName(ID, 1) == 0)
8654 	     */
8655 	    attr = xmlGetID(doc, ID);
8656 	    if (attr != NULL) {
8657 		if (attr->type == XML_ATTRIBUTE_NODE)
8658 		    elem = attr->parent;
8659 		else if (attr->type == XML_ELEMENT_NODE)
8660 		    elem = (xmlNodePtr) attr;
8661 		else
8662 		    elem = NULL;
8663 		if (elem != NULL)
8664 		    xmlXPathNodeSetAdd(ret, elem);
8665 	    }
8666 	    xmlFree(ID);
8667 	}
8668 
8669 	while (IS_BLANK_CH(*cur)) cur++;
8670 	ids = cur;
8671     }
8672     return(ret);
8673 }
8674 
8675 /**
8676  * xmlXPathIdFunction:
8677  * @ctxt:  the XPath Parser context
8678  * @nargs:  the number of arguments
8679  *
8680  * Implement the id() XPath function
8681  *    node-set id(object)
8682  * The id function selects elements by their unique ID
8683  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8684  * then the result is the union of the result of applying id to the
8685  * string value of each of the nodes in the argument node-set. When the
8686  * argument to id is of any other type, the argument is converted to a
8687  * string as if by a call to the string function; the string is split
8688  * into a whitespace-separated list of tokens (whitespace is any sequence
8689  * of characters matching the production S); the result is a node-set
8690  * containing the elements in the same document as the context node that
8691  * have a unique ID equal to any of the tokens in the list.
8692  */
8693 void
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt,int nargs)8694 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8695     xmlChar *tokens;
8696     xmlNodeSetPtr ret;
8697     xmlXPathObjectPtr obj;
8698 
8699     CHECK_ARITY(1);
8700     obj = valuePop(ctxt);
8701     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8702     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8703 	xmlNodeSetPtr ns;
8704 	int i;
8705 
8706 	ret = xmlXPathNodeSetCreate(NULL);
8707         /*
8708          * FIXME -- in an out-of-memory condition this will behave badly.
8709          * The solution is not clear -- we already popped an item from
8710          * ctxt, so the object is in a corrupt state.
8711          */
8712 
8713 	if (obj->nodesetval != NULL) {
8714 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8715 		tokens =
8716 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8717 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8718 		ret = xmlXPathNodeSetMerge(ret, ns);
8719 		xmlXPathFreeNodeSet(ns);
8720 		if (tokens != NULL)
8721 		    xmlFree(tokens);
8722 	    }
8723 	}
8724 	xmlXPathReleaseObject(ctxt->context, obj);
8725 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8726 	return;
8727     }
8728     obj = xmlXPathCacheConvertString(ctxt->context, obj);
8729     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8730     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8731     xmlXPathReleaseObject(ctxt->context, obj);
8732     return;
8733 }
8734 
8735 /**
8736  * xmlXPathLocalNameFunction:
8737  * @ctxt:  the XPath Parser context
8738  * @nargs:  the number of arguments
8739  *
8740  * Implement the local-name() XPath function
8741  *    string local-name(node-set?)
8742  * The local-name function returns a string containing the local part
8743  * of the name of the node in the argument node-set that is first in
8744  * document order. If the node-set is empty or the first node has no
8745  * name, an empty string is returned. If the argument is omitted it
8746  * defaults to the context node.
8747  */
8748 void
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8749 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8750     xmlXPathObjectPtr cur;
8751 
8752     if (ctxt == NULL) return;
8753 
8754     if (nargs == 0) {
8755 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8756 	    ctxt->context->node));
8757 	nargs = 1;
8758     }
8759 
8760     CHECK_ARITY(1);
8761     if ((ctxt->value == NULL) ||
8762 	((ctxt->value->type != XPATH_NODESET) &&
8763 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8764 	XP_ERROR(XPATH_INVALID_TYPE);
8765     cur = valuePop(ctxt);
8766 
8767     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8768 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8769     } else {
8770 	int i = 0; /* Should be first in document order !!!!! */
8771 	switch (cur->nodesetval->nodeTab[i]->type) {
8772 	case XML_ELEMENT_NODE:
8773 	case XML_ATTRIBUTE_NODE:
8774 	case XML_PI_NODE:
8775 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8776 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8777 	    else
8778 		valuePush(ctxt,
8779 		      xmlXPathCacheNewString(ctxt->context,
8780 			cur->nodesetval->nodeTab[i]->name));
8781 	    break;
8782 	case XML_NAMESPACE_DECL:
8783 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8784 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8785 	    break;
8786 	default:
8787 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8788 	}
8789     }
8790     xmlXPathReleaseObject(ctxt->context, cur);
8791 }
8792 
8793 /**
8794  * xmlXPathNamespaceURIFunction:
8795  * @ctxt:  the XPath Parser context
8796  * @nargs:  the number of arguments
8797  *
8798  * Implement the namespace-uri() XPath function
8799  *    string namespace-uri(node-set?)
8800  * The namespace-uri function returns a string containing the
8801  * namespace URI of the expanded name of the node in the argument
8802  * node-set that is first in document order. If the node-set is empty,
8803  * the first node has no name, or the expanded name has no namespace
8804  * URI, an empty string is returned. If the argument is omitted it
8805  * defaults to the context node.
8806  */
8807 void
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt,int nargs)8808 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8809     xmlXPathObjectPtr cur;
8810 
8811     if (ctxt == NULL) return;
8812 
8813     if (nargs == 0) {
8814 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8815 	    ctxt->context->node));
8816 	nargs = 1;
8817     }
8818     CHECK_ARITY(1);
8819     if ((ctxt->value == NULL) ||
8820 	((ctxt->value->type != XPATH_NODESET) &&
8821 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8822 	XP_ERROR(XPATH_INVALID_TYPE);
8823     cur = valuePop(ctxt);
8824 
8825     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8826 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8827     } else {
8828 	int i = 0; /* Should be first in document order !!!!! */
8829 	switch (cur->nodesetval->nodeTab[i]->type) {
8830 	case XML_ELEMENT_NODE:
8831 	case XML_ATTRIBUTE_NODE:
8832 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
8833 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8834 	    else
8835 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8836 			  cur->nodesetval->nodeTab[i]->ns->href));
8837 	    break;
8838 	default:
8839 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8840 	}
8841     }
8842     xmlXPathReleaseObject(ctxt->context, cur);
8843 }
8844 
8845 /**
8846  * xmlXPathNameFunction:
8847  * @ctxt:  the XPath Parser context
8848  * @nargs:  the number of arguments
8849  *
8850  * Implement the name() XPath function
8851  *    string name(node-set?)
8852  * The name function returns a string containing a QName representing
8853  * the name of the node in the argument node-set that is first in document
8854  * order. The QName must represent the name with respect to the namespace
8855  * declarations in effect on the node whose name is being represented.
8856  * Typically, this will be the form in which the name occurred in the XML
8857  * source. This need not be the case if there are namespace declarations
8858  * in effect on the node that associate multiple prefixes with the same
8859  * namespace. However, an implementation may include information about
8860  * the original prefix in its representation of nodes; in this case, an
8861  * implementation can ensure that the returned string is always the same
8862  * as the QName used in the XML source. If the argument it omitted it
8863  * defaults to the context node.
8864  * Libxml keep the original prefix so the "real qualified name" used is
8865  * returned.
8866  */
8867 static void
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8868 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8869 {
8870     xmlXPathObjectPtr cur;
8871 
8872     if (nargs == 0) {
8873 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8874 	    ctxt->context->node));
8875         nargs = 1;
8876     }
8877 
8878     CHECK_ARITY(1);
8879     if ((ctxt->value == NULL) ||
8880         ((ctxt->value->type != XPATH_NODESET) &&
8881          (ctxt->value->type != XPATH_XSLT_TREE)))
8882         XP_ERROR(XPATH_INVALID_TYPE);
8883     cur = valuePop(ctxt);
8884 
8885     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8886         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8887     } else {
8888         int i = 0;              /* Should be first in document order !!!!! */
8889 
8890         switch (cur->nodesetval->nodeTab[i]->type) {
8891             case XML_ELEMENT_NODE:
8892             case XML_ATTRIBUTE_NODE:
8893 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8894 		    valuePush(ctxt,
8895 			xmlXPathCacheNewCString(ctxt->context, ""));
8896 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8897                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8898 		    valuePush(ctxt,
8899 		        xmlXPathCacheNewString(ctxt->context,
8900 			    cur->nodesetval->nodeTab[i]->name));
8901 		} else {
8902 		    xmlChar *fullname;
8903 
8904 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8905 				     cur->nodesetval->nodeTab[i]->ns->prefix,
8906 				     NULL, 0);
8907 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
8908 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8909 		    if (fullname == NULL) {
8910 			XP_ERROR(XPATH_MEMORY_ERROR);
8911 		    }
8912 		    valuePush(ctxt, xmlXPathCacheWrapString(
8913 			ctxt->context, fullname));
8914                 }
8915                 break;
8916             default:
8917 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8918 		    cur->nodesetval->nodeTab[i]));
8919                 xmlXPathLocalNameFunction(ctxt, 1);
8920         }
8921     }
8922     xmlXPathReleaseObject(ctxt->context, cur);
8923 }
8924 
8925 
8926 /**
8927  * xmlXPathStringFunction:
8928  * @ctxt:  the XPath Parser context
8929  * @nargs:  the number of arguments
8930  *
8931  * Implement the string() XPath function
8932  *    string string(object?)
8933  * The string function converts an object to a string as follows:
8934  *    - A node-set is converted to a string by returning the value of
8935  *      the node in the node-set that is first in document order.
8936  *      If the node-set is empty, an empty string is returned.
8937  *    - A number is converted to a string as follows
8938  *      + NaN is converted to the string NaN
8939  *      + positive zero is converted to the string 0
8940  *      + negative zero is converted to the string 0
8941  *      + positive infinity is converted to the string Infinity
8942  *      + negative infinity is converted to the string -Infinity
8943  *      + if the number is an integer, the number is represented in
8944  *        decimal form as a Number with no decimal point and no leading
8945  *        zeros, preceded by a minus sign (-) if the number is negative
8946  *      + otherwise, the number is represented in decimal form as a
8947  *        Number including a decimal point with at least one digit
8948  *        before the decimal point and at least one digit after the
8949  *        decimal point, preceded by a minus sign (-) if the number
8950  *        is negative; there must be no leading zeros before the decimal
8951  *        point apart possibly from the one required digit immediately
8952  *        before the decimal point; beyond the one required digit
8953  *        after the decimal point there must be as many, but only as
8954  *        many, more digits as are needed to uniquely distinguish the
8955  *        number from all other IEEE 754 numeric values.
8956  *    - The boolean false value is converted to the string false.
8957  *      The boolean true value is converted to the string true.
8958  *
8959  * If the argument is omitted, it defaults to a node-set with the
8960  * context node as its only member.
8961  */
8962 void
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt,int nargs)8963 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8964     xmlXPathObjectPtr cur;
8965 
8966     if (ctxt == NULL) return;
8967     if (nargs == 0) {
8968     valuePush(ctxt,
8969 	xmlXPathCacheWrapString(ctxt->context,
8970 	    xmlXPathCastNodeToString(ctxt->context->node)));
8971 	return;
8972     }
8973 
8974     CHECK_ARITY(1);
8975     cur = valuePop(ctxt);
8976     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8977     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8978 }
8979 
8980 /**
8981  * xmlXPathStringLengthFunction:
8982  * @ctxt:  the XPath Parser context
8983  * @nargs:  the number of arguments
8984  *
8985  * Implement the string-length() XPath function
8986  *    number string-length(string?)
8987  * The string-length returns the number of characters in the string
8988  * (see [3.6 Strings]). If the argument is omitted, it defaults to
8989  * the context node converted to a string, in other words the value
8990  * of the context node.
8991  */
8992 void
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt,int nargs)8993 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8994     xmlXPathObjectPtr cur;
8995 
8996     if (nargs == 0) {
8997         if ((ctxt == NULL) || (ctxt->context == NULL))
8998 	    return;
8999 	if (ctxt->context->node == NULL) {
9000 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
9001 	} else {
9002 	    xmlChar *content;
9003 
9004 	    content = xmlXPathCastNodeToString(ctxt->context->node);
9005 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
9006 		xmlUTF8Strlen(content)));
9007 	    xmlFree(content);
9008 	}
9009 	return;
9010     }
9011     CHECK_ARITY(1);
9012     CAST_TO_STRING;
9013     CHECK_TYPE(XPATH_STRING);
9014     cur = valuePop(ctxt);
9015     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
9016 	xmlUTF8Strlen(cur->stringval)));
9017     xmlXPathReleaseObject(ctxt->context, cur);
9018 }
9019 
9020 /**
9021  * xmlXPathConcatFunction:
9022  * @ctxt:  the XPath Parser context
9023  * @nargs:  the number of arguments
9024  *
9025  * Implement the concat() XPath function
9026  *    string concat(string, string, string*)
9027  * The concat function returns the concatenation of its arguments.
9028  */
9029 void
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt,int nargs)9030 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9031     xmlXPathObjectPtr cur, newobj;
9032     xmlChar *tmp;
9033 
9034     if (ctxt == NULL) return;
9035     if (nargs < 2) {
9036 	CHECK_ARITY(2);
9037     }
9038 
9039     CAST_TO_STRING;
9040     cur = valuePop(ctxt);
9041     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
9042 	xmlXPathReleaseObject(ctxt->context, cur);
9043 	return;
9044     }
9045     nargs--;
9046 
9047     while (nargs > 0) {
9048 	CAST_TO_STRING;
9049 	newobj = valuePop(ctxt);
9050 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
9051 	    xmlXPathReleaseObject(ctxt->context, newobj);
9052 	    xmlXPathReleaseObject(ctxt->context, cur);
9053 	    XP_ERROR(XPATH_INVALID_TYPE);
9054 	}
9055 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
9056 	newobj->stringval = cur->stringval;
9057 	cur->stringval = tmp;
9058 	xmlXPathReleaseObject(ctxt->context, newobj);
9059 	nargs--;
9060     }
9061     valuePush(ctxt, cur);
9062 }
9063 
9064 /**
9065  * xmlXPathContainsFunction:
9066  * @ctxt:  the XPath Parser context
9067  * @nargs:  the number of arguments
9068  *
9069  * Implement the contains() XPath function
9070  *    boolean contains(string, string)
9071  * The contains function returns true if the first argument string
9072  * contains the second argument string, and otherwise returns false.
9073  */
9074 void
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt,int nargs)9075 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9076     xmlXPathObjectPtr hay, needle;
9077 
9078     CHECK_ARITY(2);
9079     CAST_TO_STRING;
9080     CHECK_TYPE(XPATH_STRING);
9081     needle = valuePop(ctxt);
9082     CAST_TO_STRING;
9083     hay = valuePop(ctxt);
9084 
9085     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9086 	xmlXPathReleaseObject(ctxt->context, hay);
9087 	xmlXPathReleaseObject(ctxt->context, needle);
9088 	XP_ERROR(XPATH_INVALID_TYPE);
9089     }
9090     if (xmlStrstr(hay->stringval, needle->stringval))
9091 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9092     else
9093 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9094     xmlXPathReleaseObject(ctxt->context, hay);
9095     xmlXPathReleaseObject(ctxt->context, needle);
9096 }
9097 
9098 /**
9099  * xmlXPathStartsWithFunction:
9100  * @ctxt:  the XPath Parser context
9101  * @nargs:  the number of arguments
9102  *
9103  * Implement the starts-with() XPath function
9104  *    boolean starts-with(string, string)
9105  * The starts-with function returns true if the first argument string
9106  * starts with the second argument string, and otherwise returns false.
9107  */
9108 void
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt,int nargs)9109 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9110     xmlXPathObjectPtr hay, needle;
9111     int n;
9112 
9113     CHECK_ARITY(2);
9114     CAST_TO_STRING;
9115     CHECK_TYPE(XPATH_STRING);
9116     needle = valuePop(ctxt);
9117     CAST_TO_STRING;
9118     hay = valuePop(ctxt);
9119 
9120     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9121 	xmlXPathReleaseObject(ctxt->context, hay);
9122 	xmlXPathReleaseObject(ctxt->context, needle);
9123 	XP_ERROR(XPATH_INVALID_TYPE);
9124     }
9125     n = xmlStrlen(needle->stringval);
9126     if (xmlStrncmp(hay->stringval, needle->stringval, n))
9127         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9128     else
9129         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9130     xmlXPathReleaseObject(ctxt->context, hay);
9131     xmlXPathReleaseObject(ctxt->context, needle);
9132 }
9133 
9134 /**
9135  * xmlXPathSubstringFunction:
9136  * @ctxt:  the XPath Parser context
9137  * @nargs:  the number of arguments
9138  *
9139  * Implement the substring() XPath function
9140  *    string substring(string, number, number?)
9141  * The substring function returns the substring of the first argument
9142  * starting at the position specified in the second argument with
9143  * length specified in the third argument. For example,
9144  * substring("12345",2,3) returns "234". If the third argument is not
9145  * specified, it returns the substring starting at the position specified
9146  * in the second argument and continuing to the end of the string. For
9147  * example, substring("12345",2) returns "2345".  More precisely, each
9148  * character in the string (see [3.6 Strings]) is considered to have a
9149  * numeric position: the position of the first character is 1, the position
9150  * of the second character is 2 and so on. The returned substring contains
9151  * those characters for which the position of the character is greater than
9152  * or equal to the second argument and, if the third argument is specified,
9153  * less than the sum of the second and third arguments; the comparisons
9154  * and addition used for the above follow the standard IEEE 754 rules. Thus:
9155  *  - substring("12345", 1.5, 2.6) returns "234"
9156  *  - substring("12345", 0, 3) returns "12"
9157  *  - substring("12345", 0 div 0, 3) returns ""
9158  *  - substring("12345", 1, 0 div 0) returns ""
9159  *  - substring("12345", -42, 1 div 0) returns "12345"
9160  *  - substring("12345", -1 div 0, 1 div 0) returns ""
9161  */
9162 void
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt,int nargs)9163 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9164     xmlXPathObjectPtr str, start, len;
9165     double le=0, in;
9166     int i, l, m;
9167     xmlChar *ret;
9168 
9169     if (nargs < 2) {
9170 	CHECK_ARITY(2);
9171     }
9172     if (nargs > 3) {
9173 	CHECK_ARITY(3);
9174     }
9175     /*
9176      * take care of possible last (position) argument
9177     */
9178     if (nargs == 3) {
9179 	CAST_TO_NUMBER;
9180 	CHECK_TYPE(XPATH_NUMBER);
9181 	len = valuePop(ctxt);
9182 	le = len->floatval;
9183 	xmlXPathReleaseObject(ctxt->context, len);
9184     }
9185 
9186     CAST_TO_NUMBER;
9187     CHECK_TYPE(XPATH_NUMBER);
9188     start = valuePop(ctxt);
9189     in = start->floatval;
9190     xmlXPathReleaseObject(ctxt->context, start);
9191     CAST_TO_STRING;
9192     CHECK_TYPE(XPATH_STRING);
9193     str = valuePop(ctxt);
9194     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9195 
9196     /*
9197      * If last pos not present, calculate last position
9198     */
9199     if (nargs != 3) {
9200 	le = (double)m;
9201 	if (in < 1.0)
9202 	    in = 1.0;
9203     }
9204 
9205     /* Need to check for the special cases where either
9206      * the index is NaN, the length is NaN, or both
9207      * arguments are infinity (relying on Inf + -Inf = NaN)
9208      */
9209     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9210         /*
9211          * To meet the requirements of the spec, the arguments
9212 	 * must be converted to integer format before
9213 	 * initial index calculations are done
9214          *
9215          * First we go to integer form, rounding up
9216 	 * and checking for special cases
9217          */
9218         i = (int) in;
9219         if (((double)i)+0.5 <= in) i++;
9220 
9221 	if (xmlXPathIsInf(le) == 1) {
9222 	    l = m;
9223 	    if (i < 1)
9224 		i = 1;
9225 	}
9226 	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9227 	    l = 0;
9228 	else {
9229 	    l = (int) le;
9230 	    if (((double)l)+0.5 <= le) l++;
9231 	}
9232 
9233 	/* Now we normalize inidices */
9234         i -= 1;
9235         l += i;
9236         if (i < 0)
9237             i = 0;
9238         if (l > m)
9239             l = m;
9240 
9241         /* number of chars to copy */
9242         l -= i;
9243 
9244         ret = xmlUTF8Strsub(str->stringval, i, l);
9245     }
9246     else {
9247         ret = NULL;
9248     }
9249     if (ret == NULL)
9250 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9251     else {
9252 	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9253 	xmlFree(ret);
9254     }
9255     xmlXPathReleaseObject(ctxt->context, str);
9256 }
9257 
9258 /**
9259  * xmlXPathSubstringBeforeFunction:
9260  * @ctxt:  the XPath Parser context
9261  * @nargs:  the number of arguments
9262  *
9263  * Implement the substring-before() XPath function
9264  *    string substring-before(string, string)
9265  * The substring-before function returns the substring of the first
9266  * argument string that precedes the first occurrence of the second
9267  * argument string in the first argument string, or the empty string
9268  * if the first argument string does not contain the second argument
9269  * string. For example, substring-before("1999/04/01","/") returns 1999.
9270  */
9271 void
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt,int nargs)9272 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9273   xmlXPathObjectPtr str;
9274   xmlXPathObjectPtr find;
9275   xmlBufPtr target;
9276   const xmlChar *point;
9277   int offset;
9278 
9279   CHECK_ARITY(2);
9280   CAST_TO_STRING;
9281   find = valuePop(ctxt);
9282   CAST_TO_STRING;
9283   str = valuePop(ctxt);
9284 
9285   target = xmlBufCreate();
9286   if (target) {
9287     point = xmlStrstr(str->stringval, find->stringval);
9288     if (point) {
9289       offset = (int)(point - str->stringval);
9290       xmlBufAdd(target, str->stringval, offset);
9291     }
9292     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9293 	xmlBufContent(target)));
9294     xmlBufFree(target);
9295   }
9296   xmlXPathReleaseObject(ctxt->context, str);
9297   xmlXPathReleaseObject(ctxt->context, find);
9298 }
9299 
9300 /**
9301  * xmlXPathSubstringAfterFunction:
9302  * @ctxt:  the XPath Parser context
9303  * @nargs:  the number of arguments
9304  *
9305  * Implement the substring-after() XPath function
9306  *    string substring-after(string, string)
9307  * The substring-after function returns the substring of the first
9308  * argument string that follows the first occurrence of the second
9309  * argument string in the first argument string, or the empty stringi
9310  * if the first argument string does not contain the second argument
9311  * string. For example, substring-after("1999/04/01","/") returns 04/01,
9312  * and substring-after("1999/04/01","19") returns 99/04/01.
9313  */
9314 void
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt,int nargs)9315 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9316   xmlXPathObjectPtr str;
9317   xmlXPathObjectPtr find;
9318   xmlBufPtr target;
9319   const xmlChar *point;
9320   int offset;
9321 
9322   CHECK_ARITY(2);
9323   CAST_TO_STRING;
9324   find = valuePop(ctxt);
9325   CAST_TO_STRING;
9326   str = valuePop(ctxt);
9327 
9328   target = xmlBufCreate();
9329   if (target) {
9330     point = xmlStrstr(str->stringval, find->stringval);
9331     if (point) {
9332       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9333       xmlBufAdd(target, &str->stringval[offset],
9334 		   xmlStrlen(str->stringval) - offset);
9335     }
9336     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9337 	xmlBufContent(target)));
9338     xmlBufFree(target);
9339   }
9340   xmlXPathReleaseObject(ctxt->context, str);
9341   xmlXPathReleaseObject(ctxt->context, find);
9342 }
9343 
9344 /**
9345  * xmlXPathNormalizeFunction:
9346  * @ctxt:  the XPath Parser context
9347  * @nargs:  the number of arguments
9348  *
9349  * Implement the normalize-space() XPath function
9350  *    string normalize-space(string?)
9351  * The normalize-space function returns the argument string with white
9352  * space normalized by stripping leading and trailing whitespace
9353  * and replacing sequences of whitespace characters by a single
9354  * space. Whitespace characters are the same allowed by the S production
9355  * in XML. If the argument is omitted, it defaults to the context
9356  * node converted to a string, in other words the value of the context node.
9357  */
9358 void
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt,int nargs)9359 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9360   xmlXPathObjectPtr obj = NULL;
9361   xmlChar *source = NULL;
9362   xmlBufPtr target;
9363   xmlChar blank;
9364 
9365   if (ctxt == NULL) return;
9366   if (nargs == 0) {
9367     /* Use current context node */
9368       valuePush(ctxt,
9369 	  xmlXPathCacheWrapString(ctxt->context,
9370 	    xmlXPathCastNodeToString(ctxt->context->node)));
9371     nargs = 1;
9372   }
9373 
9374   CHECK_ARITY(1);
9375   CAST_TO_STRING;
9376   CHECK_TYPE(XPATH_STRING);
9377   obj = valuePop(ctxt);
9378   source = obj->stringval;
9379 
9380   target = xmlBufCreate();
9381   if (target && source) {
9382 
9383     /* Skip leading whitespaces */
9384     while (IS_BLANK_CH(*source))
9385       source++;
9386 
9387     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9388     blank = 0;
9389     while (*source) {
9390       if (IS_BLANK_CH(*source)) {
9391 	blank = 0x20;
9392       } else {
9393 	if (blank) {
9394 	  xmlBufAdd(target, &blank, 1);
9395 	  blank = 0;
9396 	}
9397 	xmlBufAdd(target, source, 1);
9398       }
9399       source++;
9400     }
9401     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9402 	xmlBufContent(target)));
9403     xmlBufFree(target);
9404   }
9405   xmlXPathReleaseObject(ctxt->context, obj);
9406 }
9407 
9408 /**
9409  * xmlXPathTranslateFunction:
9410  * @ctxt:  the XPath Parser context
9411  * @nargs:  the number of arguments
9412  *
9413  * Implement the translate() XPath function
9414  *    string translate(string, string, string)
9415  * The translate function returns the first argument string with
9416  * occurrences of characters in the second argument string replaced
9417  * by the character at the corresponding position in the third argument
9418  * string. For example, translate("bar","abc","ABC") returns the string
9419  * BAr. If there is a character in the second argument string with no
9420  * character at a corresponding position in the third argument string
9421  * (because the second argument string is longer than the third argument
9422  * string), then occurrences of that character in the first argument
9423  * string are removed. For example, translate("--aaa--","abc-","ABC")
9424  * returns "AAA". If a character occurs more than once in second
9425  * argument string, then the first occurrence determines the replacement
9426  * character. If the third argument string is longer than the second
9427  * argument string, then excess characters are ignored.
9428  */
9429 void
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt,int nargs)9430 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9431     xmlXPathObjectPtr str;
9432     xmlXPathObjectPtr from;
9433     xmlXPathObjectPtr to;
9434     xmlBufPtr target;
9435     int offset, max;
9436     xmlChar ch;
9437     const xmlChar *point;
9438     xmlChar *cptr;
9439 
9440     CHECK_ARITY(3);
9441 
9442     CAST_TO_STRING;
9443     to = valuePop(ctxt);
9444     CAST_TO_STRING;
9445     from = valuePop(ctxt);
9446     CAST_TO_STRING;
9447     str = valuePop(ctxt);
9448 
9449     target = xmlBufCreate();
9450     if (target) {
9451 	max = xmlUTF8Strlen(to->stringval);
9452 	for (cptr = str->stringval; (ch=*cptr); ) {
9453 	    offset = xmlUTF8Strloc(from->stringval, cptr);
9454 	    if (offset >= 0) {
9455 		if (offset < max) {
9456 		    point = xmlUTF8Strpos(to->stringval, offset);
9457 		    if (point)
9458 			xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9459 		}
9460 	    } else
9461 		xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9462 
9463 	    /* Step to next character in input */
9464 	    cptr++;
9465 	    if ( ch & 0x80 ) {
9466 		/* if not simple ascii, verify proper format */
9467 		if ( (ch & 0xc0) != 0xc0 ) {
9468 		    xmlGenericError(xmlGenericErrorContext,
9469 			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
9470                     /* not asserting an XPath error is probably better */
9471 		    break;
9472 		}
9473 		/* then skip over remaining bytes for this char */
9474 		while ( (ch <<= 1) & 0x80 )
9475 		    if ( (*cptr++ & 0xc0) != 0x80 ) {
9476 			xmlGenericError(xmlGenericErrorContext,
9477 			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9478                         /* not asserting an XPath error is probably better */
9479 			break;
9480 		    }
9481 		if (ch & 0x80) /* must have had error encountered */
9482 		    break;
9483 	    }
9484 	}
9485     }
9486     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9487 	xmlBufContent(target)));
9488     xmlBufFree(target);
9489     xmlXPathReleaseObject(ctxt->context, str);
9490     xmlXPathReleaseObject(ctxt->context, from);
9491     xmlXPathReleaseObject(ctxt->context, to);
9492 }
9493 
9494 /**
9495  * xmlXPathBooleanFunction:
9496  * @ctxt:  the XPath Parser context
9497  * @nargs:  the number of arguments
9498  *
9499  * Implement the boolean() XPath function
9500  *    boolean boolean(object)
9501  * The boolean function converts its argument to a boolean as follows:
9502  *    - a number is true if and only if it is neither positive or
9503  *      negative zero nor NaN
9504  *    - a node-set is true if and only if it is non-empty
9505  *    - a string is true if and only if its length is non-zero
9506  */
9507 void
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt,int nargs)9508 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9509     xmlXPathObjectPtr cur;
9510 
9511     CHECK_ARITY(1);
9512     cur = valuePop(ctxt);
9513     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9514     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9515     valuePush(ctxt, cur);
9516 }
9517 
9518 /**
9519  * xmlXPathNotFunction:
9520  * @ctxt:  the XPath Parser context
9521  * @nargs:  the number of arguments
9522  *
9523  * Implement the not() XPath function
9524  *    boolean not(boolean)
9525  * The not function returns true if its argument is false,
9526  * and false otherwise.
9527  */
9528 void
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt,int nargs)9529 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9530     CHECK_ARITY(1);
9531     CAST_TO_BOOLEAN;
9532     CHECK_TYPE(XPATH_BOOLEAN);
9533     ctxt->value->boolval = ! ctxt->value->boolval;
9534 }
9535 
9536 /**
9537  * xmlXPathTrueFunction:
9538  * @ctxt:  the XPath Parser context
9539  * @nargs:  the number of arguments
9540  *
9541  * Implement the true() XPath function
9542  *    boolean true()
9543  */
9544 void
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt,int nargs)9545 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9546     CHECK_ARITY(0);
9547     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9548 }
9549 
9550 /**
9551  * xmlXPathFalseFunction:
9552  * @ctxt:  the XPath Parser context
9553  * @nargs:  the number of arguments
9554  *
9555  * Implement the false() XPath function
9556  *    boolean false()
9557  */
9558 void
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt,int nargs)9559 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9560     CHECK_ARITY(0);
9561     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9562 }
9563 
9564 /**
9565  * xmlXPathLangFunction:
9566  * @ctxt:  the XPath Parser context
9567  * @nargs:  the number of arguments
9568  *
9569  * Implement the lang() XPath function
9570  *    boolean lang(string)
9571  * The lang function returns true or false depending on whether the
9572  * language of the context node as specified by xml:lang attributes
9573  * is the same as or is a sublanguage of the language specified by
9574  * the argument string. The language of the context node is determined
9575  * by the value of the xml:lang attribute on the context node, or, if
9576  * the context node has no xml:lang attribute, by the value of the
9577  * xml:lang attribute on the nearest ancestor of the context node that
9578  * has an xml:lang attribute. If there is no such attribute, then lang
9579  * returns false. If there is such an attribute, then lang returns
9580  * true if the attribute value is equal to the argument ignoring case,
9581  * or if there is some suffix starting with - such that the attribute
9582  * value is equal to the argument ignoring that suffix of the attribute
9583  * value and ignoring case.
9584  */
9585 void
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt,int nargs)9586 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9587     xmlXPathObjectPtr val = NULL;
9588     const xmlChar *theLang = NULL;
9589     const xmlChar *lang;
9590     int ret = 0;
9591     int i;
9592 
9593     CHECK_ARITY(1);
9594     CAST_TO_STRING;
9595     CHECK_TYPE(XPATH_STRING);
9596     val = valuePop(ctxt);
9597     lang = val->stringval;
9598     theLang = xmlNodeGetLang(ctxt->context->node);
9599     if ((theLang != NULL) && (lang != NULL)) {
9600         for (i = 0;lang[i] != 0;i++)
9601 	    if (toupper(lang[i]) != toupper(theLang[i]))
9602 	        goto not_equal;
9603 	if ((theLang[i] == 0) || (theLang[i] == '-'))
9604 	    ret = 1;
9605     }
9606 not_equal:
9607     if (theLang != NULL)
9608 	xmlFree((void *)theLang);
9609 
9610     xmlXPathReleaseObject(ctxt->context, val);
9611     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9612 }
9613 
9614 /**
9615  * xmlXPathNumberFunction:
9616  * @ctxt:  the XPath Parser context
9617  * @nargs:  the number of arguments
9618  *
9619  * Implement the number() XPath function
9620  *    number number(object?)
9621  */
9622 void
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt,int nargs)9623 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9624     xmlXPathObjectPtr cur;
9625     double res;
9626 
9627     if (ctxt == NULL) return;
9628     if (nargs == 0) {
9629 	if (ctxt->context->node == NULL) {
9630 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9631 	} else {
9632 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9633 
9634 	    res = xmlXPathStringEvalNumber(content);
9635 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9636 	    xmlFree(content);
9637 	}
9638 	return;
9639     }
9640 
9641     CHECK_ARITY(1);
9642     cur = valuePop(ctxt);
9643     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9644 }
9645 
9646 /**
9647  * xmlXPathSumFunction:
9648  * @ctxt:  the XPath Parser context
9649  * @nargs:  the number of arguments
9650  *
9651  * Implement the sum() XPath function
9652  *    number sum(node-set)
9653  * The sum function returns the sum of the values of the nodes in
9654  * the argument node-set.
9655  */
9656 void
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt,int nargs)9657 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9658     xmlXPathObjectPtr cur;
9659     int i;
9660     double res = 0.0;
9661 
9662     CHECK_ARITY(1);
9663     if ((ctxt->value == NULL) ||
9664 	((ctxt->value->type != XPATH_NODESET) &&
9665 	 (ctxt->value->type != XPATH_XSLT_TREE)))
9666 	XP_ERROR(XPATH_INVALID_TYPE);
9667     cur = valuePop(ctxt);
9668 
9669     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9670 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9671 	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9672 	}
9673     }
9674     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9675     xmlXPathReleaseObject(ctxt->context, cur);
9676 }
9677 
9678 /**
9679  * xmlXPathFloorFunction:
9680  * @ctxt:  the XPath Parser context
9681  * @nargs:  the number of arguments
9682  *
9683  * Implement the floor() XPath function
9684  *    number floor(number)
9685  * The floor function returns the largest (closest to positive infinity)
9686  * number that is not greater than the argument and that is an integer.
9687  */
9688 void
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt,int nargs)9689 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9690     CHECK_ARITY(1);
9691     CAST_TO_NUMBER;
9692     CHECK_TYPE(XPATH_NUMBER);
9693 
9694     ctxt->value->floatval = floor(ctxt->value->floatval);
9695 }
9696 
9697 /**
9698  * xmlXPathCeilingFunction:
9699  * @ctxt:  the XPath Parser context
9700  * @nargs:  the number of arguments
9701  *
9702  * Implement the ceiling() XPath function
9703  *    number ceiling(number)
9704  * The ceiling function returns the smallest (closest to negative infinity)
9705  * number that is not less than the argument and that is an integer.
9706  */
9707 void
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt,int nargs)9708 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9709     CHECK_ARITY(1);
9710     CAST_TO_NUMBER;
9711     CHECK_TYPE(XPATH_NUMBER);
9712 
9713     ctxt->value->floatval = ceil(ctxt->value->floatval);
9714 }
9715 
9716 /**
9717  * xmlXPathRoundFunction:
9718  * @ctxt:  the XPath Parser context
9719  * @nargs:  the number of arguments
9720  *
9721  * Implement the round() XPath function
9722  *    number round(number)
9723  * The round function returns the number that is closest to the
9724  * argument and that is an integer. If there are two such numbers,
9725  * then the one that is closest to positive infinity is returned.
9726  */
9727 void
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt,int nargs)9728 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9729     double f;
9730 
9731     CHECK_ARITY(1);
9732     CAST_TO_NUMBER;
9733     CHECK_TYPE(XPATH_NUMBER);
9734 
9735     f = ctxt->value->floatval;
9736 
9737     if ((f >= -0.5) && (f < 0.5)) {
9738         /* Handles negative zero. */
9739         ctxt->value->floatval *= 0.0;
9740     }
9741     else {
9742         double rounded = floor(f);
9743         if (f - rounded >= 0.5)
9744             rounded += 1.0;
9745         ctxt->value->floatval = rounded;
9746     }
9747 }
9748 
9749 /************************************************************************
9750  *									*
9751  *			The Parser					*
9752  *									*
9753  ************************************************************************/
9754 
9755 /*
9756  * a few forward declarations since we use a recursive call based
9757  * implementation.
9758  */
9759 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9760 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9761 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9762 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9763 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9764 	                                  int qualified);
9765 
9766 /**
9767  * xmlXPathCurrentChar:
9768  * @ctxt:  the XPath parser context
9769  * @cur:  pointer to the beginning of the char
9770  * @len:  pointer to the length of the char read
9771  *
9772  * The current char value, if using UTF-8 this may actually span multiple
9773  * bytes in the input buffer.
9774  *
9775  * Returns the current char value and its length
9776  */
9777 
9778 static int
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt,int * len)9779 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9780     unsigned char c;
9781     unsigned int val;
9782     const xmlChar *cur;
9783 
9784     if (ctxt == NULL)
9785 	return(0);
9786     cur = ctxt->cur;
9787 
9788     /*
9789      * We are supposed to handle UTF8, check it's valid
9790      * From rfc2044: encoding of the Unicode values on UTF-8:
9791      *
9792      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9793      * 0000 0000-0000 007F   0xxxxxxx
9794      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9795      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9796      *
9797      * Check for the 0x110000 limit too
9798      */
9799     c = *cur;
9800     if (c & 0x80) {
9801 	if ((cur[1] & 0xc0) != 0x80)
9802 	    goto encoding_error;
9803 	if ((c & 0xe0) == 0xe0) {
9804 
9805 	    if ((cur[2] & 0xc0) != 0x80)
9806 		goto encoding_error;
9807 	    if ((c & 0xf0) == 0xf0) {
9808 		if (((c & 0xf8) != 0xf0) ||
9809 		    ((cur[3] & 0xc0) != 0x80))
9810 		    goto encoding_error;
9811 		/* 4-byte code */
9812 		*len = 4;
9813 		val = (cur[0] & 0x7) << 18;
9814 		val |= (cur[1] & 0x3f) << 12;
9815 		val |= (cur[2] & 0x3f) << 6;
9816 		val |= cur[3] & 0x3f;
9817 	    } else {
9818 	      /* 3-byte code */
9819 		*len = 3;
9820 		val = (cur[0] & 0xf) << 12;
9821 		val |= (cur[1] & 0x3f) << 6;
9822 		val |= cur[2] & 0x3f;
9823 	    }
9824 	} else {
9825 	  /* 2-byte code */
9826 	    *len = 2;
9827 	    val = (cur[0] & 0x1f) << 6;
9828 	    val |= cur[1] & 0x3f;
9829 	}
9830 	if (!IS_CHAR(val)) {
9831 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9832 	}
9833 	return(val);
9834     } else {
9835 	/* 1-byte code */
9836 	*len = 1;
9837 	return((int) *cur);
9838     }
9839 encoding_error:
9840     /*
9841      * If we detect an UTF8 error that probably means that the
9842      * input encoding didn't get properly advertised in the
9843      * declaration header. Report the error and switch the encoding
9844      * to ISO-Latin-1 (if you don't like this policy, just declare the
9845      * encoding !)
9846      */
9847     *len = 0;
9848     XP_ERROR0(XPATH_ENCODING_ERROR);
9849 }
9850 
9851 /**
9852  * xmlXPathParseNCName:
9853  * @ctxt:  the XPath Parser context
9854  *
9855  * parse an XML namespace non qualified name.
9856  *
9857  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9858  *
9859  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9860  *                       CombiningChar | Extender
9861  *
9862  * Returns the namespace name or NULL
9863  */
9864 
9865 xmlChar *
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt)9866 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9867     const xmlChar *in;
9868     xmlChar *ret;
9869     int count = 0;
9870 
9871     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9872     /*
9873      * Accelerator for simple ASCII names
9874      */
9875     in = ctxt->cur;
9876     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9877 	((*in >= 0x41) && (*in <= 0x5A)) ||
9878 	(*in == '_')) {
9879 	in++;
9880 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9881 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9882 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9883 	       (*in == '_') || (*in == '.') ||
9884 	       (*in == '-'))
9885 	    in++;
9886 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9887             (*in == '[') || (*in == ']') || (*in == ':') ||
9888             (*in == '@') || (*in == '*')) {
9889 	    count = in - ctxt->cur;
9890 	    if (count == 0)
9891 		return(NULL);
9892 	    ret = xmlStrndup(ctxt->cur, count);
9893 	    ctxt->cur = in;
9894 	    return(ret);
9895 	}
9896     }
9897     return(xmlXPathParseNameComplex(ctxt, 0));
9898 }
9899 
9900 
9901 /**
9902  * xmlXPathParseQName:
9903  * @ctxt:  the XPath Parser context
9904  * @prefix:  a xmlChar **
9905  *
9906  * parse an XML qualified name
9907  *
9908  * [NS 5] QName ::= (Prefix ':')? LocalPart
9909  *
9910  * [NS 6] Prefix ::= NCName
9911  *
9912  * [NS 7] LocalPart ::= NCName
9913  *
9914  * Returns the function returns the local part, and prefix is updated
9915  *   to get the Prefix if any.
9916  */
9917 
9918 static xmlChar *
xmlXPathParseQName(xmlXPathParserContextPtr ctxt,xmlChar ** prefix)9919 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9920     xmlChar *ret = NULL;
9921 
9922     *prefix = NULL;
9923     ret = xmlXPathParseNCName(ctxt);
9924     if (ret && CUR == ':') {
9925         *prefix = ret;
9926 	NEXT;
9927 	ret = xmlXPathParseNCName(ctxt);
9928     }
9929     return(ret);
9930 }
9931 
9932 /**
9933  * xmlXPathParseName:
9934  * @ctxt:  the XPath Parser context
9935  *
9936  * parse an XML name
9937  *
9938  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9939  *                  CombiningChar | Extender
9940  *
9941  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9942  *
9943  * Returns the namespace name or NULL
9944  */
9945 
9946 xmlChar *
xmlXPathParseName(xmlXPathParserContextPtr ctxt)9947 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9948     const xmlChar *in;
9949     xmlChar *ret;
9950     size_t count = 0;
9951 
9952     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9953     /*
9954      * Accelerator for simple ASCII names
9955      */
9956     in = ctxt->cur;
9957     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9958 	((*in >= 0x41) && (*in <= 0x5A)) ||
9959 	(*in == '_') || (*in == ':')) {
9960 	in++;
9961 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9962 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9963 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9964 	       (*in == '_') || (*in == '-') ||
9965 	       (*in == ':') || (*in == '.'))
9966 	    in++;
9967 	if ((*in > 0) && (*in < 0x80)) {
9968 	    count = in - ctxt->cur;
9969             if (count > XML_MAX_NAME_LENGTH) {
9970                 ctxt->cur = in;
9971                 XP_ERRORNULL(XPATH_EXPR_ERROR);
9972             }
9973 	    ret = xmlStrndup(ctxt->cur, count);
9974 	    ctxt->cur = in;
9975 	    return(ret);
9976 	}
9977     }
9978     return(xmlXPathParseNameComplex(ctxt, 1));
9979 }
9980 
9981 static xmlChar *
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,int qualified)9982 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9983     xmlChar buf[XML_MAX_NAMELEN + 5];
9984     int len = 0, l;
9985     int c;
9986 
9987     /*
9988      * Handler for more complex cases
9989      */
9990     c = CUR_CHAR(l);
9991     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9992         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9993         (c == '*') || /* accelerators */
9994 	(!IS_LETTER(c) && (c != '_') &&
9995          ((!qualified) || (c != ':')))) {
9996 	return(NULL);
9997     }
9998 
9999     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10000 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10001             (c == '.') || (c == '-') ||
10002 	    (c == '_') || ((qualified) && (c == ':')) ||
10003 	    (IS_COMBINING(c)) ||
10004 	    (IS_EXTENDER(c)))) {
10005 	COPY_BUF(l,buf,len,c);
10006 	NEXTL(l);
10007 	c = CUR_CHAR(l);
10008 	if (len >= XML_MAX_NAMELEN) {
10009 	    /*
10010 	     * Okay someone managed to make a huge name, so he's ready to pay
10011 	     * for the processing speed.
10012 	     */
10013 	    xmlChar *buffer;
10014 	    int max = len * 2;
10015 
10016             if (len > XML_MAX_NAME_LENGTH) {
10017                 XP_ERRORNULL(XPATH_EXPR_ERROR);
10018             }
10019 	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
10020 	    if (buffer == NULL) {
10021 		XP_ERRORNULL(XPATH_MEMORY_ERROR);
10022 	    }
10023 	    memcpy(buffer, buf, len);
10024 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10025 		   (c == '.') || (c == '-') ||
10026 		   (c == '_') || ((qualified) && (c == ':')) ||
10027 		   (IS_COMBINING(c)) ||
10028 		   (IS_EXTENDER(c))) {
10029 		if (len + 10 > max) {
10030                     if (max > XML_MAX_NAME_LENGTH) {
10031                         XP_ERRORNULL(XPATH_EXPR_ERROR);
10032                     }
10033 		    max *= 2;
10034 		    buffer = (xmlChar *) xmlRealloc(buffer,
10035 			                            max * sizeof(xmlChar));
10036 		    if (buffer == NULL) {
10037 			XP_ERRORNULL(XPATH_MEMORY_ERROR);
10038 		    }
10039 		}
10040 		COPY_BUF(l,buffer,len,c);
10041 		NEXTL(l);
10042 		c = CUR_CHAR(l);
10043 	    }
10044 	    buffer[len] = 0;
10045 	    return(buffer);
10046 	}
10047     }
10048     if (len == 0)
10049 	return(NULL);
10050     return(xmlStrndup(buf, len));
10051 }
10052 
10053 #define MAX_FRAC 20
10054 
10055 /**
10056  * xmlXPathStringEvalNumber:
10057  * @str:  A string to scan
10058  *
10059  *  [30a]  Float  ::= Number ('e' Digits?)?
10060  *
10061  *  [30]   Number ::=   Digits ('.' Digits?)?
10062  *                    | '.' Digits
10063  *  [31]   Digits ::=   [0-9]+
10064  *
10065  * Compile a Number in the string
10066  * In complement of the Number expression, this function also handles
10067  * negative values : '-' Number.
10068  *
10069  * Returns the double value.
10070  */
10071 double
xmlXPathStringEvalNumber(const xmlChar * str)10072 xmlXPathStringEvalNumber(const xmlChar *str) {
10073     const xmlChar *cur = str;
10074     double ret;
10075     int ok = 0;
10076     int isneg = 0;
10077     int exponent = 0;
10078     int is_exponent_negative = 0;
10079 #ifdef __GNUC__
10080     unsigned long tmp = 0;
10081     double temp;
10082 #endif
10083     if (cur == NULL) return(0);
10084     while (IS_BLANK_CH(*cur)) cur++;
10085     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10086         return(NAN);
10087     }
10088     if (*cur == '-') {
10089 	isneg = 1;
10090 	cur++;
10091     }
10092 
10093 #ifdef __GNUC__
10094     /*
10095      * tmp/temp is a workaround against a gcc compiler bug
10096      * http://veillard.com/gcc.bug
10097      */
10098     ret = 0;
10099     while ((*cur >= '0') && (*cur <= '9')) {
10100 	ret = ret * 10;
10101 	tmp = (*cur - '0');
10102 	ok = 1;
10103 	cur++;
10104 	temp = (double) tmp;
10105 	ret = ret + temp;
10106     }
10107 #else
10108     ret = 0;
10109     while ((*cur >= '0') && (*cur <= '9')) {
10110 	ret = ret * 10 + (*cur - '0');
10111 	ok = 1;
10112 	cur++;
10113     }
10114 #endif
10115 
10116     if (*cur == '.') {
10117 	int v, frac = 0, max;
10118 	double fraction = 0;
10119 
10120         cur++;
10121 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10122 	    return(NAN);
10123 	}
10124         while (*cur == '0') {
10125 	    frac = frac + 1;
10126 	    cur++;
10127         }
10128         max = frac + MAX_FRAC;
10129 	while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10130 	    v = (*cur - '0');
10131 	    fraction = fraction * 10 + v;
10132 	    frac = frac + 1;
10133 	    cur++;
10134 	}
10135 	fraction /= pow(10.0, frac);
10136 	ret = ret + fraction;
10137 	while ((*cur >= '0') && (*cur <= '9'))
10138 	    cur++;
10139     }
10140     if ((*cur == 'e') || (*cur == 'E')) {
10141       cur++;
10142       if (*cur == '-') {
10143 	is_exponent_negative = 1;
10144 	cur++;
10145       } else if (*cur == '+') {
10146         cur++;
10147       }
10148       while ((*cur >= '0') && (*cur <= '9')) {
10149         if (exponent < 1000000)
10150 	  exponent = exponent * 10 + (*cur - '0');
10151 	cur++;
10152       }
10153     }
10154     while (IS_BLANK_CH(*cur)) cur++;
10155     if (*cur != 0) return(NAN);
10156     if (isneg) ret = -ret;
10157     if (is_exponent_negative) exponent = -exponent;
10158     ret *= pow(10.0, (double)exponent);
10159     return(ret);
10160 }
10161 
10162 /**
10163  * xmlXPathCompNumber:
10164  * @ctxt:  the XPath Parser context
10165  *
10166  *  [30]   Number ::=   Digits ('.' Digits?)?
10167  *                    | '.' Digits
10168  *  [31]   Digits ::=   [0-9]+
10169  *
10170  * Compile a Number, then push it on the stack
10171  *
10172  */
10173 static void
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)10174 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10175 {
10176     double ret = 0.0;
10177     int ok = 0;
10178     int exponent = 0;
10179     int is_exponent_negative = 0;
10180 #ifdef __GNUC__
10181     unsigned long tmp = 0;
10182     double temp;
10183 #endif
10184 
10185     CHECK_ERROR;
10186     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10187         XP_ERROR(XPATH_NUMBER_ERROR);
10188     }
10189 #ifdef __GNUC__
10190     /*
10191      * tmp/temp is a workaround against a gcc compiler bug
10192      * http://veillard.com/gcc.bug
10193      */
10194     ret = 0;
10195     while ((CUR >= '0') && (CUR <= '9')) {
10196 	ret = ret * 10;
10197 	tmp = (CUR - '0');
10198         ok = 1;
10199         NEXT;
10200 	temp = (double) tmp;
10201 	ret = ret + temp;
10202     }
10203 #else
10204     ret = 0;
10205     while ((CUR >= '0') && (CUR <= '9')) {
10206 	ret = ret * 10 + (CUR - '0');
10207 	ok = 1;
10208 	NEXT;
10209     }
10210 #endif
10211     if (CUR == '.') {
10212 	int v, frac = 0, max;
10213 	double fraction = 0;
10214 
10215         NEXT;
10216         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10217             XP_ERROR(XPATH_NUMBER_ERROR);
10218         }
10219         while (CUR == '0') {
10220             frac = frac + 1;
10221             NEXT;
10222         }
10223         max = frac + MAX_FRAC;
10224         while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10225 	    v = (CUR - '0');
10226 	    fraction = fraction * 10 + v;
10227 	    frac = frac + 1;
10228             NEXT;
10229         }
10230         fraction /= pow(10.0, frac);
10231         ret = ret + fraction;
10232         while ((CUR >= '0') && (CUR <= '9'))
10233             NEXT;
10234     }
10235     if ((CUR == 'e') || (CUR == 'E')) {
10236         NEXT;
10237         if (CUR == '-') {
10238             is_exponent_negative = 1;
10239             NEXT;
10240         } else if (CUR == '+') {
10241 	    NEXT;
10242 	}
10243         while ((CUR >= '0') && (CUR <= '9')) {
10244             if (exponent < 1000000)
10245                 exponent = exponent * 10 + (CUR - '0');
10246             NEXT;
10247         }
10248         if (is_exponent_negative)
10249             exponent = -exponent;
10250         ret *= pow(10.0, (double) exponent);
10251     }
10252     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10253                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10254 }
10255 
10256 /**
10257  * xmlXPathParseLiteral:
10258  * @ctxt:  the XPath Parser context
10259  *
10260  * Parse a Literal
10261  *
10262  *  [29]   Literal ::=   '"' [^"]* '"'
10263  *                    | "'" [^']* "'"
10264  *
10265  * Returns the value found or NULL in case of error
10266  */
10267 static xmlChar *
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt)10268 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10269     const xmlChar *q;
10270     xmlChar *ret = NULL;
10271 
10272     if (CUR == '"') {
10273         NEXT;
10274 	q = CUR_PTR;
10275 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10276 	    NEXT;
10277 	if (!IS_CHAR_CH(CUR)) {
10278 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10279 	} else {
10280 	    ret = xmlStrndup(q, CUR_PTR - q);
10281 	    NEXT;
10282         }
10283     } else if (CUR == '\'') {
10284         NEXT;
10285 	q = CUR_PTR;
10286 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10287 	    NEXT;
10288 	if (!IS_CHAR_CH(CUR)) {
10289 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10290 	} else {
10291 	    ret = xmlStrndup(q, CUR_PTR - q);
10292 	    NEXT;
10293         }
10294     } else {
10295 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10296     }
10297     return(ret);
10298 }
10299 
10300 /**
10301  * xmlXPathCompLiteral:
10302  * @ctxt:  the XPath Parser context
10303  *
10304  * Parse a Literal and push it on the stack.
10305  *
10306  *  [29]   Literal ::=   '"' [^"]* '"'
10307  *                    | "'" [^']* "'"
10308  *
10309  * TODO: xmlXPathCompLiteral memory allocation could be improved.
10310  */
10311 static void
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt)10312 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10313     const xmlChar *q;
10314     xmlChar *ret = NULL;
10315 
10316     if (CUR == '"') {
10317         NEXT;
10318 	q = CUR_PTR;
10319 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10320 	    NEXT;
10321 	if (!IS_CHAR_CH(CUR)) {
10322 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10323 	} else {
10324 	    ret = xmlStrndup(q, CUR_PTR - q);
10325 	    NEXT;
10326         }
10327     } else if (CUR == '\'') {
10328         NEXT;
10329 	q = CUR_PTR;
10330 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10331 	    NEXT;
10332 	if (!IS_CHAR_CH(CUR)) {
10333 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10334 	} else {
10335 	    ret = xmlStrndup(q, CUR_PTR - q);
10336 	    NEXT;
10337         }
10338     } else {
10339 	XP_ERROR(XPATH_START_LITERAL_ERROR);
10340     }
10341     if (ret == NULL) return;
10342     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10343 	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
10344     xmlFree(ret);
10345 }
10346 
10347 /**
10348  * xmlXPathCompVariableReference:
10349  * @ctxt:  the XPath Parser context
10350  *
10351  * Parse a VariableReference, evaluate it and push it on the stack.
10352  *
10353  * The variable bindings consist of a mapping from variable names
10354  * to variable values. The value of a variable is an object, which can be
10355  * of any of the types that are possible for the value of an expression,
10356  * and may also be of additional types not specified here.
10357  *
10358  * Early evaluation is possible since:
10359  * The variable bindings [...] used to evaluate a subexpression are
10360  * always the same as those used to evaluate the containing expression.
10361  *
10362  *  [36]   VariableReference ::=   '$' QName
10363  */
10364 static void
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt)10365 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10366     xmlChar *name;
10367     xmlChar *prefix;
10368 
10369     SKIP_BLANKS;
10370     if (CUR != '$') {
10371 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10372     }
10373     NEXT;
10374     name = xmlXPathParseQName(ctxt, &prefix);
10375     if (name == NULL) {
10376         xmlFree(prefix);
10377 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10378     }
10379     ctxt->comp->last = -1;
10380     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10381 	           name, prefix);
10382     SKIP_BLANKS;
10383     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10384 	XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10385     }
10386 }
10387 
10388 /**
10389  * xmlXPathIsNodeType:
10390  * @name:  a name string
10391  *
10392  * Is the name given a NodeType one.
10393  *
10394  *  [38]   NodeType ::=   'comment'
10395  *                    | 'text'
10396  *                    | 'processing-instruction'
10397  *                    | 'node'
10398  *
10399  * Returns 1 if true 0 otherwise
10400  */
10401 int
xmlXPathIsNodeType(const xmlChar * name)10402 xmlXPathIsNodeType(const xmlChar *name) {
10403     if (name == NULL)
10404 	return(0);
10405 
10406     if (xmlStrEqual(name, BAD_CAST "node"))
10407 	return(1);
10408     if (xmlStrEqual(name, BAD_CAST "text"))
10409 	return(1);
10410     if (xmlStrEqual(name, BAD_CAST "comment"))
10411 	return(1);
10412     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10413 	return(1);
10414     return(0);
10415 }
10416 
10417 /**
10418  * xmlXPathCompFunctionCall:
10419  * @ctxt:  the XPath Parser context
10420  *
10421  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10422  *  [17]   Argument ::=   Expr
10423  *
10424  * Compile a function call, the evaluation of all arguments are
10425  * pushed on the stack
10426  */
10427 static void
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt)10428 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10429     xmlChar *name;
10430     xmlChar *prefix;
10431     int nbargs = 0;
10432     int sort = 1;
10433 
10434     name = xmlXPathParseQName(ctxt, &prefix);
10435     if (name == NULL) {
10436 	xmlFree(prefix);
10437 	XP_ERROR(XPATH_EXPR_ERROR);
10438     }
10439     SKIP_BLANKS;
10440 #ifdef DEBUG_EXPR
10441     if (prefix == NULL)
10442 	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10443 			name);
10444     else
10445 	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10446 			prefix, name);
10447 #endif
10448 
10449     if (CUR != '(') {
10450 	xmlFree(name);
10451 	xmlFree(prefix);
10452 	XP_ERROR(XPATH_EXPR_ERROR);
10453     }
10454     NEXT;
10455     SKIP_BLANKS;
10456 
10457     /*
10458     * Optimization for count(): we don't need the node-set to be sorted.
10459     */
10460     if ((prefix == NULL) && (name[0] == 'c') &&
10461 	xmlStrEqual(name, BAD_CAST "count"))
10462     {
10463 	sort = 0;
10464     }
10465     ctxt->comp->last = -1;
10466     if (CUR != ')') {
10467 	while (CUR != 0) {
10468 	    int op1 = ctxt->comp->last;
10469 	    ctxt->comp->last = -1;
10470 	    xmlXPathCompileExpr(ctxt, sort);
10471 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
10472 		xmlFree(name);
10473 		xmlFree(prefix);
10474 		return;
10475 	    }
10476 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10477 	    nbargs++;
10478 	    if (CUR == ')') break;
10479 	    if (CUR != ',') {
10480 		xmlFree(name);
10481 		xmlFree(prefix);
10482 		XP_ERROR(XPATH_EXPR_ERROR);
10483 	    }
10484 	    NEXT;
10485 	    SKIP_BLANKS;
10486 	}
10487     }
10488     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10489 	           name, prefix);
10490     NEXT;
10491     SKIP_BLANKS;
10492 }
10493 
10494 /**
10495  * xmlXPathCompPrimaryExpr:
10496  * @ctxt:  the XPath Parser context
10497  *
10498  *  [15]   PrimaryExpr ::=   VariableReference
10499  *                | '(' Expr ')'
10500  *                | Literal
10501  *                | Number
10502  *                | FunctionCall
10503  *
10504  * Compile a primary expression.
10505  */
10506 static void
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt)10507 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10508     SKIP_BLANKS;
10509     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10510     else if (CUR == '(') {
10511 	NEXT;
10512 	SKIP_BLANKS;
10513 	xmlXPathCompileExpr(ctxt, 1);
10514 	CHECK_ERROR;
10515 	if (CUR != ')') {
10516 	    XP_ERROR(XPATH_EXPR_ERROR);
10517 	}
10518 	NEXT;
10519 	SKIP_BLANKS;
10520     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10521 	xmlXPathCompNumber(ctxt);
10522     } else if ((CUR == '\'') || (CUR == '"')) {
10523 	xmlXPathCompLiteral(ctxt);
10524     } else {
10525 	xmlXPathCompFunctionCall(ctxt);
10526     }
10527     SKIP_BLANKS;
10528 }
10529 
10530 /**
10531  * xmlXPathCompFilterExpr:
10532  * @ctxt:  the XPath Parser context
10533  *
10534  *  [20]   FilterExpr ::=   PrimaryExpr
10535  *               | FilterExpr Predicate
10536  *
10537  * Compile a filter expression.
10538  * Square brackets are used to filter expressions in the same way that
10539  * they are used in location paths. It is an error if the expression to
10540  * be filtered does not evaluate to a node-set. The context node list
10541  * used for evaluating the expression in square brackets is the node-set
10542  * to be filtered listed in document order.
10543  */
10544 
10545 static void
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt)10546 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10547     xmlXPathCompPrimaryExpr(ctxt);
10548     CHECK_ERROR;
10549     SKIP_BLANKS;
10550 
10551     while (CUR == '[') {
10552 	xmlXPathCompPredicate(ctxt, 1);
10553 	SKIP_BLANKS;
10554     }
10555 
10556 
10557 }
10558 
10559 /**
10560  * xmlXPathScanName:
10561  * @ctxt:  the XPath Parser context
10562  *
10563  * Trickery: parse an XML name but without consuming the input flow
10564  * Needed to avoid insanity in the parser state.
10565  *
10566  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10567  *                  CombiningChar | Extender
10568  *
10569  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10570  *
10571  * [6] Names ::= Name (S Name)*
10572  *
10573  * Returns the Name parsed or NULL
10574  */
10575 
10576 static xmlChar *
xmlXPathScanName(xmlXPathParserContextPtr ctxt)10577 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10578     int len = 0, l;
10579     int c;
10580     const xmlChar *cur;
10581     xmlChar *ret;
10582 
10583     cur = ctxt->cur;
10584 
10585     c = CUR_CHAR(l);
10586     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10587 	(!IS_LETTER(c) && (c != '_') &&
10588          (c != ':'))) {
10589 	return(NULL);
10590     }
10591 
10592     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10593 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10594             (c == '.') || (c == '-') ||
10595 	    (c == '_') || (c == ':') ||
10596 	    (IS_COMBINING(c)) ||
10597 	    (IS_EXTENDER(c)))) {
10598 	len += l;
10599 	NEXTL(l);
10600 	c = CUR_CHAR(l);
10601     }
10602     ret = xmlStrndup(cur, ctxt->cur - cur);
10603     ctxt->cur = cur;
10604     return(ret);
10605 }
10606 
10607 /**
10608  * xmlXPathCompPathExpr:
10609  * @ctxt:  the XPath Parser context
10610  *
10611  *  [19]   PathExpr ::=   LocationPath
10612  *               | FilterExpr
10613  *               | FilterExpr '/' RelativeLocationPath
10614  *               | FilterExpr '//' RelativeLocationPath
10615  *
10616  * Compile a path expression.
10617  * The / operator and // operators combine an arbitrary expression
10618  * and a relative location path. It is an error if the expression
10619  * does not evaluate to a node-set.
10620  * The / operator does composition in the same way as when / is
10621  * used in a location path. As in location paths, // is short for
10622  * /descendant-or-self::node()/.
10623  */
10624 
10625 static void
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt)10626 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10627     int lc = 1;           /* Should we branch to LocationPath ?         */
10628     xmlChar *name = NULL; /* we may have to preparse a name to find out */
10629 
10630     SKIP_BLANKS;
10631     if ((CUR == '$') || (CUR == '(') ||
10632 	(IS_ASCII_DIGIT(CUR)) ||
10633         (CUR == '\'') || (CUR == '"') ||
10634 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10635 	lc = 0;
10636     } else if (CUR == '*') {
10637 	/* relative or absolute location path */
10638 	lc = 1;
10639     } else if (CUR == '/') {
10640 	/* relative or absolute location path */
10641 	lc = 1;
10642     } else if (CUR == '@') {
10643 	/* relative abbreviated attribute location path */
10644 	lc = 1;
10645     } else if (CUR == '.') {
10646 	/* relative abbreviated attribute location path */
10647 	lc = 1;
10648     } else {
10649 	/*
10650 	 * Problem is finding if we have a name here whether it's:
10651 	 *   - a nodetype
10652 	 *   - a function call in which case it's followed by '('
10653 	 *   - an axis in which case it's followed by ':'
10654 	 *   - a element name
10655 	 * We do an a priori analysis here rather than having to
10656 	 * maintain parsed token content through the recursive function
10657 	 * calls. This looks uglier but makes the code easier to
10658 	 * read/write/debug.
10659 	 */
10660 	SKIP_BLANKS;
10661 	name = xmlXPathScanName(ctxt);
10662 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10663 #ifdef DEBUG_STEP
10664 	    xmlGenericError(xmlGenericErrorContext,
10665 		    "PathExpr: Axis\n");
10666 #endif
10667 	    lc = 1;
10668 	    xmlFree(name);
10669 	} else if (name != NULL) {
10670 	    int len =xmlStrlen(name);
10671 
10672 
10673 	    while (NXT(len) != 0) {
10674 		if (NXT(len) == '/') {
10675 		    /* element name */
10676 #ifdef DEBUG_STEP
10677 		    xmlGenericError(xmlGenericErrorContext,
10678 			    "PathExpr: AbbrRelLocation\n");
10679 #endif
10680 		    lc = 1;
10681 		    break;
10682 		} else if (IS_BLANK_CH(NXT(len))) {
10683 		    /* ignore blanks */
10684 		    ;
10685 		} else if (NXT(len) == ':') {
10686 #ifdef DEBUG_STEP
10687 		    xmlGenericError(xmlGenericErrorContext,
10688 			    "PathExpr: AbbrRelLocation\n");
10689 #endif
10690 		    lc = 1;
10691 		    break;
10692 		} else if ((NXT(len) == '(')) {
10693 		    /* Node Type or Function */
10694 		    if (xmlXPathIsNodeType(name)) {
10695 #ifdef DEBUG_STEP
10696 		        xmlGenericError(xmlGenericErrorContext,
10697 				"PathExpr: Type search\n");
10698 #endif
10699 			lc = 1;
10700 #ifdef LIBXML_XPTR_ENABLED
10701                     } else if (ctxt->xptr &&
10702                                xmlStrEqual(name, BAD_CAST "range-to")) {
10703                         lc = 1;
10704 #endif
10705 		    } else {
10706 #ifdef DEBUG_STEP
10707 		        xmlGenericError(xmlGenericErrorContext,
10708 				"PathExpr: function call\n");
10709 #endif
10710 			lc = 0;
10711 		    }
10712                     break;
10713 		} else if ((NXT(len) == '[')) {
10714 		    /* element name */
10715 #ifdef DEBUG_STEP
10716 		    xmlGenericError(xmlGenericErrorContext,
10717 			    "PathExpr: AbbrRelLocation\n");
10718 #endif
10719 		    lc = 1;
10720 		    break;
10721 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10722 			   (NXT(len) == '=')) {
10723 		    lc = 1;
10724 		    break;
10725 		} else {
10726 		    lc = 1;
10727 		    break;
10728 		}
10729 		len++;
10730 	    }
10731 	    if (NXT(len) == 0) {
10732 #ifdef DEBUG_STEP
10733 		xmlGenericError(xmlGenericErrorContext,
10734 			"PathExpr: AbbrRelLocation\n");
10735 #endif
10736 		/* element name */
10737 		lc = 1;
10738 	    }
10739 	    xmlFree(name);
10740 	} else {
10741 	    /* make sure all cases are covered explicitly */
10742 	    XP_ERROR(XPATH_EXPR_ERROR);
10743 	}
10744     }
10745 
10746     if (lc) {
10747 	if (CUR == '/') {
10748 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10749 	} else {
10750 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10751 	}
10752 	xmlXPathCompLocationPath(ctxt);
10753     } else {
10754 	xmlXPathCompFilterExpr(ctxt);
10755 	CHECK_ERROR;
10756 	if ((CUR == '/') && (NXT(1) == '/')) {
10757 	    SKIP(2);
10758 	    SKIP_BLANKS;
10759 
10760 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10761 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10762 
10763 	    xmlXPathCompRelativeLocationPath(ctxt);
10764 	} else if (CUR == '/') {
10765 	    xmlXPathCompRelativeLocationPath(ctxt);
10766 	}
10767     }
10768     SKIP_BLANKS;
10769 }
10770 
10771 /**
10772  * xmlXPathCompUnionExpr:
10773  * @ctxt:  the XPath Parser context
10774  *
10775  *  [18]   UnionExpr ::=   PathExpr
10776  *               | UnionExpr '|' PathExpr
10777  *
10778  * Compile an union expression.
10779  */
10780 
10781 static void
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt)10782 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10783     xmlXPathCompPathExpr(ctxt);
10784     CHECK_ERROR;
10785     SKIP_BLANKS;
10786     while (CUR == '|') {
10787 	int op1 = ctxt->comp->last;
10788 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10789 
10790 	NEXT;
10791 	SKIP_BLANKS;
10792 	xmlXPathCompPathExpr(ctxt);
10793 
10794 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10795 
10796 	SKIP_BLANKS;
10797     }
10798 }
10799 
10800 /**
10801  * xmlXPathCompUnaryExpr:
10802  * @ctxt:  the XPath Parser context
10803  *
10804  *  [27]   UnaryExpr ::=   UnionExpr
10805  *                   | '-' UnaryExpr
10806  *
10807  * Compile an unary expression.
10808  */
10809 
10810 static void
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt)10811 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10812     int minus = 0;
10813     int found = 0;
10814 
10815     SKIP_BLANKS;
10816     while (CUR == '-') {
10817         minus = 1 - minus;
10818 	found = 1;
10819 	NEXT;
10820 	SKIP_BLANKS;
10821     }
10822 
10823     xmlXPathCompUnionExpr(ctxt);
10824     CHECK_ERROR;
10825     if (found) {
10826 	if (minus)
10827 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10828 	else
10829 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10830     }
10831 }
10832 
10833 /**
10834  * xmlXPathCompMultiplicativeExpr:
10835  * @ctxt:  the XPath Parser context
10836  *
10837  *  [26]   MultiplicativeExpr ::=   UnaryExpr
10838  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10839  *                   | MultiplicativeExpr 'div' UnaryExpr
10840  *                   | MultiplicativeExpr 'mod' UnaryExpr
10841  *  [34]   MultiplyOperator ::=   '*'
10842  *
10843  * Compile an Additive expression.
10844  */
10845 
10846 static void
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt)10847 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10848     xmlXPathCompUnaryExpr(ctxt);
10849     CHECK_ERROR;
10850     SKIP_BLANKS;
10851     while ((CUR == '*') ||
10852            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10853            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10854 	int op = -1;
10855 	int op1 = ctxt->comp->last;
10856 
10857         if (CUR == '*') {
10858 	    op = 0;
10859 	    NEXT;
10860 	} else if (CUR == 'd') {
10861 	    op = 1;
10862 	    SKIP(3);
10863 	} else if (CUR == 'm') {
10864 	    op = 2;
10865 	    SKIP(3);
10866 	}
10867 	SKIP_BLANKS;
10868         xmlXPathCompUnaryExpr(ctxt);
10869 	CHECK_ERROR;
10870 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10871 	SKIP_BLANKS;
10872     }
10873 }
10874 
10875 /**
10876  * xmlXPathCompAdditiveExpr:
10877  * @ctxt:  the XPath Parser context
10878  *
10879  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10880  *                   | AdditiveExpr '+' MultiplicativeExpr
10881  *                   | AdditiveExpr '-' MultiplicativeExpr
10882  *
10883  * Compile an Additive expression.
10884  */
10885 
10886 static void
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt)10887 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10888 
10889     xmlXPathCompMultiplicativeExpr(ctxt);
10890     CHECK_ERROR;
10891     SKIP_BLANKS;
10892     while ((CUR == '+') || (CUR == '-')) {
10893 	int plus;
10894 	int op1 = ctxt->comp->last;
10895 
10896         if (CUR == '+') plus = 1;
10897 	else plus = 0;
10898 	NEXT;
10899 	SKIP_BLANKS;
10900         xmlXPathCompMultiplicativeExpr(ctxt);
10901 	CHECK_ERROR;
10902 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10903 	SKIP_BLANKS;
10904     }
10905 }
10906 
10907 /**
10908  * xmlXPathCompRelationalExpr:
10909  * @ctxt:  the XPath Parser context
10910  *
10911  *  [24]   RelationalExpr ::=   AdditiveExpr
10912  *                 | RelationalExpr '<' AdditiveExpr
10913  *                 | RelationalExpr '>' AdditiveExpr
10914  *                 | RelationalExpr '<=' AdditiveExpr
10915  *                 | RelationalExpr '>=' AdditiveExpr
10916  *
10917  *  A <= B > C is allowed ? Answer from James, yes with
10918  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10919  *  which is basically what got implemented.
10920  *
10921  * Compile a Relational expression, then push the result
10922  * on the stack
10923  */
10924 
10925 static void
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt)10926 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10927     xmlXPathCompAdditiveExpr(ctxt);
10928     CHECK_ERROR;
10929     SKIP_BLANKS;
10930     while ((CUR == '<') ||
10931            (CUR == '>') ||
10932            ((CUR == '<') && (NXT(1) == '=')) ||
10933            ((CUR == '>') && (NXT(1) == '='))) {
10934 	int inf, strict;
10935 	int op1 = ctxt->comp->last;
10936 
10937         if (CUR == '<') inf = 1;
10938 	else inf = 0;
10939 	if (NXT(1) == '=') strict = 0;
10940 	else strict = 1;
10941 	NEXT;
10942 	if (!strict) NEXT;
10943 	SKIP_BLANKS;
10944         xmlXPathCompAdditiveExpr(ctxt);
10945 	CHECK_ERROR;
10946 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10947 	SKIP_BLANKS;
10948     }
10949 }
10950 
10951 /**
10952  * xmlXPathCompEqualityExpr:
10953  * @ctxt:  the XPath Parser context
10954  *
10955  *  [23]   EqualityExpr ::=   RelationalExpr
10956  *                 | EqualityExpr '=' RelationalExpr
10957  *                 | EqualityExpr '!=' RelationalExpr
10958  *
10959  *  A != B != C is allowed ? Answer from James, yes with
10960  *  (RelationalExpr = RelationalExpr) = RelationalExpr
10961  *  (RelationalExpr != RelationalExpr) != RelationalExpr
10962  *  which is basically what got implemented.
10963  *
10964  * Compile an Equality expression.
10965  *
10966  */
10967 static void
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt)10968 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10969     xmlXPathCompRelationalExpr(ctxt);
10970     CHECK_ERROR;
10971     SKIP_BLANKS;
10972     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10973 	int eq;
10974 	int op1 = ctxt->comp->last;
10975 
10976         if (CUR == '=') eq = 1;
10977 	else eq = 0;
10978 	NEXT;
10979 	if (!eq) NEXT;
10980 	SKIP_BLANKS;
10981         xmlXPathCompRelationalExpr(ctxt);
10982 	CHECK_ERROR;
10983 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10984 	SKIP_BLANKS;
10985     }
10986 }
10987 
10988 /**
10989  * xmlXPathCompAndExpr:
10990  * @ctxt:  the XPath Parser context
10991  *
10992  *  [22]   AndExpr ::=   EqualityExpr
10993  *                 | AndExpr 'and' EqualityExpr
10994  *
10995  * Compile an AND expression.
10996  *
10997  */
10998 static void
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt)10999 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
11000     xmlXPathCompEqualityExpr(ctxt);
11001     CHECK_ERROR;
11002     SKIP_BLANKS;
11003     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
11004 	int op1 = ctxt->comp->last;
11005         SKIP(3);
11006 	SKIP_BLANKS;
11007         xmlXPathCompEqualityExpr(ctxt);
11008 	CHECK_ERROR;
11009 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
11010 	SKIP_BLANKS;
11011     }
11012 }
11013 
11014 /**
11015  * xmlXPathCompileExpr:
11016  * @ctxt:  the XPath Parser context
11017  *
11018  *  [14]   Expr ::=   OrExpr
11019  *  [21]   OrExpr ::=   AndExpr
11020  *                 | OrExpr 'or' AndExpr
11021  *
11022  * Parse and compile an expression
11023  */
11024 static void
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt,int sort)11025 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
11026     xmlXPathCompAndExpr(ctxt);
11027     CHECK_ERROR;
11028     SKIP_BLANKS;
11029     while ((CUR == 'o') && (NXT(1) == 'r')) {
11030 	int op1 = ctxt->comp->last;
11031         SKIP(2);
11032 	SKIP_BLANKS;
11033         xmlXPathCompAndExpr(ctxt);
11034 	CHECK_ERROR;
11035 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
11036 	SKIP_BLANKS;
11037     }
11038     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
11039 	/* more ops could be optimized too */
11040 	/*
11041 	* This is the main place to eliminate sorting for
11042 	* operations which don't require a sorted node-set.
11043 	* E.g. count().
11044 	*/
11045 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11046     }
11047 }
11048 
11049 /**
11050  * xmlXPathCompPredicate:
11051  * @ctxt:  the XPath Parser context
11052  * @filter:  act as a filter
11053  *
11054  *  [8]   Predicate ::=   '[' PredicateExpr ']'
11055  *  [9]   PredicateExpr ::=   Expr
11056  *
11057  * Compile a predicate expression
11058  */
11059 static void
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt,int filter)11060 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11061     int op1 = ctxt->comp->last;
11062 
11063     SKIP_BLANKS;
11064     if (CUR != '[') {
11065 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11066     }
11067     NEXT;
11068     SKIP_BLANKS;
11069 
11070     ctxt->comp->last = -1;
11071     /*
11072     * This call to xmlXPathCompileExpr() will deactivate sorting
11073     * of the predicate result.
11074     * TODO: Sorting is still activated for filters, since I'm not
11075     *  sure if needed. Normally sorting should not be needed, since
11076     *  a filter can only diminish the number of items in a sequence,
11077     *  but won't change its order; so if the initial sequence is sorted,
11078     *  subsequent sorting is not needed.
11079     */
11080     if (! filter)
11081 	xmlXPathCompileExpr(ctxt, 0);
11082     else
11083 	xmlXPathCompileExpr(ctxt, 1);
11084     CHECK_ERROR;
11085 
11086     if (CUR != ']') {
11087 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11088     }
11089 
11090     if (filter)
11091 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11092     else
11093 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11094 
11095     NEXT;
11096     SKIP_BLANKS;
11097 }
11098 
11099 /**
11100  * xmlXPathCompNodeTest:
11101  * @ctxt:  the XPath Parser context
11102  * @test:  pointer to a xmlXPathTestVal
11103  * @type:  pointer to a xmlXPathTypeVal
11104  * @prefix:  placeholder for a possible name prefix
11105  *
11106  * [7] NodeTest ::=   NameTest
11107  *		    | NodeType '(' ')'
11108  *		    | 'processing-instruction' '(' Literal ')'
11109  *
11110  * [37] NameTest ::=  '*'
11111  *		    | NCName ':' '*'
11112  *		    | QName
11113  * [38] NodeType ::= 'comment'
11114  *		   | 'text'
11115  *		   | 'processing-instruction'
11116  *		   | 'node'
11117  *
11118  * Returns the name found and updates @test, @type and @prefix appropriately
11119  */
11120 static xmlChar *
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt,xmlXPathTestVal * test,xmlXPathTypeVal * type,const xmlChar ** prefix,xmlChar * name)11121 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11122 	             xmlXPathTypeVal *type, const xmlChar **prefix,
11123 		     xmlChar *name) {
11124     int blanks;
11125 
11126     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11127 	STRANGE;
11128 	return(NULL);
11129     }
11130     *type = (xmlXPathTypeVal) 0;
11131     *test = (xmlXPathTestVal) 0;
11132     *prefix = NULL;
11133     SKIP_BLANKS;
11134 
11135     if ((name == NULL) && (CUR == '*')) {
11136 	/*
11137 	 * All elements
11138 	 */
11139 	NEXT;
11140 	*test = NODE_TEST_ALL;
11141 	return(NULL);
11142     }
11143 
11144     if (name == NULL)
11145 	name = xmlXPathParseNCName(ctxt);
11146     if (name == NULL) {
11147 	XP_ERRORNULL(XPATH_EXPR_ERROR);
11148     }
11149 
11150     blanks = IS_BLANK_CH(CUR);
11151     SKIP_BLANKS;
11152     if (CUR == '(') {
11153 	NEXT;
11154 	/*
11155 	 * NodeType or PI search
11156 	 */
11157 	if (xmlStrEqual(name, BAD_CAST "comment"))
11158 	    *type = NODE_TYPE_COMMENT;
11159 	else if (xmlStrEqual(name, BAD_CAST "node"))
11160 	    *type = NODE_TYPE_NODE;
11161 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11162 	    *type = NODE_TYPE_PI;
11163 	else if (xmlStrEqual(name, BAD_CAST "text"))
11164 	    *type = NODE_TYPE_TEXT;
11165 	else {
11166 	    if (name != NULL)
11167 		xmlFree(name);
11168 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11169 	}
11170 
11171 	*test = NODE_TEST_TYPE;
11172 
11173 	SKIP_BLANKS;
11174 	if (*type == NODE_TYPE_PI) {
11175 	    /*
11176 	     * Specific case: search a PI by name.
11177 	     */
11178 	    if (name != NULL)
11179 		xmlFree(name);
11180 	    name = NULL;
11181 	    if (CUR != ')') {
11182 		name = xmlXPathParseLiteral(ctxt);
11183 		CHECK_ERROR NULL;
11184 		*test = NODE_TEST_PI;
11185 		SKIP_BLANKS;
11186 	    }
11187 	}
11188 	if (CUR != ')') {
11189 	    if (name != NULL)
11190 		xmlFree(name);
11191 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11192 	}
11193 	NEXT;
11194 	return(name);
11195     }
11196     *test = NODE_TEST_NAME;
11197     if ((!blanks) && (CUR == ':')) {
11198 	NEXT;
11199 
11200 	/*
11201 	 * Since currently the parser context don't have a
11202 	 * namespace list associated:
11203 	 * The namespace name for this prefix can be computed
11204 	 * only at evaluation time. The compilation is done
11205 	 * outside of any context.
11206 	 */
11207 #if 0
11208 	*prefix = xmlXPathNsLookup(ctxt->context, name);
11209 	if (name != NULL)
11210 	    xmlFree(name);
11211 	if (*prefix == NULL) {
11212 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11213 	}
11214 #else
11215 	*prefix = name;
11216 #endif
11217 
11218 	if (CUR == '*') {
11219 	    /*
11220 	     * All elements
11221 	     */
11222 	    NEXT;
11223 	    *test = NODE_TEST_ALL;
11224 	    return(NULL);
11225 	}
11226 
11227 	name = xmlXPathParseNCName(ctxt);
11228 	if (name == NULL) {
11229 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11230 	}
11231     }
11232     return(name);
11233 }
11234 
11235 /**
11236  * xmlXPathIsAxisName:
11237  * @name:  a preparsed name token
11238  *
11239  * [6] AxisName ::=   'ancestor'
11240  *                  | 'ancestor-or-self'
11241  *                  | 'attribute'
11242  *                  | 'child'
11243  *                  | 'descendant'
11244  *                  | 'descendant-or-self'
11245  *                  | 'following'
11246  *                  | 'following-sibling'
11247  *                  | 'namespace'
11248  *                  | 'parent'
11249  *                  | 'preceding'
11250  *                  | 'preceding-sibling'
11251  *                  | 'self'
11252  *
11253  * Returns the axis or 0
11254  */
11255 static xmlXPathAxisVal
xmlXPathIsAxisName(const xmlChar * name)11256 xmlXPathIsAxisName(const xmlChar *name) {
11257     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11258     switch (name[0]) {
11259 	case 'a':
11260 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
11261 		ret = AXIS_ANCESTOR;
11262 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11263 		ret = AXIS_ANCESTOR_OR_SELF;
11264 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
11265 		ret = AXIS_ATTRIBUTE;
11266 	    break;
11267 	case 'c':
11268 	    if (xmlStrEqual(name, BAD_CAST "child"))
11269 		ret = AXIS_CHILD;
11270 	    break;
11271 	case 'd':
11272 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
11273 		ret = AXIS_DESCENDANT;
11274 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11275 		ret = AXIS_DESCENDANT_OR_SELF;
11276 	    break;
11277 	case 'f':
11278 	    if (xmlStrEqual(name, BAD_CAST "following"))
11279 		ret = AXIS_FOLLOWING;
11280 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11281 		ret = AXIS_FOLLOWING_SIBLING;
11282 	    break;
11283 	case 'n':
11284 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
11285 		ret = AXIS_NAMESPACE;
11286 	    break;
11287 	case 'p':
11288 	    if (xmlStrEqual(name, BAD_CAST "parent"))
11289 		ret = AXIS_PARENT;
11290 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
11291 		ret = AXIS_PRECEDING;
11292 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11293 		ret = AXIS_PRECEDING_SIBLING;
11294 	    break;
11295 	case 's':
11296 	    if (xmlStrEqual(name, BAD_CAST "self"))
11297 		ret = AXIS_SELF;
11298 	    break;
11299     }
11300     return(ret);
11301 }
11302 
11303 /**
11304  * xmlXPathCompStep:
11305  * @ctxt:  the XPath Parser context
11306  *
11307  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11308  *                  | AbbreviatedStep
11309  *
11310  * [12] AbbreviatedStep ::=   '.' | '..'
11311  *
11312  * [5] AxisSpecifier ::= AxisName '::'
11313  *                  | AbbreviatedAxisSpecifier
11314  *
11315  * [13] AbbreviatedAxisSpecifier ::= '@'?
11316  *
11317  * Modified for XPtr range support as:
11318  *
11319  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11320  *                     | AbbreviatedStep
11321  *                     | 'range-to' '(' Expr ')' Predicate*
11322  *
11323  * Compile one step in a Location Path
11324  * A location step of . is short for self::node(). This is
11325  * particularly useful in conjunction with //. For example, the
11326  * location path .//para is short for
11327  * self::node()/descendant-or-self::node()/child::para
11328  * and so will select all para descendant elements of the context
11329  * node.
11330  * Similarly, a location step of .. is short for parent::node().
11331  * For example, ../title is short for parent::node()/child::title
11332  * and so will select the title children of the parent of the context
11333  * node.
11334  */
11335 static void
xmlXPathCompStep(xmlXPathParserContextPtr ctxt)11336 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11337 #ifdef LIBXML_XPTR_ENABLED
11338     int rangeto = 0;
11339     int op2 = -1;
11340 #endif
11341 
11342     SKIP_BLANKS;
11343     if ((CUR == '.') && (NXT(1) == '.')) {
11344 	SKIP(2);
11345 	SKIP_BLANKS;
11346 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11347 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11348     } else if (CUR == '.') {
11349 	NEXT;
11350 	SKIP_BLANKS;
11351     } else {
11352 	xmlChar *name = NULL;
11353 	const xmlChar *prefix = NULL;
11354 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
11355 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11356 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11357 	int op1;
11358 
11359 	/*
11360 	 * The modification needed for XPointer change to the production
11361 	 */
11362 #ifdef LIBXML_XPTR_ENABLED
11363 	if (ctxt->xptr) {
11364 	    name = xmlXPathParseNCName(ctxt);
11365 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11366                 op2 = ctxt->comp->last;
11367 		xmlFree(name);
11368 		SKIP_BLANKS;
11369 		if (CUR != '(') {
11370 		    XP_ERROR(XPATH_EXPR_ERROR);
11371 		}
11372 		NEXT;
11373 		SKIP_BLANKS;
11374 
11375 		xmlXPathCompileExpr(ctxt, 1);
11376 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11377 		CHECK_ERROR;
11378 
11379 		SKIP_BLANKS;
11380 		if (CUR != ')') {
11381 		    XP_ERROR(XPATH_EXPR_ERROR);
11382 		}
11383 		NEXT;
11384 		rangeto = 1;
11385 		goto eval_predicates;
11386 	    }
11387 	}
11388 #endif
11389 	if (CUR == '*') {
11390 	    axis = AXIS_CHILD;
11391 	} else {
11392 	    if (name == NULL)
11393 		name = xmlXPathParseNCName(ctxt);
11394 	    if (name != NULL) {
11395 		axis = xmlXPathIsAxisName(name);
11396 		if (axis != 0) {
11397 		    SKIP_BLANKS;
11398 		    if ((CUR == ':') && (NXT(1) == ':')) {
11399 			SKIP(2);
11400 			xmlFree(name);
11401 			name = NULL;
11402 		    } else {
11403 			/* an element name can conflict with an axis one :-\ */
11404 			axis = AXIS_CHILD;
11405 		    }
11406 		} else {
11407 		    axis = AXIS_CHILD;
11408 		}
11409 	    } else if (CUR == '@') {
11410 		NEXT;
11411 		axis = AXIS_ATTRIBUTE;
11412 	    } else {
11413 		axis = AXIS_CHILD;
11414 	    }
11415 	}
11416 
11417         if (ctxt->error != XPATH_EXPRESSION_OK) {
11418             xmlFree(name);
11419             return;
11420         }
11421 
11422 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11423 	if (test == 0)
11424 	    return;
11425 
11426         if ((prefix != NULL) && (ctxt->context != NULL) &&
11427 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11428 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11429 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11430 	    }
11431 	}
11432 #ifdef DEBUG_STEP
11433 	xmlGenericError(xmlGenericErrorContext,
11434 		"Basis : computing new set\n");
11435 #endif
11436 
11437 #ifdef DEBUG_STEP
11438 	xmlGenericError(xmlGenericErrorContext, "Basis : ");
11439 	if (ctxt->value == NULL)
11440 	    xmlGenericError(xmlGenericErrorContext, "no value\n");
11441 	else if (ctxt->value->nodesetval == NULL)
11442 	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
11443 	else
11444 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11445 #endif
11446 
11447 #ifdef LIBXML_XPTR_ENABLED
11448 eval_predicates:
11449 #endif
11450 	op1 = ctxt->comp->last;
11451 	ctxt->comp->last = -1;
11452 
11453 	SKIP_BLANKS;
11454 	while (CUR == '[') {
11455 	    xmlXPathCompPredicate(ctxt, 0);
11456 	}
11457 
11458 #ifdef LIBXML_XPTR_ENABLED
11459 	if (rangeto) {
11460 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11461 	} else
11462 #endif
11463 	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11464 			   test, type, (void *)prefix, (void *)name);
11465 
11466     }
11467 #ifdef DEBUG_STEP
11468     xmlGenericError(xmlGenericErrorContext, "Step : ");
11469     if (ctxt->value == NULL)
11470 	xmlGenericError(xmlGenericErrorContext, "no value\n");
11471     else if (ctxt->value->nodesetval == NULL)
11472 	xmlGenericError(xmlGenericErrorContext, "Empty\n");
11473     else
11474 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11475 		ctxt->value->nodesetval);
11476 #endif
11477 }
11478 
11479 /**
11480  * xmlXPathCompRelativeLocationPath:
11481  * @ctxt:  the XPath Parser context
11482  *
11483  *  [3]   RelativeLocationPath ::=   Step
11484  *                     | RelativeLocationPath '/' Step
11485  *                     | AbbreviatedRelativeLocationPath
11486  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11487  *
11488  * Compile a relative location path.
11489  */
11490 static void
xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt)11491 xmlXPathCompRelativeLocationPath
11492 (xmlXPathParserContextPtr ctxt) {
11493     SKIP_BLANKS;
11494     if ((CUR == '/') && (NXT(1) == '/')) {
11495 	SKIP(2);
11496 	SKIP_BLANKS;
11497 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11498 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11499     } else if (CUR == '/') {
11500 	    NEXT;
11501 	SKIP_BLANKS;
11502     }
11503     xmlXPathCompStep(ctxt);
11504     CHECK_ERROR;
11505     SKIP_BLANKS;
11506     while (CUR == '/') {
11507 	if ((CUR == '/') && (NXT(1) == '/')) {
11508 	    SKIP(2);
11509 	    SKIP_BLANKS;
11510 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11511 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11512 	    xmlXPathCompStep(ctxt);
11513 	} else if (CUR == '/') {
11514 	    NEXT;
11515 	    SKIP_BLANKS;
11516 	    xmlXPathCompStep(ctxt);
11517 	}
11518 	SKIP_BLANKS;
11519     }
11520 }
11521 
11522 /**
11523  * xmlXPathCompLocationPath:
11524  * @ctxt:  the XPath Parser context
11525  *
11526  *  [1]   LocationPath ::=   RelativeLocationPath
11527  *                     | AbsoluteLocationPath
11528  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11529  *                     | AbbreviatedAbsoluteLocationPath
11530  *  [10]   AbbreviatedAbsoluteLocationPath ::=
11531  *                           '//' RelativeLocationPath
11532  *
11533  * Compile a location path
11534  *
11535  * // is short for /descendant-or-self::node()/. For example,
11536  * //para is short for /descendant-or-self::node()/child::para and
11537  * so will select any para element in the document (even a para element
11538  * that is a document element will be selected by //para since the
11539  * document element node is a child of the root node); div//para is
11540  * short for div/descendant-or-self::node()/child::para and so will
11541  * select all para descendants of div children.
11542  */
11543 static void
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt)11544 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11545     SKIP_BLANKS;
11546     if (CUR != '/') {
11547         xmlXPathCompRelativeLocationPath(ctxt);
11548     } else {
11549 	while (CUR == '/') {
11550 	    if ((CUR == '/') && (NXT(1) == '/')) {
11551 		SKIP(2);
11552 		SKIP_BLANKS;
11553 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11554 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11555 		xmlXPathCompRelativeLocationPath(ctxt);
11556 	    } else if (CUR == '/') {
11557 		NEXT;
11558 		SKIP_BLANKS;
11559 		if ((CUR != 0 ) &&
11560 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11561 		     (CUR == '@') || (CUR == '*')))
11562 		    xmlXPathCompRelativeLocationPath(ctxt);
11563 	    }
11564 	    CHECK_ERROR;
11565 	}
11566     }
11567 }
11568 
11569 /************************************************************************
11570  *									*
11571  *		XPath precompiled expression evaluation			*
11572  *									*
11573  ************************************************************************/
11574 
11575 static int
11576 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11577 
11578 #ifdef DEBUG_STEP
11579 static void
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,int nbNodes)11580 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11581 			  int nbNodes)
11582 {
11583     xmlGenericError(xmlGenericErrorContext, "new step : ");
11584     switch (op->value) {
11585         case AXIS_ANCESTOR:
11586             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11587             break;
11588         case AXIS_ANCESTOR_OR_SELF:
11589             xmlGenericError(xmlGenericErrorContext,
11590                             "axis 'ancestors-or-self' ");
11591             break;
11592         case AXIS_ATTRIBUTE:
11593             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11594             break;
11595         case AXIS_CHILD:
11596             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11597             break;
11598         case AXIS_DESCENDANT:
11599             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11600             break;
11601         case AXIS_DESCENDANT_OR_SELF:
11602             xmlGenericError(xmlGenericErrorContext,
11603                             "axis 'descendant-or-self' ");
11604             break;
11605         case AXIS_FOLLOWING:
11606             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11607             break;
11608         case AXIS_FOLLOWING_SIBLING:
11609             xmlGenericError(xmlGenericErrorContext,
11610                             "axis 'following-siblings' ");
11611             break;
11612         case AXIS_NAMESPACE:
11613             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11614             break;
11615         case AXIS_PARENT:
11616             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11617             break;
11618         case AXIS_PRECEDING:
11619             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11620             break;
11621         case AXIS_PRECEDING_SIBLING:
11622             xmlGenericError(xmlGenericErrorContext,
11623                             "axis 'preceding-sibling' ");
11624             break;
11625         case AXIS_SELF:
11626             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11627             break;
11628     }
11629     xmlGenericError(xmlGenericErrorContext,
11630 	" context contains %d nodes\n", nbNodes);
11631     switch (op->value2) {
11632         case NODE_TEST_NONE:
11633             xmlGenericError(xmlGenericErrorContext,
11634                             "           searching for none !!!\n");
11635             break;
11636         case NODE_TEST_TYPE:
11637             xmlGenericError(xmlGenericErrorContext,
11638                             "           searching for type %d\n", op->value3);
11639             break;
11640         case NODE_TEST_PI:
11641             xmlGenericError(xmlGenericErrorContext,
11642                             "           searching for PI !!!\n");
11643             break;
11644         case NODE_TEST_ALL:
11645             xmlGenericError(xmlGenericErrorContext,
11646                             "           searching for *\n");
11647             break;
11648         case NODE_TEST_NS:
11649             xmlGenericError(xmlGenericErrorContext,
11650                             "           searching for namespace %s\n",
11651                             op->value5);
11652             break;
11653         case NODE_TEST_NAME:
11654             xmlGenericError(xmlGenericErrorContext,
11655                             "           searching for name %s\n", op->value5);
11656             if (op->value4)
11657                 xmlGenericError(xmlGenericErrorContext,
11658                                 "           with namespace %s\n", op->value4);
11659             break;
11660     }
11661     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11662 }
11663 #endif /* DEBUG_STEP */
11664 
11665 static int
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int contextSize,int hasNsNodes)11666 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11667 			    xmlXPathStepOpPtr op,
11668 			    xmlNodeSetPtr set,
11669 			    int contextSize,
11670 			    int hasNsNodes)
11671 {
11672     if (op->ch1 != -1) {
11673 	xmlXPathCompExprPtr comp = ctxt->comp;
11674 	/*
11675 	* Process inner predicates first.
11676 	*/
11677 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11678 	    /*
11679 	    * TODO: raise an internal error.
11680 	    */
11681 	}
11682 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11683 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11684 	CHECK_ERROR0;
11685 	if (contextSize <= 0)
11686 	    return(0);
11687     }
11688     if (op->ch2 != -1) {
11689 	xmlXPathContextPtr xpctxt = ctxt->context;
11690 	xmlNodePtr contextNode, oldContextNode;
11691 	xmlDocPtr oldContextDoc;
11692         int oldcs, oldpp;
11693 	int i, res, contextPos = 0, newContextSize;
11694 	xmlXPathStepOpPtr exprOp;
11695 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11696 
11697 #ifdef LIBXML_XPTR_ENABLED
11698 	/*
11699 	* URGENT TODO: Check the following:
11700 	*  We don't expect location sets if evaluating prediates, right?
11701 	*  Only filters should expect location sets, right?
11702 	*/
11703 #endif
11704 	/*
11705 	* SPEC XPath 1.0:
11706 	*  "For each node in the node-set to be filtered, the
11707 	*  PredicateExpr is evaluated with that node as the
11708 	*  context node, with the number of nodes in the
11709 	*  node-set as the context size, and with the proximity
11710 	*  position of the node in the node-set with respect to
11711 	*  the axis as the context position;"
11712 	* @oldset is the node-set" to be filtered.
11713 	*
11714 	* SPEC XPath 1.0:
11715 	*  "only predicates change the context position and
11716 	*  context size (see [2.4 Predicates])."
11717 	* Example:
11718 	*   node-set  context pos
11719 	*    nA         1
11720 	*    nB         2
11721 	*    nC         3
11722 	*   After applying predicate [position() > 1] :
11723 	*   node-set  context pos
11724 	*    nB         1
11725 	*    nC         2
11726 	*/
11727 	oldContextNode = xpctxt->node;
11728 	oldContextDoc = xpctxt->doc;
11729         oldcs = xpctxt->contextSize;
11730         oldpp = xpctxt->proximityPosition;
11731 	/*
11732 	* Get the expression of this predicate.
11733 	*/
11734 	exprOp = &ctxt->comp->steps[op->ch2];
11735 	newContextSize = 0;
11736 	for (i = 0; i < set->nodeNr; i++) {
11737 	    if (set->nodeTab[i] == NULL)
11738 		continue;
11739 
11740 	    contextNode = set->nodeTab[i];
11741 	    xpctxt->node = contextNode;
11742 	    xpctxt->contextSize = contextSize;
11743 	    xpctxt->proximityPosition = ++contextPos;
11744 
11745 	    /*
11746 	    * Also set the xpath document in case things like
11747 	    * key() are evaluated in the predicate.
11748 	    */
11749 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11750 		(contextNode->doc != NULL))
11751 		xpctxt->doc = contextNode->doc;
11752 	    /*
11753 	    * Evaluate the predicate expression with 1 context node
11754 	    * at a time; this node is packaged into a node set; this
11755 	    * node set is handed over to the evaluation mechanism.
11756 	    */
11757 	    if (contextObj == NULL)
11758 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11759 	    else {
11760 		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11761 		    contextNode) < 0) {
11762 		    ctxt->error = XPATH_MEMORY_ERROR;
11763 		    goto evaluation_exit;
11764 		}
11765 	    }
11766 
11767 	    valuePush(ctxt, contextObj);
11768 
11769 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11770 
11771 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11772 		xmlXPathNodeSetClear(set, hasNsNodes);
11773 		newContextSize = 0;
11774 		goto evaluation_exit;
11775 	    }
11776 
11777 	    if (res != 0) {
11778 		newContextSize++;
11779 	    } else {
11780 		/*
11781 		* Remove the entry from the initial node set.
11782 		*/
11783 		set->nodeTab[i] = NULL;
11784 		if (contextNode->type == XML_NAMESPACE_DECL)
11785 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11786 	    }
11787 	    if (ctxt->value == contextObj) {
11788 		/*
11789 		* Don't free the temporary XPath object holding the
11790 		* context node, in order to avoid massive recreation
11791 		* inside this loop.
11792 		*/
11793 		valuePop(ctxt);
11794 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11795 	    } else {
11796 		/*
11797 		* TODO: The object was lost in the evaluation machinery.
11798 		*  Can this happen? Maybe in internal-error cases.
11799 		*/
11800 		contextObj = NULL;
11801 	    }
11802 	}
11803 
11804 	if (contextObj != NULL) {
11805 	    if (ctxt->value == contextObj)
11806 		valuePop(ctxt);
11807 	    xmlXPathReleaseObject(xpctxt, contextObj);
11808 	}
11809 evaluation_exit:
11810 	if (exprRes != NULL)
11811 	    xmlXPathReleaseObject(ctxt->context, exprRes);
11812 	/*
11813 	* Reset/invalidate the context.
11814 	*/
11815 	xpctxt->node = oldContextNode;
11816 	xpctxt->doc = oldContextDoc;
11817 	xpctxt->contextSize = oldcs;
11818 	xpctxt->proximityPosition = oldpp;
11819 	return(newContextSize);
11820     }
11821     return(contextSize);
11822 }
11823 
11824 static int
xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int contextSize,int minPos,int maxPos,int hasNsNodes)11825 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11826 				      xmlXPathStepOpPtr op,
11827 				      xmlNodeSetPtr set,
11828 				      int contextSize,
11829 				      int minPos,
11830 				      int maxPos,
11831 				      int hasNsNodes)
11832 {
11833     if (op->ch1 != -1) {
11834 	xmlXPathCompExprPtr comp = ctxt->comp;
11835 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11836 	    /*
11837 	    * TODO: raise an internal error.
11838 	    */
11839 	}
11840 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11841 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11842 	CHECK_ERROR0;
11843 	if (contextSize <= 0)
11844 	    return(0);
11845     }
11846     /*
11847     * Check if the node set contains a sufficient number of nodes for
11848     * the requested range.
11849     */
11850     if (contextSize < minPos) {
11851 	xmlXPathNodeSetClear(set, hasNsNodes);
11852 	return(0);
11853     }
11854     if (op->ch2 == -1) {
11855 	/*
11856 	* TODO: Can this ever happen?
11857 	*/
11858 	return (contextSize);
11859     } else {
11860 	xmlDocPtr oldContextDoc;
11861         int oldcs, oldpp;
11862 	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11863 	xmlXPathStepOpPtr exprOp;
11864 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11865 	xmlNodePtr oldContextNode, contextNode = NULL;
11866 	xmlXPathContextPtr xpctxt = ctxt->context;
11867         int frame;
11868 
11869 #ifdef LIBXML_XPTR_ENABLED
11870 	    /*
11871 	    * URGENT TODO: Check the following:
11872 	    *  We don't expect location sets if evaluating prediates, right?
11873 	    *  Only filters should expect location sets, right?
11874 	*/
11875 #endif /* LIBXML_XPTR_ENABLED */
11876 
11877 	/*
11878 	* Save old context.
11879 	*/
11880 	oldContextNode = xpctxt->node;
11881 	oldContextDoc = xpctxt->doc;
11882         oldcs = xpctxt->contextSize;
11883         oldpp = xpctxt->proximityPosition;
11884 	/*
11885 	* Get the expression of this predicate.
11886 	*/
11887 	exprOp = &ctxt->comp->steps[op->ch2];
11888 	for (i = 0; i < set->nodeNr; i++) {
11889             xmlXPathObjectPtr tmp;
11890 
11891 	    if (set->nodeTab[i] == NULL)
11892 		continue;
11893 
11894 	    contextNode = set->nodeTab[i];
11895 	    xpctxt->node = contextNode;
11896 	    xpctxt->contextSize = contextSize;
11897 	    xpctxt->proximityPosition = ++contextPos;
11898 
11899 	    /*
11900 	    * Initialize the new set.
11901 	    * Also set the xpath document in case things like
11902 	    * key() evaluation are attempted on the predicate
11903 	    */
11904 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11905 		(contextNode->doc != NULL))
11906 		xpctxt->doc = contextNode->doc;
11907 	    /*
11908 	    * Evaluate the predicate expression with 1 context node
11909 	    * at a time; this node is packaged into a node set; this
11910 	    * node set is handed over to the evaluation mechanism.
11911 	    */
11912 	    if (contextObj == NULL)
11913 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11914 	    else {
11915 		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11916 		    contextNode) < 0) {
11917 		    ctxt->error = XPATH_MEMORY_ERROR;
11918 		    goto evaluation_exit;
11919 		}
11920 	    }
11921 
11922 	    valuePush(ctxt, contextObj);
11923             frame = xmlXPathSetFrame(ctxt);
11924 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11925             xmlXPathPopFrame(ctxt, frame);
11926             tmp = valuePop(ctxt);
11927 
11928 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11929                 while (tmp != contextObj) {
11930                     /*
11931                      * Free up the result
11932                      * then pop off contextObj, which will be freed later
11933                      */
11934                     xmlXPathReleaseObject(xpctxt, tmp);
11935                     tmp = valuePop(ctxt);
11936                 }
11937 		goto evaluation_error;
11938 	    }
11939             /* push the result back onto the stack */
11940             valuePush(ctxt, tmp);
11941 
11942 	    if (res)
11943 		pos++;
11944 
11945 	    if (res && (pos >= minPos) && (pos <= maxPos)) {
11946 		/*
11947 		* Fits in the requested range.
11948 		*/
11949 		newContextSize++;
11950 		if (minPos == maxPos) {
11951 		    /*
11952 		    * Only 1 node was requested.
11953 		    */
11954 		    if (contextNode->type == XML_NAMESPACE_DECL) {
11955 			/*
11956 			* As always: take care of those nasty
11957 			* namespace nodes.
11958 			*/
11959 			set->nodeTab[i] = NULL;
11960 		    }
11961 		    xmlXPathNodeSetClear(set, hasNsNodes);
11962 		    set->nodeNr = 1;
11963 		    set->nodeTab[0] = contextNode;
11964 		    goto evaluation_exit;
11965 		}
11966 		if (pos == maxPos) {
11967 		    /*
11968 		    * We are done.
11969 		    */
11970 		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11971 		    goto evaluation_exit;
11972 		}
11973 	    } else {
11974 		/*
11975 		* Remove the entry from the initial node set.
11976 		*/
11977 		set->nodeTab[i] = NULL;
11978 		if (contextNode->type == XML_NAMESPACE_DECL)
11979 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11980 	    }
11981 	    if (exprRes != NULL) {
11982 		xmlXPathReleaseObject(ctxt->context, exprRes);
11983 		exprRes = NULL;
11984 	    }
11985 	    if (ctxt->value == contextObj) {
11986 		/*
11987 		* Don't free the temporary XPath object holding the
11988 		* context node, in order to avoid massive recreation
11989 		* inside this loop.
11990 		*/
11991 		valuePop(ctxt);
11992 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11993 	    } else {
11994 		/*
11995 		* The object was lost in the evaluation machinery.
11996 		* Can this happen? Maybe in case of internal-errors.
11997 		*/
11998 		contextObj = NULL;
11999 	    }
12000 	}
12001 	goto evaluation_exit;
12002 
12003 evaluation_error:
12004 	xmlXPathNodeSetClear(set, hasNsNodes);
12005 	newContextSize = 0;
12006 
12007 evaluation_exit:
12008 	if (contextObj != NULL) {
12009 	    if (ctxt->value == contextObj)
12010 		valuePop(ctxt);
12011 	    xmlXPathReleaseObject(xpctxt, contextObj);
12012 	}
12013 	if (exprRes != NULL)
12014 	    xmlXPathReleaseObject(ctxt->context, exprRes);
12015 	/*
12016 	* Reset/invalidate the context.
12017 	*/
12018 	xpctxt->node = oldContextNode;
12019 	xpctxt->doc = oldContextDoc;
12020 	xpctxt->contextSize = oldcs;
12021 	xpctxt->proximityPosition = oldpp;
12022 	return(newContextSize);
12023     }
12024     return(contextSize);
12025 }
12026 
12027 static int
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int * maxPos)12028 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
12029 			    xmlXPathStepOpPtr op,
12030 			    int *maxPos)
12031 {
12032 
12033     xmlXPathStepOpPtr exprOp;
12034 
12035     /*
12036     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12037     */
12038 
12039     /*
12040     * If not -1, then ch1 will point to:
12041     * 1) For predicates (XPATH_OP_PREDICATE):
12042     *    - an inner predicate operator
12043     * 2) For filters (XPATH_OP_FILTER):
12044     *    - an inner filter operater OR
12045     *    - an expression selecting the node set.
12046     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
12047     */
12048     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12049 	return(0);
12050 
12051     if (op->ch2 != -1) {
12052 	exprOp = &ctxt->comp->steps[op->ch2];
12053     } else
12054 	return(0);
12055 
12056     if ((exprOp != NULL) &&
12057 	(exprOp->op == XPATH_OP_VALUE) &&
12058 	(exprOp->value4 != NULL) &&
12059 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12060     {
12061         double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12062 
12063 	/*
12064 	* We have a "[n]" predicate here.
12065 	* TODO: Unfortunately this simplistic test here is not
12066 	* able to detect a position() predicate in compound
12067 	* expressions like "[@attr = 'a" and position() = 1],
12068 	* and even not the usage of position() in
12069 	* "[position() = 1]"; thus - obviously - a position-range,
12070 	* like it "[position() < 5]", is also not detected.
12071 	* Maybe we could rewrite the AST to ease the optimization.
12072 	*/
12073 
12074         if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
12075 	    *maxPos = (int) floatval;
12076             if (floatval == (double) *maxPos)
12077                 return(1);
12078         }
12079     }
12080     return(0);
12081 }
12082 
12083 static int
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first,xmlNodePtr * last,int toBool)12084 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12085                            xmlXPathStepOpPtr op,
12086 			   xmlNodePtr * first, xmlNodePtr * last,
12087 			   int toBool)
12088 {
12089 
12090 #define XP_TEST_HIT \
12091     if (hasAxisRange != 0) { \
12092 	if (++pos == maxPos) { \
12093 	    if (addNode(seq, cur) < 0) \
12094 	        ctxt->error = XPATH_MEMORY_ERROR; \
12095 	    goto axis_range_end; } \
12096     } else { \
12097 	if (addNode(seq, cur) < 0) \
12098 	    ctxt->error = XPATH_MEMORY_ERROR; \
12099 	if (breakOnFirstHit) goto first_hit; }
12100 
12101 #define XP_TEST_HIT_NS \
12102     if (hasAxisRange != 0) { \
12103 	if (++pos == maxPos) { \
12104 	    hasNsNodes = 1; \
12105 	    if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12106 	        ctxt->error = XPATH_MEMORY_ERROR; \
12107 	goto axis_range_end; } \
12108     } else { \
12109 	hasNsNodes = 1; \
12110 	if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12111 	    ctxt->error = XPATH_MEMORY_ERROR; \
12112 	if (breakOnFirstHit) goto first_hit; }
12113 
12114     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12115     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12116     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12117     const xmlChar *prefix = op->value4;
12118     const xmlChar *name = op->value5;
12119     const xmlChar *URI = NULL;
12120 
12121 #ifdef DEBUG_STEP
12122     int nbMatches = 0, prevMatches = 0;
12123 #endif
12124     int total = 0, hasNsNodes = 0;
12125     /* The popped object holding the context nodes */
12126     xmlXPathObjectPtr obj;
12127     /* The set of context nodes for the node tests */
12128     xmlNodeSetPtr contextSeq;
12129     int contextIdx;
12130     xmlNodePtr contextNode;
12131     /* The final resulting node set wrt to all context nodes */
12132     xmlNodeSetPtr outSeq;
12133     /*
12134     * The temporary resulting node set wrt 1 context node.
12135     * Used to feed predicate evaluation.
12136     */
12137     xmlNodeSetPtr seq;
12138     xmlNodePtr cur;
12139     /* First predicate operator */
12140     xmlXPathStepOpPtr predOp;
12141     int maxPos; /* The requested position() (when a "[n]" predicate) */
12142     int hasPredicateRange, hasAxisRange, pos, size, newSize;
12143     int breakOnFirstHit;
12144 
12145     xmlXPathTraversalFunction next = NULL;
12146     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12147     xmlXPathNodeSetMergeFunction mergeAndClear;
12148     xmlNodePtr oldContextNode;
12149     xmlXPathContextPtr xpctxt = ctxt->context;
12150 
12151 
12152     CHECK_TYPE0(XPATH_NODESET);
12153     obj = valuePop(ctxt);
12154     /*
12155     * Setup namespaces.
12156     */
12157     if (prefix != NULL) {
12158         URI = xmlXPathNsLookup(xpctxt, prefix);
12159         if (URI == NULL) {
12160 	    xmlXPathReleaseObject(xpctxt, obj);
12161             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12162 	}
12163     }
12164     /*
12165     * Setup axis.
12166     *
12167     * MAYBE FUTURE TODO: merging optimizations:
12168     * - If the nodes to be traversed wrt to the initial nodes and
12169     *   the current axis cannot overlap, then we could avoid searching
12170     *   for duplicates during the merge.
12171     *   But the question is how/when to evaluate if they cannot overlap.
12172     *   Example: if we know that for two initial nodes, the one is
12173     *   not in the ancestor-or-self axis of the other, then we could safely
12174     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12175     *   the descendant-or-self axis.
12176     */
12177     mergeAndClear = xmlXPathNodeSetMergeAndClear;
12178     switch (axis) {
12179         case AXIS_ANCESTOR:
12180             first = NULL;
12181             next = xmlXPathNextAncestor;
12182             break;
12183         case AXIS_ANCESTOR_OR_SELF:
12184             first = NULL;
12185             next = xmlXPathNextAncestorOrSelf;
12186             break;
12187         case AXIS_ATTRIBUTE:
12188             first = NULL;
12189 	    last = NULL;
12190             next = xmlXPathNextAttribute;
12191 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12192             break;
12193         case AXIS_CHILD:
12194 	    last = NULL;
12195 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12196 		(type == NODE_TYPE_NODE))
12197 	    {
12198 		/*
12199 		* Optimization if an element node type is 'element'.
12200 		*/
12201 		next = xmlXPathNextChildElement;
12202 	    } else
12203 		next = xmlXPathNextChild;
12204 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12205             break;
12206         case AXIS_DESCENDANT:
12207 	    last = NULL;
12208             next = xmlXPathNextDescendant;
12209             break;
12210         case AXIS_DESCENDANT_OR_SELF:
12211 	    last = NULL;
12212             next = xmlXPathNextDescendantOrSelf;
12213             break;
12214         case AXIS_FOLLOWING:
12215 	    last = NULL;
12216             next = xmlXPathNextFollowing;
12217             break;
12218         case AXIS_FOLLOWING_SIBLING:
12219 	    last = NULL;
12220             next = xmlXPathNextFollowingSibling;
12221             break;
12222         case AXIS_NAMESPACE:
12223             first = NULL;
12224 	    last = NULL;
12225             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12226 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12227             break;
12228         case AXIS_PARENT:
12229             first = NULL;
12230             next = xmlXPathNextParent;
12231             break;
12232         case AXIS_PRECEDING:
12233             first = NULL;
12234             next = xmlXPathNextPrecedingInternal;
12235             break;
12236         case AXIS_PRECEDING_SIBLING:
12237             first = NULL;
12238             next = xmlXPathNextPrecedingSibling;
12239             break;
12240         case AXIS_SELF:
12241             first = NULL;
12242 	    last = NULL;
12243             next = xmlXPathNextSelf;
12244 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12245             break;
12246     }
12247 
12248 #ifdef DEBUG_STEP
12249     xmlXPathDebugDumpStepAxis(op,
12250 	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12251 #endif
12252 
12253     if (next == NULL) {
12254 	xmlXPathReleaseObject(xpctxt, obj);
12255         return(0);
12256     }
12257     contextSeq = obj->nodesetval;
12258     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12259 	xmlXPathReleaseObject(xpctxt, obj);
12260         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12261         return(0);
12262     }
12263     /*
12264     * Predicate optimization ---------------------------------------------
12265     * If this step has a last predicate, which contains a position(),
12266     * then we'll optimize (although not exactly "position()", but only
12267     * the  short-hand form, i.e., "[n]".
12268     *
12269     * Example - expression "/foo[parent::bar][1]":
12270     *
12271     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12272     *   ROOT                               -- op->ch1
12273     *   PREDICATE                          -- op->ch2 (predOp)
12274     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12275     *       SORT
12276     *         COLLECT  'parent' 'name' 'node' bar
12277     *           NODE
12278     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12279     *
12280     */
12281     maxPos = 0;
12282     predOp = NULL;
12283     hasPredicateRange = 0;
12284     hasAxisRange = 0;
12285     if (op->ch2 != -1) {
12286 	/*
12287 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
12288 	*/
12289 	predOp = &ctxt->comp->steps[op->ch2];
12290 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12291 	    if (predOp->ch1 != -1) {
12292 		/*
12293 		* Use the next inner predicate operator.
12294 		*/
12295 		predOp = &ctxt->comp->steps[predOp->ch1];
12296 		hasPredicateRange = 1;
12297 	    } else {
12298 		/*
12299 		* There's no other predicate than the [n] predicate.
12300 		*/
12301 		predOp = NULL;
12302 		hasAxisRange = 1;
12303 	    }
12304 	}
12305     }
12306     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12307     /*
12308     * Axis traversal -----------------------------------------------------
12309     */
12310     /*
12311      * 2.3 Node Tests
12312      *  - For the attribute axis, the principal node type is attribute.
12313      *  - For the namespace axis, the principal node type is namespace.
12314      *  - For other axes, the principal node type is element.
12315      *
12316      * A node test * is true for any node of the
12317      * principal node type. For example, child::* will
12318      * select all element children of the context node
12319      */
12320     oldContextNode = xpctxt->node;
12321     addNode = xmlXPathNodeSetAddUnique;
12322     outSeq = NULL;
12323     seq = NULL;
12324     contextNode = NULL;
12325     contextIdx = 0;
12326 
12327 
12328     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12329            (ctxt->error == XPATH_EXPRESSION_OK)) {
12330 	xpctxt->node = contextSeq->nodeTab[contextIdx++];
12331 
12332 	if (seq == NULL) {
12333 	    seq = xmlXPathNodeSetCreate(NULL);
12334 	    if (seq == NULL) {
12335 		total = 0;
12336 		goto error;
12337 	    }
12338 	}
12339 	/*
12340 	* Traverse the axis and test the nodes.
12341 	*/
12342 	pos = 0;
12343 	cur = NULL;
12344 	hasNsNodes = 0;
12345         do {
12346             cur = next(ctxt, cur);
12347             if (cur == NULL)
12348                 break;
12349 
12350 	    /*
12351 	    * QUESTION TODO: What does the "first" and "last" stuff do?
12352 	    */
12353             if ((first != NULL) && (*first != NULL)) {
12354 		if (*first == cur)
12355 		    break;
12356 		if (((total % 256) == 0) &&
12357 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12358 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12359 #else
12360 		    (xmlXPathCmpNodes(*first, cur) >= 0))
12361 #endif
12362 		{
12363 		    break;
12364 		}
12365 	    }
12366 	    if ((last != NULL) && (*last != NULL)) {
12367 		if (*last == cur)
12368 		    break;
12369 		if (((total % 256) == 0) &&
12370 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12371 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12372 #else
12373 		    (xmlXPathCmpNodes(cur, *last) >= 0))
12374 #endif
12375 		{
12376 		    break;
12377 		}
12378 	    }
12379 
12380             total++;
12381 
12382 #ifdef DEBUG_STEP
12383             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12384 #endif
12385 
12386 	    switch (test) {
12387                 case NODE_TEST_NONE:
12388 		    total = 0;
12389                     STRANGE
12390 		    goto error;
12391                 case NODE_TEST_TYPE:
12392 		    if (type == NODE_TYPE_NODE) {
12393 			switch (cur->type) {
12394 			    case XML_DOCUMENT_NODE:
12395 			    case XML_HTML_DOCUMENT_NODE:
12396 #ifdef LIBXML_DOCB_ENABLED
12397 			    case XML_DOCB_DOCUMENT_NODE:
12398 #endif
12399 			    case XML_ELEMENT_NODE:
12400 			    case XML_ATTRIBUTE_NODE:
12401 			    case XML_PI_NODE:
12402 			    case XML_COMMENT_NODE:
12403 			    case XML_CDATA_SECTION_NODE:
12404 			    case XML_TEXT_NODE:
12405 				XP_TEST_HIT
12406 				break;
12407 			    case XML_NAMESPACE_DECL: {
12408 				if (axis == AXIS_NAMESPACE) {
12409 				    XP_TEST_HIT_NS
12410 				} else {
12411 	                            hasNsNodes = 1;
12412 				    XP_TEST_HIT
12413 				}
12414 				break;
12415                             }
12416 			    default:
12417 				break;
12418 			}
12419 		    } else if (cur->type == (xmlElementType) type) {
12420 			if (cur->type == XML_NAMESPACE_DECL)
12421 			    XP_TEST_HIT_NS
12422 			else
12423 			    XP_TEST_HIT
12424 		    } else if ((type == NODE_TYPE_TEXT) &&
12425 			 (cur->type == XML_CDATA_SECTION_NODE))
12426 		    {
12427 			XP_TEST_HIT
12428 		    }
12429 		    break;
12430                 case NODE_TEST_PI:
12431                     if ((cur->type == XML_PI_NODE) &&
12432                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12433 		    {
12434 			XP_TEST_HIT
12435                     }
12436                     break;
12437                 case NODE_TEST_ALL:
12438                     if (axis == AXIS_ATTRIBUTE) {
12439                         if (cur->type == XML_ATTRIBUTE_NODE)
12440 			{
12441                             if (prefix == NULL)
12442 			    {
12443 				XP_TEST_HIT
12444                             } else if ((cur->ns != NULL) &&
12445 				(xmlStrEqual(URI, cur->ns->href)))
12446 			    {
12447 				XP_TEST_HIT
12448                             }
12449                         }
12450                     } else if (axis == AXIS_NAMESPACE) {
12451                         if (cur->type == XML_NAMESPACE_DECL)
12452 			{
12453 			    XP_TEST_HIT_NS
12454                         }
12455                     } else {
12456                         if (cur->type == XML_ELEMENT_NODE) {
12457                             if (prefix == NULL)
12458 			    {
12459 				XP_TEST_HIT
12460 
12461                             } else if ((cur->ns != NULL) &&
12462 				(xmlStrEqual(URI, cur->ns->href)))
12463 			    {
12464 				XP_TEST_HIT
12465                             }
12466                         }
12467                     }
12468                     break;
12469                 case NODE_TEST_NS:{
12470                         TODO;
12471                         break;
12472                     }
12473                 case NODE_TEST_NAME:
12474                     if (axis == AXIS_ATTRIBUTE) {
12475                         if (cur->type != XML_ATTRIBUTE_NODE)
12476 			    break;
12477 		    } else if (axis == AXIS_NAMESPACE) {
12478                         if (cur->type != XML_NAMESPACE_DECL)
12479 			    break;
12480 		    } else {
12481 		        if (cur->type != XML_ELEMENT_NODE)
12482 			    break;
12483 		    }
12484                     switch (cur->type) {
12485                         case XML_ELEMENT_NODE:
12486                             if (xmlStrEqual(name, cur->name)) {
12487                                 if (prefix == NULL) {
12488                                     if (cur->ns == NULL)
12489 				    {
12490 					XP_TEST_HIT
12491                                     }
12492                                 } else {
12493                                     if ((cur->ns != NULL) &&
12494                                         (xmlStrEqual(URI, cur->ns->href)))
12495 				    {
12496 					XP_TEST_HIT
12497                                     }
12498                                 }
12499                             }
12500                             break;
12501                         case XML_ATTRIBUTE_NODE:{
12502                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12503 
12504                                 if (xmlStrEqual(name, attr->name)) {
12505                                     if (prefix == NULL) {
12506                                         if ((attr->ns == NULL) ||
12507                                             (attr->ns->prefix == NULL))
12508 					{
12509 					    XP_TEST_HIT
12510                                         }
12511                                     } else {
12512                                         if ((attr->ns != NULL) &&
12513                                             (xmlStrEqual(URI,
12514 					      attr->ns->href)))
12515 					{
12516 					    XP_TEST_HIT
12517                                         }
12518                                     }
12519                                 }
12520                                 break;
12521                             }
12522                         case XML_NAMESPACE_DECL:
12523                             if (cur->type == XML_NAMESPACE_DECL) {
12524                                 xmlNsPtr ns = (xmlNsPtr) cur;
12525 
12526                                 if ((ns->prefix != NULL) && (name != NULL)
12527                                     && (xmlStrEqual(ns->prefix, name)))
12528 				{
12529 				    XP_TEST_HIT_NS
12530                                 }
12531                             }
12532                             break;
12533                         default:
12534                             break;
12535                     }
12536                     break;
12537 	    } /* switch(test) */
12538         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12539 
12540 	goto apply_predicates;
12541 
12542 axis_range_end: /* ----------------------------------------------------- */
12543 	/*
12544 	* We have a "/foo[n]", and position() = n was reached.
12545 	* Note that we can have as well "/foo/::parent::foo[1]", so
12546 	* a duplicate-aware merge is still needed.
12547 	* Merge with the result.
12548 	*/
12549 	if (outSeq == NULL) {
12550 	    outSeq = seq;
12551 	    seq = NULL;
12552 	} else
12553 	    outSeq = mergeAndClear(outSeq, seq, 0);
12554 	/*
12555 	* Break if only a true/false result was requested.
12556 	*/
12557 	if (toBool)
12558 	    break;
12559 	continue;
12560 
12561 first_hit: /* ---------------------------------------------------------- */
12562 	/*
12563 	* Break if only a true/false result was requested and
12564 	* no predicates existed and a node test succeeded.
12565 	*/
12566 	if (outSeq == NULL) {
12567 	    outSeq = seq;
12568 	    seq = NULL;
12569 	} else
12570 	    outSeq = mergeAndClear(outSeq, seq, 0);
12571 	break;
12572 
12573 #ifdef DEBUG_STEP
12574 	if (seq != NULL)
12575 	    nbMatches += seq->nodeNr;
12576 #endif
12577 
12578 apply_predicates: /* --------------------------------------------------- */
12579         if (ctxt->error != XPATH_EXPRESSION_OK)
12580 	    goto error;
12581 
12582         /*
12583 	* Apply predicates.
12584 	*/
12585         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12586 	    /*
12587 	    * E.g. when we have a "/foo[some expression][n]".
12588 	    */
12589 	    /*
12590 	    * QUESTION TODO: The old predicate evaluation took into
12591 	    *  account location-sets.
12592 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12593 	    *  Do we expect such a set here?
12594 	    *  All what I learned now from the evaluation semantics
12595 	    *  does not indicate that a location-set will be processed
12596 	    *  here, so this looks OK.
12597 	    */
12598 	    /*
12599 	    * Iterate over all predicates, starting with the outermost
12600 	    * predicate.
12601 	    * TODO: Problem: we cannot execute the inner predicates first
12602 	    *  since we cannot go back *up* the operator tree!
12603 	    *  Options we have:
12604 	    *  1) Use of recursive functions (like is it currently done
12605 	    *     via xmlXPathCompOpEval())
12606 	    *  2) Add a predicate evaluation information stack to the
12607 	    *     context struct
12608 	    *  3) Change the way the operators are linked; we need a
12609 	    *     "parent" field on xmlXPathStepOp
12610 	    *
12611 	    * For the moment, I'll try to solve this with a recursive
12612 	    * function: xmlXPathCompOpEvalPredicate().
12613 	    */
12614 	    size = seq->nodeNr;
12615 	    if (hasPredicateRange != 0)
12616 		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12617 		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
12618 	    else
12619 		newSize = xmlXPathCompOpEvalPredicate(ctxt,
12620 		    predOp, seq, size, hasNsNodes);
12621 
12622 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12623 		total = 0;
12624 		goto error;
12625 	    }
12626 	    /*
12627 	    * Add the filtered set of nodes to the result node set.
12628 	    */
12629 	    if (newSize == 0) {
12630 		/*
12631 		* The predicates filtered all nodes out.
12632 		*/
12633 		xmlXPathNodeSetClear(seq, hasNsNodes);
12634 	    } else if (seq->nodeNr > 0) {
12635 		/*
12636 		* Add to result set.
12637 		*/
12638 		if (outSeq == NULL) {
12639 		    if (size != newSize) {
12640 			/*
12641 			* We need to merge and clear here, since
12642 			* the sequence will contained NULLed entries.
12643 			*/
12644 			outSeq = mergeAndClear(NULL, seq, 1);
12645 		    } else {
12646 			outSeq = seq;
12647 			seq = NULL;
12648 		    }
12649 		} else
12650 		    outSeq = mergeAndClear(outSeq, seq,
12651 			(size != newSize) ? 1: 0);
12652 		/*
12653 		* Break if only a true/false result was requested.
12654 		*/
12655 		if (toBool)
12656 		    break;
12657 	    }
12658         } else if (seq->nodeNr > 0) {
12659 	    /*
12660 	    * Add to result set.
12661 	    */
12662 	    if (outSeq == NULL) {
12663 		outSeq = seq;
12664 		seq = NULL;
12665 	    } else {
12666 		outSeq = mergeAndClear(outSeq, seq, 0);
12667 	    }
12668 	}
12669     }
12670 
12671 error:
12672     if ((obj->boolval) && (obj->user != NULL)) {
12673 	/*
12674 	* QUESTION TODO: What does this do and why?
12675 	* TODO: Do we have to do this also for the "error"
12676 	* cleanup further down?
12677 	*/
12678 	ctxt->value->boolval = 1;
12679 	ctxt->value->user = obj->user;
12680 	obj->user = NULL;
12681 	obj->boolval = 0;
12682     }
12683     xmlXPathReleaseObject(xpctxt, obj);
12684 
12685     /*
12686     * Ensure we return at least an emtpy set.
12687     */
12688     if (outSeq == NULL) {
12689 	if ((seq != NULL) && (seq->nodeNr == 0))
12690 	    outSeq = seq;
12691 	else
12692 	    outSeq = xmlXPathNodeSetCreate(NULL);
12693         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12694     }
12695     if ((seq != NULL) && (seq != outSeq)) {
12696 	 xmlXPathFreeNodeSet(seq);
12697     }
12698     /*
12699     * Hand over the result. Better to push the set also in
12700     * case of errors.
12701     */
12702     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12703     /*
12704     * Reset the context node.
12705     */
12706     xpctxt->node = oldContextNode;
12707     /*
12708     * When traversing the namespace axis in "toBool" mode, it's
12709     * possible that tmpNsList wasn't freed.
12710     */
12711     if (xpctxt->tmpNsList != NULL) {
12712         xmlFree(xpctxt->tmpNsList);
12713         xpctxt->tmpNsList = NULL;
12714     }
12715 
12716 #ifdef DEBUG_STEP
12717     xmlGenericError(xmlGenericErrorContext,
12718 	"\nExamined %d nodes, found %d nodes at that step\n",
12719 	total, nbMatches);
12720 #endif
12721 
12722     return(total);
12723 }
12724 
12725 static int
12726 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12727 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12728 
12729 /**
12730  * xmlXPathCompOpEvalFirst:
12731  * @ctxt:  the XPath parser context with the compiled expression
12732  * @op:  an XPath compiled operation
12733  * @first:  the first elem found so far
12734  *
12735  * Evaluate the Precompiled XPath operation searching only the first
12736  * element in document order
12737  *
12738  * Returns the number of examined objects.
12739  */
12740 static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12741 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12742                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12743 {
12744     int total = 0, cur;
12745     xmlXPathCompExprPtr comp;
12746     xmlXPathObjectPtr arg1, arg2;
12747 
12748     CHECK_ERROR0;
12749     comp = ctxt->comp;
12750     switch (op->op) {
12751         case XPATH_OP_END:
12752             return (0);
12753         case XPATH_OP_UNION:
12754             total =
12755                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12756                                         first);
12757 	    CHECK_ERROR0;
12758             if ((ctxt->value != NULL)
12759                 && (ctxt->value->type == XPATH_NODESET)
12760                 && (ctxt->value->nodesetval != NULL)
12761                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12762                 /*
12763                  * limit tree traversing to first node in the result
12764                  */
12765 		/*
12766 		* OPTIMIZE TODO: This implicitely sorts
12767 		*  the result, even if not needed. E.g. if the argument
12768 		*  of the count() function, no sorting is needed.
12769 		* OPTIMIZE TODO: How do we know if the node-list wasn't
12770 		*  aready sorted?
12771 		*/
12772 		if (ctxt->value->nodesetval->nodeNr > 1)
12773 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12774                 *first = ctxt->value->nodesetval->nodeTab[0];
12775             }
12776             cur =
12777                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12778                                         first);
12779 	    CHECK_ERROR0;
12780 
12781             arg2 = valuePop(ctxt);
12782             arg1 = valuePop(ctxt);
12783             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12784                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12785 	        xmlXPathReleaseObject(ctxt->context, arg1);
12786 	        xmlXPathReleaseObject(ctxt->context, arg2);
12787                 XP_ERROR0(XPATH_INVALID_TYPE);
12788             }
12789 
12790             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12791                                                     arg2->nodesetval);
12792             valuePush(ctxt, arg1);
12793 	    xmlXPathReleaseObject(ctxt->context, arg2);
12794             /* optimizer */
12795 	    if (total > cur)
12796 		xmlXPathCompSwap(op);
12797             return (total + cur);
12798         case XPATH_OP_ROOT:
12799             xmlXPathRoot(ctxt);
12800             return (0);
12801         case XPATH_OP_NODE:
12802             if (op->ch1 != -1)
12803                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12804 	    CHECK_ERROR0;
12805             if (op->ch2 != -1)
12806                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12807 	    CHECK_ERROR0;
12808 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12809 		ctxt->context->node));
12810             return (total);
12811         case XPATH_OP_COLLECT:{
12812                 if (op->ch1 == -1)
12813                     return (total);
12814 
12815                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12816 		CHECK_ERROR0;
12817 
12818                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12819                 return (total);
12820             }
12821         case XPATH_OP_VALUE:
12822             valuePush(ctxt,
12823                       xmlXPathCacheObjectCopy(ctxt->context,
12824 			(xmlXPathObjectPtr) op->value4));
12825             return (0);
12826         case XPATH_OP_SORT:
12827             if (op->ch1 != -1)
12828                 total +=
12829                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12830                                             first);
12831 	    CHECK_ERROR0;
12832             if ((ctxt->value != NULL)
12833                 && (ctxt->value->type == XPATH_NODESET)
12834                 && (ctxt->value->nodesetval != NULL)
12835 		&& (ctxt->value->nodesetval->nodeNr > 1))
12836                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12837             return (total);
12838 #ifdef XP_OPTIMIZED_FILTER_FIRST
12839 	case XPATH_OP_FILTER:
12840                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12841             return (total);
12842 #endif
12843         default:
12844             return (xmlXPathCompOpEval(ctxt, op));
12845     }
12846 }
12847 
12848 /**
12849  * xmlXPathCompOpEvalLast:
12850  * @ctxt:  the XPath parser context with the compiled expression
12851  * @op:  an XPath compiled operation
12852  * @last:  the last elem found so far
12853  *
12854  * Evaluate the Precompiled XPath operation searching only the last
12855  * element in document order
12856  *
12857  * Returns the number of nodes traversed
12858  */
12859 static int
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * last)12860 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12861                        xmlNodePtr * last)
12862 {
12863     int total = 0, cur;
12864     xmlXPathCompExprPtr comp;
12865     xmlXPathObjectPtr arg1, arg2;
12866 
12867     CHECK_ERROR0;
12868     comp = ctxt->comp;
12869     switch (op->op) {
12870         case XPATH_OP_END:
12871             return (0);
12872         case XPATH_OP_UNION:
12873             total =
12874                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12875 	    CHECK_ERROR0;
12876             if ((ctxt->value != NULL)
12877                 && (ctxt->value->type == XPATH_NODESET)
12878                 && (ctxt->value->nodesetval != NULL)
12879                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12880                 /*
12881                  * limit tree traversing to first node in the result
12882                  */
12883 		if (ctxt->value->nodesetval->nodeNr > 1)
12884 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12885                 *last =
12886                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12887                                                      nodesetval->nodeNr -
12888                                                      1];
12889             }
12890             cur =
12891                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12892 	    CHECK_ERROR0;
12893             if ((ctxt->value != NULL)
12894                 && (ctxt->value->type == XPATH_NODESET)
12895                 && (ctxt->value->nodesetval != NULL)
12896                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12897             }
12898 
12899             arg2 = valuePop(ctxt);
12900             arg1 = valuePop(ctxt);
12901             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12902                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12903 	        xmlXPathReleaseObject(ctxt->context, arg1);
12904 	        xmlXPathReleaseObject(ctxt->context, arg2);
12905                 XP_ERROR0(XPATH_INVALID_TYPE);
12906             }
12907 
12908             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12909                                                     arg2->nodesetval);
12910             valuePush(ctxt, arg1);
12911 	    xmlXPathReleaseObject(ctxt->context, arg2);
12912             /* optimizer */
12913 	    if (total > cur)
12914 		xmlXPathCompSwap(op);
12915             return (total + cur);
12916         case XPATH_OP_ROOT:
12917             xmlXPathRoot(ctxt);
12918             return (0);
12919         case XPATH_OP_NODE:
12920             if (op->ch1 != -1)
12921                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12922 	    CHECK_ERROR0;
12923             if (op->ch2 != -1)
12924                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12925 	    CHECK_ERROR0;
12926 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12927 		ctxt->context->node));
12928             return (total);
12929         case XPATH_OP_COLLECT:{
12930                 if (op->ch1 == -1)
12931                     return (0);
12932 
12933                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12934 		CHECK_ERROR0;
12935 
12936                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12937                 return (total);
12938             }
12939         case XPATH_OP_VALUE:
12940             valuePush(ctxt,
12941                       xmlXPathCacheObjectCopy(ctxt->context,
12942 			(xmlXPathObjectPtr) op->value4));
12943             return (0);
12944         case XPATH_OP_SORT:
12945             if (op->ch1 != -1)
12946                 total +=
12947                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12948                                            last);
12949 	    CHECK_ERROR0;
12950             if ((ctxt->value != NULL)
12951                 && (ctxt->value->type == XPATH_NODESET)
12952                 && (ctxt->value->nodesetval != NULL)
12953 		&& (ctxt->value->nodesetval->nodeNr > 1))
12954                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12955             return (total);
12956         default:
12957             return (xmlXPathCompOpEval(ctxt, op));
12958     }
12959 }
12960 
12961 #ifdef XP_OPTIMIZED_FILTER_FIRST
12962 static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12963 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12964 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
12965 {
12966     int total = 0;
12967     xmlXPathCompExprPtr comp;
12968     xmlXPathObjectPtr res;
12969     xmlXPathObjectPtr obj;
12970     xmlNodeSetPtr oldset;
12971     xmlNodePtr oldnode;
12972     xmlDocPtr oldDoc;
12973     int oldcs, oldpp;
12974     int i;
12975 
12976     CHECK_ERROR0;
12977     comp = ctxt->comp;
12978     /*
12979     * Optimization for ()[last()] selection i.e. the last elem
12980     */
12981     if ((op->ch1 != -1) && (op->ch2 != -1) &&
12982 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12983 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12984 	int f = comp->steps[op->ch2].ch1;
12985 
12986 	if ((f != -1) &&
12987 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12988 	    (comp->steps[f].value5 == NULL) &&
12989 	    (comp->steps[f].value == 0) &&
12990 	    (comp->steps[f].value4 != NULL) &&
12991 	    (xmlStrEqual
12992 	    (comp->steps[f].value4, BAD_CAST "last"))) {
12993 	    xmlNodePtr last = NULL;
12994 
12995 	    total +=
12996 		xmlXPathCompOpEvalLast(ctxt,
12997 		    &comp->steps[op->ch1],
12998 		    &last);
12999 	    CHECK_ERROR0;
13000 	    /*
13001 	    * The nodeset should be in document order,
13002 	    * Keep only the last value
13003 	    */
13004 	    if ((ctxt->value != NULL) &&
13005 		(ctxt->value->type == XPATH_NODESET) &&
13006 		(ctxt->value->nodesetval != NULL) &&
13007 		(ctxt->value->nodesetval->nodeTab != NULL) &&
13008 		(ctxt->value->nodesetval->nodeNr > 1)) {
13009                 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13010 		*first = *(ctxt->value->nodesetval->nodeTab);
13011 	    }
13012 	    return (total);
13013 	}
13014     }
13015 
13016     if (op->ch1 != -1)
13017 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13018     CHECK_ERROR0;
13019     if (op->ch2 == -1)
13020 	return (total);
13021     if (ctxt->value == NULL)
13022 	return (total);
13023 
13024 #ifdef LIBXML_XPTR_ENABLED
13025     /*
13026     * Hum are we filtering the result of an XPointer expression
13027     */
13028     if (ctxt->value->type == XPATH_LOCATIONSET) {
13029 	xmlXPathObjectPtr tmp = NULL;
13030 	xmlLocationSetPtr newlocset = NULL;
13031 	xmlLocationSetPtr oldlocset;
13032 
13033 	/*
13034 	* Extract the old locset, and then evaluate the result of the
13035 	* expression for all the element in the locset. use it to grow
13036 	* up a new locset.
13037 	*/
13038 	CHECK_TYPE0(XPATH_LOCATIONSET);
13039 
13040 	if ((ctxt->value->user == NULL) ||
13041             (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13042 	    return (total);
13043 
13044 	obj = valuePop(ctxt);
13045 	oldlocset = obj->user;
13046         oldnode = ctxt->context->node;
13047         oldcs = ctxt->context->contextSize;
13048         oldpp = ctxt->context->proximityPosition;
13049 
13050 	newlocset = xmlXPtrLocationSetCreate(NULL);
13051 
13052 	for (i = 0; i < oldlocset->locNr; i++) {
13053 	    /*
13054 	    * Run the evaluation with a node list made of a
13055 	    * single item in the nodelocset.
13056 	    */
13057 	    ctxt->context->node = oldlocset->locTab[i]->user;
13058 	    ctxt->context->contextSize = oldlocset->locNr;
13059 	    ctxt->context->proximityPosition = i + 1;
13060 	    if (tmp == NULL) {
13061 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13062 		    ctxt->context->node);
13063 	    } else {
13064 		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13065 		                             ctxt->context->node) < 0) {
13066 		    ctxt->error = XPATH_MEMORY_ERROR;
13067 		}
13068 	    }
13069 	    valuePush(ctxt, tmp);
13070 	    if (op->ch2 != -1)
13071 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13072 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13073                 xmlXPtrFreeLocationSet(newlocset);
13074                 goto xptr_error;
13075 	    }
13076 	    /*
13077 	    * The result of the evaluation need to be tested to
13078 	    * decided whether the filter succeeded or not
13079 	    */
13080 	    res = valuePop(ctxt);
13081 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13082 		xmlXPtrLocationSetAdd(newlocset,
13083 		    xmlXPathCacheObjectCopy(ctxt->context,
13084 			oldlocset->locTab[i]));
13085 	    }
13086 	    /*
13087 	    * Cleanup
13088 	    */
13089 	    if (res != NULL) {
13090 		xmlXPathReleaseObject(ctxt->context, res);
13091 	    }
13092 	    if (ctxt->value == tmp) {
13093 		valuePop(ctxt);
13094 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13095 		/*
13096 		* REVISIT TODO: Don't create a temporary nodeset
13097 		* for everly iteration.
13098 		*/
13099 		/* OLD: xmlXPathFreeObject(res); */
13100 	    } else
13101 		tmp = NULL;
13102 	    /*
13103 	    * Only put the first node in the result, then leave.
13104 	    */
13105 	    if (newlocset->locNr > 0) {
13106 		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
13107 		break;
13108 	    }
13109 	}
13110 	if (tmp != NULL) {
13111 	    xmlXPathReleaseObject(ctxt->context, tmp);
13112 	}
13113 	/*
13114 	* The result is used as the new evaluation locset.
13115 	*/
13116 	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13117 xptr_error:
13118 	xmlXPathReleaseObject(ctxt->context, obj);
13119 	ctxt->context->node = oldnode;
13120 	ctxt->context->contextSize = oldcs;
13121 	ctxt->context->proximityPosition = oldpp;
13122 	return (total);
13123     }
13124 #endif /* LIBXML_XPTR_ENABLED */
13125 
13126     /*
13127     * Extract the old set, and then evaluate the result of the
13128     * expression for all the element in the set. use it to grow
13129     * up a new set.
13130     */
13131     CHECK_TYPE0(XPATH_NODESET);
13132 
13133     if ((ctxt->value->nodesetval != NULL) &&
13134         (ctxt->value->nodesetval->nodeNr != 0)) {
13135 	xmlNodeSetPtr newset;
13136 	xmlXPathObjectPtr tmp = NULL;
13137 
13138         obj = valuePop(ctxt);
13139         oldset = obj->nodesetval;
13140         oldnode = ctxt->context->node;
13141         oldDoc = ctxt->context->doc;
13142         oldcs = ctxt->context->contextSize;
13143         oldpp = ctxt->context->proximityPosition;
13144 
13145 	/*
13146 	* Initialize the new set.
13147 	* Also set the xpath document in case things like
13148 	* key() evaluation are attempted on the predicate
13149 	*/
13150 	newset = xmlXPathNodeSetCreate(NULL);
13151         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13152 
13153 	for (i = 0; i < oldset->nodeNr; i++) {
13154 	    /*
13155 	    * Run the evaluation with a node list made of
13156 	    * a single item in the nodeset.
13157 	    */
13158 	    ctxt->context->node = oldset->nodeTab[i];
13159 	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13160 		(oldset->nodeTab[i]->doc != NULL))
13161 		ctxt->context->doc = oldset->nodeTab[i]->doc;
13162 	    if (tmp == NULL) {
13163 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13164 		    ctxt->context->node);
13165 	    } else {
13166 		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13167 		                             ctxt->context->node) < 0) {
13168 		    ctxt->error = XPATH_MEMORY_ERROR;
13169 		}
13170 	    }
13171 	    valuePush(ctxt, tmp);
13172 	    ctxt->context->contextSize = oldset->nodeNr;
13173 	    ctxt->context->proximityPosition = i + 1;
13174 	    if (op->ch2 != -1)
13175 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13176 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13177 		xmlXPathFreeNodeSet(newset);
13178                 goto error;
13179 	    }
13180 	    /*
13181 	    * The result of the evaluation needs to be tested to
13182 	    * decide whether the filter succeeded or not
13183 	    */
13184 	    res = valuePop(ctxt);
13185 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13186 		if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13187 		    ctxt->error = XPATH_MEMORY_ERROR;
13188 	    }
13189 	    /*
13190 	    * Cleanup
13191 	    */
13192 	    if (res != NULL) {
13193 		xmlXPathReleaseObject(ctxt->context, res);
13194 	    }
13195 	    if (ctxt->value == tmp) {
13196 		valuePop(ctxt);
13197 		/*
13198 		* Don't free the temporary nodeset
13199 		* in order to avoid massive recreation inside this
13200 		* loop.
13201 		*/
13202 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13203 	    } else
13204 		tmp = NULL;
13205 	    /*
13206 	    * Only put the first node in the result, then leave.
13207 	    */
13208 	    if (newset->nodeNr > 0) {
13209 		*first = *(newset->nodeTab);
13210 		break;
13211 	    }
13212 	}
13213 	if (tmp != NULL) {
13214 	    xmlXPathReleaseObject(ctxt->context, tmp);
13215 	}
13216 	/*
13217 	* The result is used as the new evaluation set.
13218 	*/
13219 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13220 error:
13221 	xmlXPathReleaseObject(ctxt->context, obj);
13222 	ctxt->context->node = oldnode;
13223 	ctxt->context->doc = oldDoc;
13224 	ctxt->context->contextSize = oldcs;
13225 	ctxt->context->proximityPosition = oldpp;
13226     }
13227     return(total);
13228 }
13229 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13230 
13231 /**
13232  * xmlXPathCompOpEval:
13233  * @ctxt:  the XPath parser context with the compiled expression
13234  * @op:  an XPath compiled operation
13235  *
13236  * Evaluate the Precompiled XPath operation
13237  * Returns the number of nodes traversed
13238  */
13239 static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op)13240 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13241 {
13242     int total = 0;
13243     int equal, ret;
13244     xmlXPathCompExprPtr comp;
13245     xmlXPathObjectPtr arg1, arg2;
13246 
13247     CHECK_ERROR0;
13248     comp = ctxt->comp;
13249     switch (op->op) {
13250         case XPATH_OP_END:
13251             return (0);
13252         case XPATH_OP_AND:
13253             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13254 	    CHECK_ERROR0;
13255             xmlXPathBooleanFunction(ctxt, 1);
13256             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13257                 return (total);
13258             arg2 = valuePop(ctxt);
13259             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13260 	    if (ctxt->error) {
13261 		xmlXPathFreeObject(arg2);
13262 		return(0);
13263 	    }
13264             xmlXPathBooleanFunction(ctxt, 1);
13265             if (ctxt->value != NULL)
13266                 ctxt->value->boolval &= arg2->boolval;
13267 	    xmlXPathReleaseObject(ctxt->context, arg2);
13268             return (total);
13269         case XPATH_OP_OR:
13270             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13271 	    CHECK_ERROR0;
13272             xmlXPathBooleanFunction(ctxt, 1);
13273             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13274                 return (total);
13275             arg2 = valuePop(ctxt);
13276             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13277 	    if (ctxt->error) {
13278 		xmlXPathFreeObject(arg2);
13279 		return(0);
13280 	    }
13281             xmlXPathBooleanFunction(ctxt, 1);
13282             if (ctxt->value != NULL)
13283                 ctxt->value->boolval |= arg2->boolval;
13284 	    xmlXPathReleaseObject(ctxt->context, arg2);
13285             return (total);
13286         case XPATH_OP_EQUAL:
13287             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13288 	    CHECK_ERROR0;
13289             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13290 	    CHECK_ERROR0;
13291 	    if (op->value)
13292 		equal = xmlXPathEqualValues(ctxt);
13293 	    else
13294 		equal = xmlXPathNotEqualValues(ctxt);
13295 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13296             return (total);
13297         case XPATH_OP_CMP:
13298             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13299 	    CHECK_ERROR0;
13300             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13301 	    CHECK_ERROR0;
13302             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13303 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13304             return (total);
13305         case XPATH_OP_PLUS:
13306             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13307 	    CHECK_ERROR0;
13308             if (op->ch2 != -1) {
13309                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13310 	    }
13311 	    CHECK_ERROR0;
13312             if (op->value == 0)
13313                 xmlXPathSubValues(ctxt);
13314             else if (op->value == 1)
13315                 xmlXPathAddValues(ctxt);
13316             else if (op->value == 2)
13317                 xmlXPathValueFlipSign(ctxt);
13318             else if (op->value == 3) {
13319                 CAST_TO_NUMBER;
13320                 CHECK_TYPE0(XPATH_NUMBER);
13321             }
13322             return (total);
13323         case XPATH_OP_MULT:
13324             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13325 	    CHECK_ERROR0;
13326             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13327 	    CHECK_ERROR0;
13328             if (op->value == 0)
13329                 xmlXPathMultValues(ctxt);
13330             else if (op->value == 1)
13331                 xmlXPathDivValues(ctxt);
13332             else if (op->value == 2)
13333                 xmlXPathModValues(ctxt);
13334             return (total);
13335         case XPATH_OP_UNION:
13336             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13337 	    CHECK_ERROR0;
13338             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13339 	    CHECK_ERROR0;
13340 
13341             arg2 = valuePop(ctxt);
13342             arg1 = valuePop(ctxt);
13343             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13344                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13345 	        xmlXPathReleaseObject(ctxt->context, arg1);
13346 	        xmlXPathReleaseObject(ctxt->context, arg2);
13347                 XP_ERROR0(XPATH_INVALID_TYPE);
13348             }
13349 
13350 	    if ((arg1->nodesetval == NULL) ||
13351 		((arg2->nodesetval != NULL) &&
13352 		 (arg2->nodesetval->nodeNr != 0)))
13353 	    {
13354 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13355 							arg2->nodesetval);
13356 	    }
13357 
13358             valuePush(ctxt, arg1);
13359 	    xmlXPathReleaseObject(ctxt->context, arg2);
13360             return (total);
13361         case XPATH_OP_ROOT:
13362             xmlXPathRoot(ctxt);
13363             return (total);
13364         case XPATH_OP_NODE:
13365             if (op->ch1 != -1)
13366                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13367 	    CHECK_ERROR0;
13368             if (op->ch2 != -1)
13369                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13370 	    CHECK_ERROR0;
13371 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13372 		ctxt->context->node));
13373             return (total);
13374         case XPATH_OP_COLLECT:{
13375                 if (op->ch1 == -1)
13376                     return (total);
13377 
13378                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13379 		CHECK_ERROR0;
13380 
13381                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13382                 return (total);
13383             }
13384         case XPATH_OP_VALUE:
13385             valuePush(ctxt,
13386                       xmlXPathCacheObjectCopy(ctxt->context,
13387 			(xmlXPathObjectPtr) op->value4));
13388             return (total);
13389         case XPATH_OP_VARIABLE:{
13390 		xmlXPathObjectPtr val;
13391 
13392                 if (op->ch1 != -1)
13393                     total +=
13394                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13395                 if (op->value5 == NULL) {
13396 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13397 		    if (val == NULL)
13398 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13399                     valuePush(ctxt, val);
13400 		} else {
13401                     const xmlChar *URI;
13402 
13403                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13404                     if (URI == NULL) {
13405                         xmlGenericError(xmlGenericErrorContext,
13406             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13407                                     (char *) op->value4, (char *)op->value5);
13408                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13409                         return (total);
13410                     }
13411 		    val = xmlXPathVariableLookupNS(ctxt->context,
13412                                                        op->value4, URI);
13413 		    if (val == NULL)
13414 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13415                     valuePush(ctxt, val);
13416                 }
13417                 return (total);
13418             }
13419         case XPATH_OP_FUNCTION:{
13420                 xmlXPathFunction func;
13421                 const xmlChar *oldFunc, *oldFuncURI;
13422 		int i;
13423                 int frame;
13424 
13425                 frame = xmlXPathSetFrame(ctxt);
13426                 if (op->ch1 != -1) {
13427                     total +=
13428                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13429                     if (ctxt->error != XPATH_EXPRESSION_OK) {
13430                         xmlXPathPopFrame(ctxt, frame);
13431                         return (total);
13432                     }
13433                 }
13434 		if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13435 		    xmlGenericError(xmlGenericErrorContext,
13436 			    "xmlXPathCompOpEval: parameter error\n");
13437 		    ctxt->error = XPATH_INVALID_OPERAND;
13438                     xmlXPathPopFrame(ctxt, frame);
13439 		    return (total);
13440 		}
13441 		for (i = 0; i < op->value; i++) {
13442 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13443 			xmlGenericError(xmlGenericErrorContext,
13444 				"xmlXPathCompOpEval: parameter error\n");
13445 			ctxt->error = XPATH_INVALID_OPERAND;
13446                         xmlXPathPopFrame(ctxt, frame);
13447 			return (total);
13448 		    }
13449                 }
13450                 if (op->cache != NULL)
13451                     func = op->cache;
13452                 else {
13453                     const xmlChar *URI = NULL;
13454 
13455                     if (op->value5 == NULL)
13456                         func =
13457                             xmlXPathFunctionLookup(ctxt->context,
13458                                                    op->value4);
13459                     else {
13460                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
13461                         if (URI == NULL) {
13462                             xmlGenericError(xmlGenericErrorContext,
13463             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13464                                     (char *)op->value4, (char *)op->value5);
13465                             xmlXPathPopFrame(ctxt, frame);
13466                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13467                             return (total);
13468                         }
13469                         func = xmlXPathFunctionLookupNS(ctxt->context,
13470                                                         op->value4, URI);
13471                     }
13472                     if (func == NULL) {
13473                         xmlGenericError(xmlGenericErrorContext,
13474                                 "xmlXPathCompOpEval: function %s not found\n",
13475                                         (char *)op->value4);
13476                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13477                     }
13478                     op->cache = func;
13479                     op->cacheURI = (void *) URI;
13480                 }
13481                 oldFunc = ctxt->context->function;
13482                 oldFuncURI = ctxt->context->functionURI;
13483                 ctxt->context->function = op->value4;
13484                 ctxt->context->functionURI = op->cacheURI;
13485                 func(ctxt, op->value);
13486                 ctxt->context->function = oldFunc;
13487                 ctxt->context->functionURI = oldFuncURI;
13488                 xmlXPathPopFrame(ctxt, frame);
13489                 return (total);
13490             }
13491         case XPATH_OP_ARG:
13492             if (op->ch1 != -1) {
13493                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13494 	        CHECK_ERROR0;
13495             }
13496             if (op->ch2 != -1) {
13497                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13498 	        CHECK_ERROR0;
13499 	    }
13500             return (total);
13501         case XPATH_OP_PREDICATE:
13502         case XPATH_OP_FILTER:{
13503                 xmlXPathObjectPtr res;
13504                 xmlXPathObjectPtr obj, tmp;
13505                 xmlNodeSetPtr newset = NULL;
13506                 xmlNodeSetPtr oldset;
13507                 xmlNodePtr oldnode;
13508 		xmlDocPtr oldDoc;
13509                 int oldcs, oldpp;
13510                 int i;
13511 
13512                 /*
13513                  * Optimization for ()[1] selection i.e. the first elem
13514                  */
13515                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13516 #ifdef XP_OPTIMIZED_FILTER_FIRST
13517 		    /*
13518 		    * FILTER TODO: Can we assume that the inner processing
13519 		    *  will result in an ordered list if we have an
13520 		    *  XPATH_OP_FILTER?
13521 		    *  What about an additional field or flag on
13522 		    *  xmlXPathObject like @sorted ? This way we wouln'd need
13523 		    *  to assume anything, so it would be more robust and
13524 		    *  easier to optimize.
13525 		    */
13526                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13527 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13528 #else
13529 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13530 #endif
13531                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13532                     xmlXPathObjectPtr val;
13533 
13534                     val = comp->steps[op->ch2].value4;
13535                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13536                         (val->floatval == 1.0)) {
13537                         xmlNodePtr first = NULL;
13538 
13539                         total +=
13540                             xmlXPathCompOpEvalFirst(ctxt,
13541                                                     &comp->steps[op->ch1],
13542                                                     &first);
13543 			CHECK_ERROR0;
13544                         /*
13545                          * The nodeset should be in document order,
13546                          * Keep only the first value
13547                          */
13548                         if ((ctxt->value != NULL) &&
13549                             (ctxt->value->type == XPATH_NODESET) &&
13550                             (ctxt->value->nodesetval != NULL) &&
13551                             (ctxt->value->nodesetval->nodeNr > 1))
13552                             xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13553                                                         1, 1);
13554                         return (total);
13555                     }
13556                 }
13557                 /*
13558                  * Optimization for ()[last()] selection i.e. the last elem
13559                  */
13560                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13561                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13562                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13563                     int f = comp->steps[op->ch2].ch1;
13564 
13565                     if ((f != -1) &&
13566                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13567                         (comp->steps[f].value5 == NULL) &&
13568                         (comp->steps[f].value == 0) &&
13569                         (comp->steps[f].value4 != NULL) &&
13570                         (xmlStrEqual
13571                          (comp->steps[f].value4, BAD_CAST "last"))) {
13572                         xmlNodePtr last = NULL;
13573 
13574                         total +=
13575                             xmlXPathCompOpEvalLast(ctxt,
13576                                                    &comp->steps[op->ch1],
13577                                                    &last);
13578 			CHECK_ERROR0;
13579                         /*
13580                          * The nodeset should be in document order,
13581                          * Keep only the last value
13582                          */
13583                         if ((ctxt->value != NULL) &&
13584                             (ctxt->value->type == XPATH_NODESET) &&
13585                             (ctxt->value->nodesetval != NULL) &&
13586                             (ctxt->value->nodesetval->nodeTab != NULL) &&
13587                             (ctxt->value->nodesetval->nodeNr > 1))
13588                             xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13589                         return (total);
13590                     }
13591                 }
13592 		/*
13593 		* Process inner predicates first.
13594 		* Example "index[parent::book][1]":
13595 		* ...
13596 		*   PREDICATE   <-- we are here "[1]"
13597 		*     PREDICATE <-- process "[parent::book]" first
13598 		*       SORT
13599 		*         COLLECT  'parent' 'name' 'node' book
13600 		*           NODE
13601 		*     ELEM Object is a number : 1
13602 		*/
13603                 if (op->ch1 != -1)
13604                     total +=
13605                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13606 		CHECK_ERROR0;
13607                 if (op->ch2 == -1)
13608                     return (total);
13609                 if (ctxt->value == NULL)
13610                     return (total);
13611 
13612 #ifdef LIBXML_XPTR_ENABLED
13613                 /*
13614                  * Hum are we filtering the result of an XPointer expression
13615                  */
13616                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13617                     xmlLocationSetPtr newlocset = NULL;
13618                     xmlLocationSetPtr oldlocset;
13619 
13620                     /*
13621                      * Extract the old locset, and then evaluate the result of the
13622                      * expression for all the element in the locset. use it to grow
13623                      * up a new locset.
13624                      */
13625                     CHECK_TYPE0(XPATH_LOCATIONSET);
13626 
13627                     if ((ctxt->value->user == NULL) ||
13628                         (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13629                         return (total);
13630 
13631                     obj = valuePop(ctxt);
13632                     oldlocset = obj->user;
13633                     oldnode = ctxt->context->node;
13634                     oldcs = ctxt->context->contextSize;
13635                     oldpp = ctxt->context->proximityPosition;
13636 
13637                     newlocset = xmlXPtrLocationSetCreate(NULL);
13638 
13639                     for (i = 0; i < oldlocset->locNr; i++) {
13640                         /*
13641                          * Run the evaluation with a node list made of a
13642                          * single item in the nodelocset.
13643                          */
13644                         ctxt->context->node = oldlocset->locTab[i]->user;
13645                         ctxt->context->contextSize = oldlocset->locNr;
13646                         ctxt->context->proximityPosition = i + 1;
13647 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13648 			    ctxt->context->node);
13649                         valuePush(ctxt, tmp);
13650 
13651                         if (op->ch2 != -1)
13652                             total +=
13653                                 xmlXPathCompOpEval(ctxt,
13654                                                    &comp->steps[op->ch2]);
13655 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13656                             xmlXPtrFreeLocationSet(newlocset);
13657                             goto filter_xptr_error;
13658 			}
13659 
13660                         /*
13661                          * The result of the evaluation need to be tested to
13662                          * decided whether the filter succeeded or not
13663                          */
13664                         res = valuePop(ctxt);
13665                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13666                             xmlXPtrLocationSetAdd(newlocset,
13667                                                   xmlXPathObjectCopy
13668                                                   (oldlocset->locTab[i]));
13669                         }
13670 
13671                         /*
13672                          * Cleanup
13673                          */
13674                         if (res != NULL) {
13675 			    xmlXPathReleaseObject(ctxt->context, res);
13676 			}
13677                         if (ctxt->value == tmp) {
13678                             res = valuePop(ctxt);
13679 			    xmlXPathReleaseObject(ctxt->context, res);
13680                         }
13681                     }
13682 
13683                     /*
13684                      * The result is used as the new evaluation locset.
13685                      */
13686                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13687 filter_xptr_error:
13688 		    xmlXPathReleaseObject(ctxt->context, obj);
13689                     ctxt->context->node = oldnode;
13690                     ctxt->context->contextSize = oldcs;
13691                     ctxt->context->proximityPosition = oldpp;
13692                     return (total);
13693                 }
13694 #endif /* LIBXML_XPTR_ENABLED */
13695 
13696                 /*
13697                  * Extract the old set, and then evaluate the result of the
13698                  * expression for all the element in the set. use it to grow
13699                  * up a new set.
13700                  */
13701                 CHECK_TYPE0(XPATH_NODESET);
13702 
13703                 if ((ctxt->value->nodesetval != NULL) &&
13704                     (ctxt->value->nodesetval->nodeNr != 0)) {
13705                     obj = valuePop(ctxt);
13706                     oldset = obj->nodesetval;
13707                     oldnode = ctxt->context->node;
13708                     oldDoc = ctxt->context->doc;
13709                     oldcs = ctxt->context->contextSize;
13710                     oldpp = ctxt->context->proximityPosition;
13711 		    tmp = NULL;
13712                     /*
13713                      * Initialize the new set.
13714 		     * Also set the xpath document in case things like
13715 		     * key() evaluation are attempted on the predicate
13716                      */
13717                     newset = xmlXPathNodeSetCreate(NULL);
13718 		    /*
13719 		    * SPEC XPath 1.0:
13720 		    *  "For each node in the node-set to be filtered, the
13721 		    *  PredicateExpr is evaluated with that node as the
13722 		    *  context node, with the number of nodes in the
13723 		    *  node-set as the context size, and with the proximity
13724 		    *  position of the node in the node-set with respect to
13725 		    *  the axis as the context position;"
13726 		    * @oldset is the node-set" to be filtered.
13727 		    *
13728 		    * SPEC XPath 1.0:
13729 		    *  "only predicates change the context position and
13730 		    *  context size (see [2.4 Predicates])."
13731 		    * Example:
13732 		    *   node-set  context pos
13733 		    *    nA         1
13734 		    *    nB         2
13735 		    *    nC         3
13736 		    *   After applying predicate [position() > 1] :
13737 		    *   node-set  context pos
13738 		    *    nB         1
13739 		    *    nC         2
13740 		    *
13741 		    * removed the first node in the node-set, then
13742 		    * the context position of the
13743 		    */
13744                     for (i = 0; i < oldset->nodeNr; i++) {
13745                         /*
13746                          * Run the evaluation with a node list made of
13747                          * a single item in the nodeset.
13748                          */
13749                         ctxt->context->node = oldset->nodeTab[i];
13750 			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13751 			    (oldset->nodeTab[i]->doc != NULL))
13752 		            ctxt->context->doc = oldset->nodeTab[i]->doc;
13753 			if (tmp == NULL) {
13754 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13755 				ctxt->context->node);
13756 			} else {
13757 			    if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13758 				               ctxt->context->node) < 0) {
13759 				ctxt->error = XPATH_MEMORY_ERROR;
13760 			    }
13761 			}
13762                         valuePush(ctxt, tmp);
13763                         ctxt->context->contextSize = oldset->nodeNr;
13764                         ctxt->context->proximityPosition = i + 1;
13765 			/*
13766 			* Evaluate the predicate against the context node.
13767 			* Can/should we optimize position() predicates
13768 			* here (e.g. "[1]")?
13769 			*/
13770                         if (op->ch2 != -1)
13771                             total +=
13772                                 xmlXPathCompOpEval(ctxt,
13773                                                    &comp->steps[op->ch2]);
13774 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13775 			    xmlXPathFreeNodeSet(newset);
13776                             goto filter_error;
13777 			}
13778 
13779                         /*
13780                          * The result of the evaluation needs to be tested to
13781                          * decide whether the filter succeeded or not
13782                          */
13783 			/*
13784 			* OPTIMIZE TODO: Can we use
13785 			* xmlXPathNodeSetAdd*Unique()* instead?
13786 			*/
13787                         res = valuePop(ctxt);
13788                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13789                             if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13790 			        < 0)
13791 				ctxt->error = XPATH_MEMORY_ERROR;
13792                         }
13793 
13794                         /*
13795                          * Cleanup
13796                          */
13797                         if (res != NULL) {
13798 			    xmlXPathReleaseObject(ctxt->context, res);
13799 			}
13800                         if (ctxt->value == tmp) {
13801                             valuePop(ctxt);
13802 			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
13803 			    /*
13804 			    * Don't free the temporary nodeset
13805 			    * in order to avoid massive recreation inside this
13806 			    * loop.
13807 			    */
13808                         } else
13809 			    tmp = NULL;
13810                     }
13811 		    if (tmp != NULL)
13812 			xmlXPathReleaseObject(ctxt->context, tmp);
13813                     /*
13814                      * The result is used as the new evaluation set.
13815                      */
13816 		    valuePush(ctxt,
13817 			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13818 filter_error:
13819 		    xmlXPathReleaseObject(ctxt->context, obj);
13820 		    ctxt->context->node = oldnode;
13821 		    ctxt->context->doc = oldDoc;
13822                     ctxt->context->contextSize = oldcs;
13823                     ctxt->context->proximityPosition = oldpp;
13824                 }
13825                 return (total);
13826             }
13827         case XPATH_OP_SORT:
13828             if (op->ch1 != -1)
13829                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13830 	    CHECK_ERROR0;
13831             if ((ctxt->value != NULL) &&
13832                 (ctxt->value->type == XPATH_NODESET) &&
13833                 (ctxt->value->nodesetval != NULL) &&
13834 		(ctxt->value->nodesetval->nodeNr > 1))
13835 	    {
13836                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13837 	    }
13838             return (total);
13839 #ifdef LIBXML_XPTR_ENABLED
13840         case XPATH_OP_RANGETO:{
13841                 xmlXPathObjectPtr range;
13842                 xmlXPathObjectPtr res, obj;
13843                 xmlXPathObjectPtr tmp;
13844                 xmlLocationSetPtr newlocset = NULL;
13845 		    xmlLocationSetPtr oldlocset;
13846                 xmlNodeSetPtr oldset;
13847                 xmlNodePtr oldnode = ctxt->context->node;
13848                 int oldcs = ctxt->context->contextSize;
13849                 int oldpp = ctxt->context->proximityPosition;
13850                 int i, j;
13851 
13852                 if (op->ch1 != -1) {
13853                     total +=
13854                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13855                     CHECK_ERROR0;
13856                 }
13857                 if (ctxt->value == NULL) {
13858                     XP_ERROR0(XPATH_INVALID_OPERAND);
13859                 }
13860                 if (op->ch2 == -1)
13861                     return (total);
13862 
13863                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13864                     /*
13865                      * Extract the old locset, and then evaluate the result of the
13866                      * expression for all the element in the locset. use it to grow
13867                      * up a new locset.
13868                      */
13869                     CHECK_TYPE0(XPATH_LOCATIONSET);
13870 
13871                     if ((ctxt->value->user == NULL) ||
13872                         (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13873                         return (total);
13874 
13875                     obj = valuePop(ctxt);
13876                     oldlocset = obj->user;
13877 
13878                     newlocset = xmlXPtrLocationSetCreate(NULL);
13879 
13880                     for (i = 0; i < oldlocset->locNr; i++) {
13881                         /*
13882                          * Run the evaluation with a node list made of a
13883                          * single item in the nodelocset.
13884                          */
13885                         ctxt->context->node = oldlocset->locTab[i]->user;
13886                         ctxt->context->contextSize = oldlocset->locNr;
13887                         ctxt->context->proximityPosition = i + 1;
13888 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13889 			    ctxt->context->node);
13890                         valuePush(ctxt, tmp);
13891 
13892                         if (op->ch2 != -1)
13893                             total +=
13894                                 xmlXPathCompOpEval(ctxt,
13895                                                    &comp->steps[op->ch2]);
13896 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13897                             xmlXPtrFreeLocationSet(newlocset);
13898                             goto rangeto_error;
13899 			}
13900 
13901                         res = valuePop(ctxt);
13902 			if (res->type == XPATH_LOCATIONSET) {
13903 			    xmlLocationSetPtr rloc =
13904 			        (xmlLocationSetPtr)res->user;
13905 			    for (j=0; j<rloc->locNr; j++) {
13906 			        range = xmlXPtrNewRange(
13907 				  oldlocset->locTab[i]->user,
13908 				  oldlocset->locTab[i]->index,
13909 				  rloc->locTab[j]->user2,
13910 				  rloc->locTab[j]->index2);
13911 				if (range != NULL) {
13912 				    xmlXPtrLocationSetAdd(newlocset, range);
13913 				}
13914 			    }
13915 			} else {
13916 			    range = xmlXPtrNewRangeNodeObject(
13917 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
13918                             if (range != NULL) {
13919                                 xmlXPtrLocationSetAdd(newlocset,range);
13920 			    }
13921                         }
13922 
13923                         /*
13924                          * Cleanup
13925                          */
13926                         if (res != NULL) {
13927 			    xmlXPathReleaseObject(ctxt->context, res);
13928 			}
13929                         if (ctxt->value == tmp) {
13930                             res = valuePop(ctxt);
13931 			    xmlXPathReleaseObject(ctxt->context, res);
13932                         }
13933                     }
13934 		} else {	/* Not a location set */
13935                     CHECK_TYPE0(XPATH_NODESET);
13936                     obj = valuePop(ctxt);
13937                     oldset = obj->nodesetval;
13938 
13939                     newlocset = xmlXPtrLocationSetCreate(NULL);
13940 
13941                     if (oldset != NULL) {
13942                         for (i = 0; i < oldset->nodeNr; i++) {
13943                             /*
13944                              * Run the evaluation with a node list made of a single item
13945                              * in the nodeset.
13946                              */
13947                             ctxt->context->node = oldset->nodeTab[i];
13948 			    /*
13949 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
13950 			    */
13951 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13952 				ctxt->context->node);
13953                             valuePush(ctxt, tmp);
13954 
13955                             if (op->ch2 != -1)
13956                                 total +=
13957                                     xmlXPathCompOpEval(ctxt,
13958                                                    &comp->steps[op->ch2]);
13959 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
13960                                 xmlXPtrFreeLocationSet(newlocset);
13961                                 goto rangeto_error;
13962 			    }
13963 
13964                             res = valuePop(ctxt);
13965                             range =
13966                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13967                                                       res);
13968                             if (range != NULL) {
13969                                 xmlXPtrLocationSetAdd(newlocset, range);
13970                             }
13971 
13972                             /*
13973                              * Cleanup
13974                              */
13975                             if (res != NULL) {
13976 				xmlXPathReleaseObject(ctxt->context, res);
13977 			    }
13978                             if (ctxt->value == tmp) {
13979                                 res = valuePop(ctxt);
13980 				xmlXPathReleaseObject(ctxt->context, res);
13981                             }
13982                         }
13983                     }
13984                 }
13985 
13986                 /*
13987                  * The result is used as the new evaluation set.
13988                  */
13989                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13990 rangeto_error:
13991 		xmlXPathReleaseObject(ctxt->context, obj);
13992                 ctxt->context->node = oldnode;
13993                 ctxt->context->contextSize = oldcs;
13994                 ctxt->context->proximityPosition = oldpp;
13995                 return (total);
13996             }
13997 #endif /* LIBXML_XPTR_ENABLED */
13998     }
13999     xmlGenericError(xmlGenericErrorContext,
14000                     "XPath: unknown precompiled operation %d\n", op->op);
14001     ctxt->error = XPATH_INVALID_OPERAND;
14002     return (total);
14003 }
14004 
14005 /**
14006  * xmlXPathCompOpEvalToBoolean:
14007  * @ctxt:  the XPath parser context
14008  *
14009  * Evaluates if the expression evaluates to true.
14010  *
14011  * Returns 1 if true, 0 if false and -1 on API or internal errors.
14012  */
14013 static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int isPredicate)14014 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14015 			    xmlXPathStepOpPtr op,
14016 			    int isPredicate)
14017 {
14018     xmlXPathObjectPtr resObj = NULL;
14019 
14020 start:
14021     /* comp = ctxt->comp; */
14022     switch (op->op) {
14023         case XPATH_OP_END:
14024             return (0);
14025 	case XPATH_OP_VALUE:
14026 	    resObj = (xmlXPathObjectPtr) op->value4;
14027 	    if (isPredicate)
14028 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14029 	    return(xmlXPathCastToBoolean(resObj));
14030 	case XPATH_OP_SORT:
14031 	    /*
14032 	    * We don't need sorting for boolean results. Skip this one.
14033 	    */
14034             if (op->ch1 != -1) {
14035 		op = &ctxt->comp->steps[op->ch1];
14036 		goto start;
14037 	    }
14038 	    return(0);
14039 	case XPATH_OP_COLLECT:
14040 	    if (op->ch1 == -1)
14041 		return(0);
14042 
14043             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14044 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14045 		return(-1);
14046 
14047             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14048 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14049 		return(-1);
14050 
14051 	    resObj = valuePop(ctxt);
14052 	    if (resObj == NULL)
14053 		return(-1);
14054 	    break;
14055 	default:
14056 	    /*
14057 	    * Fallback to call xmlXPathCompOpEval().
14058 	    */
14059 	    xmlXPathCompOpEval(ctxt, op);
14060 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14061 		return(-1);
14062 
14063 	    resObj = valuePop(ctxt);
14064 	    if (resObj == NULL)
14065 		return(-1);
14066 	    break;
14067     }
14068 
14069     if (resObj) {
14070 	int res;
14071 
14072 	if (resObj->type == XPATH_BOOLEAN) {
14073 	    res = resObj->boolval;
14074 	} else if (isPredicate) {
14075 	    /*
14076 	    * For predicates a result of type "number" is handled
14077 	    * differently:
14078 	    * SPEC XPath 1.0:
14079 	    * "If the result is a number, the result will be converted
14080 	    *  to true if the number is equal to the context position
14081 	    *  and will be converted to false otherwise;"
14082 	    */
14083 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14084 	} else {
14085 	    res = xmlXPathCastToBoolean(resObj);
14086 	}
14087 	xmlXPathReleaseObject(ctxt->context, resObj);
14088 	return(res);
14089     }
14090 
14091     return(0);
14092 }
14093 
14094 #ifdef XPATH_STREAMING
14095 /**
14096  * xmlXPathRunStreamEval:
14097  * @ctxt:  the XPath parser context with the compiled expression
14098  *
14099  * Evaluate the Precompiled Streamable XPath expression in the given context.
14100  */
14101 static int
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt,xmlPatternPtr comp,xmlXPathObjectPtr * resultSeq,int toBool)14102 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14103 		      xmlXPathObjectPtr *resultSeq, int toBool)
14104 {
14105     int max_depth, min_depth;
14106     int from_root;
14107     int ret, depth;
14108     int eval_all_nodes;
14109     xmlNodePtr cur = NULL, limit = NULL;
14110     xmlStreamCtxtPtr patstream = NULL;
14111 
14112     int nb_nodes = 0;
14113 
14114     if ((ctxt == NULL) || (comp == NULL))
14115         return(-1);
14116     max_depth = xmlPatternMaxDepth(comp);
14117     if (max_depth == -1)
14118         return(-1);
14119     if (max_depth == -2)
14120         max_depth = 10000;
14121     min_depth = xmlPatternMinDepth(comp);
14122     if (min_depth == -1)
14123         return(-1);
14124     from_root = xmlPatternFromRoot(comp);
14125     if (from_root < 0)
14126         return(-1);
14127 #if 0
14128     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14129 #endif
14130 
14131     if (! toBool) {
14132 	if (resultSeq == NULL)
14133 	    return(-1);
14134 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14135 	if (*resultSeq == NULL)
14136 	    return(-1);
14137     }
14138 
14139     /*
14140      * handle the special cases of "/" amd "." being matched
14141      */
14142     if (min_depth == 0) {
14143 	if (from_root) {
14144 	    /* Select "/" */
14145 	    if (toBool)
14146 		return(1);
14147 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14148 		                     (xmlNodePtr) ctxt->doc);
14149 	} else {
14150 	    /* Select "self::node()" */
14151 	    if (toBool)
14152 		return(1);
14153 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14154 	}
14155     }
14156     if (max_depth == 0) {
14157 	return(0);
14158     }
14159 
14160     if (from_root) {
14161         cur = (xmlNodePtr)ctxt->doc;
14162     } else if (ctxt->node != NULL) {
14163         switch (ctxt->node->type) {
14164             case XML_ELEMENT_NODE:
14165             case XML_DOCUMENT_NODE:
14166             case XML_DOCUMENT_FRAG_NODE:
14167             case XML_HTML_DOCUMENT_NODE:
14168 #ifdef LIBXML_DOCB_ENABLED
14169             case XML_DOCB_DOCUMENT_NODE:
14170 #endif
14171 	        cur = ctxt->node;
14172 		break;
14173             case XML_ATTRIBUTE_NODE:
14174             case XML_TEXT_NODE:
14175             case XML_CDATA_SECTION_NODE:
14176             case XML_ENTITY_REF_NODE:
14177             case XML_ENTITY_NODE:
14178             case XML_PI_NODE:
14179             case XML_COMMENT_NODE:
14180             case XML_NOTATION_NODE:
14181             case XML_DTD_NODE:
14182             case XML_DOCUMENT_TYPE_NODE:
14183             case XML_ELEMENT_DECL:
14184             case XML_ATTRIBUTE_DECL:
14185             case XML_ENTITY_DECL:
14186             case XML_NAMESPACE_DECL:
14187             case XML_XINCLUDE_START:
14188             case XML_XINCLUDE_END:
14189 		break;
14190 	}
14191 	limit = cur;
14192     }
14193     if (cur == NULL) {
14194         return(0);
14195     }
14196 
14197     patstream = xmlPatternGetStreamCtxt(comp);
14198     if (patstream == NULL) {
14199 	/*
14200 	* QUESTION TODO: Is this an error?
14201 	*/
14202 	return(0);
14203     }
14204 
14205     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14206 
14207     if (from_root) {
14208 	ret = xmlStreamPush(patstream, NULL, NULL);
14209 	if (ret < 0) {
14210 	} else if (ret == 1) {
14211 	    if (toBool)
14212 		goto return_1;
14213 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14214 	}
14215     }
14216     depth = 0;
14217     goto scan_children;
14218 next_node:
14219     do {
14220         nb_nodes++;
14221 
14222 	switch (cur->type) {
14223 	    case XML_ELEMENT_NODE:
14224 	    case XML_TEXT_NODE:
14225 	    case XML_CDATA_SECTION_NODE:
14226 	    case XML_COMMENT_NODE:
14227 	    case XML_PI_NODE:
14228 		if (cur->type == XML_ELEMENT_NODE) {
14229 		    ret = xmlStreamPush(patstream, cur->name,
14230 				(cur->ns ? cur->ns->href : NULL));
14231 		} else if (eval_all_nodes)
14232 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14233 		else
14234 		    break;
14235 
14236 		if (ret < 0) {
14237 		    /* NOP. */
14238 		} else if (ret == 1) {
14239 		    if (toBool)
14240 			goto return_1;
14241 		    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14242 		        < 0) {
14243 			ctxt->lastError.domain = XML_FROM_XPATH;
14244 			ctxt->lastError.code = XML_ERR_NO_MEMORY;
14245 		    }
14246 		}
14247 		if ((cur->children == NULL) || (depth >= max_depth)) {
14248 		    ret = xmlStreamPop(patstream);
14249 		    while (cur->next != NULL) {
14250 			cur = cur->next;
14251 			if ((cur->type != XML_ENTITY_DECL) &&
14252 			    (cur->type != XML_DTD_NODE))
14253 			    goto next_node;
14254 		    }
14255 		}
14256 	    default:
14257 		break;
14258 	}
14259 
14260 scan_children:
14261 	if (cur->type == XML_NAMESPACE_DECL) break;
14262 	if ((cur->children != NULL) && (depth < max_depth)) {
14263 	    /*
14264 	     * Do not descend on entities declarations
14265 	     */
14266 	    if (cur->children->type != XML_ENTITY_DECL) {
14267 		cur = cur->children;
14268 		depth++;
14269 		/*
14270 		 * Skip DTDs
14271 		 */
14272 		if (cur->type != XML_DTD_NODE)
14273 		    continue;
14274 	    }
14275 	}
14276 
14277 	if (cur == limit)
14278 	    break;
14279 
14280 	while (cur->next != NULL) {
14281 	    cur = cur->next;
14282 	    if ((cur->type != XML_ENTITY_DECL) &&
14283 		(cur->type != XML_DTD_NODE))
14284 		goto next_node;
14285 	}
14286 
14287 	do {
14288 	    cur = cur->parent;
14289 	    depth--;
14290 	    if ((cur == NULL) || (cur == limit))
14291 	        goto done;
14292 	    if (cur->type == XML_ELEMENT_NODE) {
14293 		ret = xmlStreamPop(patstream);
14294 	    } else if ((eval_all_nodes) &&
14295 		((cur->type == XML_TEXT_NODE) ||
14296 		 (cur->type == XML_CDATA_SECTION_NODE) ||
14297 		 (cur->type == XML_COMMENT_NODE) ||
14298 		 (cur->type == XML_PI_NODE)))
14299 	    {
14300 		ret = xmlStreamPop(patstream);
14301 	    }
14302 	    if (cur->next != NULL) {
14303 		cur = cur->next;
14304 		break;
14305 	    }
14306 	} while (cur != NULL);
14307 
14308     } while ((cur != NULL) && (depth >= 0));
14309 
14310 done:
14311 
14312 #if 0
14313     printf("stream eval: checked %d nodes selected %d\n",
14314            nb_nodes, retObj->nodesetval->nodeNr);
14315 #endif
14316 
14317     if (patstream)
14318 	xmlFreeStreamCtxt(patstream);
14319     return(0);
14320 
14321 return_1:
14322     if (patstream)
14323 	xmlFreeStreamCtxt(patstream);
14324     return(1);
14325 }
14326 #endif /* XPATH_STREAMING */
14327 
14328 /**
14329  * xmlXPathRunEval:
14330  * @ctxt:  the XPath parser context with the compiled expression
14331  * @toBool:  evaluate to a boolean result
14332  *
14333  * Evaluate the Precompiled XPath expression in the given context.
14334  */
14335 static int
xmlXPathRunEval(xmlXPathParserContextPtr ctxt,int toBool)14336 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14337 {
14338     xmlXPathCompExprPtr comp;
14339 
14340     if ((ctxt == NULL) || (ctxt->comp == NULL))
14341 	return(-1);
14342 
14343     if (ctxt->valueTab == NULL) {
14344 	/* Allocate the value stack */
14345 	ctxt->valueTab = (xmlXPathObjectPtr *)
14346 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14347 	if (ctxt->valueTab == NULL) {
14348 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14349 	    xmlFree(ctxt);
14350 	}
14351 	ctxt->valueNr = 0;
14352 	ctxt->valueMax = 10;
14353 	ctxt->value = NULL;
14354         ctxt->valueFrame = 0;
14355     }
14356 #ifdef XPATH_STREAMING
14357     if (ctxt->comp->stream) {
14358 	int res;
14359 
14360 	if (toBool) {
14361 	    /*
14362 	    * Evaluation to boolean result.
14363 	    */
14364 	    res = xmlXPathRunStreamEval(ctxt->context,
14365 		ctxt->comp->stream, NULL, 1);
14366 	    if (res != -1)
14367 		return(res);
14368 	} else {
14369 	    xmlXPathObjectPtr resObj = NULL;
14370 
14371 	    /*
14372 	    * Evaluation to a sequence.
14373 	    */
14374 	    res = xmlXPathRunStreamEval(ctxt->context,
14375 		ctxt->comp->stream, &resObj, 0);
14376 
14377 	    if ((res != -1) && (resObj != NULL)) {
14378 		valuePush(ctxt, resObj);
14379 		return(0);
14380 	    }
14381 	    if (resObj != NULL)
14382 		xmlXPathReleaseObject(ctxt->context, resObj);
14383 	}
14384 	/*
14385 	* QUESTION TODO: This falls back to normal XPath evaluation
14386 	* if res == -1. Is this intended?
14387 	*/
14388     }
14389 #endif
14390     comp = ctxt->comp;
14391     if (comp->last < 0) {
14392 	xmlGenericError(xmlGenericErrorContext,
14393 	    "xmlXPathRunEval: last is less than zero\n");
14394 	return(-1);
14395     }
14396     if (toBool)
14397 	return(xmlXPathCompOpEvalToBoolean(ctxt,
14398 	    &comp->steps[comp->last], 0));
14399     else
14400 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14401 
14402     return(0);
14403 }
14404 
14405 /************************************************************************
14406  *									*
14407  *			Public interfaces				*
14408  *									*
14409  ************************************************************************/
14410 
14411 /**
14412  * xmlXPathEvalPredicate:
14413  * @ctxt:  the XPath context
14414  * @res:  the Predicate Expression evaluation result
14415  *
14416  * Evaluate a predicate result for the current node.
14417  * A PredicateExpr is evaluated by evaluating the Expr and converting
14418  * the result to a boolean. If the result is a number, the result will
14419  * be converted to true if the number is equal to the position of the
14420  * context node in the context node list (as returned by the position
14421  * function) and will be converted to false otherwise; if the result
14422  * is not a number, then the result will be converted as if by a call
14423  * to the boolean function.
14424  *
14425  * Returns 1 if predicate is true, 0 otherwise
14426  */
14427 int
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt,xmlXPathObjectPtr res)14428 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14429     if ((ctxt == NULL) || (res == NULL)) return(0);
14430     switch (res->type) {
14431         case XPATH_BOOLEAN:
14432 	    return(res->boolval);
14433         case XPATH_NUMBER:
14434 	    return(res->floatval == ctxt->proximityPosition);
14435         case XPATH_NODESET:
14436         case XPATH_XSLT_TREE:
14437 	    if (res->nodesetval == NULL)
14438 		return(0);
14439 	    return(res->nodesetval->nodeNr != 0);
14440         case XPATH_STRING:
14441 	    return((res->stringval != NULL) &&
14442 	           (xmlStrlen(res->stringval) != 0));
14443         default:
14444 	    STRANGE
14445     }
14446     return(0);
14447 }
14448 
14449 /**
14450  * xmlXPathEvaluatePredicateResult:
14451  * @ctxt:  the XPath Parser context
14452  * @res:  the Predicate Expression evaluation result
14453  *
14454  * Evaluate a predicate result for the current node.
14455  * A PredicateExpr is evaluated by evaluating the Expr and converting
14456  * the result to a boolean. If the result is a number, the result will
14457  * be converted to true if the number is equal to the position of the
14458  * context node in the context node list (as returned by the position
14459  * function) and will be converted to false otherwise; if the result
14460  * is not a number, then the result will be converted as if by a call
14461  * to the boolean function.
14462  *
14463  * Returns 1 if predicate is true, 0 otherwise
14464  */
14465 int
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr res)14466 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14467                                 xmlXPathObjectPtr res) {
14468     if ((ctxt == NULL) || (res == NULL)) return(0);
14469     switch (res->type) {
14470         case XPATH_BOOLEAN:
14471 	    return(res->boolval);
14472         case XPATH_NUMBER:
14473 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14474 	    return((res->floatval == ctxt->context->proximityPosition) &&
14475 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14476 #else
14477 	    return(res->floatval == ctxt->context->proximityPosition);
14478 #endif
14479         case XPATH_NODESET:
14480         case XPATH_XSLT_TREE:
14481 	    if (res->nodesetval == NULL)
14482 		return(0);
14483 	    return(res->nodesetval->nodeNr != 0);
14484         case XPATH_STRING:
14485 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
14486 #ifdef LIBXML_XPTR_ENABLED
14487 	case XPATH_LOCATIONSET:{
14488 	    xmlLocationSetPtr ptr = res->user;
14489 	    if (ptr == NULL)
14490 	        return(0);
14491 	    return (ptr->locNr != 0);
14492 	    }
14493 #endif
14494         default:
14495 	    STRANGE
14496     }
14497     return(0);
14498 }
14499 
14500 #ifdef XPATH_STREAMING
14501 /**
14502  * xmlXPathTryStreamCompile:
14503  * @ctxt: an XPath context
14504  * @str:  the XPath expression
14505  *
14506  * Try to compile the XPath expression as a streamable subset.
14507  *
14508  * Returns the compiled expression or NULL if failed to compile.
14509  */
14510 static xmlXPathCompExprPtr
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14511 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14512     /*
14513      * Optimization: use streaming patterns when the XPath expression can
14514      * be compiled to a stream lookup
14515      */
14516     xmlPatternPtr stream;
14517     xmlXPathCompExprPtr comp;
14518     xmlDictPtr dict = NULL;
14519     const xmlChar **namespaces = NULL;
14520     xmlNsPtr ns;
14521     int i, j;
14522 
14523     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14524         (!xmlStrchr(str, '@'))) {
14525 	const xmlChar *tmp;
14526 
14527 	/*
14528 	 * We don't try to handle expressions using the verbose axis
14529 	 * specifiers ("::"), just the simplied form at this point.
14530 	 * Additionally, if there is no list of namespaces available and
14531 	 *  there's a ":" in the expression, indicating a prefixed QName,
14532 	 *  then we won't try to compile either. xmlPatterncompile() needs
14533 	 *  to have a list of namespaces at compilation time in order to
14534 	 *  compile prefixed name tests.
14535 	 */
14536 	tmp = xmlStrchr(str, ':');
14537 	if ((tmp != NULL) &&
14538 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14539 	    return(NULL);
14540 
14541 	if (ctxt != NULL) {
14542 	    dict = ctxt->dict;
14543 	    if (ctxt->nsNr > 0) {
14544 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14545 		if (namespaces == NULL) {
14546 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14547 		    return(NULL);
14548 		}
14549 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14550 		    ns = ctxt->namespaces[j];
14551 		    namespaces[i++] = ns->href;
14552 		    namespaces[i++] = ns->prefix;
14553 		}
14554 		namespaces[i++] = NULL;
14555 		namespaces[i] = NULL;
14556 	    }
14557 	}
14558 
14559 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14560 			&namespaces[0]);
14561 	if (namespaces != NULL) {
14562 	    xmlFree((xmlChar **)namespaces);
14563 	}
14564 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14565 	    comp = xmlXPathNewCompExpr();
14566 	    if (comp == NULL) {
14567 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14568 		return(NULL);
14569 	    }
14570 	    comp->stream = stream;
14571 	    comp->dict = dict;
14572 	    if (comp->dict)
14573 		xmlDictReference(comp->dict);
14574 	    return(comp);
14575 	}
14576 	xmlFreePattern(stream);
14577     }
14578     return(NULL);
14579 }
14580 #endif /* XPATH_STREAMING */
14581 
14582 static void
xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op)14583 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14584 {
14585     /*
14586     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14587     * internal representation.
14588     */
14589 
14590     if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14591         (op->ch1 != -1) &&
14592         (op->ch2 == -1 /* no predicate */))
14593     {
14594         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14595 
14596         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14597             ((xmlXPathAxisVal) prevop->value ==
14598                 AXIS_DESCENDANT_OR_SELF) &&
14599             (prevop->ch2 == -1) &&
14600             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14601             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14602         {
14603             /*
14604             * This is a "descendant-or-self::node()" without predicates.
14605             * Try to eliminate it.
14606             */
14607 
14608             switch ((xmlXPathAxisVal) op->value) {
14609                 case AXIS_CHILD:
14610                 case AXIS_DESCENDANT:
14611                     /*
14612                     * Convert "descendant-or-self::node()/child::" or
14613                     * "descendant-or-self::node()/descendant::" to
14614                     * "descendant::"
14615                     */
14616                     op->ch1   = prevop->ch1;
14617                     op->value = AXIS_DESCENDANT;
14618                     break;
14619                 case AXIS_SELF:
14620                 case AXIS_DESCENDANT_OR_SELF:
14621                     /*
14622                     * Convert "descendant-or-self::node()/self::" or
14623                     * "descendant-or-self::node()/descendant-or-self::" to
14624                     * to "descendant-or-self::"
14625                     */
14626                     op->ch1   = prevop->ch1;
14627                     op->value = AXIS_DESCENDANT_OR_SELF;
14628                     break;
14629                 default:
14630                     break;
14631             }
14632 	}
14633     }
14634 
14635     /* OP_VALUE has invalid ch1. */
14636     if (op->op == XPATH_OP_VALUE)
14637         return;
14638 
14639     /* Recurse */
14640     if (op->ch1 != -1)
14641         xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
14642     if (op->ch2 != -1)
14643 	xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
14644 }
14645 
14646 /**
14647  * xmlXPathCtxtCompile:
14648  * @ctxt: an XPath context
14649  * @str:  the XPath expression
14650  *
14651  * Compile an XPath expression
14652  *
14653  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14654  *         the caller has to free the object.
14655  */
14656 xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14657 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14658     xmlXPathParserContextPtr pctxt;
14659     xmlXPathCompExprPtr comp;
14660 
14661 #ifdef XPATH_STREAMING
14662     comp = xmlXPathTryStreamCompile(ctxt, str);
14663     if (comp != NULL)
14664         return(comp);
14665 #endif
14666 
14667     xmlXPathInit();
14668 
14669     pctxt = xmlXPathNewParserContext(str, ctxt);
14670     if (pctxt == NULL)
14671         return NULL;
14672     xmlXPathCompileExpr(pctxt, 1);
14673 
14674     if( pctxt->error != XPATH_EXPRESSION_OK )
14675     {
14676         xmlXPathFreeParserContext(pctxt);
14677         return(NULL);
14678     }
14679 
14680     if (*pctxt->cur != 0) {
14681 	/*
14682 	 * aleksey: in some cases this line prints *second* error message
14683 	 * (see bug #78858) and probably this should be fixed.
14684 	 * However, we are not sure that all error messages are printed
14685 	 * out in other places. It's not critical so we leave it as-is for now
14686 	 */
14687 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14688 	comp = NULL;
14689     } else {
14690 	comp = pctxt->comp;
14691 	pctxt->comp = NULL;
14692     }
14693     xmlXPathFreeParserContext(pctxt);
14694 
14695     if (comp != NULL) {
14696 	comp->expr = xmlStrdup(str);
14697 #ifdef DEBUG_EVAL_COUNTS
14698 	comp->string = xmlStrdup(str);
14699 	comp->nb = 0;
14700 #endif
14701 	if ((comp->nbStep > 1) && (comp->last >= 0)) {
14702 	    xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
14703 	}
14704     }
14705     return(comp);
14706 }
14707 
14708 /**
14709  * xmlXPathCompile:
14710  * @str:  the XPath expression
14711  *
14712  * Compile an XPath expression
14713  *
14714  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14715  *         the caller has to free the object.
14716  */
14717 xmlXPathCompExprPtr
xmlXPathCompile(const xmlChar * str)14718 xmlXPathCompile(const xmlChar *str) {
14719     return(xmlXPathCtxtCompile(NULL, str));
14720 }
14721 
14722 /**
14723  * xmlXPathCompiledEvalInternal:
14724  * @comp:  the compiled XPath expression
14725  * @ctxt:  the XPath context
14726  * @resObj: the resulting XPath object or NULL
14727  * @toBool: 1 if only a boolean result is requested
14728  *
14729  * Evaluate the Precompiled XPath expression in the given context.
14730  * The caller has to free @resObj.
14731  *
14732  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14733  *         the caller has to free the object.
14734  */
14735 static int
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt,xmlXPathObjectPtr * resObjPtr,int toBool)14736 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14737 			     xmlXPathContextPtr ctxt,
14738 			     xmlXPathObjectPtr *resObjPtr,
14739 			     int toBool)
14740 {
14741     xmlXPathParserContextPtr pctxt;
14742     xmlXPathObjectPtr resObj;
14743 #ifndef LIBXML_THREAD_ENABLED
14744     static int reentance = 0;
14745 #endif
14746     int res;
14747 
14748     CHECK_CTXT_NEG(ctxt)
14749 
14750     if (comp == NULL)
14751 	return(-1);
14752     xmlXPathInit();
14753 
14754 #ifndef LIBXML_THREAD_ENABLED
14755     reentance++;
14756     if (reentance > 1)
14757 	xmlXPathDisableOptimizer = 1;
14758 #endif
14759 
14760 #ifdef DEBUG_EVAL_COUNTS
14761     comp->nb++;
14762     if ((comp->string != NULL) && (comp->nb > 100)) {
14763 	fprintf(stderr, "100 x %s\n", comp->string);
14764 	comp->nb = 0;
14765     }
14766 #endif
14767     pctxt = xmlXPathCompParserContext(comp, ctxt);
14768     res = xmlXPathRunEval(pctxt, toBool);
14769 
14770     if (pctxt->error != XPATH_EXPRESSION_OK) {
14771         resObj = NULL;
14772     } else {
14773         resObj = valuePop(pctxt);
14774         if (resObj == NULL) {
14775             if (!toBool)
14776                 xmlGenericError(xmlGenericErrorContext,
14777                     "xmlXPathCompiledEval: No result on the stack.\n");
14778         } else if (pctxt->valueNr > 0) {
14779             xmlGenericError(xmlGenericErrorContext,
14780                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14781                 pctxt->valueNr);
14782         }
14783     }
14784 
14785     if (resObjPtr)
14786         *resObjPtr = resObj;
14787     else
14788         xmlXPathReleaseObject(ctxt, resObj);
14789 
14790     pctxt->comp = NULL;
14791     xmlXPathFreeParserContext(pctxt);
14792 #ifndef LIBXML_THREAD_ENABLED
14793     reentance--;
14794 #endif
14795 
14796     return(res);
14797 }
14798 
14799 /**
14800  * xmlXPathCompiledEval:
14801  * @comp:  the compiled XPath expression
14802  * @ctx:  the XPath context
14803  *
14804  * Evaluate the Precompiled XPath expression in the given context.
14805  *
14806  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14807  *         the caller has to free the object.
14808  */
14809 xmlXPathObjectPtr
xmlXPathCompiledEval(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctx)14810 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14811 {
14812     xmlXPathObjectPtr res = NULL;
14813 
14814     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14815     return(res);
14816 }
14817 
14818 /**
14819  * xmlXPathCompiledEvalToBoolean:
14820  * @comp:  the compiled XPath expression
14821  * @ctxt:  the XPath context
14822  *
14823  * Applies the XPath boolean() function on the result of the given
14824  * compiled expression.
14825  *
14826  * Returns 1 if the expression evaluated to true, 0 if to false and
14827  *         -1 in API and internal errors.
14828  */
14829 int
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)14830 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14831 			      xmlXPathContextPtr ctxt)
14832 {
14833     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14834 }
14835 
14836 /**
14837  * xmlXPathEvalExpr:
14838  * @ctxt:  the XPath Parser context
14839  *
14840  * Parse and evaluate an XPath expression in the given context,
14841  * then push the result on the context stack
14842  */
14843 void
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt)14844 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14845 #ifdef XPATH_STREAMING
14846     xmlXPathCompExprPtr comp;
14847 #endif
14848 
14849     if (ctxt == NULL) return;
14850 
14851 #ifdef XPATH_STREAMING
14852     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14853     if (comp != NULL) {
14854         if (ctxt->comp != NULL)
14855 	    xmlXPathFreeCompExpr(ctxt->comp);
14856         ctxt->comp = comp;
14857     } else
14858 #endif
14859     {
14860 	xmlXPathCompileExpr(ctxt, 1);
14861         CHECK_ERROR;
14862 
14863         /* Check for trailing characters. */
14864         if (*ctxt->cur != 0)
14865             XP_ERROR(XPATH_EXPR_ERROR);
14866 
14867 	if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0))
14868 	    xmlXPathOptimizeExpression(ctxt->comp,
14869 		&ctxt->comp->steps[ctxt->comp->last]);
14870     }
14871 
14872     xmlXPathRunEval(ctxt, 0);
14873 }
14874 
14875 /**
14876  * xmlXPathEval:
14877  * @str:  the XPath expression
14878  * @ctx:  the XPath context
14879  *
14880  * Evaluate the XPath Location Path in the given context.
14881  *
14882  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14883  *         the caller has to free the object.
14884  */
14885 xmlXPathObjectPtr
xmlXPathEval(const xmlChar * str,xmlXPathContextPtr ctx)14886 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14887     xmlXPathParserContextPtr ctxt;
14888     xmlXPathObjectPtr res;
14889 
14890     CHECK_CTXT(ctx)
14891 
14892     xmlXPathInit();
14893 
14894     ctxt = xmlXPathNewParserContext(str, ctx);
14895     if (ctxt == NULL)
14896         return NULL;
14897     xmlXPathEvalExpr(ctxt);
14898 
14899     if (ctxt->error != XPATH_EXPRESSION_OK) {
14900 	res = NULL;
14901     } else {
14902 	res = valuePop(ctxt);
14903         if (res == NULL) {
14904             xmlGenericError(xmlGenericErrorContext,
14905                 "xmlXPathCompiledEval: No result on the stack.\n");
14906         } else if (ctxt->valueNr > 0) {
14907             xmlGenericError(xmlGenericErrorContext,
14908                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14909                 ctxt->valueNr);
14910         }
14911     }
14912 
14913     xmlXPathFreeParserContext(ctxt);
14914     return(res);
14915 }
14916 
14917 /**
14918  * xmlXPathSetContextNode:
14919  * @node: the node to to use as the context node
14920  * @ctx:  the XPath context
14921  *
14922  * Sets 'node' as the context node. The node must be in the same
14923  * document as that associated with the context.
14924  *
14925  * Returns -1 in case of error or 0 if successful
14926  */
14927 int
xmlXPathSetContextNode(xmlNodePtr node,xmlXPathContextPtr ctx)14928 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14929     if ((node == NULL) || (ctx == NULL))
14930         return(-1);
14931 
14932     if (node->doc == ctx->doc) {
14933         ctx->node = node;
14934 	return(0);
14935     }
14936     return(-1);
14937 }
14938 
14939 /**
14940  * xmlXPathNodeEval:
14941  * @node: the node to to use as the context node
14942  * @str:  the XPath expression
14943  * @ctx:  the XPath context
14944  *
14945  * Evaluate the XPath Location Path in the given context. The node 'node'
14946  * is set as the context node. The context node is not restored.
14947  *
14948  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14949  *         the caller has to free the object.
14950  */
14951 xmlXPathObjectPtr
xmlXPathNodeEval(xmlNodePtr node,const xmlChar * str,xmlXPathContextPtr ctx)14952 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14953     if (str == NULL)
14954         return(NULL);
14955     if (xmlXPathSetContextNode(node, ctx) < 0)
14956         return(NULL);
14957     return(xmlXPathEval(str, ctx));
14958 }
14959 
14960 /**
14961  * xmlXPathEvalExpression:
14962  * @str:  the XPath expression
14963  * @ctxt:  the XPath context
14964  *
14965  * Alias for xmlXPathEval().
14966  *
14967  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14968  *         the caller has to free the object.
14969  */
14970 xmlXPathObjectPtr
xmlXPathEvalExpression(const xmlChar * str,xmlXPathContextPtr ctxt)14971 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14972     return(xmlXPathEval(str, ctxt));
14973 }
14974 
14975 /************************************************************************
14976  *									*
14977  *	Extra functions not pertaining to the XPath spec		*
14978  *									*
14979  ************************************************************************/
14980 /**
14981  * xmlXPathEscapeUriFunction:
14982  * @ctxt:  the XPath Parser context
14983  * @nargs:  the number of arguments
14984  *
14985  * Implement the escape-uri() XPath function
14986  *    string escape-uri(string $str, bool $escape-reserved)
14987  *
14988  * This function applies the URI escaping rules defined in section 2 of [RFC
14989  * 2396] to the string supplied as $uri-part, which typically represents all
14990  * or part of a URI. The effect of the function is to replace any special
14991  * character in the string by an escape sequence of the form %xx%yy...,
14992  * where xxyy... is the hexadecimal representation of the octets used to
14993  * represent the character in UTF-8.
14994  *
14995  * The set of characters that are escaped depends on the setting of the
14996  * boolean argument $escape-reserved.
14997  *
14998  * If $escape-reserved is true, all characters are escaped other than lower
14999  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15000  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15001  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15002  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15003  * A-F).
15004  *
15005  * If $escape-reserved is false, the behavior differs in that characters
15006  * referred to in [RFC 2396] as reserved characters are not escaped. These
15007  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15008  *
15009  * [RFC 2396] does not define whether escaped URIs should use lower case or
15010  * upper case for hexadecimal digits. To ensure that escaped URIs can be
15011  * compared using string comparison functions, this function must always use
15012  * the upper-case letters A-F.
15013  *
15014  * Generally, $escape-reserved should be set to true when escaping a string
15015  * that is to form a single part of a URI, and to false when escaping an
15016  * entire URI or URI reference.
15017  *
15018  * In the case of non-ascii characters, the string is encoded according to
15019  * utf-8 and then converted according to RFC 2396.
15020  *
15021  * Examples
15022  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15023  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15024  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15025  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15026  *
15027  */
15028 static void
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt,int nargs)15029 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15030     xmlXPathObjectPtr str;
15031     int escape_reserved;
15032     xmlBufPtr target;
15033     xmlChar *cptr;
15034     xmlChar escape[4];
15035 
15036     CHECK_ARITY(2);
15037 
15038     escape_reserved = xmlXPathPopBoolean(ctxt);
15039 
15040     CAST_TO_STRING;
15041     str = valuePop(ctxt);
15042 
15043     target = xmlBufCreate();
15044 
15045     escape[0] = '%';
15046     escape[3] = 0;
15047 
15048     if (target) {
15049 	for (cptr = str->stringval; *cptr; cptr++) {
15050 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
15051 		(*cptr >= 'a' && *cptr <= 'z') ||
15052 		(*cptr >= '0' && *cptr <= '9') ||
15053 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
15054 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
15055 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15056 		(*cptr == '%' &&
15057 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15058 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15059 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
15060 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15061 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15062 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15063 		(!escape_reserved &&
15064 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15065 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15066 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15067 		  *cptr == ','))) {
15068 		xmlBufAdd(target, cptr, 1);
15069 	    } else {
15070 		if ((*cptr >> 4) < 10)
15071 		    escape[1] = '0' + (*cptr >> 4);
15072 		else
15073 		    escape[1] = 'A' - 10 + (*cptr >> 4);
15074 		if ((*cptr & 0xF) < 10)
15075 		    escape[2] = '0' + (*cptr & 0xF);
15076 		else
15077 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
15078 
15079 		xmlBufAdd(target, &escape[0], 3);
15080 	    }
15081 	}
15082     }
15083     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15084 	xmlBufContent(target)));
15085     xmlBufFree(target);
15086     xmlXPathReleaseObject(ctxt->context, str);
15087 }
15088 
15089 /**
15090  * xmlXPathRegisterAllFunctions:
15091  * @ctxt:  the XPath context
15092  *
15093  * Registers all default XPath functions in this context
15094  */
15095 void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)15096 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15097 {
15098     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15099                          xmlXPathBooleanFunction);
15100     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15101                          xmlXPathCeilingFunction);
15102     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15103                          xmlXPathCountFunction);
15104     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15105                          xmlXPathConcatFunction);
15106     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15107                          xmlXPathContainsFunction);
15108     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15109                          xmlXPathIdFunction);
15110     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15111                          xmlXPathFalseFunction);
15112     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15113                          xmlXPathFloorFunction);
15114     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15115                          xmlXPathLastFunction);
15116     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15117                          xmlXPathLangFunction);
15118     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15119                          xmlXPathLocalNameFunction);
15120     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15121                          xmlXPathNotFunction);
15122     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15123                          xmlXPathNameFunction);
15124     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15125                          xmlXPathNamespaceURIFunction);
15126     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15127                          xmlXPathNormalizeFunction);
15128     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15129                          xmlXPathNumberFunction);
15130     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15131                          xmlXPathPositionFunction);
15132     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15133                          xmlXPathRoundFunction);
15134     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15135                          xmlXPathStringFunction);
15136     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15137                          xmlXPathStringLengthFunction);
15138     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15139                          xmlXPathStartsWithFunction);
15140     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15141                          xmlXPathSubstringFunction);
15142     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15143                          xmlXPathSubstringBeforeFunction);
15144     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15145                          xmlXPathSubstringAfterFunction);
15146     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15147                          xmlXPathSumFunction);
15148     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15149                          xmlXPathTrueFunction);
15150     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15151                          xmlXPathTranslateFunction);
15152 
15153     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15154 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15155                          xmlXPathEscapeUriFunction);
15156 }
15157 
15158 #endif /* LIBXML_XPATH_ENABLED */
15159 #define bottom_xpath
15160 #include "elfgcchack.h"
15161