• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * xpath.c: XML Path Language implementation
3  *          XPath is a language for addressing parts of an XML document,
4  *          designed to be used by both XSLT and XPointer
5  *
6  * Reference: W3C Recommendation 16 November 1999
7  *     http://www.w3.org/TR/1999/REC-xpath-19991116
8  * Public reference:
9  *     http://www.w3.org/TR/xpath
10  *
11  * See Copyright for the status of this software
12  *
13  * Author: daniel@veillard.com
14  *
15  */
16 
17 /* To avoid EBCDIC trouble when parsing on zOS */
18 #if defined(__MVS__)
19 #pragma convert("ISO8859-1")
20 #endif
21 
22 #define IN_LIBXML
23 #include "libxml.h"
24 
25 #include <limits.h>
26 #include <string.h>
27 #include <stddef.h>
28 #include <math.h>
29 #include <float.h>
30 #include <ctype.h>
31 
32 #include <libxml/xmlmemory.h>
33 #include <libxml/tree.h>
34 #include <libxml/valid.h>
35 #include <libxml/xpath.h>
36 #include <libxml/xpathInternals.h>
37 #include <libxml/parserInternals.h>
38 #include <libxml/hash.h>
39 #ifdef LIBXML_XPTR_LOCS_ENABLED
40 #include <libxml/xpointer.h>
41 #endif
42 #ifdef LIBXML_DEBUG_ENABLED
43 #include <libxml/debugXML.h>
44 #endif
45 #include <libxml/xmlerror.h>
46 #include <libxml/threads.h>
47 #include <libxml/globals.h>
48 #ifdef LIBXML_PATTERN_ENABLED
49 #include <libxml/pattern.h>
50 #endif
51 
52 #include "private/buf.h"
53 #include "private/error.h"
54 #include "private/xpath.h"
55 
56 #ifdef LIBXML_PATTERN_ENABLED
57 #define XPATH_STREAMING
58 #endif
59 
60 #define TODO								\
61     xmlGenericError(xmlGenericErrorContext,				\
62 	    "Unimplemented block at %s:%d\n",				\
63             __FILE__, __LINE__);
64 
65 /**
66  * WITH_TIM_SORT:
67  *
68  * Use the Timsort algorithm provided in timsort.h to sort
69  * nodeset as this is a great improvement over the old Shell sort
70  * used in xmlXPathNodeSetSort()
71  */
72 #define WITH_TIM_SORT
73 
74 /*
75 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
76 * If defined, this will use xmlXPathCmpNodesExt() instead of
77 * xmlXPathCmpNodes(). The new function is optimized comparison of
78 * non-element nodes; actually it will speed up comparison only if
79 * xmlXPathOrderDocElems() was called in order to index the elements of
80 * a tree in document order; Libxslt does such an indexing, thus it will
81 * benefit from this optimization.
82 */
83 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
84 
85 /*
86 * XP_OPTIMIZED_FILTER_FIRST:
87 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
88 * in a way, that it stop evaluation at the first node.
89 */
90 #define XP_OPTIMIZED_FILTER_FIRST
91 
92 /*
93 * XP_DEBUG_OBJ_USAGE:
94 * Internal flag to enable tracking of how much XPath objects have been
95 * created.
96 */
97 /* #define XP_DEBUG_OBJ_USAGE */
98 
99 /*
100  * XPATH_MAX_STEPS:
101  * when compiling an XPath expression we arbitrary limit the maximum
102  * number of step operation in the compiled expression. 1000000 is
103  * an insanely large value which should never be reached under normal
104  * circumstances
105  */
106 #define XPATH_MAX_STEPS 1000000
107 
108 /*
109  * XPATH_MAX_STACK_DEPTH:
110  * when evaluating an XPath expression we arbitrary limit the maximum
111  * number of object allowed to be pushed on the stack. 1000000 is
112  * an insanely large value which should never be reached under normal
113  * circumstances
114  */
115 #define XPATH_MAX_STACK_DEPTH 1000000
116 
117 /*
118  * XPATH_MAX_NODESET_LENGTH:
119  * when evaluating an XPath expression nodesets are created and we
120  * arbitrary limit the maximum length of those node set. 10000000 is
121  * an insanely large value which should never be reached under normal
122  * circumstances, one would first need to construct an in memory tree
123  * with more than 10 millions nodes.
124  */
125 #define XPATH_MAX_NODESET_LENGTH 10000000
126 
127 /*
128  * XPATH_MAX_RECRUSION_DEPTH:
129  * Maximum amount of nested functions calls when parsing or evaluating
130  * expressions
131  */
132 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
133 #define XPATH_MAX_RECURSION_DEPTH 500
134 #elif defined(_WIN32)
135 /* Windows typically limits stack size to 1MB. */
136 #define XPATH_MAX_RECURSION_DEPTH 1000
137 #else
138 #define XPATH_MAX_RECURSION_DEPTH 5000
139 #endif
140 
141 /*
142  * TODO:
143  * There are a few spots where some tests are done which depend upon ascii
144  * data.  These should be enhanced for full UTF8 support (see particularly
145  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
146  */
147 
148 static void
149 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes);
150 
151 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
152 /**
153  * xmlXPathCmpNodesExt:
154  * @node1:  the first node
155  * @node2:  the second node
156  *
157  * Compare two nodes w.r.t document order.
158  * This one is optimized for handling of non-element nodes.
159  *
160  * Returns -2 in case of error 1 if first point < second point, 0 if
161  *         it's the same node, -1 otherwise
162  */
163 static int
xmlXPathCmpNodesExt(xmlNodePtr node1,xmlNodePtr node2)164 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
165     int depth1, depth2;
166     int misc = 0, precedence1 = 0, precedence2 = 0;
167     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
168     xmlNodePtr cur, root;
169     ptrdiff_t l1, l2;
170 
171     if ((node1 == NULL) || (node2 == NULL))
172 	return(-2);
173 
174     if (node1 == node2)
175 	return(0);
176 
177     /*
178      * a couple of optimizations which will avoid computations in most cases
179      */
180     switch (node1->type) {
181 	case XML_ELEMENT_NODE:
182 	    if (node2->type == XML_ELEMENT_NODE) {
183 		if ((0 > (ptrdiff_t) node1->content) &&
184 		    (0 > (ptrdiff_t) node2->content) &&
185 		    (node1->doc == node2->doc))
186 		{
187 		    l1 = -((ptrdiff_t) node1->content);
188 		    l2 = -((ptrdiff_t) node2->content);
189 		    if (l1 < l2)
190 			return(1);
191 		    if (l1 > l2)
192 			return(-1);
193 		} else
194 		    goto turtle_comparison;
195 	    }
196 	    break;
197 	case XML_ATTRIBUTE_NODE:
198 	    precedence1 = 1; /* element is owner */
199 	    miscNode1 = node1;
200 	    node1 = node1->parent;
201 	    misc = 1;
202 	    break;
203 	case XML_TEXT_NODE:
204 	case XML_CDATA_SECTION_NODE:
205 	case XML_COMMENT_NODE:
206 	case XML_PI_NODE: {
207 	    miscNode1 = node1;
208 	    /*
209 	    * Find nearest element node.
210 	    */
211 	    if (node1->prev != NULL) {
212 		do {
213 		    node1 = node1->prev;
214 		    if (node1->type == XML_ELEMENT_NODE) {
215 			precedence1 = 3; /* element in prev-sibl axis */
216 			break;
217 		    }
218 		    if (node1->prev == NULL) {
219 			precedence1 = 2; /* element is parent */
220 			/*
221 			* URGENT TODO: Are there any cases, where the
222 			* parent of such a node is not an element node?
223 			*/
224 			node1 = node1->parent;
225 			break;
226 		    }
227 		} while (1);
228 	    } else {
229 		precedence1 = 2; /* element is parent */
230 		node1 = node1->parent;
231 	    }
232 	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
233 		(0 <= (ptrdiff_t) node1->content)) {
234 		/*
235 		* Fallback for whatever case.
236 		*/
237 		node1 = miscNode1;
238 		precedence1 = 0;
239 	    } else
240 		misc = 1;
241 	}
242 	    break;
243 	case XML_NAMESPACE_DECL:
244 	    /*
245 	    * TODO: why do we return 1 for namespace nodes?
246 	    */
247 	    return(1);
248 	default:
249 	    break;
250     }
251     switch (node2->type) {
252 	case XML_ELEMENT_NODE:
253 	    break;
254 	case XML_ATTRIBUTE_NODE:
255 	    precedence2 = 1; /* element is owner */
256 	    miscNode2 = node2;
257 	    node2 = node2->parent;
258 	    misc = 1;
259 	    break;
260 	case XML_TEXT_NODE:
261 	case XML_CDATA_SECTION_NODE:
262 	case XML_COMMENT_NODE:
263 	case XML_PI_NODE: {
264 	    miscNode2 = node2;
265 	    if (node2->prev != NULL) {
266 		do {
267 		    node2 = node2->prev;
268 		    if (node2->type == XML_ELEMENT_NODE) {
269 			precedence2 = 3; /* element in prev-sibl axis */
270 			break;
271 		    }
272 		    if (node2->prev == NULL) {
273 			precedence2 = 2; /* element is parent */
274 			node2 = node2->parent;
275 			break;
276 		    }
277 		} while (1);
278 	    } else {
279 		precedence2 = 2; /* element is parent */
280 		node2 = node2->parent;
281 	    }
282 	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
283 		(0 <= (ptrdiff_t) node2->content))
284 	    {
285 		node2 = miscNode2;
286 		precedence2 = 0;
287 	    } else
288 		misc = 1;
289 	}
290 	    break;
291 	case XML_NAMESPACE_DECL:
292 	    return(1);
293 	default:
294 	    break;
295     }
296     if (misc) {
297 	if (node1 == node2) {
298 	    if (precedence1 == precedence2) {
299 		/*
300 		* The ugly case; but normally there aren't many
301 		* adjacent non-element nodes around.
302 		*/
303 		cur = miscNode2->prev;
304 		while (cur != NULL) {
305 		    if (cur == miscNode1)
306 			return(1);
307 		    if (cur->type == XML_ELEMENT_NODE)
308 			return(-1);
309 		    cur = cur->prev;
310 		}
311 		return (-1);
312 	    } else {
313 		/*
314 		* Evaluate based on higher precedence wrt to the element.
315 		* TODO: This assumes attributes are sorted before content.
316 		*   Is this 100% correct?
317 		*/
318 		if (precedence1 < precedence2)
319 		    return(1);
320 		else
321 		    return(-1);
322 	    }
323 	}
324 	/*
325 	* Special case: One of the helper-elements is contained by the other.
326 	* <foo>
327 	*   <node2>
328 	*     <node1>Text-1(precedence1 == 2)</node1>
329 	*   </node2>
330 	*   Text-6(precedence2 == 3)
331 	* </foo>
332 	*/
333 	if ((precedence2 == 3) && (precedence1 > 1)) {
334 	    cur = node1->parent;
335 	    while (cur) {
336 		if (cur == node2)
337 		    return(1);
338 		cur = cur->parent;
339 	    }
340 	}
341 	if ((precedence1 == 3) && (precedence2 > 1)) {
342 	    cur = node2->parent;
343 	    while (cur) {
344 		if (cur == node1)
345 		    return(-1);
346 		cur = cur->parent;
347 	    }
348 	}
349     }
350 
351     /*
352      * Speedup using document order if available.
353      */
354     if ((node1->type == XML_ELEMENT_NODE) &&
355 	(node2->type == XML_ELEMENT_NODE) &&
356 	(0 > (ptrdiff_t) node1->content) &&
357 	(0 > (ptrdiff_t) node2->content) &&
358 	(node1->doc == node2->doc)) {
359 
360 	l1 = -((ptrdiff_t) node1->content);
361 	l2 = -((ptrdiff_t) node2->content);
362 	if (l1 < l2)
363 	    return(1);
364 	if (l1 > l2)
365 	    return(-1);
366     }
367 
368 turtle_comparison:
369 
370     if (node1 == node2->prev)
371 	return(1);
372     if (node1 == node2->next)
373 	return(-1);
374     /*
375      * compute depth to root
376      */
377     for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
378 	if (cur->parent == node1)
379 	    return(1);
380 	depth2++;
381     }
382     root = cur;
383     for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
384 	if (cur->parent == node2)
385 	    return(-1);
386 	depth1++;
387     }
388     /*
389      * Distinct document (or distinct entities :-( ) case.
390      */
391     if (root != cur) {
392 	return(-2);
393     }
394     /*
395      * get the nearest common ancestor.
396      */
397     while (depth1 > depth2) {
398 	depth1--;
399 	node1 = node1->parent;
400     }
401     while (depth2 > depth1) {
402 	depth2--;
403 	node2 = node2->parent;
404     }
405     while (node1->parent != node2->parent) {
406 	node1 = node1->parent;
407 	node2 = node2->parent;
408 	/* should not happen but just in case ... */
409 	if ((node1 == NULL) || (node2 == NULL))
410 	    return(-2);
411     }
412     /*
413      * Find who's first.
414      */
415     if (node1 == node2->prev)
416 	return(1);
417     if (node1 == node2->next)
418 	return(-1);
419     /*
420      * Speedup using document order if available.
421      */
422     if ((node1->type == XML_ELEMENT_NODE) &&
423 	(node2->type == XML_ELEMENT_NODE) &&
424 	(0 > (ptrdiff_t) node1->content) &&
425 	(0 > (ptrdiff_t) node2->content) &&
426 	(node1->doc == node2->doc)) {
427 
428 	l1 = -((ptrdiff_t) node1->content);
429 	l2 = -((ptrdiff_t) node2->content);
430 	if (l1 < l2)
431 	    return(1);
432 	if (l1 > l2)
433 	    return(-1);
434     }
435 
436     for (cur = node1->next;cur != NULL;cur = cur->next)
437 	if (cur == node2)
438 	    return(1);
439     return(-1); /* assume there is no sibling list corruption */
440 }
441 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
442 
443 /*
444  * Wrapper for the Timsort algorithm from timsort.h
445  */
446 #ifdef WITH_TIM_SORT
447 #define SORT_NAME libxml_domnode
448 #define SORT_TYPE xmlNodePtr
449 /**
450  * wrap_cmp:
451  * @x: a node
452  * @y: another node
453  *
454  * Comparison function for the Timsort implementation
455  *
456  * Returns -2 in case of error -1 if first point < second point, 0 if
457  *         it's the same node, +1 otherwise
458  */
459 static
460 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
461 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
wrap_cmp(xmlNodePtr x,xmlNodePtr y)462     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
463     {
464         int res = xmlXPathCmpNodesExt(x, y);
465         return res == -2 ? res : -res;
466     }
467 #else
wrap_cmp(xmlNodePtr x,xmlNodePtr y)468     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
469     {
470         int res = xmlXPathCmpNodes(x, y);
471         return res == -2 ? res : -res;
472     }
473 #endif
474 #define SORT_CMP(x, y)  (wrap_cmp(x, y))
475 #include "timsort.h"
476 #endif /* WITH_TIM_SORT */
477 
478 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
479 
480 /************************************************************************
481  *									*
482  *			Floating point stuff				*
483  *									*
484  ************************************************************************/
485 
486 double xmlXPathNAN = 0.0;
487 double xmlXPathPINF = 0.0;
488 double xmlXPathNINF = 0.0;
489 
490 /**
491  * xmlXPathInit:
492  *
493  * DEPRECATED: Alias for xmlInitParser.
494  */
495 void
xmlXPathInit(void)496 xmlXPathInit(void) {
497     xmlInitParser();
498 }
499 
500 /**
501  * xmlInitXPathInternal:
502  *
503  * Initialize the XPath environment
504  */
505 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
506 void
xmlInitXPathInternal(void)507 xmlInitXPathInternal(void) {
508 #if defined(NAN) && defined(INFINITY)
509     xmlXPathNAN = NAN;
510     xmlXPathPINF = INFINITY;
511     xmlXPathNINF = -INFINITY;
512 #else
513     /* MSVC doesn't allow division by zero in constant expressions. */
514     double zero = 0.0;
515     xmlXPathNAN = 0.0 / zero;
516     xmlXPathPINF = 1.0 / zero;
517     xmlXPathNINF = -xmlXPathPINF;
518 #endif
519 }
520 
521 /**
522  * xmlXPathIsNaN:
523  * @val:  a double value
524  *
525  * Returns 1 if the value is a NaN, 0 otherwise
526  */
527 int
xmlXPathIsNaN(double val)528 xmlXPathIsNaN(double val) {
529 #ifdef isnan
530     return isnan(val);
531 #else
532     return !(val == val);
533 #endif
534 }
535 
536 /**
537  * xmlXPathIsInf:
538  * @val:  a double value
539  *
540  * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
541  */
542 int
xmlXPathIsInf(double val)543 xmlXPathIsInf(double val) {
544 #ifdef isinf
545     return isinf(val) ? (val > 0 ? 1 : -1) : 0;
546 #else
547     if (val >= xmlXPathPINF)
548         return 1;
549     if (val <= -xmlXPathPINF)
550         return -1;
551     return 0;
552 #endif
553 }
554 
555 #endif /* SCHEMAS or XPATH */
556 
557 #ifdef LIBXML_XPATH_ENABLED
558 
559 /*
560  * TODO: when compatibility allows remove all "fake node libxslt" strings
561  *       the test should just be name[0] = ' '
562  */
563 #ifdef DEBUG_XPATH_EXPRESSION
564 #define DEBUG_STEP
565 #define DEBUG_EXPR
566 #define DEBUG_EVAL_COUNTS
567 #endif
568 
569 static xmlNs xmlXPathXMLNamespaceStruct = {
570     NULL,
571     XML_NAMESPACE_DECL,
572     XML_XML_NAMESPACE,
573     BAD_CAST "xml",
574     NULL,
575     NULL
576 };
577 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
578 #ifndef LIBXML_THREAD_ENABLED
579 /*
580  * Optimizer is disabled only when threaded apps are detected while
581  * the library ain't compiled for thread safety.
582  */
583 static int xmlXPathDisableOptimizer = 0;
584 #endif
585 
586 /************************************************************************
587  *									*
588  *			Error handling routines				*
589  *									*
590  ************************************************************************/
591 
592 /**
593  * XP_ERRORNULL:
594  * @X:  the error code
595  *
596  * Macro to raise an XPath error and return NULL.
597  */
598 #define XP_ERRORNULL(X)							\
599     { xmlXPathErr(ctxt, X); return(NULL); }
600 
601 /*
602  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
603  */
604 static const char* const xmlXPathErrorMessages[] = {
605     "Ok\n",
606     "Number encoding\n",
607     "Unfinished literal\n",
608     "Start of literal\n",
609     "Expected $ for variable reference\n",
610     "Undefined variable\n",
611     "Invalid predicate\n",
612     "Invalid expression\n",
613     "Missing closing curly brace\n",
614     "Unregistered function\n",
615     "Invalid operand\n",
616     "Invalid type\n",
617     "Invalid number of arguments\n",
618     "Invalid context size\n",
619     "Invalid context position\n",
620     "Memory allocation error\n",
621     "Syntax error\n",
622     "Resource error\n",
623     "Sub resource error\n",
624     "Undefined namespace prefix\n",
625     "Encoding error\n",
626     "Char out of XML range\n",
627     "Invalid or incomplete context\n",
628     "Stack usage error\n",
629     "Forbidden variable\n",
630     "Operation limit exceeded\n",
631     "Recursion limit exceeded\n",
632     "?? Unknown error ??\n"	/* Must be last in the list! */
633 };
634 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
635 		   sizeof(xmlXPathErrorMessages[0])) - 1)
636 /**
637  * xmlXPathErrMemory:
638  * @ctxt:  an XPath context
639  * @extra:  extra information
640  *
641  * Handle a redefinition of attribute error
642  */
643 static void
xmlXPathErrMemory(xmlXPathContextPtr ctxt,const char * extra)644 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
645 {
646     if (ctxt != NULL) {
647         xmlResetError(&ctxt->lastError);
648         if (extra) {
649             xmlChar buf[200];
650 
651             xmlStrPrintf(buf, 200,
652                          "Memory allocation failed : %s\n",
653                          extra);
654             ctxt->lastError.message = (char *) xmlStrdup(buf);
655         } else {
656             ctxt->lastError.message = (char *)
657 	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
658         }
659         ctxt->lastError.domain = XML_FROM_XPATH;
660         ctxt->lastError.code = XML_ERR_NO_MEMORY;
661 	if (ctxt->error != NULL)
662 	    ctxt->error(ctxt->userData, &ctxt->lastError);
663     } else {
664         if (extra)
665             __xmlRaiseError(NULL, NULL, NULL,
666                             NULL, NULL, XML_FROM_XPATH,
667                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
668                             extra, NULL, NULL, 0, 0,
669                             "Memory allocation failed : %s\n", extra);
670         else
671             __xmlRaiseError(NULL, NULL, NULL,
672                             NULL, NULL, XML_FROM_XPATH,
673                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
674                             NULL, NULL, NULL, 0, 0,
675                             "Memory allocation failed\n");
676     }
677 }
678 
679 /**
680  * xmlXPathPErrMemory:
681  * @ctxt:  an XPath parser context
682  * @extra:  extra information
683  *
684  * Handle a redefinition of attribute error
685  */
686 static void
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt,const char * extra)687 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
688 {
689     if (ctxt == NULL)
690 	xmlXPathErrMemory(NULL, extra);
691     else {
692 	ctxt->error = XPATH_MEMORY_ERROR;
693 	xmlXPathErrMemory(ctxt->context, extra);
694     }
695 }
696 
697 /**
698  * xmlXPathErr:
699  * @ctxt:  a XPath parser context
700  * @error:  the error code
701  *
702  * Handle an XPath error
703  */
704 void
xmlXPathErr(xmlXPathParserContextPtr ctxt,int error)705 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
706 {
707     if ((error < 0) || (error > MAXERRNO))
708 	error = MAXERRNO;
709     if (ctxt == NULL) {
710 	__xmlRaiseError(NULL, NULL, NULL,
711 			NULL, NULL, XML_FROM_XPATH,
712 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
713 			XML_ERR_ERROR, NULL, 0,
714 			NULL, NULL, NULL, 0, 0,
715 			"%s", xmlXPathErrorMessages[error]);
716 	return;
717     }
718     /* Only report the first error */
719     if (ctxt->error != 0)
720         return;
721     ctxt->error = error;
722     if (ctxt->context == NULL) {
723 	__xmlRaiseError(NULL, NULL, NULL,
724 			NULL, NULL, XML_FROM_XPATH,
725 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
726 			XML_ERR_ERROR, NULL, 0,
727 			(const char *) ctxt->base, NULL, NULL,
728 			ctxt->cur - ctxt->base, 0,
729 			"%s", xmlXPathErrorMessages[error]);
730 	return;
731     }
732 
733     /* cleanup current last error */
734     xmlResetError(&ctxt->context->lastError);
735 
736     ctxt->context->lastError.domain = XML_FROM_XPATH;
737     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
738                            XPATH_EXPRESSION_OK;
739     ctxt->context->lastError.level = XML_ERR_ERROR;
740     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
741     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
742     ctxt->context->lastError.node = ctxt->context->debugNode;
743     if (ctxt->context->error != NULL) {
744 	ctxt->context->error(ctxt->context->userData,
745 	                     &ctxt->context->lastError);
746     } else {
747 	__xmlRaiseError(NULL, NULL, NULL,
748 			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
749 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
750 			XML_ERR_ERROR, NULL, 0,
751 			(const char *) ctxt->base, NULL, NULL,
752 			ctxt->cur - ctxt->base, 0,
753 			"%s", xmlXPathErrorMessages[error]);
754     }
755 
756 }
757 
758 /**
759  * xmlXPatherror:
760  * @ctxt:  the XPath Parser context
761  * @file:  the file name
762  * @line:  the line number
763  * @no:  the error number
764  *
765  * Formats an error message.
766  */
767 void
xmlXPatherror(xmlXPathParserContextPtr ctxt,const char * file ATTRIBUTE_UNUSED,int line ATTRIBUTE_UNUSED,int no)768 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
769               int line ATTRIBUTE_UNUSED, int no) {
770     xmlXPathErr(ctxt, no);
771 }
772 
773 /**
774  * xmlXPathCheckOpLimit:
775  * @ctxt:  the XPath Parser context
776  * @opCount:  the number of operations to be added
777  *
778  * Adds opCount to the running total of operations and returns -1 if the
779  * operation limit is exceeded. Returns 0 otherwise.
780  */
781 static int
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt,unsigned long opCount)782 xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
783     xmlXPathContextPtr xpctxt = ctxt->context;
784 
785     if ((opCount > xpctxt->opLimit) ||
786         (xpctxt->opCount > xpctxt->opLimit - opCount)) {
787         xpctxt->opCount = xpctxt->opLimit;
788         xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
789         return(-1);
790     }
791 
792     xpctxt->opCount += opCount;
793     return(0);
794 }
795 
796 #define OP_LIMIT_EXCEEDED(ctxt, n) \
797     ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
798 
799 /************************************************************************
800  *									*
801  *			Utilities					*
802  *									*
803  ************************************************************************/
804 
805 /**
806  * xsltPointerList:
807  *
808  * Pointer-list for various purposes.
809  */
810 typedef struct _xmlPointerList xmlPointerList;
811 typedef xmlPointerList *xmlPointerListPtr;
812 struct _xmlPointerList {
813     void **items;
814     int number;
815     int size;
816 };
817 /*
818 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
819 * and here, we should make the functions public.
820 */
821 static int
xmlPointerListAddSize(xmlPointerListPtr list,void * item,int initialSize)822 xmlPointerListAddSize(xmlPointerListPtr list,
823 		       void *item,
824 		       int initialSize)
825 {
826     if (list->size <= list->number) {
827         void **tmp;
828         size_t newSize;
829 
830         if (list->size == 0) {
831             if (initialSize <= 0)
832                 initialSize = 1;
833             newSize = initialSize;
834         } else {
835             if (list->size > 50000000) {
836                 xmlXPathErrMemory(NULL,
837                     "xmlPointerListAddSize: re-allocating item\n");
838                 return(-1);
839             }
840 	    newSize = list->size * 2;
841         }
842 	tmp = (void **) xmlRealloc(list->items, newSize * sizeof(void *));
843 	if (tmp == NULL) {
844 	    xmlXPathErrMemory(NULL,
845 		"xmlPointerListAddSize: re-allocating item\n");
846 	    return(-1);
847 	}
848         list->items = tmp;
849         list->size = newSize;
850     }
851     list->items[list->number++] = item;
852     return(0);
853 }
854 
855 /**
856  * xsltPointerListCreate:
857  *
858  * Creates an xsltPointerList structure.
859  *
860  * Returns a xsltPointerList structure or NULL in case of an error.
861  */
862 static xmlPointerListPtr
xmlPointerListCreate(int initialSize)863 xmlPointerListCreate(int initialSize)
864 {
865     xmlPointerListPtr ret;
866 
867     ret = xmlMalloc(sizeof(xmlPointerList));
868     if (ret == NULL) {
869 	xmlXPathErrMemory(NULL,
870 	    "xmlPointerListCreate: allocating item\n");
871 	return (NULL);
872     }
873     memset(ret, 0, sizeof(xmlPointerList));
874     if (initialSize > 0) {
875 	xmlPointerListAddSize(ret, NULL, initialSize);
876 	ret->number = 0;
877     }
878     return (ret);
879 }
880 
881 /**
882  * xsltPointerListFree:
883  *
884  * Frees the xsltPointerList structure. This does not free
885  * the content of the list.
886  */
887 static void
xmlPointerListFree(xmlPointerListPtr list)888 xmlPointerListFree(xmlPointerListPtr list)
889 {
890     if (list == NULL)
891 	return;
892     if (list->items != NULL)
893 	xmlFree(list->items);
894     xmlFree(list);
895 }
896 
897 /************************************************************************
898  *									*
899  *			Parser Types					*
900  *									*
901  ************************************************************************/
902 
903 /*
904  * Types are private:
905  */
906 
907 typedef enum {
908     XPATH_OP_END=0,
909     XPATH_OP_AND,
910     XPATH_OP_OR,
911     XPATH_OP_EQUAL,
912     XPATH_OP_CMP,
913     XPATH_OP_PLUS,
914     XPATH_OP_MULT,
915     XPATH_OP_UNION,
916     XPATH_OP_ROOT,
917     XPATH_OP_NODE,
918     XPATH_OP_COLLECT,
919     XPATH_OP_VALUE, /* 11 */
920     XPATH_OP_VARIABLE,
921     XPATH_OP_FUNCTION,
922     XPATH_OP_ARG,
923     XPATH_OP_PREDICATE,
924     XPATH_OP_FILTER, /* 16 */
925     XPATH_OP_SORT /* 17 */
926 #ifdef LIBXML_XPTR_LOCS_ENABLED
927     ,XPATH_OP_RANGETO
928 #endif
929 } xmlXPathOp;
930 
931 typedef enum {
932     AXIS_ANCESTOR = 1,
933     AXIS_ANCESTOR_OR_SELF,
934     AXIS_ATTRIBUTE,
935     AXIS_CHILD,
936     AXIS_DESCENDANT,
937     AXIS_DESCENDANT_OR_SELF,
938     AXIS_FOLLOWING,
939     AXIS_FOLLOWING_SIBLING,
940     AXIS_NAMESPACE,
941     AXIS_PARENT,
942     AXIS_PRECEDING,
943     AXIS_PRECEDING_SIBLING,
944     AXIS_SELF
945 } xmlXPathAxisVal;
946 
947 typedef enum {
948     NODE_TEST_NONE = 0,
949     NODE_TEST_TYPE = 1,
950     NODE_TEST_PI = 2,
951     NODE_TEST_ALL = 3,
952     NODE_TEST_NS = 4,
953     NODE_TEST_NAME = 5
954 } xmlXPathTestVal;
955 
956 typedef enum {
957     NODE_TYPE_NODE = 0,
958     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
959     NODE_TYPE_TEXT = XML_TEXT_NODE,
960     NODE_TYPE_PI = XML_PI_NODE
961 } xmlXPathTypeVal;
962 
963 typedef struct _xmlXPathStepOp xmlXPathStepOp;
964 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
965 struct _xmlXPathStepOp {
966     xmlXPathOp op;		/* The identifier of the operation */
967     int ch1;			/* First child */
968     int ch2;			/* Second child */
969     int value;
970     int value2;
971     int value3;
972     void *value4;
973     void *value5;
974     xmlXPathFunction cache;
975     void *cacheURI;
976 };
977 
978 struct _xmlXPathCompExpr {
979     int nbStep;			/* Number of steps in this expression */
980     int maxStep;		/* Maximum number of steps allocated */
981     xmlXPathStepOp *steps;	/* ops for computation of this expression */
982     int last;			/* index of last step in expression */
983     xmlChar *expr;		/* the expression being computed */
984     xmlDictPtr dict;		/* the dictionary to use if any */
985 #ifdef DEBUG_EVAL_COUNTS
986     int nb;
987     xmlChar *string;
988 #endif
989 #ifdef XPATH_STREAMING
990     xmlPatternPtr stream;
991 #endif
992 };
993 
994 /************************************************************************
995  *									*
996  *			Forward declarations				*
997  *									*
998  ************************************************************************/
999 static void
1000 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
1001 static void
1002 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
1003 static int
1004 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
1005                         xmlXPathStepOpPtr op, xmlNodePtr *first);
1006 static int
1007 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
1008 			    xmlXPathStepOpPtr op,
1009 			    int isPredicate);
1010 static void
1011 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
1012 
1013 /************************************************************************
1014  *									*
1015  *			Parser Type functions				*
1016  *									*
1017  ************************************************************************/
1018 
1019 /**
1020  * xmlXPathNewCompExpr:
1021  *
1022  * Create a new Xpath component
1023  *
1024  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1025  */
1026 static xmlXPathCompExprPtr
xmlXPathNewCompExpr(void)1027 xmlXPathNewCompExpr(void) {
1028     xmlXPathCompExprPtr cur;
1029 
1030     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1031     if (cur == NULL) {
1032         xmlXPathErrMemory(NULL, "allocating component\n");
1033 	return(NULL);
1034     }
1035     memset(cur, 0, sizeof(xmlXPathCompExpr));
1036     cur->maxStep = 10;
1037     cur->nbStep = 0;
1038     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1039 	                                   sizeof(xmlXPathStepOp));
1040     if (cur->steps == NULL) {
1041         xmlXPathErrMemory(NULL, "allocating steps\n");
1042 	xmlFree(cur);
1043 	return(NULL);
1044     }
1045     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1046     cur->last = -1;
1047 #ifdef DEBUG_EVAL_COUNTS
1048     cur->nb = 0;
1049 #endif
1050     return(cur);
1051 }
1052 
1053 /**
1054  * xmlXPathFreeCompExpr:
1055  * @comp:  an XPATH comp
1056  *
1057  * Free up the memory allocated by @comp
1058  */
1059 void
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)1060 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1061 {
1062     xmlXPathStepOpPtr op;
1063     int i;
1064 
1065     if (comp == NULL)
1066         return;
1067     if (comp->dict == NULL) {
1068 	for (i = 0; i < comp->nbStep; i++) {
1069 	    op = &comp->steps[i];
1070 	    if (op->value4 != NULL) {
1071 		if (op->op == XPATH_OP_VALUE)
1072 		    xmlXPathFreeObject(op->value4);
1073 		else
1074 		    xmlFree(op->value4);
1075 	    }
1076 	    if (op->value5 != NULL)
1077 		xmlFree(op->value5);
1078 	}
1079     } else {
1080 	for (i = 0; i < comp->nbStep; i++) {
1081 	    op = &comp->steps[i];
1082 	    if (op->value4 != NULL) {
1083 		if (op->op == XPATH_OP_VALUE)
1084 		    xmlXPathFreeObject(op->value4);
1085 	    }
1086 	}
1087         xmlDictFree(comp->dict);
1088     }
1089     if (comp->steps != NULL) {
1090         xmlFree(comp->steps);
1091     }
1092 #ifdef DEBUG_EVAL_COUNTS
1093     if (comp->string != NULL) {
1094         xmlFree(comp->string);
1095     }
1096 #endif
1097 #ifdef XPATH_STREAMING
1098     if (comp->stream != NULL) {
1099         xmlFreePatternList(comp->stream);
1100     }
1101 #endif
1102     if (comp->expr != NULL) {
1103         xmlFree(comp->expr);
1104     }
1105 
1106     xmlFree(comp);
1107 }
1108 
1109 /**
1110  * xmlXPathCompExprAdd:
1111  * @comp:  the compiled expression
1112  * @ch1: first child index
1113  * @ch2: second child index
1114  * @op:  an op
1115  * @value:  the first int value
1116  * @value2:  the second int value
1117  * @value3:  the third int value
1118  * @value4:  the first string value
1119  * @value5:  the second string value
1120  *
1121  * Add a step to an XPath Compiled Expression
1122  *
1123  * Returns -1 in case of failure, the index otherwise
1124  */
1125 static int
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt,int ch1,int ch2,xmlXPathOp op,int value,int value2,int value3,void * value4,void * value5)1126 xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1127    xmlXPathOp op, int value,
1128    int value2, int value3, void *value4, void *value5) {
1129     xmlXPathCompExprPtr comp = ctxt->comp;
1130     if (comp->nbStep >= comp->maxStep) {
1131 	xmlXPathStepOp *real;
1132 
1133         if (comp->maxStep >= XPATH_MAX_STEPS) {
1134 	    xmlXPathPErrMemory(ctxt, "adding step\n");
1135 	    return(-1);
1136         }
1137 	comp->maxStep *= 2;
1138 	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1139 		                      comp->maxStep * sizeof(xmlXPathStepOp));
1140 	if (real == NULL) {
1141 	    comp->maxStep /= 2;
1142 	    xmlXPathPErrMemory(ctxt, "adding step\n");
1143 	    return(-1);
1144 	}
1145 	comp->steps = real;
1146     }
1147     comp->last = comp->nbStep;
1148     comp->steps[comp->nbStep].ch1 = ch1;
1149     comp->steps[comp->nbStep].ch2 = ch2;
1150     comp->steps[comp->nbStep].op = op;
1151     comp->steps[comp->nbStep].value = value;
1152     comp->steps[comp->nbStep].value2 = value2;
1153     comp->steps[comp->nbStep].value3 = value3;
1154     if ((comp->dict != NULL) &&
1155         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1156 	 (op == XPATH_OP_COLLECT))) {
1157         if (value4 != NULL) {
1158 	    comp->steps[comp->nbStep].value4 = (xmlChar *)
1159 	        (void *)xmlDictLookup(comp->dict, value4, -1);
1160 	    xmlFree(value4);
1161 	} else
1162 	    comp->steps[comp->nbStep].value4 = NULL;
1163         if (value5 != NULL) {
1164 	    comp->steps[comp->nbStep].value5 = (xmlChar *)
1165 	        (void *)xmlDictLookup(comp->dict, value5, -1);
1166 	    xmlFree(value5);
1167 	} else
1168 	    comp->steps[comp->nbStep].value5 = NULL;
1169     } else {
1170 	comp->steps[comp->nbStep].value4 = value4;
1171 	comp->steps[comp->nbStep].value5 = value5;
1172     }
1173     comp->steps[comp->nbStep].cache = NULL;
1174     return(comp->nbStep++);
1175 }
1176 
1177 /**
1178  * xmlXPathCompSwap:
1179  * @comp:  the compiled expression
1180  * @op: operation index
1181  *
1182  * Swaps 2 operations in the compiled expression
1183  */
1184 static void
xmlXPathCompSwap(xmlXPathStepOpPtr op)1185 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1186     int tmp;
1187 
1188 #ifndef LIBXML_THREAD_ENABLED
1189     /*
1190      * Since this manipulates possibly shared variables, this is
1191      * disabled if one detects that the library is used in a multithreaded
1192      * application
1193      */
1194     if (xmlXPathDisableOptimizer)
1195 	return;
1196 #endif
1197 
1198     tmp = op->ch1;
1199     op->ch1 = op->ch2;
1200     op->ch2 = tmp;
1201 }
1202 
1203 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
1204     xmlXPathCompExprAdd(ctxt, (op1), (op2),			\
1205 	                (op), (val), (val2), (val3), (val4), (val5))
1206 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
1207     xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,		\
1208 	                (op), (val), (val2), (val3), (val4), (val5))
1209 
1210 #define PUSH_LEAVE_EXPR(op, val, val2)					\
1211 xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1212 
1213 #define PUSH_UNARY_EXPR(op, ch, val, val2)				\
1214 xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1215 
1216 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
1217 xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),			\
1218 			(val), (val2), 0 ,NULL ,NULL)
1219 
1220 /************************************************************************
1221  *									*
1222  *		XPath object cache structures				*
1223  *									*
1224  ************************************************************************/
1225 
1226 /* #define XP_DEFAULT_CACHE_ON */
1227 
1228 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1229 
1230 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1231 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1232 struct _xmlXPathContextCache {
1233     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1234     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1235     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1236     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1237     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1238     int maxNodeset;
1239     int maxString;
1240     int maxBoolean;
1241     int maxNumber;
1242     int maxMisc;
1243 #ifdef XP_DEBUG_OBJ_USAGE
1244     int dbgCachedAll;
1245     int dbgCachedNodeset;
1246     int dbgCachedString;
1247     int dbgCachedBool;
1248     int dbgCachedNumber;
1249     int dbgCachedPoint;
1250     int dbgCachedRange;
1251     int dbgCachedLocset;
1252     int dbgCachedUsers;
1253     int dbgCachedXSLTTree;
1254     int dbgCachedUndefined;
1255 
1256 
1257     int dbgReusedAll;
1258     int dbgReusedNodeset;
1259     int dbgReusedString;
1260     int dbgReusedBool;
1261     int dbgReusedNumber;
1262     int dbgReusedPoint;
1263     int dbgReusedRange;
1264     int dbgReusedLocset;
1265     int dbgReusedUsers;
1266     int dbgReusedXSLTTree;
1267     int dbgReusedUndefined;
1268 
1269 #endif
1270 };
1271 
1272 /************************************************************************
1273  *									*
1274  *		Debugging related functions				*
1275  *									*
1276  ************************************************************************/
1277 
1278 #define STRANGE							\
1279     xmlGenericError(xmlGenericErrorContext,				\
1280 	    "Internal error at %s:%d\n",				\
1281             __FILE__, __LINE__);
1282 
1283 #ifdef LIBXML_DEBUG_ENABLED
1284 static void
xmlXPathDebugDumpNode(FILE * output,xmlNodePtr cur,int depth)1285 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1286     int i;
1287     char shift[100];
1288 
1289     for (i = 0;((i < depth) && (i < 25));i++)
1290         shift[2 * i] = shift[2 * i + 1] = ' ';
1291     shift[2 * i] = shift[2 * i + 1] = 0;
1292     if (cur == NULL) {
1293 	fprintf(output, "%s", shift);
1294 	fprintf(output, "Node is NULL !\n");
1295 	return;
1296 
1297     }
1298 
1299     if ((cur->type == XML_DOCUMENT_NODE) ||
1300 	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
1301 	fprintf(output, "%s", shift);
1302 	fprintf(output, " /\n");
1303     } else if (cur->type == XML_ATTRIBUTE_NODE)
1304 	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1305     else
1306 	xmlDebugDumpOneNode(output, cur, depth);
1307 }
1308 static void
xmlXPathDebugDumpNodeList(FILE * output,xmlNodePtr cur,int depth)1309 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1310     xmlNodePtr tmp;
1311     int i;
1312     char shift[100];
1313 
1314     for (i = 0;((i < depth) && (i < 25));i++)
1315         shift[2 * i] = shift[2 * i + 1] = ' ';
1316     shift[2 * i] = shift[2 * i + 1] = 0;
1317     if (cur == NULL) {
1318 	fprintf(output, "%s", shift);
1319 	fprintf(output, "Node is NULL !\n");
1320 	return;
1321 
1322     }
1323 
1324     while (cur != NULL) {
1325 	tmp = cur;
1326 	cur = cur->next;
1327 	xmlDebugDumpOneNode(output, tmp, depth);
1328     }
1329 }
1330 
1331 static void
xmlXPathDebugDumpNodeSet(FILE * output,xmlNodeSetPtr cur,int depth)1332 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1333     int i;
1334     char shift[100];
1335 
1336     for (i = 0;((i < depth) && (i < 25));i++)
1337         shift[2 * i] = shift[2 * i + 1] = ' ';
1338     shift[2 * i] = shift[2 * i + 1] = 0;
1339 
1340     if (cur == NULL) {
1341 	fprintf(output, "%s", shift);
1342 	fprintf(output, "NodeSet is NULL !\n");
1343 	return;
1344 
1345     }
1346 
1347     if (cur != NULL) {
1348 	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1349 	for (i = 0;i < cur->nodeNr;i++) {
1350 	    fprintf(output, "%s", shift);
1351 	    fprintf(output, "%d", i + 1);
1352 	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1353 	}
1354     }
1355 }
1356 
1357 static void
xmlXPathDebugDumpValueTree(FILE * output,xmlNodeSetPtr cur,int depth)1358 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1359     int i;
1360     char shift[100];
1361 
1362     for (i = 0;((i < depth) && (i < 25));i++)
1363         shift[2 * i] = shift[2 * i + 1] = ' ';
1364     shift[2 * i] = shift[2 * i + 1] = 0;
1365 
1366     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1367 	fprintf(output, "%s", shift);
1368 	fprintf(output, "Value Tree is NULL !\n");
1369 	return;
1370 
1371     }
1372 
1373     fprintf(output, "%s", shift);
1374     fprintf(output, "%d", i + 1);
1375     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1376 }
1377 #if defined(LIBXML_XPTR_LOCS_ENABLED)
1378 static void
xmlXPathDebugDumpLocationSet(FILE * output,xmlLocationSetPtr cur,int depth)1379 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1380     int i;
1381     char shift[100];
1382 
1383     for (i = 0;((i < depth) && (i < 25));i++)
1384         shift[2 * i] = shift[2 * i + 1] = ' ';
1385     shift[2 * i] = shift[2 * i + 1] = 0;
1386 
1387     if (cur == NULL) {
1388 	fprintf(output, "%s", shift);
1389 	fprintf(output, "LocationSet is NULL !\n");
1390 	return;
1391 
1392     }
1393 
1394     for (i = 0;i < cur->locNr;i++) {
1395 	fprintf(output, "%s", shift);
1396         fprintf(output, "%d : ", i + 1);
1397 	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1398     }
1399 }
1400 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1401 
1402 /**
1403  * xmlXPathDebugDumpObject:
1404  * @output:  the FILE * to dump the output
1405  * @cur:  the object to inspect
1406  * @depth:  indentation level
1407  *
1408  * Dump the content of the object for debugging purposes
1409  */
1410 void
xmlXPathDebugDumpObject(FILE * output,xmlXPathObjectPtr cur,int depth)1411 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1412     int i;
1413     char shift[100];
1414 
1415     if (output == NULL) return;
1416 
1417     for (i = 0;((i < depth) && (i < 25));i++)
1418         shift[2 * i] = shift[2 * i + 1] = ' ';
1419     shift[2 * i] = shift[2 * i + 1] = 0;
1420 
1421 
1422     fprintf(output, "%s", shift);
1423 
1424     if (cur == NULL) {
1425         fprintf(output, "Object is empty (NULL)\n");
1426 	return;
1427     }
1428     switch(cur->type) {
1429         case XPATH_UNDEFINED:
1430 	    fprintf(output, "Object is uninitialized\n");
1431 	    break;
1432         case XPATH_NODESET:
1433 	    fprintf(output, "Object is a Node Set :\n");
1434 	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1435 	    break;
1436 	case XPATH_XSLT_TREE:
1437 	    fprintf(output, "Object is an XSLT value tree :\n");
1438 	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1439 	    break;
1440         case XPATH_BOOLEAN:
1441 	    fprintf(output, "Object is a Boolean : ");
1442 	    if (cur->boolval) fprintf(output, "true\n");
1443 	    else fprintf(output, "false\n");
1444 	    break;
1445         case XPATH_NUMBER:
1446 	    switch (xmlXPathIsInf(cur->floatval)) {
1447 	    case 1:
1448 		fprintf(output, "Object is a number : Infinity\n");
1449 		break;
1450 	    case -1:
1451 		fprintf(output, "Object is a number : -Infinity\n");
1452 		break;
1453 	    default:
1454 		if (xmlXPathIsNaN(cur->floatval)) {
1455 		    fprintf(output, "Object is a number : NaN\n");
1456 		} else if (cur->floatval == 0) {
1457                     /* Omit sign for negative zero. */
1458 		    fprintf(output, "Object is a number : 0\n");
1459 		} else {
1460 		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
1461 		}
1462 	    }
1463 	    break;
1464         case XPATH_STRING:
1465 	    fprintf(output, "Object is a string : ");
1466 	    xmlDebugDumpString(output, cur->stringval);
1467 	    fprintf(output, "\n");
1468 	    break;
1469 #ifdef LIBXML_XPTR_LOCS_ENABLED
1470 	case XPATH_POINT:
1471 	    fprintf(output, "Object is a point : index %d in node", cur->index);
1472 	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1473 	    fprintf(output, "\n");
1474 	    break;
1475 	case XPATH_RANGE:
1476 	    if ((cur->user2 == NULL) ||
1477 		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1478 		fprintf(output, "Object is a collapsed range :\n");
1479 		fprintf(output, "%s", shift);
1480 		if (cur->index >= 0)
1481 		    fprintf(output, "index %d in ", cur->index);
1482 		fprintf(output, "node\n");
1483 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1484 			              depth + 1);
1485 	    } else  {
1486 		fprintf(output, "Object is a range :\n");
1487 		fprintf(output, "%s", shift);
1488 		fprintf(output, "From ");
1489 		if (cur->index >= 0)
1490 		    fprintf(output, "index %d in ", cur->index);
1491 		fprintf(output, "node\n");
1492 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1493 			              depth + 1);
1494 		fprintf(output, "%s", shift);
1495 		fprintf(output, "To ");
1496 		if (cur->index2 >= 0)
1497 		    fprintf(output, "index %d in ", cur->index2);
1498 		fprintf(output, "node\n");
1499 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1500 			              depth + 1);
1501 		fprintf(output, "\n");
1502 	    }
1503 	    break;
1504 	case XPATH_LOCATIONSET:
1505 	    fprintf(output, "Object is a Location Set:\n");
1506 	    xmlXPathDebugDumpLocationSet(output,
1507 		    (xmlLocationSetPtr) cur->user, depth);
1508 	    break;
1509 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1510 	case XPATH_USERS:
1511 	    fprintf(output, "Object is user defined\n");
1512 	    break;
1513     }
1514 }
1515 
1516 static void
xmlXPathDebugDumpStepOp(FILE * output,xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op,int depth)1517 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1518 	                     xmlXPathStepOpPtr op, int depth) {
1519     int i;
1520     char shift[100];
1521 
1522     for (i = 0;((i < depth) && (i < 25));i++)
1523         shift[2 * i] = shift[2 * i + 1] = ' ';
1524     shift[2 * i] = shift[2 * i + 1] = 0;
1525 
1526     fprintf(output, "%s", shift);
1527     if (op == NULL) {
1528 	fprintf(output, "Step is NULL\n");
1529 	return;
1530     }
1531     switch (op->op) {
1532         case XPATH_OP_END:
1533 	    fprintf(output, "END"); break;
1534         case XPATH_OP_AND:
1535 	    fprintf(output, "AND"); break;
1536         case XPATH_OP_OR:
1537 	    fprintf(output, "OR"); break;
1538         case XPATH_OP_EQUAL:
1539 	     if (op->value)
1540 		 fprintf(output, "EQUAL =");
1541 	     else
1542 		 fprintf(output, "EQUAL !=");
1543 	     break;
1544         case XPATH_OP_CMP:
1545 	     if (op->value)
1546 		 fprintf(output, "CMP <");
1547 	     else
1548 		 fprintf(output, "CMP >");
1549 	     if (!op->value2)
1550 		 fprintf(output, "=");
1551 	     break;
1552         case XPATH_OP_PLUS:
1553 	     if (op->value == 0)
1554 		 fprintf(output, "PLUS -");
1555 	     else if (op->value == 1)
1556 		 fprintf(output, "PLUS +");
1557 	     else if (op->value == 2)
1558 		 fprintf(output, "PLUS unary -");
1559 	     else if (op->value == 3)
1560 		 fprintf(output, "PLUS unary - -");
1561 	     break;
1562         case XPATH_OP_MULT:
1563 	     if (op->value == 0)
1564 		 fprintf(output, "MULT *");
1565 	     else if (op->value == 1)
1566 		 fprintf(output, "MULT div");
1567 	     else
1568 		 fprintf(output, "MULT mod");
1569 	     break;
1570         case XPATH_OP_UNION:
1571 	     fprintf(output, "UNION"); break;
1572         case XPATH_OP_ROOT:
1573 	     fprintf(output, "ROOT"); break;
1574         case XPATH_OP_NODE:
1575 	     fprintf(output, "NODE"); break;
1576         case XPATH_OP_SORT:
1577 	     fprintf(output, "SORT"); break;
1578         case XPATH_OP_COLLECT: {
1579 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1580 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1581 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1582 	    const xmlChar *prefix = op->value4;
1583 	    const xmlChar *name = op->value5;
1584 
1585 	    fprintf(output, "COLLECT ");
1586 	    switch (axis) {
1587 		case AXIS_ANCESTOR:
1588 		    fprintf(output, " 'ancestors' "); break;
1589 		case AXIS_ANCESTOR_OR_SELF:
1590 		    fprintf(output, " 'ancestors-or-self' "); break;
1591 		case AXIS_ATTRIBUTE:
1592 		    fprintf(output, " 'attributes' "); break;
1593 		case AXIS_CHILD:
1594 		    fprintf(output, " 'child' "); break;
1595 		case AXIS_DESCENDANT:
1596 		    fprintf(output, " 'descendant' "); break;
1597 		case AXIS_DESCENDANT_OR_SELF:
1598 		    fprintf(output, " 'descendant-or-self' "); break;
1599 		case AXIS_FOLLOWING:
1600 		    fprintf(output, " 'following' "); break;
1601 		case AXIS_FOLLOWING_SIBLING:
1602 		    fprintf(output, " 'following-siblings' "); break;
1603 		case AXIS_NAMESPACE:
1604 		    fprintf(output, " 'namespace' "); break;
1605 		case AXIS_PARENT:
1606 		    fprintf(output, " 'parent' "); break;
1607 		case AXIS_PRECEDING:
1608 		    fprintf(output, " 'preceding' "); break;
1609 		case AXIS_PRECEDING_SIBLING:
1610 		    fprintf(output, " 'preceding-sibling' "); break;
1611 		case AXIS_SELF:
1612 		    fprintf(output, " 'self' "); break;
1613 	    }
1614 	    switch (test) {
1615                 case NODE_TEST_NONE:
1616 		    fprintf(output, "'none' "); break;
1617                 case NODE_TEST_TYPE:
1618 		    fprintf(output, "'type' "); break;
1619                 case NODE_TEST_PI:
1620 		    fprintf(output, "'PI' "); break;
1621                 case NODE_TEST_ALL:
1622 		    fprintf(output, "'all' "); break;
1623                 case NODE_TEST_NS:
1624 		    fprintf(output, "'namespace' "); break;
1625                 case NODE_TEST_NAME:
1626 		    fprintf(output, "'name' "); break;
1627 	    }
1628 	    switch (type) {
1629                 case NODE_TYPE_NODE:
1630 		    fprintf(output, "'node' "); break;
1631                 case NODE_TYPE_COMMENT:
1632 		    fprintf(output, "'comment' "); break;
1633                 case NODE_TYPE_TEXT:
1634 		    fprintf(output, "'text' "); break;
1635                 case NODE_TYPE_PI:
1636 		    fprintf(output, "'PI' "); break;
1637 	    }
1638 	    if (prefix != NULL)
1639 		fprintf(output, "%s:", prefix);
1640 	    if (name != NULL)
1641 		fprintf(output, "%s", (const char *) name);
1642 	    break;
1643 
1644         }
1645 	case XPATH_OP_VALUE: {
1646 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1647 
1648 	    fprintf(output, "ELEM ");
1649 	    xmlXPathDebugDumpObject(output, object, 0);
1650 	    goto finish;
1651 	}
1652 	case XPATH_OP_VARIABLE: {
1653 	    const xmlChar *prefix = op->value5;
1654 	    const xmlChar *name = op->value4;
1655 
1656 	    if (prefix != NULL)
1657 		fprintf(output, "VARIABLE %s:%s", prefix, name);
1658 	    else
1659 		fprintf(output, "VARIABLE %s", name);
1660 	    break;
1661 	}
1662 	case XPATH_OP_FUNCTION: {
1663 	    int nbargs = op->value;
1664 	    const xmlChar *prefix = op->value5;
1665 	    const xmlChar *name = op->value4;
1666 
1667 	    if (prefix != NULL)
1668 		fprintf(output, "FUNCTION %s:%s(%d args)",
1669 			prefix, name, nbargs);
1670 	    else
1671 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1672 	    break;
1673 	}
1674         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1675         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1676         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1677 #ifdef LIBXML_XPTR_LOCS_ENABLED
1678         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1679 #endif
1680 	default:
1681         fprintf(output, "UNKNOWN %d\n", op->op); return;
1682     }
1683     fprintf(output, "\n");
1684 finish:
1685     if (op->ch1 >= 0)
1686 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1687     if (op->ch2 >= 0)
1688 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1689 }
1690 
1691 /**
1692  * xmlXPathDebugDumpCompExpr:
1693  * @output:  the FILE * for the output
1694  * @comp:  the precompiled XPath expression
1695  * @depth:  the indentation level.
1696  *
1697  * Dumps the tree of the compiled XPath expression.
1698  */
1699 void
xmlXPathDebugDumpCompExpr(FILE * output,xmlXPathCompExprPtr comp,int depth)1700 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1701 	                  int depth) {
1702     int i;
1703     char shift[100];
1704 
1705     if ((output == NULL) || (comp == NULL)) return;
1706 
1707     for (i = 0;((i < depth) && (i < 25));i++)
1708         shift[2 * i] = shift[2 * i + 1] = ' ';
1709     shift[2 * i] = shift[2 * i + 1] = 0;
1710 
1711     fprintf(output, "%s", shift);
1712 
1713 #ifdef XPATH_STREAMING
1714     if (comp->stream) {
1715         fprintf(output, "Streaming Expression\n");
1716     } else
1717 #endif
1718     {
1719         fprintf(output, "Compiled Expression : %d elements\n",
1720                 comp->nbStep);
1721         i = comp->last;
1722         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1723     }
1724 }
1725 
1726 #ifdef XP_DEBUG_OBJ_USAGE
1727 
1728 /*
1729 * XPath object usage related debugging variables.
1730 */
1731 static int xmlXPathDebugObjCounterUndefined = 0;
1732 static int xmlXPathDebugObjCounterNodeset = 0;
1733 static int xmlXPathDebugObjCounterBool = 0;
1734 static int xmlXPathDebugObjCounterNumber = 0;
1735 static int xmlXPathDebugObjCounterString = 0;
1736 static int xmlXPathDebugObjCounterPoint = 0;
1737 static int xmlXPathDebugObjCounterRange = 0;
1738 static int xmlXPathDebugObjCounterLocset = 0;
1739 static int xmlXPathDebugObjCounterUsers = 0;
1740 static int xmlXPathDebugObjCounterXSLTTree = 0;
1741 static int xmlXPathDebugObjCounterAll = 0;
1742 
1743 static int xmlXPathDebugObjTotalUndefined = 0;
1744 static int xmlXPathDebugObjTotalNodeset = 0;
1745 static int xmlXPathDebugObjTotalBool = 0;
1746 static int xmlXPathDebugObjTotalNumber = 0;
1747 static int xmlXPathDebugObjTotalString = 0;
1748 static int xmlXPathDebugObjTotalPoint = 0;
1749 static int xmlXPathDebugObjTotalRange = 0;
1750 static int xmlXPathDebugObjTotalLocset = 0;
1751 static int xmlXPathDebugObjTotalUsers = 0;
1752 static int xmlXPathDebugObjTotalXSLTTree = 0;
1753 static int xmlXPathDebugObjTotalAll = 0;
1754 
1755 static int xmlXPathDebugObjMaxUndefined = 0;
1756 static int xmlXPathDebugObjMaxNodeset = 0;
1757 static int xmlXPathDebugObjMaxBool = 0;
1758 static int xmlXPathDebugObjMaxNumber = 0;
1759 static int xmlXPathDebugObjMaxString = 0;
1760 static int xmlXPathDebugObjMaxPoint = 0;
1761 static int xmlXPathDebugObjMaxRange = 0;
1762 static int xmlXPathDebugObjMaxLocset = 0;
1763 static int xmlXPathDebugObjMaxUsers = 0;
1764 static int xmlXPathDebugObjMaxXSLTTree = 0;
1765 static int xmlXPathDebugObjMaxAll = 0;
1766 
1767 static void
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)1768 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1769 {
1770     if (ctxt != NULL) {
1771 	if (ctxt->cache != NULL) {
1772 	    xmlXPathContextCachePtr cache =
1773 		(xmlXPathContextCachePtr) ctxt->cache;
1774 
1775 	    cache->dbgCachedAll = 0;
1776 	    cache->dbgCachedNodeset = 0;
1777 	    cache->dbgCachedString = 0;
1778 	    cache->dbgCachedBool = 0;
1779 	    cache->dbgCachedNumber = 0;
1780 	    cache->dbgCachedPoint = 0;
1781 	    cache->dbgCachedRange = 0;
1782 	    cache->dbgCachedLocset = 0;
1783 	    cache->dbgCachedUsers = 0;
1784 	    cache->dbgCachedXSLTTree = 0;
1785 	    cache->dbgCachedUndefined = 0;
1786 
1787 	    cache->dbgReusedAll = 0;
1788 	    cache->dbgReusedNodeset = 0;
1789 	    cache->dbgReusedString = 0;
1790 	    cache->dbgReusedBool = 0;
1791 	    cache->dbgReusedNumber = 0;
1792 	    cache->dbgReusedPoint = 0;
1793 	    cache->dbgReusedRange = 0;
1794 	    cache->dbgReusedLocset = 0;
1795 	    cache->dbgReusedUsers = 0;
1796 	    cache->dbgReusedXSLTTree = 0;
1797 	    cache->dbgReusedUndefined = 0;
1798 	}
1799     }
1800 
1801     xmlXPathDebugObjCounterUndefined = 0;
1802     xmlXPathDebugObjCounterNodeset = 0;
1803     xmlXPathDebugObjCounterBool = 0;
1804     xmlXPathDebugObjCounterNumber = 0;
1805     xmlXPathDebugObjCounterString = 0;
1806     xmlXPathDebugObjCounterPoint = 0;
1807     xmlXPathDebugObjCounterRange = 0;
1808     xmlXPathDebugObjCounterLocset = 0;
1809     xmlXPathDebugObjCounterUsers = 0;
1810     xmlXPathDebugObjCounterXSLTTree = 0;
1811     xmlXPathDebugObjCounterAll = 0;
1812 
1813     xmlXPathDebugObjTotalUndefined = 0;
1814     xmlXPathDebugObjTotalNodeset = 0;
1815     xmlXPathDebugObjTotalBool = 0;
1816     xmlXPathDebugObjTotalNumber = 0;
1817     xmlXPathDebugObjTotalString = 0;
1818     xmlXPathDebugObjTotalPoint = 0;
1819     xmlXPathDebugObjTotalRange = 0;
1820     xmlXPathDebugObjTotalLocset = 0;
1821     xmlXPathDebugObjTotalUsers = 0;
1822     xmlXPathDebugObjTotalXSLTTree = 0;
1823     xmlXPathDebugObjTotalAll = 0;
1824 
1825     xmlXPathDebugObjMaxUndefined = 0;
1826     xmlXPathDebugObjMaxNodeset = 0;
1827     xmlXPathDebugObjMaxBool = 0;
1828     xmlXPathDebugObjMaxNumber = 0;
1829     xmlXPathDebugObjMaxString = 0;
1830     xmlXPathDebugObjMaxPoint = 0;
1831     xmlXPathDebugObjMaxRange = 0;
1832     xmlXPathDebugObjMaxLocset = 0;
1833     xmlXPathDebugObjMaxUsers = 0;
1834     xmlXPathDebugObjMaxXSLTTree = 0;
1835     xmlXPathDebugObjMaxAll = 0;
1836 
1837 }
1838 
1839 static void
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,xmlXPathObjectType objType)1840 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1841 			      xmlXPathObjectType objType)
1842 {
1843     int isCached = 0;
1844 
1845     if (ctxt != NULL) {
1846 	if (ctxt->cache != NULL) {
1847 	    xmlXPathContextCachePtr cache =
1848 		(xmlXPathContextCachePtr) ctxt->cache;
1849 
1850 	    isCached = 1;
1851 
1852 	    cache->dbgReusedAll++;
1853 	    switch (objType) {
1854 		case XPATH_UNDEFINED:
1855 		    cache->dbgReusedUndefined++;
1856 		    break;
1857 		case XPATH_NODESET:
1858 		    cache->dbgReusedNodeset++;
1859 		    break;
1860 		case XPATH_BOOLEAN:
1861 		    cache->dbgReusedBool++;
1862 		    break;
1863 		case XPATH_NUMBER:
1864 		    cache->dbgReusedNumber++;
1865 		    break;
1866 		case XPATH_STRING:
1867 		    cache->dbgReusedString++;
1868 		    break;
1869 #ifdef LIBXML_XPTR_LOCS_ENABLED
1870 		case XPATH_POINT:
1871 		    cache->dbgReusedPoint++;
1872 		    break;
1873 		case XPATH_RANGE:
1874 		    cache->dbgReusedRange++;
1875 		    break;
1876 		case XPATH_LOCATIONSET:
1877 		    cache->dbgReusedLocset++;
1878 		    break;
1879 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1880 		case XPATH_USERS:
1881 		    cache->dbgReusedUsers++;
1882 		    break;
1883 		case XPATH_XSLT_TREE:
1884 		    cache->dbgReusedXSLTTree++;
1885 		    break;
1886 		default:
1887 		    break;
1888 	    }
1889 	}
1890     }
1891 
1892     switch (objType) {
1893 	case XPATH_UNDEFINED:
1894 	    if (! isCached)
1895 		xmlXPathDebugObjTotalUndefined++;
1896 	    xmlXPathDebugObjCounterUndefined++;
1897 	    if (xmlXPathDebugObjCounterUndefined >
1898 		xmlXPathDebugObjMaxUndefined)
1899 		xmlXPathDebugObjMaxUndefined =
1900 		    xmlXPathDebugObjCounterUndefined;
1901 	    break;
1902 	case XPATH_NODESET:
1903 	    if (! isCached)
1904 		xmlXPathDebugObjTotalNodeset++;
1905 	    xmlXPathDebugObjCounterNodeset++;
1906 	    if (xmlXPathDebugObjCounterNodeset >
1907 		xmlXPathDebugObjMaxNodeset)
1908 		xmlXPathDebugObjMaxNodeset =
1909 		    xmlXPathDebugObjCounterNodeset;
1910 	    break;
1911 	case XPATH_BOOLEAN:
1912 	    if (! isCached)
1913 		xmlXPathDebugObjTotalBool++;
1914 	    xmlXPathDebugObjCounterBool++;
1915 	    if (xmlXPathDebugObjCounterBool >
1916 		xmlXPathDebugObjMaxBool)
1917 		xmlXPathDebugObjMaxBool =
1918 		    xmlXPathDebugObjCounterBool;
1919 	    break;
1920 	case XPATH_NUMBER:
1921 	    if (! isCached)
1922 		xmlXPathDebugObjTotalNumber++;
1923 	    xmlXPathDebugObjCounterNumber++;
1924 	    if (xmlXPathDebugObjCounterNumber >
1925 		xmlXPathDebugObjMaxNumber)
1926 		xmlXPathDebugObjMaxNumber =
1927 		    xmlXPathDebugObjCounterNumber;
1928 	    break;
1929 	case XPATH_STRING:
1930 	    if (! isCached)
1931 		xmlXPathDebugObjTotalString++;
1932 	    xmlXPathDebugObjCounterString++;
1933 	    if (xmlXPathDebugObjCounterString >
1934 		xmlXPathDebugObjMaxString)
1935 		xmlXPathDebugObjMaxString =
1936 		    xmlXPathDebugObjCounterString;
1937 	    break;
1938 #ifdef LIBXML_XPTR_LOCS_ENABLED
1939 	case XPATH_POINT:
1940 	    if (! isCached)
1941 		xmlXPathDebugObjTotalPoint++;
1942 	    xmlXPathDebugObjCounterPoint++;
1943 	    if (xmlXPathDebugObjCounterPoint >
1944 		xmlXPathDebugObjMaxPoint)
1945 		xmlXPathDebugObjMaxPoint =
1946 		    xmlXPathDebugObjCounterPoint;
1947 	    break;
1948 	case XPATH_RANGE:
1949 	    if (! isCached)
1950 		xmlXPathDebugObjTotalRange++;
1951 	    xmlXPathDebugObjCounterRange++;
1952 	    if (xmlXPathDebugObjCounterRange >
1953 		xmlXPathDebugObjMaxRange)
1954 		xmlXPathDebugObjMaxRange =
1955 		    xmlXPathDebugObjCounterRange;
1956 	    break;
1957 	case XPATH_LOCATIONSET:
1958 	    if (! isCached)
1959 		xmlXPathDebugObjTotalLocset++;
1960 	    xmlXPathDebugObjCounterLocset++;
1961 	    if (xmlXPathDebugObjCounterLocset >
1962 		xmlXPathDebugObjMaxLocset)
1963 		xmlXPathDebugObjMaxLocset =
1964 		    xmlXPathDebugObjCounterLocset;
1965 	    break;
1966 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1967 	case XPATH_USERS:
1968 	    if (! isCached)
1969 		xmlXPathDebugObjTotalUsers++;
1970 	    xmlXPathDebugObjCounterUsers++;
1971 	    if (xmlXPathDebugObjCounterUsers >
1972 		xmlXPathDebugObjMaxUsers)
1973 		xmlXPathDebugObjMaxUsers =
1974 		    xmlXPathDebugObjCounterUsers;
1975 	    break;
1976 	case XPATH_XSLT_TREE:
1977 	    if (! isCached)
1978 		xmlXPathDebugObjTotalXSLTTree++;
1979 	    xmlXPathDebugObjCounterXSLTTree++;
1980 	    if (xmlXPathDebugObjCounterXSLTTree >
1981 		xmlXPathDebugObjMaxXSLTTree)
1982 		xmlXPathDebugObjMaxXSLTTree =
1983 		    xmlXPathDebugObjCounterXSLTTree;
1984 	    break;
1985 	default:
1986 	    break;
1987     }
1988     if (! isCached)
1989 	xmlXPathDebugObjTotalAll++;
1990     xmlXPathDebugObjCounterAll++;
1991     if (xmlXPathDebugObjCounterAll >
1992 	xmlXPathDebugObjMaxAll)
1993 	xmlXPathDebugObjMaxAll =
1994 	    xmlXPathDebugObjCounterAll;
1995 }
1996 
1997 static void
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,xmlXPathObjectType objType)1998 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1999 			      xmlXPathObjectType objType)
2000 {
2001     int isCached = 0;
2002 
2003     if (ctxt != NULL) {
2004 	if (ctxt->cache != NULL) {
2005 	    xmlXPathContextCachePtr cache =
2006 		(xmlXPathContextCachePtr) ctxt->cache;
2007 
2008 	    isCached = 1;
2009 
2010 	    cache->dbgCachedAll++;
2011 	    switch (objType) {
2012 		case XPATH_UNDEFINED:
2013 		    cache->dbgCachedUndefined++;
2014 		    break;
2015 		case XPATH_NODESET:
2016 		    cache->dbgCachedNodeset++;
2017 		    break;
2018 		case XPATH_BOOLEAN:
2019 		    cache->dbgCachedBool++;
2020 		    break;
2021 		case XPATH_NUMBER:
2022 		    cache->dbgCachedNumber++;
2023 		    break;
2024 		case XPATH_STRING:
2025 		    cache->dbgCachedString++;
2026 		    break;
2027 #ifdef LIBXML_XPTR_LOCS_ENABLED
2028 		case XPATH_POINT:
2029 		    cache->dbgCachedPoint++;
2030 		    break;
2031 		case XPATH_RANGE:
2032 		    cache->dbgCachedRange++;
2033 		    break;
2034 		case XPATH_LOCATIONSET:
2035 		    cache->dbgCachedLocset++;
2036 		    break;
2037 #endif /* LIBXML_XPTR_LOCS_ENABLED */
2038 		case XPATH_USERS:
2039 		    cache->dbgCachedUsers++;
2040 		    break;
2041 		case XPATH_XSLT_TREE:
2042 		    cache->dbgCachedXSLTTree++;
2043 		    break;
2044 		default:
2045 		    break;
2046 	    }
2047 
2048 	}
2049     }
2050     switch (objType) {
2051 	case XPATH_UNDEFINED:
2052 	    xmlXPathDebugObjCounterUndefined--;
2053 	    break;
2054 	case XPATH_NODESET:
2055 	    xmlXPathDebugObjCounterNodeset--;
2056 	    break;
2057 	case XPATH_BOOLEAN:
2058 	    xmlXPathDebugObjCounterBool--;
2059 	    break;
2060 	case XPATH_NUMBER:
2061 	    xmlXPathDebugObjCounterNumber--;
2062 	    break;
2063 	case XPATH_STRING:
2064 	    xmlXPathDebugObjCounterString--;
2065 	    break;
2066 #ifdef LIBXML_XPTR_LOCS_ENABLED
2067 	case XPATH_POINT:
2068 	    xmlXPathDebugObjCounterPoint--;
2069 	    break;
2070 	case XPATH_RANGE:
2071 	    xmlXPathDebugObjCounterRange--;
2072 	    break;
2073 	case XPATH_LOCATIONSET:
2074 	    xmlXPathDebugObjCounterLocset--;
2075 	    break;
2076 #endif /* LIBXML_XPTR_LOCS_ENABLED */
2077 	case XPATH_USERS:
2078 	    xmlXPathDebugObjCounterUsers--;
2079 	    break;
2080 	case XPATH_XSLT_TREE:
2081 	    xmlXPathDebugObjCounterXSLTTree--;
2082 	    break;
2083 	default:
2084 	    break;
2085     }
2086     xmlXPathDebugObjCounterAll--;
2087 }
2088 
2089 static void
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)2090 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2091 {
2092     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2093 	reqXSLTTree, reqUndefined;
2094     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2095 	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2096     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2097 	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2098     int leftObjs = xmlXPathDebugObjCounterAll;
2099 
2100     reqAll = xmlXPathDebugObjTotalAll;
2101     reqNodeset = xmlXPathDebugObjTotalNodeset;
2102     reqString = xmlXPathDebugObjTotalString;
2103     reqBool = xmlXPathDebugObjTotalBool;
2104     reqNumber = xmlXPathDebugObjTotalNumber;
2105     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2106     reqUndefined = xmlXPathDebugObjTotalUndefined;
2107 
2108     printf("# XPath object usage:\n");
2109 
2110     if (ctxt != NULL) {
2111 	if (ctxt->cache != NULL) {
2112 	    xmlXPathContextCachePtr cache =
2113 		(xmlXPathContextCachePtr) ctxt->cache;
2114 
2115 	    reAll = cache->dbgReusedAll;
2116 	    reqAll += reAll;
2117 	    reNodeset = cache->dbgReusedNodeset;
2118 	    reqNodeset += reNodeset;
2119 	    reString = cache->dbgReusedString;
2120 	    reqString += reString;
2121 	    reBool = cache->dbgReusedBool;
2122 	    reqBool += reBool;
2123 	    reNumber = cache->dbgReusedNumber;
2124 	    reqNumber += reNumber;
2125 	    reXSLTTree = cache->dbgReusedXSLTTree;
2126 	    reqXSLTTree += reXSLTTree;
2127 	    reUndefined = cache->dbgReusedUndefined;
2128 	    reqUndefined += reUndefined;
2129 
2130 	    caAll = cache->dbgCachedAll;
2131 	    caBool = cache->dbgCachedBool;
2132 	    caNodeset = cache->dbgCachedNodeset;
2133 	    caString = cache->dbgCachedString;
2134 	    caNumber = cache->dbgCachedNumber;
2135 	    caXSLTTree = cache->dbgCachedXSLTTree;
2136 	    caUndefined = cache->dbgCachedUndefined;
2137 
2138 	    if (cache->nodesetObjs)
2139 		leftObjs -= cache->nodesetObjs->number;
2140 	    if (cache->stringObjs)
2141 		leftObjs -= cache->stringObjs->number;
2142 	    if (cache->booleanObjs)
2143 		leftObjs -= cache->booleanObjs->number;
2144 	    if (cache->numberObjs)
2145 		leftObjs -= cache->numberObjs->number;
2146 	    if (cache->miscObjs)
2147 		leftObjs -= cache->miscObjs->number;
2148 	}
2149     }
2150 
2151     printf("# all\n");
2152     printf("#   total  : %d\n", reqAll);
2153     printf("#   left  : %d\n", leftObjs);
2154     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2155     printf("#   reused : %d\n", reAll);
2156     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2157 
2158     printf("# node-sets\n");
2159     printf("#   total  : %d\n", reqNodeset);
2160     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2161     printf("#   reused : %d\n", reNodeset);
2162     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2163 
2164     printf("# strings\n");
2165     printf("#   total  : %d\n", reqString);
2166     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2167     printf("#   reused : %d\n", reString);
2168     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2169 
2170     printf("# booleans\n");
2171     printf("#   total  : %d\n", reqBool);
2172     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2173     printf("#   reused : %d\n", reBool);
2174     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2175 
2176     printf("# numbers\n");
2177     printf("#   total  : %d\n", reqNumber);
2178     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2179     printf("#   reused : %d\n", reNumber);
2180     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2181 
2182     printf("# XSLT result tree fragments\n");
2183     printf("#   total  : %d\n", reqXSLTTree);
2184     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2185     printf("#   reused : %d\n", reXSLTTree);
2186     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2187 
2188     printf("# undefined\n");
2189     printf("#   total  : %d\n", reqUndefined);
2190     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2191     printf("#   reused : %d\n", reUndefined);
2192     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2193 
2194 }
2195 
2196 #endif /* XP_DEBUG_OBJ_USAGE */
2197 
2198 #endif /* LIBXML_DEBUG_ENABLED */
2199 
2200 /************************************************************************
2201  *									*
2202  *			XPath object caching				*
2203  *									*
2204  ************************************************************************/
2205 
2206 /**
2207  * xmlXPathNewCache:
2208  *
2209  * Create a new object cache
2210  *
2211  * Returns the xmlXPathCache just allocated.
2212  */
2213 static xmlXPathContextCachePtr
xmlXPathNewCache(void)2214 xmlXPathNewCache(void)
2215 {
2216     xmlXPathContextCachePtr ret;
2217 
2218     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2219     if (ret == NULL) {
2220         xmlXPathErrMemory(NULL, "creating object cache\n");
2221 	return(NULL);
2222     }
2223     memset(ret, 0 , sizeof(xmlXPathContextCache));
2224     ret->maxNodeset = 100;
2225     ret->maxString = 100;
2226     ret->maxBoolean = 100;
2227     ret->maxNumber = 100;
2228     ret->maxMisc = 100;
2229     return(ret);
2230 }
2231 
2232 static void
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)2233 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2234 {
2235     int i;
2236     xmlXPathObjectPtr obj;
2237 
2238     if (list == NULL)
2239 	return;
2240 
2241     for (i = 0; i < list->number; i++) {
2242 	obj = list->items[i];
2243 	/*
2244 	* Note that it is already assured that we don't need to
2245 	* look out for namespace nodes in the node-set.
2246 	*/
2247 	if (obj->nodesetval != NULL) {
2248 	    if (obj->nodesetval->nodeTab != NULL)
2249 		xmlFree(obj->nodesetval->nodeTab);
2250 	    xmlFree(obj->nodesetval);
2251 	}
2252 	xmlFree(obj);
2253 #ifdef XP_DEBUG_OBJ_USAGE
2254 	xmlXPathDebugObjCounterAll--;
2255 #endif
2256     }
2257     xmlPointerListFree(list);
2258 }
2259 
2260 static void
xmlXPathFreeCache(xmlXPathContextCachePtr cache)2261 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2262 {
2263     if (cache == NULL)
2264 	return;
2265     if (cache->nodesetObjs)
2266 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2267     if (cache->stringObjs)
2268 	xmlXPathCacheFreeObjectList(cache->stringObjs);
2269     if (cache->booleanObjs)
2270 	xmlXPathCacheFreeObjectList(cache->booleanObjs);
2271     if (cache->numberObjs)
2272 	xmlXPathCacheFreeObjectList(cache->numberObjs);
2273     if (cache->miscObjs)
2274 	xmlXPathCacheFreeObjectList(cache->miscObjs);
2275     xmlFree(cache);
2276 }
2277 
2278 /**
2279  * xmlXPathContextSetCache:
2280  *
2281  * @ctxt:  the XPath context
2282  * @active: enables/disables (creates/frees) the cache
2283  * @value: a value with semantics dependent on @options
2284  * @options: options (currently only the value 0 is used)
2285  *
2286  * Creates/frees an object cache on the XPath context.
2287  * If activates XPath objects (xmlXPathObject) will be cached internally
2288  * to be reused.
2289  * @options:
2290  *   0: This will set the XPath object caching:
2291  *      @value:
2292  *        This will set the maximum number of XPath objects
2293  *        to be cached per slot
2294  *        There are 5 slots for: node-set, string, number, boolean, and
2295  *        misc objects. Use <0 for the default number (100).
2296  *   Other values for @options have currently no effect.
2297  *
2298  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2299  */
2300 int
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,int active,int value,int options)2301 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2302 			int active,
2303 			int value,
2304 			int options)
2305 {
2306     if (ctxt == NULL)
2307 	return(-1);
2308     if (active) {
2309 	xmlXPathContextCachePtr cache;
2310 
2311 	if (ctxt->cache == NULL) {
2312 	    ctxt->cache = xmlXPathNewCache();
2313 	    if (ctxt->cache == NULL)
2314 		return(-1);
2315 	}
2316 	cache = (xmlXPathContextCachePtr) ctxt->cache;
2317 	if (options == 0) {
2318 	    if (value < 0)
2319 		value = 100;
2320 	    cache->maxNodeset = value;
2321 	    cache->maxString = value;
2322 	    cache->maxNumber = value;
2323 	    cache->maxBoolean = value;
2324 	    cache->maxMisc = value;
2325 	}
2326     } else if (ctxt->cache != NULL) {
2327 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2328 	ctxt->cache = NULL;
2329     }
2330     return(0);
2331 }
2332 
2333 /**
2334  * xmlXPathCacheWrapNodeSet:
2335  * @ctxt: the XPath context
2336  * @val:  the NodePtr value
2337  *
2338  * This is the cached version of xmlXPathWrapNodeSet().
2339  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2340  *
2341  * Returns the created or reused object.
2342  *
2343  * In case of error the node set is destroyed and NULL is returned.
2344  */
2345 static xmlXPathObjectPtr
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt,xmlNodeSetPtr val)2346 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2347 {
2348     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2349 	xmlXPathContextCachePtr cache =
2350 	    (xmlXPathContextCachePtr) ctxt->cache;
2351 
2352 	if ((cache->miscObjs != NULL) &&
2353 	    (cache->miscObjs->number != 0))
2354 	{
2355 	    xmlXPathObjectPtr ret;
2356 
2357 	    ret = (xmlXPathObjectPtr)
2358 		cache->miscObjs->items[--cache->miscObjs->number];
2359 	    ret->type = XPATH_NODESET;
2360 	    ret->nodesetval = val;
2361 #ifdef XP_DEBUG_OBJ_USAGE
2362 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2363 #endif
2364 	    return(ret);
2365 	}
2366     }
2367 
2368     return(xmlXPathWrapNodeSet(val));
2369 
2370 }
2371 
2372 /**
2373  * xmlXPathCacheWrapString:
2374  * @ctxt: the XPath context
2375  * @val:  the xmlChar * value
2376  *
2377  * This is the cached version of xmlXPathWrapString().
2378  * Wraps the @val string into an XPath object.
2379  *
2380  * Returns the created or reused object.
2381  */
2382 static xmlXPathObjectPtr
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt,xmlChar * val)2383 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2384 {
2385     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2386 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2387 
2388 	if ((cache->stringObjs != NULL) &&
2389 	    (cache->stringObjs->number != 0))
2390 	{
2391 
2392 	    xmlXPathObjectPtr ret;
2393 
2394 	    ret = (xmlXPathObjectPtr)
2395 		cache->stringObjs->items[--cache->stringObjs->number];
2396 	    ret->type = XPATH_STRING;
2397 	    ret->stringval = val;
2398 #ifdef XP_DEBUG_OBJ_USAGE
2399 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2400 #endif
2401 	    return(ret);
2402 	} else if ((cache->miscObjs != NULL) &&
2403 	    (cache->miscObjs->number != 0))
2404 	{
2405 	    xmlXPathObjectPtr ret;
2406 	    /*
2407 	    * Fallback to misc-cache.
2408 	    */
2409 	    ret = (xmlXPathObjectPtr)
2410 		cache->miscObjs->items[--cache->miscObjs->number];
2411 
2412 	    ret->type = XPATH_STRING;
2413 	    ret->stringval = val;
2414 #ifdef XP_DEBUG_OBJ_USAGE
2415 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2416 #endif
2417 	    return(ret);
2418 	}
2419     }
2420     return(xmlXPathWrapString(val));
2421 }
2422 
2423 /**
2424  * xmlXPathCacheNewNodeSet:
2425  * @ctxt: the XPath context
2426  * @val:  the NodePtr value
2427  *
2428  * This is the cached version of xmlXPathNewNodeSet().
2429  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2430  * it with the single Node @val
2431  *
2432  * Returns the created or reused object.
2433  */
2434 static xmlXPathObjectPtr
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt,xmlNodePtr val)2435 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2436 {
2437     if ((ctxt != NULL) && (ctxt->cache)) {
2438 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2439 
2440 	if ((cache->nodesetObjs != NULL) &&
2441 	    (cache->nodesetObjs->number != 0))
2442 	{
2443 	    xmlXPathObjectPtr ret;
2444 	    /*
2445 	    * Use the nodeset-cache.
2446 	    */
2447 	    ret = (xmlXPathObjectPtr)
2448 		cache->nodesetObjs->items[--cache->nodesetObjs->number];
2449 	    ret->type = XPATH_NODESET;
2450 	    ret->boolval = 0;
2451 	    if (val) {
2452 		if ((ret->nodesetval->nodeMax == 0) ||
2453 		    (val->type == XML_NAMESPACE_DECL))
2454 		{
2455                     /* TODO: Check memory error. */
2456 		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2457 		} else {
2458 		    ret->nodesetval->nodeTab[0] = val;
2459 		    ret->nodesetval->nodeNr = 1;
2460 		}
2461 	    }
2462 #ifdef XP_DEBUG_OBJ_USAGE
2463 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2464 #endif
2465 	    return(ret);
2466 	} else if ((cache->miscObjs != NULL) &&
2467 	    (cache->miscObjs->number != 0))
2468 	{
2469 	    xmlXPathObjectPtr ret;
2470             xmlNodeSetPtr set;
2471 	    /*
2472 	    * Fallback to misc-cache.
2473 	    */
2474 
2475 	    set = xmlXPathNodeSetCreate(val);
2476 	    if (set == NULL) {
2477 		ctxt->lastError.domain = XML_FROM_XPATH;
2478 		ctxt->lastError.code = XML_ERR_NO_MEMORY;
2479 		return(NULL);
2480 	    }
2481 
2482 	    ret = (xmlXPathObjectPtr)
2483 		cache->miscObjs->items[--cache->miscObjs->number];
2484 
2485 	    ret->type = XPATH_NODESET;
2486 	    ret->boolval = 0;
2487 	    ret->nodesetval = set;
2488 #ifdef XP_DEBUG_OBJ_USAGE
2489 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2490 #endif
2491 	    return(ret);
2492 	}
2493     }
2494     return(xmlXPathNewNodeSet(val));
2495 }
2496 
2497 /**
2498  * xmlXPathCacheNewString:
2499  * @ctxt: the XPath context
2500  * @val:  the xmlChar * value
2501  *
2502  * This is the cached version of xmlXPathNewString().
2503  * Acquire an xmlXPathObjectPtr of type string and of value @val
2504  *
2505  * Returns the created or reused object.
2506  */
2507 static xmlXPathObjectPtr
xmlXPathCacheNewString(xmlXPathContextPtr ctxt,const xmlChar * val)2508 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2509 {
2510     if ((ctxt != NULL) && (ctxt->cache)) {
2511 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2512 
2513 	if ((cache->stringObjs != NULL) &&
2514 	    (cache->stringObjs->number != 0))
2515 	{
2516 	    xmlXPathObjectPtr ret;
2517             xmlChar *copy;
2518 
2519             if (val == NULL)
2520                 val = BAD_CAST "";
2521             copy = xmlStrdup(val);
2522             if (copy == NULL) {
2523                 xmlXPathErrMemory(ctxt, NULL);
2524                 return(NULL);
2525             }
2526 
2527 	    ret = (xmlXPathObjectPtr)
2528 		cache->stringObjs->items[--cache->stringObjs->number];
2529 	    ret->type = XPATH_STRING;
2530             ret->stringval = copy;
2531 #ifdef XP_DEBUG_OBJ_USAGE
2532 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2533 #endif
2534 	    return(ret);
2535 	} else if ((cache->miscObjs != NULL) &&
2536 	    (cache->miscObjs->number != 0))
2537 	{
2538 	    xmlXPathObjectPtr ret;
2539             xmlChar *copy;
2540 
2541             if (val == NULL)
2542                 val = BAD_CAST "";
2543             copy = xmlStrdup(val);
2544             if (copy == NULL) {
2545                 xmlXPathErrMemory(ctxt, NULL);
2546                 return(NULL);
2547             }
2548 
2549 	    ret = (xmlXPathObjectPtr)
2550 		cache->miscObjs->items[--cache->miscObjs->number];
2551 
2552 	    ret->type = XPATH_STRING;
2553             ret->stringval = copy;
2554 #ifdef XP_DEBUG_OBJ_USAGE
2555 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2556 #endif
2557 	    return(ret);
2558 	}
2559     }
2560     return(xmlXPathNewString(val));
2561 }
2562 
2563 /**
2564  * xmlXPathCacheNewCString:
2565  * @ctxt: the XPath context
2566  * @val:  the char * value
2567  *
2568  * This is the cached version of xmlXPathNewCString().
2569  * Acquire an xmlXPathObjectPtr of type string and of value @val
2570  *
2571  * Returns the created or reused object.
2572  */
2573 static xmlXPathObjectPtr
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt,const char * val)2574 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2575 {
2576     return xmlXPathCacheNewString(ctxt, BAD_CAST val);
2577 }
2578 
2579 /**
2580  * xmlXPathCacheNewBoolean:
2581  * @ctxt: the XPath context
2582  * @val:  the boolean value
2583  *
2584  * This is the cached version of xmlXPathNewBoolean().
2585  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2586  *
2587  * Returns the created or reused object.
2588  */
2589 static xmlXPathObjectPtr
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt,int val)2590 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2591 {
2592     if ((ctxt != NULL) && (ctxt->cache)) {
2593 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2594 
2595 	if ((cache->booleanObjs != NULL) &&
2596 	    (cache->booleanObjs->number != 0))
2597 	{
2598 	    xmlXPathObjectPtr ret;
2599 
2600 	    ret = (xmlXPathObjectPtr)
2601 		cache->booleanObjs->items[--cache->booleanObjs->number];
2602 	    ret->type = XPATH_BOOLEAN;
2603 	    ret->boolval = (val != 0);
2604 #ifdef XP_DEBUG_OBJ_USAGE
2605 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2606 #endif
2607 	    return(ret);
2608 	} else if ((cache->miscObjs != NULL) &&
2609 	    (cache->miscObjs->number != 0))
2610 	{
2611 	    xmlXPathObjectPtr ret;
2612 
2613 	    ret = (xmlXPathObjectPtr)
2614 		cache->miscObjs->items[--cache->miscObjs->number];
2615 
2616 	    ret->type = XPATH_BOOLEAN;
2617 	    ret->boolval = (val != 0);
2618 #ifdef XP_DEBUG_OBJ_USAGE
2619 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2620 #endif
2621 	    return(ret);
2622 	}
2623     }
2624     return(xmlXPathNewBoolean(val));
2625 }
2626 
2627 /**
2628  * xmlXPathCacheNewFloat:
2629  * @ctxt: the XPath context
2630  * @val:  the double value
2631  *
2632  * This is the cached version of xmlXPathNewFloat().
2633  * Acquires an xmlXPathObjectPtr of type double and of value @val
2634  *
2635  * Returns the created or reused object.
2636  */
2637 static xmlXPathObjectPtr
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt,double val)2638 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2639 {
2640      if ((ctxt != NULL) && (ctxt->cache)) {
2641 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2642 
2643 	if ((cache->numberObjs != NULL) &&
2644 	    (cache->numberObjs->number != 0))
2645 	{
2646 	    xmlXPathObjectPtr ret;
2647 
2648 	    ret = (xmlXPathObjectPtr)
2649 		cache->numberObjs->items[--cache->numberObjs->number];
2650 	    ret->type = XPATH_NUMBER;
2651 	    ret->floatval = val;
2652 #ifdef XP_DEBUG_OBJ_USAGE
2653 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2654 #endif
2655 	    return(ret);
2656 	} else if ((cache->miscObjs != NULL) &&
2657 	    (cache->miscObjs->number != 0))
2658 	{
2659 	    xmlXPathObjectPtr ret;
2660 
2661 	    ret = (xmlXPathObjectPtr)
2662 		cache->miscObjs->items[--cache->miscObjs->number];
2663 
2664 	    ret->type = XPATH_NUMBER;
2665 	    ret->floatval = val;
2666 #ifdef XP_DEBUG_OBJ_USAGE
2667 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2668 #endif
2669 	    return(ret);
2670 	}
2671     }
2672     return(xmlXPathNewFloat(val));
2673 }
2674 
2675 /**
2676  * xmlXPathCacheConvertString:
2677  * @ctxt: the XPath context
2678  * @val:  an XPath object
2679  *
2680  * This is the cached version of xmlXPathConvertString().
2681  * Converts an existing object to its string() equivalent
2682  *
2683  * Returns a created or reused object, the old one is freed (cached)
2684  *         (or the operation is done directly on @val)
2685  */
2686 
2687 static xmlXPathObjectPtr
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2688 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2689     xmlChar *res = NULL;
2690 
2691     if (val == NULL)
2692 	return(xmlXPathCacheNewCString(ctxt, ""));
2693 
2694     switch (val->type) {
2695     case XPATH_UNDEFINED:
2696 #ifdef DEBUG_EXPR
2697 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2698 #endif
2699 	break;
2700     case XPATH_NODESET:
2701     case XPATH_XSLT_TREE:
2702 	res = xmlXPathCastNodeSetToString(val->nodesetval);
2703 	break;
2704     case XPATH_STRING:
2705 	return(val);
2706     case XPATH_BOOLEAN:
2707 	res = xmlXPathCastBooleanToString(val->boolval);
2708 	break;
2709     case XPATH_NUMBER:
2710 	res = xmlXPathCastNumberToString(val->floatval);
2711 	break;
2712     case XPATH_USERS:
2713 #ifdef LIBXML_XPTR_LOCS_ENABLED
2714     case XPATH_POINT:
2715     case XPATH_RANGE:
2716     case XPATH_LOCATIONSET:
2717 #endif /* LIBXML_XPTR_LOCS_ENABLED */
2718 	TODO;
2719 	break;
2720     }
2721     xmlXPathReleaseObject(ctxt, val);
2722     if (res == NULL)
2723 	return(xmlXPathCacheNewCString(ctxt, ""));
2724     return(xmlXPathCacheWrapString(ctxt, res));
2725 }
2726 
2727 /**
2728  * xmlXPathCacheObjectCopy:
2729  * @ctxt: the XPath context
2730  * @val:  the original object
2731  *
2732  * This is the cached version of xmlXPathObjectCopy().
2733  * Acquire a copy of a given object
2734  *
2735  * Returns a created or reused created object.
2736  */
2737 static xmlXPathObjectPtr
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2738 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2739 {
2740     if (val == NULL)
2741 	return(NULL);
2742 
2743     if (XP_HAS_CACHE(ctxt)) {
2744 	switch (val->type) {
2745 	    case XPATH_NODESET:
2746 		return(xmlXPathCacheWrapNodeSet(ctxt,
2747 		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2748 	    case XPATH_STRING:
2749 		return(xmlXPathCacheNewString(ctxt, val->stringval));
2750 	    case XPATH_BOOLEAN:
2751 		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2752 	    case XPATH_NUMBER:
2753 		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2754 	    default:
2755 		break;
2756 	}
2757     }
2758     return(xmlXPathObjectCopy(val));
2759 }
2760 
2761 /**
2762  * xmlXPathCacheConvertBoolean:
2763  * @ctxt: the XPath context
2764  * @val:  an XPath object
2765  *
2766  * This is the cached version of xmlXPathConvertBoolean().
2767  * Converts an existing object to its boolean() equivalent
2768  *
2769  * Returns a created or reused object, the old one is freed (or the operation
2770  *         is done directly on @val)
2771  */
2772 static xmlXPathObjectPtr
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2773 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2774     xmlXPathObjectPtr ret;
2775 
2776     if (val == NULL)
2777 	return(xmlXPathCacheNewBoolean(ctxt, 0));
2778     if (val->type == XPATH_BOOLEAN)
2779 	return(val);
2780     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2781     xmlXPathReleaseObject(ctxt, val);
2782     return(ret);
2783 }
2784 
2785 /**
2786  * xmlXPathCacheConvertNumber:
2787  * @ctxt: the XPath context
2788  * @val:  an XPath object
2789  *
2790  * This is the cached version of xmlXPathConvertNumber().
2791  * Converts an existing object to its number() equivalent
2792  *
2793  * Returns a created or reused object, the old one is freed (or the operation
2794  *         is done directly on @val)
2795  */
2796 static xmlXPathObjectPtr
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2797 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2798     xmlXPathObjectPtr ret;
2799 
2800     if (val == NULL)
2801 	return(xmlXPathCacheNewFloat(ctxt, 0.0));
2802     if (val->type == XPATH_NUMBER)
2803 	return(val);
2804     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2805     xmlXPathReleaseObject(ctxt, val);
2806     return(ret);
2807 }
2808 
2809 /************************************************************************
2810  *									*
2811  *		Parser stacks related functions and macros		*
2812  *									*
2813  ************************************************************************/
2814 
2815 /**
2816  * valuePop:
2817  * @ctxt: an XPath evaluation context
2818  *
2819  * Pops the top XPath object from the value stack
2820  *
2821  * Returns the XPath object just removed
2822  */
2823 xmlXPathObjectPtr
valuePop(xmlXPathParserContextPtr ctxt)2824 valuePop(xmlXPathParserContextPtr ctxt)
2825 {
2826     xmlXPathObjectPtr ret;
2827 
2828     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2829         return (NULL);
2830 
2831     ctxt->valueNr--;
2832     if (ctxt->valueNr > 0)
2833         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2834     else
2835         ctxt->value = NULL;
2836     ret = ctxt->valueTab[ctxt->valueNr];
2837     ctxt->valueTab[ctxt->valueNr] = NULL;
2838     return (ret);
2839 }
2840 /**
2841  * valuePush:
2842  * @ctxt:  an XPath evaluation context
2843  * @value:  the XPath object
2844  *
2845  * Pushes a new XPath object on top of the value stack. If value is NULL,
2846  * a memory error is recorded in the parser context.
2847  *
2848  * Returns the number of items on the value stack, or -1 in case of error.
2849  *
2850  * The object is destroyed in case of error.
2851  */
2852 int
valuePush(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr value)2853 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2854 {
2855     if (ctxt == NULL) return(-1);
2856     if (value == NULL) {
2857         /*
2858          * A NULL value typically indicates that a memory allocation failed,
2859          * so we set ctxt->error here to propagate the error.
2860          */
2861 	ctxt->error = XPATH_MEMORY_ERROR;
2862         return(-1);
2863     }
2864     if (ctxt->valueNr >= ctxt->valueMax) {
2865         xmlXPathObjectPtr *tmp;
2866 
2867         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2868             xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2869             xmlXPathFreeObject(value);
2870             return (-1);
2871         }
2872         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2873                                              2 * ctxt->valueMax *
2874                                              sizeof(ctxt->valueTab[0]));
2875         if (tmp == NULL) {
2876             xmlXPathPErrMemory(ctxt, "pushing value\n");
2877             xmlXPathFreeObject(value);
2878             return (-1);
2879         }
2880         ctxt->valueMax *= 2;
2881 	ctxt->valueTab = tmp;
2882     }
2883     ctxt->valueTab[ctxt->valueNr] = value;
2884     ctxt->value = value;
2885     return (ctxt->valueNr++);
2886 }
2887 
2888 /**
2889  * xmlXPathPopBoolean:
2890  * @ctxt:  an XPath parser context
2891  *
2892  * Pops a boolean from the stack, handling conversion if needed.
2893  * Check error with #xmlXPathCheckError.
2894  *
2895  * Returns the boolean
2896  */
2897 int
xmlXPathPopBoolean(xmlXPathParserContextPtr ctxt)2898 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2899     xmlXPathObjectPtr obj;
2900     int ret;
2901 
2902     obj = valuePop(ctxt);
2903     if (obj == NULL) {
2904 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2905 	return(0);
2906     }
2907     if (obj->type != XPATH_BOOLEAN)
2908 	ret = xmlXPathCastToBoolean(obj);
2909     else
2910         ret = obj->boolval;
2911     xmlXPathReleaseObject(ctxt->context, obj);
2912     return(ret);
2913 }
2914 
2915 /**
2916  * xmlXPathPopNumber:
2917  * @ctxt:  an XPath parser context
2918  *
2919  * Pops a number from the stack, handling conversion if needed.
2920  * Check error with #xmlXPathCheckError.
2921  *
2922  * Returns the number
2923  */
2924 double
xmlXPathPopNumber(xmlXPathParserContextPtr ctxt)2925 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2926     xmlXPathObjectPtr obj;
2927     double ret;
2928 
2929     obj = valuePop(ctxt);
2930     if (obj == NULL) {
2931 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2932 	return(0);
2933     }
2934     if (obj->type != XPATH_NUMBER)
2935 	ret = xmlXPathCastToNumber(obj);
2936     else
2937         ret = obj->floatval;
2938     xmlXPathReleaseObject(ctxt->context, obj);
2939     return(ret);
2940 }
2941 
2942 /**
2943  * xmlXPathPopString:
2944  * @ctxt:  an XPath parser context
2945  *
2946  * Pops a string from the stack, handling conversion if needed.
2947  * Check error with #xmlXPathCheckError.
2948  *
2949  * Returns the string
2950  */
2951 xmlChar *
xmlXPathPopString(xmlXPathParserContextPtr ctxt)2952 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2953     xmlXPathObjectPtr obj;
2954     xmlChar * ret;
2955 
2956     obj = valuePop(ctxt);
2957     if (obj == NULL) {
2958 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2959 	return(NULL);
2960     }
2961     ret = xmlXPathCastToString(obj);	/* this does required strdup */
2962     /* TODO: needs refactoring somewhere else */
2963     if (obj->stringval == ret)
2964 	obj->stringval = NULL;
2965     xmlXPathReleaseObject(ctxt->context, obj);
2966     return(ret);
2967 }
2968 
2969 /**
2970  * xmlXPathPopNodeSet:
2971  * @ctxt:  an XPath parser context
2972  *
2973  * Pops a node-set from the stack, handling conversion if needed.
2974  * Check error with #xmlXPathCheckError.
2975  *
2976  * Returns the node-set
2977  */
2978 xmlNodeSetPtr
xmlXPathPopNodeSet(xmlXPathParserContextPtr ctxt)2979 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2980     xmlXPathObjectPtr obj;
2981     xmlNodeSetPtr ret;
2982 
2983     if (ctxt == NULL) return(NULL);
2984     if (ctxt->value == NULL) {
2985 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2986 	return(NULL);
2987     }
2988     if (!xmlXPathStackIsNodeSet(ctxt)) {
2989 	xmlXPathSetTypeError(ctxt);
2990 	return(NULL);
2991     }
2992     obj = valuePop(ctxt);
2993     ret = obj->nodesetval;
2994 #if 0
2995     /* to fix memory leak of not clearing obj->user */
2996     if (obj->boolval && obj->user != NULL)
2997         xmlFreeNodeList((xmlNodePtr) obj->user);
2998 #endif
2999     obj->nodesetval = NULL;
3000     xmlXPathReleaseObject(ctxt->context, obj);
3001     return(ret);
3002 }
3003 
3004 /**
3005  * xmlXPathPopExternal:
3006  * @ctxt:  an XPath parser context
3007  *
3008  * Pops an external object from the stack, handling conversion if needed.
3009  * Check error with #xmlXPathCheckError.
3010  *
3011  * Returns the object
3012  */
3013 void *
xmlXPathPopExternal(xmlXPathParserContextPtr ctxt)3014 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3015     xmlXPathObjectPtr obj;
3016     void * ret;
3017 
3018     if ((ctxt == NULL) || (ctxt->value == NULL)) {
3019 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3020 	return(NULL);
3021     }
3022     if (ctxt->value->type != XPATH_USERS) {
3023 	xmlXPathSetTypeError(ctxt);
3024 	return(NULL);
3025     }
3026     obj = valuePop(ctxt);
3027     ret = obj->user;
3028     obj->user = NULL;
3029     xmlXPathReleaseObject(ctxt->context, obj);
3030     return(ret);
3031 }
3032 
3033 /*
3034  * Macros for accessing the content. Those should be used only by the parser,
3035  * and not exported.
3036  *
3037  * Dirty macros, i.e. one need to make assumption on the context to use them
3038  *
3039  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3040  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3041  *           in ISO-Latin or UTF-8.
3042  *           This should be used internally by the parser
3043  *           only to compare to ASCII values otherwise it would break when
3044  *           running with UTF-8 encoding.
3045  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3046  *           to compare on ASCII based substring.
3047  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3048  *           strings within the parser.
3049  *   CURRENT Returns the current char value, with the full decoding of
3050  *           UTF-8 if we are using this mode. It returns an int.
3051  *   NEXT    Skip to the next character, this does the proper decoding
3052  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3053  *           It returns the pointer to the current xmlChar.
3054  */
3055 
3056 #define CUR (*ctxt->cur)
3057 #define SKIP(val) ctxt->cur += (val)
3058 #define NXT(val) ctxt->cur[(val)]
3059 #define CUR_PTR ctxt->cur
3060 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3061 
3062 #define COPY_BUF(l,b,i,v)                                              \
3063     if (l == 1) b[i++] = v;                                            \
3064     else i += xmlCopyChar(l,&b[i],v)
3065 
3066 #define NEXTL(l)  ctxt->cur += l
3067 
3068 #define SKIP_BLANKS							\
3069     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3070 
3071 #define CURRENT (*ctxt->cur)
3072 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3073 
3074 
3075 #ifndef DBL_DIG
3076 #define DBL_DIG 16
3077 #endif
3078 #ifndef DBL_EPSILON
3079 #define DBL_EPSILON 1E-9
3080 #endif
3081 
3082 #define UPPER_DOUBLE 1E9
3083 #define LOWER_DOUBLE 1E-5
3084 #define	LOWER_DOUBLE_EXP 5
3085 
3086 #define INTEGER_DIGITS DBL_DIG
3087 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3088 #define EXPONENT_DIGITS (3 + 2)
3089 
3090 /**
3091  * xmlXPathFormatNumber:
3092  * @number:     number to format
3093  * @buffer:     output buffer
3094  * @buffersize: size of output buffer
3095  *
3096  * Convert the number into a string representation.
3097  */
3098 static void
xmlXPathFormatNumber(double number,char buffer[],int buffersize)3099 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3100 {
3101     switch (xmlXPathIsInf(number)) {
3102     case 1:
3103 	if (buffersize > (int)sizeof("Infinity"))
3104 	    snprintf(buffer, buffersize, "Infinity");
3105 	break;
3106     case -1:
3107 	if (buffersize > (int)sizeof("-Infinity"))
3108 	    snprintf(buffer, buffersize, "-Infinity");
3109 	break;
3110     default:
3111 	if (xmlXPathIsNaN(number)) {
3112 	    if (buffersize > (int)sizeof("NaN"))
3113 		snprintf(buffer, buffersize, "NaN");
3114 	} else if (number == 0) {
3115             /* Omit sign for negative zero. */
3116 	    snprintf(buffer, buffersize, "0");
3117 	} else if ((number > INT_MIN) && (number < INT_MAX) &&
3118                    (number == (int) number)) {
3119 	    char work[30];
3120 	    char *ptr, *cur;
3121 	    int value = (int) number;
3122 
3123             ptr = &buffer[0];
3124 	    if (value == 0) {
3125 		*ptr++ = '0';
3126 	    } else {
3127 		snprintf(work, 29, "%d", value);
3128 		cur = &work[0];
3129 		while ((*cur) && (ptr - buffer < buffersize)) {
3130 		    *ptr++ = *cur++;
3131 		}
3132 	    }
3133 	    if (ptr - buffer < buffersize) {
3134 		*ptr = 0;
3135 	    } else if (buffersize > 0) {
3136 		ptr--;
3137 		*ptr = 0;
3138 	    }
3139 	} else {
3140 	    /*
3141 	      For the dimension of work,
3142 	          DBL_DIG is number of significant digits
3143 		  EXPONENT is only needed for "scientific notation"
3144 	          3 is sign, decimal point, and terminating zero
3145 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3146 	      Note that this dimension is slightly (a few characters)
3147 	      larger than actually necessary.
3148 	    */
3149 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3150 	    int integer_place, fraction_place;
3151 	    char *ptr;
3152 	    char *after_fraction;
3153 	    double absolute_value;
3154 	    int size;
3155 
3156 	    absolute_value = fabs(number);
3157 
3158 	    /*
3159 	     * First choose format - scientific or regular floating point.
3160 	     * In either case, result is in work, and after_fraction points
3161 	     * just past the fractional part.
3162 	    */
3163 	    if ( ((absolute_value > UPPER_DOUBLE) ||
3164 		  (absolute_value < LOWER_DOUBLE)) &&
3165 		 (absolute_value != 0.0) ) {
3166 		/* Use scientific notation */
3167 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3168 		fraction_place = DBL_DIG - 1;
3169 		size = snprintf(work, sizeof(work),"%*.*e",
3170 			 integer_place, fraction_place, number);
3171 		while ((size > 0) && (work[size] != 'e')) size--;
3172 
3173 	    }
3174 	    else {
3175 		/* Use regular notation */
3176 		if (absolute_value > 0.0) {
3177 		    integer_place = (int)log10(absolute_value);
3178 		    if (integer_place > 0)
3179 		        fraction_place = DBL_DIG - integer_place - 1;
3180 		    else
3181 		        fraction_place = DBL_DIG - integer_place;
3182 		} else {
3183 		    fraction_place = 1;
3184 		}
3185 		size = snprintf(work, sizeof(work), "%0.*f",
3186 				fraction_place, number);
3187 	    }
3188 
3189 	    /* Remove leading spaces sometimes inserted by snprintf */
3190 	    while (work[0] == ' ') {
3191 	        for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3192 		size--;
3193 	    }
3194 
3195 	    /* Remove fractional trailing zeroes */
3196 	    after_fraction = work + size;
3197 	    ptr = after_fraction;
3198 	    while (*(--ptr) == '0')
3199 		;
3200 	    if (*ptr != '.')
3201 	        ptr++;
3202 	    while ((*ptr++ = *after_fraction++) != 0);
3203 
3204 	    /* Finally copy result back to caller */
3205 	    size = strlen(work) + 1;
3206 	    if (size > buffersize) {
3207 		work[buffersize - 1] = 0;
3208 		size = buffersize;
3209 	    }
3210 	    memmove(buffer, work, size);
3211 	}
3212 	break;
3213     }
3214 }
3215 
3216 
3217 /************************************************************************
3218  *									*
3219  *			Routines to handle NodeSets			*
3220  *									*
3221  ************************************************************************/
3222 
3223 /**
3224  * xmlXPathOrderDocElems:
3225  * @doc:  an input document
3226  *
3227  * Call this routine to speed up XPath computation on static documents.
3228  * This stamps all the element nodes with the document order
3229  * Like for line information, the order is kept in the element->content
3230  * field, the value stored is actually - the node number (starting at -1)
3231  * to be able to differentiate from line numbers.
3232  *
3233  * Returns the number of elements found in the document or -1 in case
3234  *    of error.
3235  */
3236 long
xmlXPathOrderDocElems(xmlDocPtr doc)3237 xmlXPathOrderDocElems(xmlDocPtr doc) {
3238     ptrdiff_t count = 0;
3239     xmlNodePtr cur;
3240 
3241     if (doc == NULL)
3242 	return(-1);
3243     cur = doc->children;
3244     while (cur != NULL) {
3245 	if (cur->type == XML_ELEMENT_NODE) {
3246 	    cur->content = (void *) (-(++count));
3247 	    if (cur->children != NULL) {
3248 		cur = cur->children;
3249 		continue;
3250 	    }
3251 	}
3252 	if (cur->next != NULL) {
3253 	    cur = cur->next;
3254 	    continue;
3255 	}
3256 	do {
3257 	    cur = cur->parent;
3258 	    if (cur == NULL)
3259 		break;
3260 	    if (cur == (xmlNodePtr) doc) {
3261 		cur = NULL;
3262 		break;
3263 	    }
3264 	    if (cur->next != NULL) {
3265 		cur = cur->next;
3266 		break;
3267 	    }
3268 	} while (cur != NULL);
3269     }
3270     return(count);
3271 }
3272 
3273 /**
3274  * xmlXPathCmpNodes:
3275  * @node1:  the first node
3276  * @node2:  the second node
3277  *
3278  * Compare two nodes w.r.t document order
3279  *
3280  * Returns -2 in case of error 1 if first point < second point, 0 if
3281  *         it's the same node, -1 otherwise
3282  */
3283 int
xmlXPathCmpNodes(xmlNodePtr node1,xmlNodePtr node2)3284 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3285     int depth1, depth2;
3286     int attr1 = 0, attr2 = 0;
3287     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3288     xmlNodePtr cur, root;
3289 
3290     if ((node1 == NULL) || (node2 == NULL))
3291 	return(-2);
3292     /*
3293      * a couple of optimizations which will avoid computations in most cases
3294      */
3295     if (node1 == node2)		/* trivial case */
3296 	return(0);
3297     if (node1->type == XML_ATTRIBUTE_NODE) {
3298 	attr1 = 1;
3299 	attrNode1 = node1;
3300 	node1 = node1->parent;
3301     }
3302     if (node2->type == XML_ATTRIBUTE_NODE) {
3303 	attr2 = 1;
3304 	attrNode2 = node2;
3305 	node2 = node2->parent;
3306     }
3307     if (node1 == node2) {
3308 	if (attr1 == attr2) {
3309 	    /* not required, but we keep attributes in order */
3310 	    if (attr1 != 0) {
3311 	        cur = attrNode2->prev;
3312 		while (cur != NULL) {
3313 		    if (cur == attrNode1)
3314 		        return (1);
3315 		    cur = cur->prev;
3316 		}
3317 		return (-1);
3318 	    }
3319 	    return(0);
3320 	}
3321 	if (attr2 == 1)
3322 	    return(1);
3323 	return(-1);
3324     }
3325     if ((node1->type == XML_NAMESPACE_DECL) ||
3326         (node2->type == XML_NAMESPACE_DECL))
3327 	return(1);
3328     if (node1 == node2->prev)
3329 	return(1);
3330     if (node1 == node2->next)
3331 	return(-1);
3332 
3333     /*
3334      * Speedup using document order if available.
3335      */
3336     if ((node1->type == XML_ELEMENT_NODE) &&
3337 	(node2->type == XML_ELEMENT_NODE) &&
3338 	(0 > (ptrdiff_t) node1->content) &&
3339 	(0 > (ptrdiff_t) node2->content) &&
3340 	(node1->doc == node2->doc)) {
3341 	ptrdiff_t l1, l2;
3342 
3343 	l1 = -((ptrdiff_t) node1->content);
3344 	l2 = -((ptrdiff_t) node2->content);
3345 	if (l1 < l2)
3346 	    return(1);
3347 	if (l1 > l2)
3348 	    return(-1);
3349     }
3350 
3351     /*
3352      * compute depth to root
3353      */
3354     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3355 	if (cur->parent == node1)
3356 	    return(1);
3357 	depth2++;
3358     }
3359     root = cur;
3360     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3361 	if (cur->parent == node2)
3362 	    return(-1);
3363 	depth1++;
3364     }
3365     /*
3366      * Distinct document (or distinct entities :-( ) case.
3367      */
3368     if (root != cur) {
3369 	return(-2);
3370     }
3371     /*
3372      * get the nearest common ancestor.
3373      */
3374     while (depth1 > depth2) {
3375 	depth1--;
3376 	node1 = node1->parent;
3377     }
3378     while (depth2 > depth1) {
3379 	depth2--;
3380 	node2 = node2->parent;
3381     }
3382     while (node1->parent != node2->parent) {
3383 	node1 = node1->parent;
3384 	node2 = node2->parent;
3385 	/* should not happen but just in case ... */
3386 	if ((node1 == NULL) || (node2 == NULL))
3387 	    return(-2);
3388     }
3389     /*
3390      * Find who's first.
3391      */
3392     if (node1 == node2->prev)
3393 	return(1);
3394     if (node1 == node2->next)
3395 	return(-1);
3396     /*
3397      * Speedup using document order if available.
3398      */
3399     if ((node1->type == XML_ELEMENT_NODE) &&
3400 	(node2->type == XML_ELEMENT_NODE) &&
3401 	(0 > (ptrdiff_t) node1->content) &&
3402 	(0 > (ptrdiff_t) node2->content) &&
3403 	(node1->doc == node2->doc)) {
3404 	ptrdiff_t l1, l2;
3405 
3406 	l1 = -((ptrdiff_t) node1->content);
3407 	l2 = -((ptrdiff_t) node2->content);
3408 	if (l1 < l2)
3409 	    return(1);
3410 	if (l1 > l2)
3411 	    return(-1);
3412     }
3413 
3414     for (cur = node1->next;cur != NULL;cur = cur->next)
3415 	if (cur == node2)
3416 	    return(1);
3417     return(-1); /* assume there is no sibling list corruption */
3418 }
3419 
3420 /**
3421  * xmlXPathNodeSetSort:
3422  * @set:  the node set
3423  *
3424  * Sort the node set in document order
3425  */
3426 void
xmlXPathNodeSetSort(xmlNodeSetPtr set)3427 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3428 #ifndef WITH_TIM_SORT
3429     int i, j, incr, len;
3430     xmlNodePtr tmp;
3431 #endif
3432 
3433     if (set == NULL)
3434 	return;
3435 
3436 #ifndef WITH_TIM_SORT
3437     /*
3438      * Use the old Shell's sort implementation to sort the node-set
3439      * Timsort ought to be quite faster
3440      */
3441     len = set->nodeNr;
3442     for (incr = len / 2; incr > 0; incr /= 2) {
3443 	for (i = incr; i < len; i++) {
3444 	    j = i - incr;
3445 	    while (j >= 0) {
3446 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3447 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
3448 			set->nodeTab[j + incr]) == -1)
3449 #else
3450 		if (xmlXPathCmpNodes(set->nodeTab[j],
3451 			set->nodeTab[j + incr]) == -1)
3452 #endif
3453 		{
3454 		    tmp = set->nodeTab[j];
3455 		    set->nodeTab[j] = set->nodeTab[j + incr];
3456 		    set->nodeTab[j + incr] = tmp;
3457 		    j -= incr;
3458 		} else
3459 		    break;
3460 	    }
3461 	}
3462     }
3463 #else /* WITH_TIM_SORT */
3464     libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3465 #endif /* WITH_TIM_SORT */
3466 }
3467 
3468 #define XML_NODESET_DEFAULT	10
3469 /**
3470  * xmlXPathNodeSetDupNs:
3471  * @node:  the parent node of the namespace XPath node
3472  * @ns:  the libxml namespace declaration node.
3473  *
3474  * Namespace node in libxml don't match the XPath semantic. In a node set
3475  * the namespace nodes are duplicated and the next pointer is set to the
3476  * parent node in the XPath semantic.
3477  *
3478  * Returns the newly created object.
3479  */
3480 static xmlNodePtr
xmlXPathNodeSetDupNs(xmlNodePtr node,xmlNsPtr ns)3481 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3482     xmlNsPtr cur;
3483 
3484     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3485 	return(NULL);
3486     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3487 	return((xmlNodePtr) ns);
3488 
3489     /*
3490      * Allocate a new Namespace and fill the fields.
3491      */
3492     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3493     if (cur == NULL) {
3494         xmlXPathErrMemory(NULL, "duplicating namespace\n");
3495 	return(NULL);
3496     }
3497     memset(cur, 0, sizeof(xmlNs));
3498     cur->type = XML_NAMESPACE_DECL;
3499     if (ns->href != NULL)
3500 	cur->href = xmlStrdup(ns->href);
3501     if (ns->prefix != NULL)
3502 	cur->prefix = xmlStrdup(ns->prefix);
3503     cur->next = (xmlNsPtr) node;
3504     return((xmlNodePtr) cur);
3505 }
3506 
3507 /**
3508  * xmlXPathNodeSetFreeNs:
3509  * @ns:  the XPath namespace node found in a nodeset.
3510  *
3511  * Namespace nodes in libxml don't match the XPath semantic. In a node set
3512  * the namespace nodes are duplicated and the next pointer is set to the
3513  * parent node in the XPath semantic. Check if such a node needs to be freed
3514  */
3515 void
xmlXPathNodeSetFreeNs(xmlNsPtr ns)3516 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3517     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3518 	return;
3519 
3520     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3521 	if (ns->href != NULL)
3522 	    xmlFree((xmlChar *)ns->href);
3523 	if (ns->prefix != NULL)
3524 	    xmlFree((xmlChar *)ns->prefix);
3525 	xmlFree(ns);
3526     }
3527 }
3528 
3529 /**
3530  * xmlXPathNodeSetCreate:
3531  * @val:  an initial xmlNodePtr, or NULL
3532  *
3533  * Create a new xmlNodeSetPtr of type double and of value @val
3534  *
3535  * Returns the newly created object.
3536  */
3537 xmlNodeSetPtr
xmlXPathNodeSetCreate(xmlNodePtr val)3538 xmlXPathNodeSetCreate(xmlNodePtr val) {
3539     xmlNodeSetPtr ret;
3540 
3541     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3542     if (ret == NULL) {
3543         xmlXPathErrMemory(NULL, "creating nodeset\n");
3544 	return(NULL);
3545     }
3546     memset(ret, 0 , sizeof(xmlNodeSet));
3547     if (val != NULL) {
3548         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3549 					     sizeof(xmlNodePtr));
3550 	if (ret->nodeTab == NULL) {
3551 	    xmlXPathErrMemory(NULL, "creating nodeset\n");
3552 	    xmlFree(ret);
3553 	    return(NULL);
3554 	}
3555 	memset(ret->nodeTab, 0 ,
3556 	       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3557         ret->nodeMax = XML_NODESET_DEFAULT;
3558 	if (val->type == XML_NAMESPACE_DECL) {
3559 	    xmlNsPtr ns = (xmlNsPtr) val;
3560             xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3561 
3562             if (nsNode == NULL) {
3563                 xmlXPathFreeNodeSet(ret);
3564                 return(NULL);
3565             }
3566 	    ret->nodeTab[ret->nodeNr++] = nsNode;
3567 	} else
3568 	    ret->nodeTab[ret->nodeNr++] = val;
3569     }
3570     return(ret);
3571 }
3572 
3573 /**
3574  * xmlXPathNodeSetContains:
3575  * @cur:  the node-set
3576  * @val:  the node
3577  *
3578  * checks whether @cur contains @val
3579  *
3580  * Returns true (1) if @cur contains @val, false (0) otherwise
3581  */
3582 int
xmlXPathNodeSetContains(xmlNodeSetPtr cur,xmlNodePtr val)3583 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3584     int i;
3585 
3586     if ((cur == NULL) || (val == NULL)) return(0);
3587     if (val->type == XML_NAMESPACE_DECL) {
3588 	for (i = 0; i < cur->nodeNr; i++) {
3589 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3590 		xmlNsPtr ns1, ns2;
3591 
3592 		ns1 = (xmlNsPtr) val;
3593 		ns2 = (xmlNsPtr) cur->nodeTab[i];
3594 		if (ns1 == ns2)
3595 		    return(1);
3596 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3597 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
3598 		    return(1);
3599 	    }
3600 	}
3601     } else {
3602 	for (i = 0; i < cur->nodeNr; i++) {
3603 	    if (cur->nodeTab[i] == val)
3604 		return(1);
3605 	}
3606     }
3607     return(0);
3608 }
3609 
3610 /**
3611  * xmlXPathNodeSetAddNs:
3612  * @cur:  the initial node set
3613  * @node:  the hosting node
3614  * @ns:  a the namespace node
3615  *
3616  * add a new namespace node to an existing NodeSet
3617  *
3618  * Returns 0 in case of success and -1 in case of error
3619  */
3620 int
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur,xmlNodePtr node,xmlNsPtr ns)3621 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3622     int i;
3623     xmlNodePtr nsNode;
3624 
3625     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3626         (ns->type != XML_NAMESPACE_DECL) ||
3627 	(node->type != XML_ELEMENT_NODE))
3628 	return(-1);
3629 
3630     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3631     /*
3632      * prevent duplicates
3633      */
3634     for (i = 0;i < cur->nodeNr;i++) {
3635         if ((cur->nodeTab[i] != NULL) &&
3636 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3637 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3638 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3639 	    return(0);
3640     }
3641 
3642     /*
3643      * grow the nodeTab if needed
3644      */
3645     if (cur->nodeMax == 0) {
3646         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3647 					     sizeof(xmlNodePtr));
3648 	if (cur->nodeTab == NULL) {
3649 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3650 	    return(-1);
3651 	}
3652 	memset(cur->nodeTab, 0 ,
3653 	       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3654         cur->nodeMax = XML_NODESET_DEFAULT;
3655     } else if (cur->nodeNr == cur->nodeMax) {
3656         xmlNodePtr *temp;
3657 
3658         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3659             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3660             return(-1);
3661         }
3662 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3663 				      sizeof(xmlNodePtr));
3664 	if (temp == NULL) {
3665 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3666 	    return(-1);
3667 	}
3668         cur->nodeMax *= 2;
3669 	cur->nodeTab = temp;
3670     }
3671     nsNode = xmlXPathNodeSetDupNs(node, ns);
3672     if(nsNode == NULL)
3673         return(-1);
3674     cur->nodeTab[cur->nodeNr++] = nsNode;
3675     return(0);
3676 }
3677 
3678 /**
3679  * xmlXPathNodeSetAdd:
3680  * @cur:  the initial node set
3681  * @val:  a new xmlNodePtr
3682  *
3683  * add a new xmlNodePtr to an existing NodeSet
3684  *
3685  * Returns 0 in case of success, and -1 in case of error
3686  */
3687 int
xmlXPathNodeSetAdd(xmlNodeSetPtr cur,xmlNodePtr val)3688 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3689     int i;
3690 
3691     if ((cur == NULL) || (val == NULL)) return(-1);
3692 
3693     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3694     /*
3695      * prevent duplicates
3696      */
3697     for (i = 0;i < cur->nodeNr;i++)
3698         if (cur->nodeTab[i] == val) return(0);
3699 
3700     /*
3701      * grow the nodeTab if needed
3702      */
3703     if (cur->nodeMax == 0) {
3704         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3705 					     sizeof(xmlNodePtr));
3706 	if (cur->nodeTab == NULL) {
3707 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3708 	    return(-1);
3709 	}
3710 	memset(cur->nodeTab, 0 ,
3711 	       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3712         cur->nodeMax = XML_NODESET_DEFAULT;
3713     } else if (cur->nodeNr == cur->nodeMax) {
3714         xmlNodePtr *temp;
3715 
3716         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3717             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3718             return(-1);
3719         }
3720 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3721 				      sizeof(xmlNodePtr));
3722 	if (temp == NULL) {
3723 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3724 	    return(-1);
3725 	}
3726         cur->nodeMax *= 2;
3727 	cur->nodeTab = temp;
3728     }
3729     if (val->type == XML_NAMESPACE_DECL) {
3730 	xmlNsPtr ns = (xmlNsPtr) val;
3731         xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3732 
3733         if (nsNode == NULL)
3734             return(-1);
3735 	cur->nodeTab[cur->nodeNr++] = nsNode;
3736     } else
3737 	cur->nodeTab[cur->nodeNr++] = val;
3738     return(0);
3739 }
3740 
3741 /**
3742  * xmlXPathNodeSetAddUnique:
3743  * @cur:  the initial node set
3744  * @val:  a new xmlNodePtr
3745  *
3746  * add a new xmlNodePtr to an existing NodeSet, optimized version
3747  * when we are sure the node is not already in the set.
3748  *
3749  * Returns 0 in case of success and -1 in case of failure
3750  */
3751 int
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur,xmlNodePtr val)3752 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3753     if ((cur == NULL) || (val == NULL)) return(-1);
3754 
3755     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3756     /*
3757      * grow the nodeTab if needed
3758      */
3759     if (cur->nodeMax == 0) {
3760         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3761 					     sizeof(xmlNodePtr));
3762 	if (cur->nodeTab == NULL) {
3763 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3764 	    return(-1);
3765 	}
3766 	memset(cur->nodeTab, 0 ,
3767 	       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3768         cur->nodeMax = XML_NODESET_DEFAULT;
3769     } else if (cur->nodeNr == cur->nodeMax) {
3770         xmlNodePtr *temp;
3771 
3772         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3773             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3774             return(-1);
3775         }
3776 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3777 				      sizeof(xmlNodePtr));
3778 	if (temp == NULL) {
3779 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3780 	    return(-1);
3781 	}
3782 	cur->nodeTab = temp;
3783         cur->nodeMax *= 2;
3784     }
3785     if (val->type == XML_NAMESPACE_DECL) {
3786 	xmlNsPtr ns = (xmlNsPtr) val;
3787         xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3788 
3789         if (nsNode == NULL)
3790             return(-1);
3791 	cur->nodeTab[cur->nodeNr++] = nsNode;
3792     } else
3793 	cur->nodeTab[cur->nodeNr++] = val;
3794     return(0);
3795 }
3796 
3797 /**
3798  * xmlXPathNodeSetMerge:
3799  * @val1:  the first NodeSet or NULL
3800  * @val2:  the second NodeSet
3801  *
3802  * Merges two nodesets, all nodes from @val2 are added to @val1
3803  * if @val1 is NULL, a new set is created and copied from @val2
3804  *
3805  * Returns @val1 once extended or NULL in case of error.
3806  *
3807  * Frees @val1 in case of error.
3808  */
3809 xmlNodeSetPtr
xmlXPathNodeSetMerge(xmlNodeSetPtr val1,xmlNodeSetPtr val2)3810 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3811     int i, j, initNr, skip;
3812     xmlNodePtr n1, n2;
3813 
3814     if (val2 == NULL) return(val1);
3815     if (val1 == NULL) {
3816 	val1 = xmlXPathNodeSetCreate(NULL);
3817         if (val1 == NULL)
3818             return (NULL);
3819     }
3820 
3821     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3822     initNr = val1->nodeNr;
3823 
3824     for (i = 0;i < val2->nodeNr;i++) {
3825 	n2 = val2->nodeTab[i];
3826 	/*
3827 	 * check against duplicates
3828 	 */
3829 	skip = 0;
3830 	for (j = 0; j < initNr; j++) {
3831 	    n1 = val1->nodeTab[j];
3832 	    if (n1 == n2) {
3833 		skip = 1;
3834 		break;
3835 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3836 		       (n2->type == XML_NAMESPACE_DECL)) {
3837 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3838 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3839 			((xmlNsPtr) n2)->prefix)))
3840 		{
3841 		    skip = 1;
3842 		    break;
3843 		}
3844 	    }
3845 	}
3846 	if (skip)
3847 	    continue;
3848 
3849 	/*
3850 	 * grow the nodeTab if needed
3851 	 */
3852 	if (val1->nodeMax == 0) {
3853 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3854 						    sizeof(xmlNodePtr));
3855 	    if (val1->nodeTab == NULL) {
3856 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3857 		goto error;
3858 	    }
3859 	    memset(val1->nodeTab, 0 ,
3860 		   XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3861 	    val1->nodeMax = XML_NODESET_DEFAULT;
3862 	} else if (val1->nodeNr == val1->nodeMax) {
3863 	    xmlNodePtr *temp;
3864 
3865             if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3866                 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3867                 goto error;
3868             }
3869 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3870 					     sizeof(xmlNodePtr));
3871 	    if (temp == NULL) {
3872 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3873 		goto error;
3874 	    }
3875 	    val1->nodeTab = temp;
3876 	    val1->nodeMax *= 2;
3877 	}
3878 	if (n2->type == XML_NAMESPACE_DECL) {
3879 	    xmlNsPtr ns = (xmlNsPtr) n2;
3880             xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3881 
3882             if (nsNode == NULL)
3883                 goto error;
3884 	    val1->nodeTab[val1->nodeNr++] = nsNode;
3885 	} else
3886 	    val1->nodeTab[val1->nodeNr++] = n2;
3887     }
3888 
3889     return(val1);
3890 
3891 error:
3892     xmlXPathFreeNodeSet(val1);
3893     return(NULL);
3894 }
3895 
3896 
3897 /**
3898  * xmlXPathNodeSetMergeAndClear:
3899  * @set1:  the first NodeSet or NULL
3900  * @set2:  the second NodeSet
3901  *
3902  * Merges two nodesets, all nodes from @set2 are added to @set1.
3903  * Checks for duplicate nodes. Clears set2.
3904  *
3905  * Returns @set1 once extended or NULL in case of error.
3906  *
3907  * Frees @set1 in case of error.
3908  */
3909 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1,xmlNodeSetPtr set2)3910 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3911 {
3912     {
3913 	int i, j, initNbSet1;
3914 	xmlNodePtr n1, n2;
3915 
3916 	initNbSet1 = set1->nodeNr;
3917 	for (i = 0;i < set2->nodeNr;i++) {
3918 	    n2 = set2->nodeTab[i];
3919 	    /*
3920 	    * Skip duplicates.
3921 	    */
3922 	    for (j = 0; j < initNbSet1; j++) {
3923 		n1 = set1->nodeTab[j];
3924 		if (n1 == n2) {
3925 		    goto skip_node;
3926 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
3927 		    (n2->type == XML_NAMESPACE_DECL))
3928 		{
3929 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3930 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
3931 			((xmlNsPtr) n2)->prefix)))
3932 		    {
3933 			/*
3934 			* Free the namespace node.
3935 			*/
3936 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3937 			goto skip_node;
3938 		    }
3939 		}
3940 	    }
3941 	    /*
3942 	    * grow the nodeTab if needed
3943 	    */
3944 	    if (set1->nodeMax == 0) {
3945 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3946 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3947 		if (set1->nodeTab == NULL) {
3948 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3949 		    goto error;
3950 		}
3951 		memset(set1->nodeTab, 0,
3952 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3953 		set1->nodeMax = XML_NODESET_DEFAULT;
3954 	    } else if (set1->nodeNr >= set1->nodeMax) {
3955 		xmlNodePtr *temp;
3956 
3957                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3958                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3959                     goto error;
3960                 }
3961 		temp = (xmlNodePtr *) xmlRealloc(
3962 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3963 		if (temp == NULL) {
3964 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3965 		    goto error;
3966 		}
3967 		set1->nodeTab = temp;
3968 		set1->nodeMax *= 2;
3969 	    }
3970 	    set1->nodeTab[set1->nodeNr++] = n2;
3971 skip_node:
3972             set2->nodeTab[i] = NULL;
3973 	}
3974     }
3975     set2->nodeNr = 0;
3976     return(set1);
3977 
3978 error:
3979     xmlXPathFreeNodeSet(set1);
3980     xmlXPathNodeSetClear(set2, 1);
3981     return(NULL);
3982 }
3983 
3984 /**
3985  * xmlXPathNodeSetMergeAndClearNoDupls:
3986  * @set1:  the first NodeSet or NULL
3987  * @set2:  the second NodeSet
3988  *
3989  * Merges two nodesets, all nodes from @set2 are added to @set1.
3990  * Doesn't check for duplicate nodes. Clears set2.
3991  *
3992  * Returns @set1 once extended or NULL in case of error.
3993  *
3994  * Frees @set1 in case of error.
3995  */
3996 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1,xmlNodeSetPtr set2)3997 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3998 {
3999     {
4000 	int i;
4001 	xmlNodePtr n2;
4002 
4003 	for (i = 0;i < set2->nodeNr;i++) {
4004 	    n2 = set2->nodeTab[i];
4005 	    if (set1->nodeMax == 0) {
4006 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4007 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4008 		if (set1->nodeTab == NULL) {
4009 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4010 		    goto error;
4011 		}
4012 		memset(set1->nodeTab, 0,
4013 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4014 		set1->nodeMax = XML_NODESET_DEFAULT;
4015 	    } else if (set1->nodeNr >= set1->nodeMax) {
4016 		xmlNodePtr *temp;
4017 
4018                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4019                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4020                     goto error;
4021                 }
4022 		temp = (xmlNodePtr *) xmlRealloc(
4023 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4024 		if (temp == NULL) {
4025 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4026 		    goto error;
4027 		}
4028 		set1->nodeTab = temp;
4029 		set1->nodeMax *= 2;
4030 	    }
4031 	    set1->nodeTab[set1->nodeNr++] = n2;
4032             set2->nodeTab[i] = NULL;
4033 	}
4034     }
4035     set2->nodeNr = 0;
4036     return(set1);
4037 
4038 error:
4039     xmlXPathFreeNodeSet(set1);
4040     xmlXPathNodeSetClear(set2, 1);
4041     return(NULL);
4042 }
4043 
4044 /**
4045  * xmlXPathNodeSetDel:
4046  * @cur:  the initial node set
4047  * @val:  an xmlNodePtr
4048  *
4049  * Removes an xmlNodePtr from an existing NodeSet
4050  */
4051 void
xmlXPathNodeSetDel(xmlNodeSetPtr cur,xmlNodePtr val)4052 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4053     int i;
4054 
4055     if (cur == NULL) return;
4056     if (val == NULL) return;
4057 
4058     /*
4059      * find node in nodeTab
4060      */
4061     for (i = 0;i < cur->nodeNr;i++)
4062         if (cur->nodeTab[i] == val) break;
4063 
4064     if (i >= cur->nodeNr) {	/* not found */
4065 #ifdef DEBUG
4066         xmlGenericError(xmlGenericErrorContext,
4067 	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4068 		val->name);
4069 #endif
4070         return;
4071     }
4072     if ((cur->nodeTab[i] != NULL) &&
4073 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4074 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4075     cur->nodeNr--;
4076     for (;i < cur->nodeNr;i++)
4077         cur->nodeTab[i] = cur->nodeTab[i + 1];
4078     cur->nodeTab[cur->nodeNr] = NULL;
4079 }
4080 
4081 /**
4082  * xmlXPathNodeSetRemove:
4083  * @cur:  the initial node set
4084  * @val:  the index to remove
4085  *
4086  * Removes an entry from an existing NodeSet list.
4087  */
4088 void
xmlXPathNodeSetRemove(xmlNodeSetPtr cur,int val)4089 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4090     if (cur == NULL) return;
4091     if (val >= cur->nodeNr) return;
4092     if ((cur->nodeTab[val] != NULL) &&
4093 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4094 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4095     cur->nodeNr--;
4096     for (;val < cur->nodeNr;val++)
4097         cur->nodeTab[val] = cur->nodeTab[val + 1];
4098     cur->nodeTab[cur->nodeNr] = NULL;
4099 }
4100 
4101 /**
4102  * xmlXPathFreeNodeSet:
4103  * @obj:  the xmlNodeSetPtr to free
4104  *
4105  * Free the NodeSet compound (not the actual nodes !).
4106  */
4107 void
xmlXPathFreeNodeSet(xmlNodeSetPtr obj)4108 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4109     if (obj == NULL) return;
4110     if (obj->nodeTab != NULL) {
4111 	int i;
4112 
4113 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
4114 	for (i = 0;i < obj->nodeNr;i++)
4115 	    if ((obj->nodeTab[i] != NULL) &&
4116 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4117 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4118 	xmlFree(obj->nodeTab);
4119     }
4120     xmlFree(obj);
4121 }
4122 
4123 /**
4124  * xmlXPathNodeSetClearFromPos:
4125  * @set: the node set to be cleared
4126  * @pos: the start position to clear from
4127  *
4128  * Clears the list from temporary XPath objects (e.g. namespace nodes
4129  * are feed) starting with the entry at @pos, but does *not* free the list
4130  * itself. Sets the length of the list to @pos.
4131  */
4132 static void
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set,int pos,int hasNsNodes)4133 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4134 {
4135     if ((set == NULL) || (pos >= set->nodeNr))
4136 	return;
4137     else if ((hasNsNodes)) {
4138 	int i;
4139 	xmlNodePtr node;
4140 
4141 	for (i = pos; i < set->nodeNr; i++) {
4142 	    node = set->nodeTab[i];
4143 	    if ((node != NULL) &&
4144 		(node->type == XML_NAMESPACE_DECL))
4145 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4146 	}
4147     }
4148     set->nodeNr = pos;
4149 }
4150 
4151 /**
4152  * xmlXPathNodeSetClear:
4153  * @set:  the node set to clear
4154  *
4155  * Clears the list from all temporary XPath objects (e.g. namespace nodes
4156  * are feed), but does *not* free the list itself. Sets the length of the
4157  * list to 0.
4158  */
4159 static void
xmlXPathNodeSetClear(xmlNodeSetPtr set,int hasNsNodes)4160 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4161 {
4162     xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4163 }
4164 
4165 /**
4166  * xmlXPathNodeSetKeepLast:
4167  * @set: the node set to be cleared
4168  *
4169  * Move the last node to the first position and clear temporary XPath objects
4170  * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4171  * to 1.
4172  */
4173 static void
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)4174 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4175 {
4176     int i;
4177     xmlNodePtr node;
4178 
4179     if ((set == NULL) || (set->nodeNr <= 1))
4180 	return;
4181     for (i = 0; i < set->nodeNr - 1; i++) {
4182         node = set->nodeTab[i];
4183         if ((node != NULL) &&
4184             (node->type == XML_NAMESPACE_DECL))
4185             xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4186     }
4187     set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4188     set->nodeNr = 1;
4189 }
4190 
4191 /**
4192  * xmlXPathFreeValueTree:
4193  * @obj:  the xmlNodeSetPtr to free
4194  *
4195  * Free the NodeSet compound and the actual tree, this is different
4196  * from xmlXPathFreeNodeSet()
4197  */
4198 static void
xmlXPathFreeValueTree(xmlNodeSetPtr obj)4199 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4200     int i;
4201 
4202     if (obj == NULL) return;
4203 
4204     if (obj->nodeTab != NULL) {
4205 	for (i = 0;i < obj->nodeNr;i++) {
4206 	    if (obj->nodeTab[i] != NULL) {
4207 		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4208 		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4209 		} else {
4210 		    xmlFreeNodeList(obj->nodeTab[i]);
4211 		}
4212 	    }
4213 	}
4214 	xmlFree(obj->nodeTab);
4215     }
4216     xmlFree(obj);
4217 }
4218 
4219 #if defined(DEBUG) || defined(DEBUG_STEP)
4220 /**
4221  * xmlGenericErrorContextNodeSet:
4222  * @output:  a FILE * for the output
4223  * @obj:  the xmlNodeSetPtr to display
4224  *
4225  * Quick display of a NodeSet
4226  */
4227 void
xmlGenericErrorContextNodeSet(FILE * output,xmlNodeSetPtr obj)4228 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4229     int i;
4230 
4231     if (output == NULL) output = xmlGenericErrorContext;
4232     if (obj == NULL)  {
4233         fprintf(output, "NodeSet == NULL !\n");
4234 	return;
4235     }
4236     if (obj->nodeNr == 0) {
4237         fprintf(output, "NodeSet is empty\n");
4238 	return;
4239     }
4240     if (obj->nodeTab == NULL) {
4241 	fprintf(output, " nodeTab == NULL !\n");
4242 	return;
4243     }
4244     for (i = 0; i < obj->nodeNr; i++) {
4245         if (obj->nodeTab[i] == NULL) {
4246 	    fprintf(output, " NULL !\n");
4247 	    return;
4248         }
4249 	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4250 	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4251 	    fprintf(output, " /");
4252 	else if (obj->nodeTab[i]->name == NULL)
4253 	    fprintf(output, " noname!");
4254 	else fprintf(output, " %s", obj->nodeTab[i]->name);
4255     }
4256     fprintf(output, "\n");
4257 }
4258 #endif
4259 
4260 /**
4261  * xmlXPathNewNodeSet:
4262  * @val:  the NodePtr value
4263  *
4264  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4265  * it with the single Node @val
4266  *
4267  * Returns the newly created object.
4268  */
4269 xmlXPathObjectPtr
xmlXPathNewNodeSet(xmlNodePtr val)4270 xmlXPathNewNodeSet(xmlNodePtr val) {
4271     xmlXPathObjectPtr ret;
4272 
4273     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4274     if (ret == NULL) {
4275         xmlXPathErrMemory(NULL, "creating nodeset\n");
4276 	return(NULL);
4277     }
4278     memset(ret, 0 , sizeof(xmlXPathObject));
4279     ret->type = XPATH_NODESET;
4280     ret->boolval = 0;
4281     /* TODO: Check memory error. */
4282     ret->nodesetval = xmlXPathNodeSetCreate(val);
4283     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4284 #ifdef XP_DEBUG_OBJ_USAGE
4285     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4286 #endif
4287     return(ret);
4288 }
4289 
4290 /**
4291  * xmlXPathNewValueTree:
4292  * @val:  the NodePtr value
4293  *
4294  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4295  * it with the tree root @val
4296  *
4297  * Returns the newly created object.
4298  */
4299 xmlXPathObjectPtr
xmlXPathNewValueTree(xmlNodePtr val)4300 xmlXPathNewValueTree(xmlNodePtr val) {
4301     xmlXPathObjectPtr ret;
4302 
4303     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4304     if (ret == NULL) {
4305         xmlXPathErrMemory(NULL, "creating result value tree\n");
4306 	return(NULL);
4307     }
4308     memset(ret, 0 , sizeof(xmlXPathObject));
4309     ret->type = XPATH_XSLT_TREE;
4310     ret->boolval = 0;
4311     ret->user = (void *) val;
4312     ret->nodesetval = xmlXPathNodeSetCreate(val);
4313 #ifdef XP_DEBUG_OBJ_USAGE
4314     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4315 #endif
4316     return(ret);
4317 }
4318 
4319 /**
4320  * xmlXPathNewNodeSetList:
4321  * @val:  an existing NodeSet
4322  *
4323  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4324  * it with the Nodeset @val
4325  *
4326  * Returns the newly created object.
4327  */
4328 xmlXPathObjectPtr
xmlXPathNewNodeSetList(xmlNodeSetPtr val)4329 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4330 {
4331     xmlXPathObjectPtr ret;
4332     int i;
4333 
4334     if (val == NULL)
4335         ret = NULL;
4336     else if (val->nodeTab == NULL)
4337         ret = xmlXPathNewNodeSet(NULL);
4338     else {
4339         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4340         if (ret) {
4341             for (i = 1; i < val->nodeNr; ++i) {
4342                 /* TODO: Propagate memory error. */
4343                 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4344 		    < 0) break;
4345 	    }
4346 	}
4347     }
4348 
4349     return (ret);
4350 }
4351 
4352 /**
4353  * xmlXPathWrapNodeSet:
4354  * @val:  the NodePtr value
4355  *
4356  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4357  *
4358  * Returns the newly created object.
4359  *
4360  * In case of error the node set is destroyed and NULL is returned.
4361  */
4362 xmlXPathObjectPtr
xmlXPathWrapNodeSet(xmlNodeSetPtr val)4363 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4364     xmlXPathObjectPtr ret;
4365 
4366     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4367     if (ret == NULL) {
4368         xmlXPathErrMemory(NULL, "creating node set object\n");
4369         xmlXPathFreeNodeSet(val);
4370 	return(NULL);
4371     }
4372     memset(ret, 0 , sizeof(xmlXPathObject));
4373     ret->type = XPATH_NODESET;
4374     ret->nodesetval = val;
4375 #ifdef XP_DEBUG_OBJ_USAGE
4376     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4377 #endif
4378     return(ret);
4379 }
4380 
4381 /**
4382  * xmlXPathFreeNodeSetList:
4383  * @obj:  an existing NodeSetList object
4384  *
4385  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4386  * the list contrary to xmlXPathFreeObject().
4387  */
4388 void
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj)4389 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4390     if (obj == NULL) return;
4391 #ifdef XP_DEBUG_OBJ_USAGE
4392     xmlXPathDebugObjUsageReleased(NULL, obj->type);
4393 #endif
4394     xmlFree(obj);
4395 }
4396 
4397 /**
4398  * xmlXPathDifference:
4399  * @nodes1:  a node-set
4400  * @nodes2:  a node-set
4401  *
4402  * Implements the EXSLT - Sets difference() function:
4403  *    node-set set:difference (node-set, node-set)
4404  *
4405  * Returns the difference between the two node sets, or nodes1 if
4406  *         nodes2 is empty
4407  */
4408 xmlNodeSetPtr
xmlXPathDifference(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4409 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4410     xmlNodeSetPtr ret;
4411     int i, l1;
4412     xmlNodePtr cur;
4413 
4414     if (xmlXPathNodeSetIsEmpty(nodes2))
4415 	return(nodes1);
4416 
4417     /* TODO: Check memory error. */
4418     ret = xmlXPathNodeSetCreate(NULL);
4419     if (xmlXPathNodeSetIsEmpty(nodes1))
4420 	return(ret);
4421 
4422     l1 = xmlXPathNodeSetGetLength(nodes1);
4423 
4424     for (i = 0; i < l1; i++) {
4425 	cur = xmlXPathNodeSetItem(nodes1, i);
4426 	if (!xmlXPathNodeSetContains(nodes2, cur)) {
4427             /* TODO: Propagate memory error. */
4428 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4429 	        break;
4430 	}
4431     }
4432     return(ret);
4433 }
4434 
4435 /**
4436  * xmlXPathIntersection:
4437  * @nodes1:  a node-set
4438  * @nodes2:  a node-set
4439  *
4440  * Implements the EXSLT - Sets intersection() function:
4441  *    node-set set:intersection (node-set, node-set)
4442  *
4443  * Returns a node set comprising the nodes that are within both the
4444  *         node sets passed as arguments
4445  */
4446 xmlNodeSetPtr
xmlXPathIntersection(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4447 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4448     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4449     int i, l1;
4450     xmlNodePtr cur;
4451 
4452     if (ret == NULL)
4453         return(ret);
4454     if (xmlXPathNodeSetIsEmpty(nodes1))
4455 	return(ret);
4456     if (xmlXPathNodeSetIsEmpty(nodes2))
4457 	return(ret);
4458 
4459     l1 = xmlXPathNodeSetGetLength(nodes1);
4460 
4461     for (i = 0; i < l1; i++) {
4462 	cur = xmlXPathNodeSetItem(nodes1, i);
4463 	if (xmlXPathNodeSetContains(nodes2, cur)) {
4464             /* TODO: Propagate memory error. */
4465 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4466 	        break;
4467 	}
4468     }
4469     return(ret);
4470 }
4471 
4472 /**
4473  * xmlXPathDistinctSorted:
4474  * @nodes:  a node-set, sorted by document order
4475  *
4476  * Implements the EXSLT - Sets distinct() function:
4477  *    node-set set:distinct (node-set)
4478  *
4479  * Returns a subset of the nodes contained in @nodes, or @nodes if
4480  *         it is empty
4481  */
4482 xmlNodeSetPtr
xmlXPathDistinctSorted(xmlNodeSetPtr nodes)4483 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4484     xmlNodeSetPtr ret;
4485     xmlHashTablePtr hash;
4486     int i, l;
4487     xmlChar * strval;
4488     xmlNodePtr cur;
4489 
4490     if (xmlXPathNodeSetIsEmpty(nodes))
4491 	return(nodes);
4492 
4493     ret = xmlXPathNodeSetCreate(NULL);
4494     if (ret == NULL)
4495         return(ret);
4496     l = xmlXPathNodeSetGetLength(nodes);
4497     hash = xmlHashCreate (l);
4498     for (i = 0; i < l; i++) {
4499 	cur = xmlXPathNodeSetItem(nodes, i);
4500 	strval = xmlXPathCastNodeToString(cur);
4501 	if (xmlHashLookup(hash, strval) == NULL) {
4502 	    if (xmlHashAddEntry(hash, strval, strval) < 0) {
4503                 xmlFree(strval);
4504                 goto error;
4505             }
4506 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4507 	        goto error;
4508 	} else {
4509 	    xmlFree(strval);
4510 	}
4511     }
4512     xmlHashFree(hash, xmlHashDefaultDeallocator);
4513     return(ret);
4514 
4515 error:
4516     xmlHashFree(hash, xmlHashDefaultDeallocator);
4517     xmlXPathFreeNodeSet(ret);
4518     return(NULL);
4519 }
4520 
4521 /**
4522  * xmlXPathDistinct:
4523  * @nodes:  a node-set
4524  *
4525  * Implements the EXSLT - Sets distinct() function:
4526  *    node-set set:distinct (node-set)
4527  * @nodes is sorted by document order, then #exslSetsDistinctSorted
4528  * is called with the sorted node-set
4529  *
4530  * Returns a subset of the nodes contained in @nodes, or @nodes if
4531  *         it is empty
4532  */
4533 xmlNodeSetPtr
xmlXPathDistinct(xmlNodeSetPtr nodes)4534 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4535     if (xmlXPathNodeSetIsEmpty(nodes))
4536 	return(nodes);
4537 
4538     xmlXPathNodeSetSort(nodes);
4539     return(xmlXPathDistinctSorted(nodes));
4540 }
4541 
4542 /**
4543  * xmlXPathHasSameNodes:
4544  * @nodes1:  a node-set
4545  * @nodes2:  a node-set
4546  *
4547  * Implements the EXSLT - Sets has-same-nodes function:
4548  *    boolean set:has-same-node(node-set, node-set)
4549  *
4550  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4551  *         otherwise
4552  */
4553 int
xmlXPathHasSameNodes(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4554 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4555     int i, l;
4556     xmlNodePtr cur;
4557 
4558     if (xmlXPathNodeSetIsEmpty(nodes1) ||
4559 	xmlXPathNodeSetIsEmpty(nodes2))
4560 	return(0);
4561 
4562     l = xmlXPathNodeSetGetLength(nodes1);
4563     for (i = 0; i < l; i++) {
4564 	cur = xmlXPathNodeSetItem(nodes1, i);
4565 	if (xmlXPathNodeSetContains(nodes2, cur))
4566 	    return(1);
4567     }
4568     return(0);
4569 }
4570 
4571 /**
4572  * xmlXPathNodeLeadingSorted:
4573  * @nodes: a node-set, sorted by document order
4574  * @node: a node
4575  *
4576  * Implements the EXSLT - Sets leading() function:
4577  *    node-set set:leading (node-set, node-set)
4578  *
4579  * Returns the nodes in @nodes that precede @node in document order,
4580  *         @nodes if @node is NULL or an empty node-set if @nodes
4581  *         doesn't contain @node
4582  */
4583 xmlNodeSetPtr
xmlXPathNodeLeadingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4584 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4585     int i, l;
4586     xmlNodePtr cur;
4587     xmlNodeSetPtr ret;
4588 
4589     if (node == NULL)
4590 	return(nodes);
4591 
4592     ret = xmlXPathNodeSetCreate(NULL);
4593     if (ret == NULL)
4594         return(ret);
4595     if (xmlXPathNodeSetIsEmpty(nodes) ||
4596 	(!xmlXPathNodeSetContains(nodes, node)))
4597 	return(ret);
4598 
4599     l = xmlXPathNodeSetGetLength(nodes);
4600     for (i = 0; i < l; i++) {
4601 	cur = xmlXPathNodeSetItem(nodes, i);
4602 	if (cur == node)
4603 	    break;
4604         /* TODO: Propagate memory error. */
4605 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4606 	    break;
4607     }
4608     return(ret);
4609 }
4610 
4611 /**
4612  * xmlXPathNodeLeading:
4613  * @nodes:  a node-set
4614  * @node:  a node
4615  *
4616  * Implements the EXSLT - Sets leading() function:
4617  *    node-set set:leading (node-set, node-set)
4618  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4619  * is called.
4620  *
4621  * Returns the nodes in @nodes that precede @node in document order,
4622  *         @nodes if @node is NULL or an empty node-set if @nodes
4623  *         doesn't contain @node
4624  */
4625 xmlNodeSetPtr
xmlXPathNodeLeading(xmlNodeSetPtr nodes,xmlNodePtr node)4626 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4627     xmlXPathNodeSetSort(nodes);
4628     return(xmlXPathNodeLeadingSorted(nodes, node));
4629 }
4630 
4631 /**
4632  * xmlXPathLeadingSorted:
4633  * @nodes1:  a node-set, sorted by document order
4634  * @nodes2:  a node-set, sorted by document order
4635  *
4636  * Implements the EXSLT - Sets leading() function:
4637  *    node-set set:leading (node-set, node-set)
4638  *
4639  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4640  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4641  *         an empty node-set if @nodes1 doesn't contain @nodes2
4642  */
4643 xmlNodeSetPtr
xmlXPathLeadingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4644 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4645     if (xmlXPathNodeSetIsEmpty(nodes2))
4646 	return(nodes1);
4647     return(xmlXPathNodeLeadingSorted(nodes1,
4648 				     xmlXPathNodeSetItem(nodes2, 1)));
4649 }
4650 
4651 /**
4652  * xmlXPathLeading:
4653  * @nodes1:  a node-set
4654  * @nodes2:  a node-set
4655  *
4656  * Implements the EXSLT - Sets leading() function:
4657  *    node-set set:leading (node-set, node-set)
4658  * @nodes1 and @nodes2 are sorted by document order, then
4659  * #exslSetsLeadingSorted is called.
4660  *
4661  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4662  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4663  *         an empty node-set if @nodes1 doesn't contain @nodes2
4664  */
4665 xmlNodeSetPtr
xmlXPathLeading(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4666 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4667     if (xmlXPathNodeSetIsEmpty(nodes2))
4668 	return(nodes1);
4669     if (xmlXPathNodeSetIsEmpty(nodes1))
4670 	return(xmlXPathNodeSetCreate(NULL));
4671     xmlXPathNodeSetSort(nodes1);
4672     xmlXPathNodeSetSort(nodes2);
4673     return(xmlXPathNodeLeadingSorted(nodes1,
4674 				     xmlXPathNodeSetItem(nodes2, 1)));
4675 }
4676 
4677 /**
4678  * xmlXPathNodeTrailingSorted:
4679  * @nodes: a node-set, sorted by document order
4680  * @node: a node
4681  *
4682  * Implements the EXSLT - Sets trailing() function:
4683  *    node-set set:trailing (node-set, node-set)
4684  *
4685  * Returns the nodes in @nodes that follow @node in document order,
4686  *         @nodes if @node is NULL or an empty node-set if @nodes
4687  *         doesn't contain @node
4688  */
4689 xmlNodeSetPtr
xmlXPathNodeTrailingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4690 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4691     int i, l;
4692     xmlNodePtr cur;
4693     xmlNodeSetPtr ret;
4694 
4695     if (node == NULL)
4696 	return(nodes);
4697 
4698     ret = xmlXPathNodeSetCreate(NULL);
4699     if (ret == NULL)
4700         return(ret);
4701     if (xmlXPathNodeSetIsEmpty(nodes) ||
4702 	(!xmlXPathNodeSetContains(nodes, node)))
4703 	return(ret);
4704 
4705     l = xmlXPathNodeSetGetLength(nodes);
4706     for (i = l - 1; i >= 0; i--) {
4707 	cur = xmlXPathNodeSetItem(nodes, i);
4708 	if (cur == node)
4709 	    break;
4710         /* TODO: Propagate memory error. */
4711 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4712 	    break;
4713     }
4714     xmlXPathNodeSetSort(ret);	/* bug 413451 */
4715     return(ret);
4716 }
4717 
4718 /**
4719  * xmlXPathNodeTrailing:
4720  * @nodes:  a node-set
4721  * @node:  a node
4722  *
4723  * Implements the EXSLT - Sets trailing() function:
4724  *    node-set set:trailing (node-set, node-set)
4725  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4726  * is called.
4727  *
4728  * Returns the nodes in @nodes that follow @node in document order,
4729  *         @nodes if @node is NULL or an empty node-set if @nodes
4730  *         doesn't contain @node
4731  */
4732 xmlNodeSetPtr
xmlXPathNodeTrailing(xmlNodeSetPtr nodes,xmlNodePtr node)4733 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4734     xmlXPathNodeSetSort(nodes);
4735     return(xmlXPathNodeTrailingSorted(nodes, node));
4736 }
4737 
4738 /**
4739  * xmlXPathTrailingSorted:
4740  * @nodes1:  a node-set, sorted by document order
4741  * @nodes2:  a node-set, sorted by document order
4742  *
4743  * Implements the EXSLT - Sets trailing() function:
4744  *    node-set set:trailing (node-set, node-set)
4745  *
4746  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4747  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4748  *         an empty node-set if @nodes1 doesn't contain @nodes2
4749  */
4750 xmlNodeSetPtr
xmlXPathTrailingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4751 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4752     if (xmlXPathNodeSetIsEmpty(nodes2))
4753 	return(nodes1);
4754     return(xmlXPathNodeTrailingSorted(nodes1,
4755 				      xmlXPathNodeSetItem(nodes2, 0)));
4756 }
4757 
4758 /**
4759  * xmlXPathTrailing:
4760  * @nodes1:  a node-set
4761  * @nodes2:  a node-set
4762  *
4763  * Implements the EXSLT - Sets trailing() function:
4764  *    node-set set:trailing (node-set, node-set)
4765  * @nodes1 and @nodes2 are sorted by document order, then
4766  * #xmlXPathTrailingSorted is called.
4767  *
4768  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4769  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4770  *         an empty node-set if @nodes1 doesn't contain @nodes2
4771  */
4772 xmlNodeSetPtr
xmlXPathTrailing(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4773 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4774     if (xmlXPathNodeSetIsEmpty(nodes2))
4775 	return(nodes1);
4776     if (xmlXPathNodeSetIsEmpty(nodes1))
4777 	return(xmlXPathNodeSetCreate(NULL));
4778     xmlXPathNodeSetSort(nodes1);
4779     xmlXPathNodeSetSort(nodes2);
4780     return(xmlXPathNodeTrailingSorted(nodes1,
4781 				      xmlXPathNodeSetItem(nodes2, 0)));
4782 }
4783 
4784 /************************************************************************
4785  *									*
4786  *		Routines to handle extra functions			*
4787  *									*
4788  ************************************************************************/
4789 
4790 /**
4791  * xmlXPathRegisterFunc:
4792  * @ctxt:  the XPath context
4793  * @name:  the function name
4794  * @f:  the function implementation or NULL
4795  *
4796  * Register a new function. If @f is NULL it unregisters the function
4797  *
4798  * Returns 0 in case of success, -1 in case of error
4799  */
4800 int
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathFunction f)4801 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4802 		     xmlXPathFunction f) {
4803     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4804 }
4805 
4806 /**
4807  * xmlXPathRegisterFuncNS:
4808  * @ctxt:  the XPath context
4809  * @name:  the function name
4810  * @ns_uri:  the function namespace URI
4811  * @f:  the function implementation or NULL
4812  *
4813  * Register a new function. If @f is NULL it unregisters the function
4814  *
4815  * Returns 0 in case of success, -1 in case of error
4816  */
4817 int
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathFunction f)4818 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4819 		       const xmlChar *ns_uri, xmlXPathFunction f) {
4820     if (ctxt == NULL)
4821 	return(-1);
4822     if (name == NULL)
4823 	return(-1);
4824 
4825     if (ctxt->funcHash == NULL)
4826 	ctxt->funcHash = xmlHashCreate(0);
4827     if (ctxt->funcHash == NULL)
4828 	return(-1);
4829     if (f == NULL)
4830         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4831 XML_IGNORE_FPTR_CAST_WARNINGS
4832     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4833 XML_POP_WARNINGS
4834 }
4835 
4836 /**
4837  * xmlXPathRegisterFuncLookup:
4838  * @ctxt:  the XPath context
4839  * @f:  the lookup function
4840  * @funcCtxt:  the lookup data
4841  *
4842  * Registers an external mechanism to do function lookup.
4843  */
4844 void
xmlXPathRegisterFuncLookup(xmlXPathContextPtr ctxt,xmlXPathFuncLookupFunc f,void * funcCtxt)4845 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4846 			    xmlXPathFuncLookupFunc f,
4847 			    void *funcCtxt) {
4848     if (ctxt == NULL)
4849 	return;
4850     ctxt->funcLookupFunc = f;
4851     ctxt->funcLookupData = funcCtxt;
4852 }
4853 
4854 /**
4855  * xmlXPathFunctionLookup:
4856  * @ctxt:  the XPath context
4857  * @name:  the function name
4858  *
4859  * Search in the Function array of the context for the given
4860  * function.
4861  *
4862  * Returns the xmlXPathFunction or NULL if not found
4863  */
4864 xmlXPathFunction
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt,const xmlChar * name)4865 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4866     if (ctxt == NULL)
4867 	return (NULL);
4868 
4869     if (ctxt->funcLookupFunc != NULL) {
4870 	xmlXPathFunction ret;
4871 	xmlXPathFuncLookupFunc f;
4872 
4873 	f = ctxt->funcLookupFunc;
4874 	ret = f(ctxt->funcLookupData, name, NULL);
4875 	if (ret != NULL)
4876 	    return(ret);
4877     }
4878     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4879 }
4880 
4881 /**
4882  * xmlXPathFunctionLookupNS:
4883  * @ctxt:  the XPath context
4884  * @name:  the function name
4885  * @ns_uri:  the function namespace URI
4886  *
4887  * Search in the Function array of the context for the given
4888  * function.
4889  *
4890  * Returns the xmlXPathFunction or NULL if not found
4891  */
4892 xmlXPathFunction
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4893 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4894 			 const xmlChar *ns_uri) {
4895     xmlXPathFunction ret;
4896 
4897     if (ctxt == NULL)
4898 	return(NULL);
4899     if (name == NULL)
4900 	return(NULL);
4901 
4902     if (ctxt->funcLookupFunc != NULL) {
4903 	xmlXPathFuncLookupFunc f;
4904 
4905 	f = ctxt->funcLookupFunc;
4906 	ret = f(ctxt->funcLookupData, name, ns_uri);
4907 	if (ret != NULL)
4908 	    return(ret);
4909     }
4910 
4911     if (ctxt->funcHash == NULL)
4912 	return(NULL);
4913 
4914 XML_IGNORE_FPTR_CAST_WARNINGS
4915     ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4916 XML_POP_WARNINGS
4917     return(ret);
4918 }
4919 
4920 /**
4921  * xmlXPathRegisteredFuncsCleanup:
4922  * @ctxt:  the XPath context
4923  *
4924  * Cleanup the XPath context data associated to registered functions
4925  */
4926 void
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt)4927 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4928     if (ctxt == NULL)
4929 	return;
4930 
4931     xmlHashFree(ctxt->funcHash, NULL);
4932     ctxt->funcHash = NULL;
4933 }
4934 
4935 /************************************************************************
4936  *									*
4937  *			Routines to handle Variables			*
4938  *									*
4939  ************************************************************************/
4940 
4941 /**
4942  * xmlXPathRegisterVariable:
4943  * @ctxt:  the XPath context
4944  * @name:  the variable name
4945  * @value:  the variable value or NULL
4946  *
4947  * Register a new variable value. If @value is NULL it unregisters
4948  * the variable
4949  *
4950  * Returns 0 in case of success, -1 in case of error
4951  */
4952 int
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathObjectPtr value)4953 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4954 			 xmlXPathObjectPtr value) {
4955     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4956 }
4957 
4958 /**
4959  * xmlXPathRegisterVariableNS:
4960  * @ctxt:  the XPath context
4961  * @name:  the variable name
4962  * @ns_uri:  the variable namespace URI
4963  * @value:  the variable value or NULL
4964  *
4965  * Register a new variable value. If @value is NULL it unregisters
4966  * the variable
4967  *
4968  * Returns 0 in case of success, -1 in case of error
4969  */
4970 int
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathObjectPtr value)4971 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4972 			   const xmlChar *ns_uri,
4973 			   xmlXPathObjectPtr value) {
4974     if (ctxt == NULL)
4975 	return(-1);
4976     if (name == NULL)
4977 	return(-1);
4978 
4979     if (ctxt->varHash == NULL)
4980 	ctxt->varHash = xmlHashCreate(0);
4981     if (ctxt->varHash == NULL)
4982 	return(-1);
4983     if (value == NULL)
4984         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4985 	                           xmlXPathFreeObjectEntry));
4986     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4987 			       (void *) value, xmlXPathFreeObjectEntry));
4988 }
4989 
4990 /**
4991  * xmlXPathRegisterVariableLookup:
4992  * @ctxt:  the XPath context
4993  * @f:  the lookup function
4994  * @data:  the lookup data
4995  *
4996  * register an external mechanism to do variable lookup
4997  */
4998 void
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,xmlXPathVariableLookupFunc f,void * data)4999 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5000 	 xmlXPathVariableLookupFunc f, void *data) {
5001     if (ctxt == NULL)
5002 	return;
5003     ctxt->varLookupFunc = f;
5004     ctxt->varLookupData = data;
5005 }
5006 
5007 /**
5008  * xmlXPathVariableLookup:
5009  * @ctxt:  the XPath context
5010  * @name:  the variable name
5011  *
5012  * Search in the Variable array of the context for the given
5013  * variable value.
5014  *
5015  * Returns a copy of the value or NULL if not found
5016  */
5017 xmlXPathObjectPtr
xmlXPathVariableLookup(xmlXPathContextPtr ctxt,const xmlChar * name)5018 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5019     if (ctxt == NULL)
5020 	return(NULL);
5021 
5022     if (ctxt->varLookupFunc != NULL) {
5023 	xmlXPathObjectPtr ret;
5024 
5025 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5026 	        (ctxt->varLookupData, name, NULL);
5027 	return(ret);
5028     }
5029     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5030 }
5031 
5032 /**
5033  * xmlXPathVariableLookupNS:
5034  * @ctxt:  the XPath context
5035  * @name:  the variable name
5036  * @ns_uri:  the variable namespace URI
5037  *
5038  * Search in the Variable array of the context for the given
5039  * variable value.
5040  *
5041  * Returns the a copy of the value or NULL if not found
5042  */
5043 xmlXPathObjectPtr
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)5044 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5045 			 const xmlChar *ns_uri) {
5046     if (ctxt == NULL)
5047 	return(NULL);
5048 
5049     if (ctxt->varLookupFunc != NULL) {
5050 	xmlXPathObjectPtr ret;
5051 
5052 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5053 	        (ctxt->varLookupData, name, ns_uri);
5054 	if (ret != NULL) return(ret);
5055     }
5056 
5057     if (ctxt->varHash == NULL)
5058 	return(NULL);
5059     if (name == NULL)
5060 	return(NULL);
5061 
5062     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5063 		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5064 }
5065 
5066 /**
5067  * xmlXPathRegisteredVariablesCleanup:
5068  * @ctxt:  the XPath context
5069  *
5070  * Cleanup the XPath context data associated to registered variables
5071  */
5072 void
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt)5073 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5074     if (ctxt == NULL)
5075 	return;
5076 
5077     xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5078     ctxt->varHash = NULL;
5079 }
5080 
5081 /**
5082  * xmlXPathRegisterNs:
5083  * @ctxt:  the XPath context
5084  * @prefix:  the namespace prefix cannot be NULL or empty string
5085  * @ns_uri:  the namespace name
5086  *
5087  * Register a new namespace. If @ns_uri is NULL it unregisters
5088  * the namespace
5089  *
5090  * Returns 0 in case of success, -1 in case of error
5091  */
5092 int
xmlXPathRegisterNs(xmlXPathContextPtr ctxt,const xmlChar * prefix,const xmlChar * ns_uri)5093 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5094 			   const xmlChar *ns_uri) {
5095     xmlChar *copy;
5096 
5097     if (ctxt == NULL)
5098 	return(-1);
5099     if (prefix == NULL)
5100 	return(-1);
5101     if (prefix[0] == 0)
5102 	return(-1);
5103 
5104     if (ctxt->nsHash == NULL)
5105 	ctxt->nsHash = xmlHashCreate(10);
5106     if (ctxt->nsHash == NULL)
5107 	return(-1);
5108     if (ns_uri == NULL)
5109         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5110 	                          xmlHashDefaultDeallocator));
5111 
5112     copy = xmlStrdup(ns_uri);
5113     if (copy == NULL)
5114         return(-1);
5115     if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
5116                            xmlHashDefaultDeallocator) < 0) {
5117         xmlFree(copy);
5118         return(-1);
5119     }
5120 
5121     return(0);
5122 }
5123 
5124 /**
5125  * xmlXPathNsLookup:
5126  * @ctxt:  the XPath context
5127  * @prefix:  the namespace prefix value
5128  *
5129  * Search in the namespace declaration array of the context for the given
5130  * namespace name associated to the given prefix
5131  *
5132  * Returns the value or NULL if not found
5133  */
5134 const xmlChar *
xmlXPathNsLookup(xmlXPathContextPtr ctxt,const xmlChar * prefix)5135 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5136     if (ctxt == NULL)
5137 	return(NULL);
5138     if (prefix == NULL)
5139 	return(NULL);
5140 
5141 #ifdef XML_XML_NAMESPACE
5142     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5143 	return(XML_XML_NAMESPACE);
5144 #endif
5145 
5146     if (ctxt->namespaces != NULL) {
5147 	int i;
5148 
5149 	for (i = 0;i < ctxt->nsNr;i++) {
5150 	    if ((ctxt->namespaces[i] != NULL) &&
5151 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5152 		return(ctxt->namespaces[i]->href);
5153 	}
5154     }
5155 
5156     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5157 }
5158 
5159 /**
5160  * xmlXPathRegisteredNsCleanup:
5161  * @ctxt:  the XPath context
5162  *
5163  * Cleanup the XPath context data associated to registered variables
5164  */
5165 void
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt)5166 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5167     if (ctxt == NULL)
5168 	return;
5169 
5170     xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5171     ctxt->nsHash = NULL;
5172 }
5173 
5174 /************************************************************************
5175  *									*
5176  *			Routines to handle Values			*
5177  *									*
5178  ************************************************************************/
5179 
5180 /* Allocations are terrible, one needs to optimize all this !!! */
5181 
5182 /**
5183  * xmlXPathNewFloat:
5184  * @val:  the double value
5185  *
5186  * Create a new xmlXPathObjectPtr of type double and of value @val
5187  *
5188  * Returns the newly created object.
5189  */
5190 xmlXPathObjectPtr
xmlXPathNewFloat(double val)5191 xmlXPathNewFloat(double val) {
5192     xmlXPathObjectPtr ret;
5193 
5194     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5195     if (ret == NULL) {
5196         xmlXPathErrMemory(NULL, "creating float object\n");
5197 	return(NULL);
5198     }
5199     memset(ret, 0 , sizeof(xmlXPathObject));
5200     ret->type = XPATH_NUMBER;
5201     ret->floatval = val;
5202 #ifdef XP_DEBUG_OBJ_USAGE
5203     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5204 #endif
5205     return(ret);
5206 }
5207 
5208 /**
5209  * xmlXPathNewBoolean:
5210  * @val:  the boolean value
5211  *
5212  * Create a new xmlXPathObjectPtr of type boolean and of value @val
5213  *
5214  * Returns the newly created object.
5215  */
5216 xmlXPathObjectPtr
xmlXPathNewBoolean(int val)5217 xmlXPathNewBoolean(int val) {
5218     xmlXPathObjectPtr ret;
5219 
5220     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5221     if (ret == NULL) {
5222         xmlXPathErrMemory(NULL, "creating boolean object\n");
5223 	return(NULL);
5224     }
5225     memset(ret, 0 , sizeof(xmlXPathObject));
5226     ret->type = XPATH_BOOLEAN;
5227     ret->boolval = (val != 0);
5228 #ifdef XP_DEBUG_OBJ_USAGE
5229     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5230 #endif
5231     return(ret);
5232 }
5233 
5234 /**
5235  * xmlXPathNewString:
5236  * @val:  the xmlChar * value
5237  *
5238  * Create a new xmlXPathObjectPtr of type string and of value @val
5239  *
5240  * Returns the newly created object.
5241  */
5242 xmlXPathObjectPtr
xmlXPathNewString(const xmlChar * val)5243 xmlXPathNewString(const xmlChar *val) {
5244     xmlXPathObjectPtr ret;
5245 
5246     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5247     if (ret == NULL) {
5248         xmlXPathErrMemory(NULL, "creating string object\n");
5249 	return(NULL);
5250     }
5251     memset(ret, 0 , sizeof(xmlXPathObject));
5252     ret->type = XPATH_STRING;
5253     if (val == NULL)
5254         val = BAD_CAST "";
5255     ret->stringval = xmlStrdup(val);
5256     if (ret->stringval == NULL) {
5257         xmlFree(ret);
5258         return(NULL);
5259     }
5260 #ifdef XP_DEBUG_OBJ_USAGE
5261     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5262 #endif
5263     return(ret);
5264 }
5265 
5266 /**
5267  * xmlXPathWrapString:
5268  * @val:  the xmlChar * value
5269  *
5270  * Wraps the @val string into an XPath object.
5271  *
5272  * Returns the newly created object.
5273  *
5274  * Frees @val in case of error.
5275  */
5276 xmlXPathObjectPtr
xmlXPathWrapString(xmlChar * val)5277 xmlXPathWrapString (xmlChar *val) {
5278     xmlXPathObjectPtr ret;
5279 
5280     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5281     if (ret == NULL) {
5282         xmlXPathErrMemory(NULL, "creating string object\n");
5283         xmlFree(val);
5284 	return(NULL);
5285     }
5286     memset(ret, 0 , sizeof(xmlXPathObject));
5287     ret->type = XPATH_STRING;
5288     ret->stringval = val;
5289 #ifdef XP_DEBUG_OBJ_USAGE
5290     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5291 #endif
5292     return(ret);
5293 }
5294 
5295 /**
5296  * xmlXPathNewCString:
5297  * @val:  the char * value
5298  *
5299  * Create a new xmlXPathObjectPtr of type string and of value @val
5300  *
5301  * Returns the newly created object.
5302  */
5303 xmlXPathObjectPtr
xmlXPathNewCString(const char * val)5304 xmlXPathNewCString(const char *val) {
5305     return(xmlXPathNewString(BAD_CAST val));
5306 }
5307 
5308 /**
5309  * xmlXPathWrapCString:
5310  * @val:  the char * value
5311  *
5312  * Wraps a string into an XPath object.
5313  *
5314  * Returns the newly created object.
5315  */
5316 xmlXPathObjectPtr
xmlXPathWrapCString(char * val)5317 xmlXPathWrapCString (char * val) {
5318     return(xmlXPathWrapString((xmlChar *)(val)));
5319 }
5320 
5321 /**
5322  * xmlXPathWrapExternal:
5323  * @val:  the user data
5324  *
5325  * Wraps the @val data into an XPath object.
5326  *
5327  * Returns the newly created object.
5328  */
5329 xmlXPathObjectPtr
xmlXPathWrapExternal(void * val)5330 xmlXPathWrapExternal (void *val) {
5331     xmlXPathObjectPtr ret;
5332 
5333     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5334     if (ret == NULL) {
5335         xmlXPathErrMemory(NULL, "creating user object\n");
5336 	return(NULL);
5337     }
5338     memset(ret, 0 , sizeof(xmlXPathObject));
5339     ret->type = XPATH_USERS;
5340     ret->user = val;
5341 #ifdef XP_DEBUG_OBJ_USAGE
5342     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5343 #endif
5344     return(ret);
5345 }
5346 
5347 /**
5348  * xmlXPathObjectCopy:
5349  * @val:  the original object
5350  *
5351  * allocate a new copy of a given object
5352  *
5353  * Returns the newly created object.
5354  */
5355 xmlXPathObjectPtr
xmlXPathObjectCopy(xmlXPathObjectPtr val)5356 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5357     xmlXPathObjectPtr ret;
5358 
5359     if (val == NULL)
5360 	return(NULL);
5361 
5362     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5363     if (ret == NULL) {
5364         xmlXPathErrMemory(NULL, "copying object\n");
5365 	return(NULL);
5366     }
5367     memcpy(ret, val , sizeof(xmlXPathObject));
5368 #ifdef XP_DEBUG_OBJ_USAGE
5369     xmlXPathDebugObjUsageRequested(NULL, val->type);
5370 #endif
5371     switch (val->type) {
5372 	case XPATH_BOOLEAN:
5373 	case XPATH_NUMBER:
5374 #ifdef LIBXML_XPTR_LOCS_ENABLED
5375 	case XPATH_POINT:
5376 	case XPATH_RANGE:
5377 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5378 	    break;
5379 	case XPATH_STRING:
5380 	    ret->stringval = xmlStrdup(val->stringval);
5381             if (ret->stringval == NULL) {
5382                 xmlFree(ret);
5383                 return(NULL);
5384             }
5385 	    break;
5386 	case XPATH_XSLT_TREE:
5387 #if 0
5388 /*
5389   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5390   this previous handling is no longer correct, and can cause some serious
5391   problems (ref. bug 145547)
5392 */
5393 	    if ((val->nodesetval != NULL) &&
5394 		(val->nodesetval->nodeTab != NULL)) {
5395 		xmlNodePtr cur, tmp;
5396 		xmlDocPtr top;
5397 
5398 		ret->boolval = 1;
5399 		top =  xmlNewDoc(NULL);
5400 		top->name = (char *)
5401 		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
5402 		ret->user = top;
5403 		if (top != NULL) {
5404 		    top->doc = top;
5405 		    cur = val->nodesetval->nodeTab[0]->children;
5406 		    while (cur != NULL) {
5407 			tmp = xmlDocCopyNode(cur, top, 1);
5408 			xmlAddChild((xmlNodePtr) top, tmp);
5409 			cur = cur->next;
5410 		    }
5411 		}
5412 
5413 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5414 	    } else
5415 		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5416 	    /* Deallocate the copied tree value */
5417 	    break;
5418 #endif
5419 	case XPATH_NODESET:
5420             /* TODO: Check memory error. */
5421 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5422 	    /* Do not deallocate the copied tree value */
5423 	    ret->boolval = 0;
5424 	    break;
5425 #ifdef LIBXML_XPTR_LOCS_ENABLED
5426 	case XPATH_LOCATIONSET:
5427 	{
5428 	    xmlLocationSetPtr loc = val->user;
5429 	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5430 	    break;
5431 	}
5432 #endif
5433         case XPATH_USERS:
5434 	    ret->user = val->user;
5435 	    break;
5436         case XPATH_UNDEFINED:
5437 	    xmlGenericError(xmlGenericErrorContext,
5438 		    "xmlXPathObjectCopy: unsupported type %d\n",
5439 		    val->type);
5440 	    break;
5441     }
5442     return(ret);
5443 }
5444 
5445 /**
5446  * xmlXPathFreeObject:
5447  * @obj:  the object to free
5448  *
5449  * Free up an xmlXPathObjectPtr object.
5450  */
5451 void
xmlXPathFreeObject(xmlXPathObjectPtr obj)5452 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5453     if (obj == NULL) return;
5454     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5455 	if (obj->boolval) {
5456 #if 0
5457 	    if (obj->user != NULL) {
5458                 xmlXPathFreeNodeSet(obj->nodesetval);
5459 		xmlFreeNodeList((xmlNodePtr) obj->user);
5460 	    } else
5461 #endif
5462 	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5463 	    if (obj->nodesetval != NULL)
5464 		xmlXPathFreeValueTree(obj->nodesetval);
5465 	} else {
5466 	    if (obj->nodesetval != NULL)
5467 		xmlXPathFreeNodeSet(obj->nodesetval);
5468 	}
5469 #ifdef LIBXML_XPTR_LOCS_ENABLED
5470     } else if (obj->type == XPATH_LOCATIONSET) {
5471 	if (obj->user != NULL)
5472 	    xmlXPtrFreeLocationSet(obj->user);
5473 #endif
5474     } else if (obj->type == XPATH_STRING) {
5475 	if (obj->stringval != NULL)
5476 	    xmlFree(obj->stringval);
5477     }
5478 #ifdef XP_DEBUG_OBJ_USAGE
5479     xmlXPathDebugObjUsageReleased(NULL, obj->type);
5480 #endif
5481     xmlFree(obj);
5482 }
5483 
5484 static void
xmlXPathFreeObjectEntry(void * obj,const xmlChar * name ATTRIBUTE_UNUSED)5485 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5486     xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5487 }
5488 
5489 /**
5490  * xmlXPathReleaseObject:
5491  * @obj:  the xmlXPathObjectPtr to free or to cache
5492  *
5493  * Depending on the state of the cache this frees the given
5494  * XPath object or stores it in the cache.
5495  */
5496 static void
xmlXPathReleaseObject(xmlXPathContextPtr ctxt,xmlXPathObjectPtr obj)5497 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5498 {
5499 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5500 	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5501     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5502 
5503 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5504 
5505     if (obj == NULL)
5506 	return;
5507     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5508 	 xmlXPathFreeObject(obj);
5509     } else {
5510 	xmlXPathContextCachePtr cache =
5511 	    (xmlXPathContextCachePtr) ctxt->cache;
5512 
5513 	switch (obj->type) {
5514 	    case XPATH_NODESET:
5515 	    case XPATH_XSLT_TREE:
5516 		if (obj->nodesetval != NULL) {
5517 		    if (obj->boolval) {
5518 			/*
5519 			* It looks like the @boolval is used for
5520 			* evaluation if this an XSLT Result Tree Fragment.
5521 			* TODO: Check if this assumption is correct.
5522 			*/
5523 			obj->type = XPATH_XSLT_TREE; /* just for debugging */
5524 			xmlXPathFreeValueTree(obj->nodesetval);
5525 			obj->nodesetval = NULL;
5526 		    } else if ((obj->nodesetval->nodeMax <= 40) &&
5527 			(XP_CACHE_WANTS(cache->nodesetObjs,
5528 					cache->maxNodeset)))
5529 		    {
5530 			XP_CACHE_ADD(cache->nodesetObjs, obj);
5531 			goto obj_cached;
5532 		    } else {
5533 			xmlXPathFreeNodeSet(obj->nodesetval);
5534 			obj->nodesetval = NULL;
5535 		    }
5536 		}
5537 		break;
5538 	    case XPATH_STRING:
5539 		if (obj->stringval != NULL)
5540 		    xmlFree(obj->stringval);
5541 
5542 		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5543 		    XP_CACHE_ADD(cache->stringObjs, obj);
5544 		    goto obj_cached;
5545 		}
5546 		break;
5547 	    case XPATH_BOOLEAN:
5548 		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5549 		    XP_CACHE_ADD(cache->booleanObjs, obj);
5550 		    goto obj_cached;
5551 		}
5552 		break;
5553 	    case XPATH_NUMBER:
5554 		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5555 		    XP_CACHE_ADD(cache->numberObjs, obj);
5556 		    goto obj_cached;
5557 		}
5558 		break;
5559 #ifdef LIBXML_XPTR_LOCS_ENABLED
5560 	    case XPATH_LOCATIONSET:
5561 		if (obj->user != NULL) {
5562 		    xmlXPtrFreeLocationSet(obj->user);
5563 		}
5564 		goto free_obj;
5565 #endif
5566 	    default:
5567 		goto free_obj;
5568 	}
5569 
5570 	/*
5571 	* Fallback to adding to the misc-objects slot.
5572 	*/
5573 	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5574 	    XP_CACHE_ADD(cache->miscObjs, obj);
5575 	} else
5576 	    goto free_obj;
5577 
5578 obj_cached:
5579 
5580 #ifdef XP_DEBUG_OBJ_USAGE
5581 	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5582 #endif
5583 
5584 	if (obj->nodesetval != NULL) {
5585 	    xmlNodeSetPtr tmpset = obj->nodesetval;
5586 
5587 	    /*
5588 	    * TODO: Due to those nasty ns-nodes, we need to traverse
5589 	    *  the list and free the ns-nodes.
5590 	    * URGENT TODO: Check if it's actually slowing things down.
5591 	    *  Maybe we shouldn't try to preserve the list.
5592 	    */
5593 	    if (tmpset->nodeNr > 1) {
5594 		int i;
5595 		xmlNodePtr node;
5596 
5597 		for (i = 0; i < tmpset->nodeNr; i++) {
5598 		    node = tmpset->nodeTab[i];
5599 		    if ((node != NULL) &&
5600 			(node->type == XML_NAMESPACE_DECL))
5601 		    {
5602 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5603 		    }
5604 		}
5605 	    } else if (tmpset->nodeNr == 1) {
5606 		if ((tmpset->nodeTab[0] != NULL) &&
5607 		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5608 		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5609 	    }
5610 	    tmpset->nodeNr = 0;
5611 	    memset(obj, 0, sizeof(xmlXPathObject));
5612 	    obj->nodesetval = tmpset;
5613 	} else
5614 	    memset(obj, 0, sizeof(xmlXPathObject));
5615 
5616 	return;
5617 
5618 free_obj:
5619 	/*
5620 	* Cache is full; free the object.
5621 	*/
5622 	if (obj->nodesetval != NULL)
5623 	    xmlXPathFreeNodeSet(obj->nodesetval);
5624 #ifdef XP_DEBUG_OBJ_USAGE
5625 	xmlXPathDebugObjUsageReleased(NULL, obj->type);
5626 #endif
5627 	xmlFree(obj);
5628     }
5629     return;
5630 }
5631 
5632 
5633 /************************************************************************
5634  *									*
5635  *			Type Casting Routines				*
5636  *									*
5637  ************************************************************************/
5638 
5639 /**
5640  * xmlXPathCastBooleanToString:
5641  * @val:  a boolean
5642  *
5643  * Converts a boolean to its string value.
5644  *
5645  * Returns a newly allocated string.
5646  */
5647 xmlChar *
xmlXPathCastBooleanToString(int val)5648 xmlXPathCastBooleanToString (int val) {
5649     xmlChar *ret;
5650     if (val)
5651 	ret = xmlStrdup((const xmlChar *) "true");
5652     else
5653 	ret = xmlStrdup((const xmlChar *) "false");
5654     return(ret);
5655 }
5656 
5657 /**
5658  * xmlXPathCastNumberToString:
5659  * @val:  a number
5660  *
5661  * Converts a number to its string value.
5662  *
5663  * Returns a newly allocated string.
5664  */
5665 xmlChar *
xmlXPathCastNumberToString(double val)5666 xmlXPathCastNumberToString (double val) {
5667     xmlChar *ret;
5668     switch (xmlXPathIsInf(val)) {
5669     case 1:
5670 	ret = xmlStrdup((const xmlChar *) "Infinity");
5671 	break;
5672     case -1:
5673 	ret = xmlStrdup((const xmlChar *) "-Infinity");
5674 	break;
5675     default:
5676 	if (xmlXPathIsNaN(val)) {
5677 	    ret = xmlStrdup((const xmlChar *) "NaN");
5678 	} else if (val == 0) {
5679             /* Omit sign for negative zero. */
5680 	    ret = xmlStrdup((const xmlChar *) "0");
5681 	} else {
5682 	    /* could be improved */
5683 	    char buf[100];
5684 	    xmlXPathFormatNumber(val, buf, 99);
5685 	    buf[99] = 0;
5686 	    ret = xmlStrdup((const xmlChar *) buf);
5687 	}
5688     }
5689     return(ret);
5690 }
5691 
5692 /**
5693  * xmlXPathCastNodeToString:
5694  * @node:  a node
5695  *
5696  * Converts a node to its string value.
5697  *
5698  * Returns a newly allocated string.
5699  */
5700 xmlChar *
xmlXPathCastNodeToString(xmlNodePtr node)5701 xmlXPathCastNodeToString (xmlNodePtr node) {
5702 xmlChar *ret;
5703     if ((ret = xmlNodeGetContent(node)) == NULL)
5704 	ret = xmlStrdup((const xmlChar *) "");
5705     return(ret);
5706 }
5707 
5708 /**
5709  * xmlXPathCastNodeSetToString:
5710  * @ns:  a node-set
5711  *
5712  * Converts a node-set to its string value.
5713  *
5714  * Returns a newly allocated string.
5715  */
5716 xmlChar *
xmlXPathCastNodeSetToString(xmlNodeSetPtr ns)5717 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5718     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5719 	return(xmlStrdup((const xmlChar *) ""));
5720 
5721     if (ns->nodeNr > 1)
5722 	xmlXPathNodeSetSort(ns);
5723     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5724 }
5725 
5726 /**
5727  * xmlXPathCastToString:
5728  * @val:  an XPath object
5729  *
5730  * Converts an existing object to its string() equivalent
5731  *
5732  * Returns the allocated string value of the object, NULL in case of error.
5733  *         It's up to the caller to free the string memory with xmlFree().
5734  */
5735 xmlChar *
xmlXPathCastToString(xmlXPathObjectPtr val)5736 xmlXPathCastToString(xmlXPathObjectPtr val) {
5737     xmlChar *ret = NULL;
5738 
5739     if (val == NULL)
5740 	return(xmlStrdup((const xmlChar *) ""));
5741     switch (val->type) {
5742 	case XPATH_UNDEFINED:
5743 #ifdef DEBUG_EXPR
5744 	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5745 #endif
5746 	    ret = xmlStrdup((const xmlChar *) "");
5747 	    break;
5748         case XPATH_NODESET:
5749         case XPATH_XSLT_TREE:
5750 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
5751 	    break;
5752 	case XPATH_STRING:
5753 	    return(xmlStrdup(val->stringval));
5754         case XPATH_BOOLEAN:
5755 	    ret = xmlXPathCastBooleanToString(val->boolval);
5756 	    break;
5757 	case XPATH_NUMBER: {
5758 	    ret = xmlXPathCastNumberToString(val->floatval);
5759 	    break;
5760 	}
5761 	case XPATH_USERS:
5762 #ifdef LIBXML_XPTR_LOCS_ENABLED
5763 	case XPATH_POINT:
5764 	case XPATH_RANGE:
5765 	case XPATH_LOCATIONSET:
5766 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5767 	    TODO
5768 	    ret = xmlStrdup((const xmlChar *) "");
5769 	    break;
5770     }
5771     return(ret);
5772 }
5773 
5774 /**
5775  * xmlXPathConvertString:
5776  * @val:  an XPath object
5777  *
5778  * Converts an existing object to its string() equivalent
5779  *
5780  * Returns the new object, the old one is freed (or the operation
5781  *         is done directly on @val)
5782  */
5783 xmlXPathObjectPtr
xmlXPathConvertString(xmlXPathObjectPtr val)5784 xmlXPathConvertString(xmlXPathObjectPtr val) {
5785     xmlChar *res = NULL;
5786 
5787     if (val == NULL)
5788 	return(xmlXPathNewCString(""));
5789 
5790     switch (val->type) {
5791     case XPATH_UNDEFINED:
5792 #ifdef DEBUG_EXPR
5793 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5794 #endif
5795 	break;
5796     case XPATH_NODESET:
5797     case XPATH_XSLT_TREE:
5798 	res = xmlXPathCastNodeSetToString(val->nodesetval);
5799 	break;
5800     case XPATH_STRING:
5801 	return(val);
5802     case XPATH_BOOLEAN:
5803 	res = xmlXPathCastBooleanToString(val->boolval);
5804 	break;
5805     case XPATH_NUMBER:
5806 	res = xmlXPathCastNumberToString(val->floatval);
5807 	break;
5808     case XPATH_USERS:
5809 #ifdef LIBXML_XPTR_LOCS_ENABLED
5810     case XPATH_POINT:
5811     case XPATH_RANGE:
5812     case XPATH_LOCATIONSET:
5813 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5814 	TODO;
5815 	break;
5816     }
5817     xmlXPathFreeObject(val);
5818     if (res == NULL)
5819 	return(xmlXPathNewCString(""));
5820     return(xmlXPathWrapString(res));
5821 }
5822 
5823 /**
5824  * xmlXPathCastBooleanToNumber:
5825  * @val:  a boolean
5826  *
5827  * Converts a boolean to its number value
5828  *
5829  * Returns the number value
5830  */
5831 double
xmlXPathCastBooleanToNumber(int val)5832 xmlXPathCastBooleanToNumber(int val) {
5833     if (val)
5834 	return(1.0);
5835     return(0.0);
5836 }
5837 
5838 /**
5839  * xmlXPathCastStringToNumber:
5840  * @val:  a string
5841  *
5842  * Converts a string to its number value
5843  *
5844  * Returns the number value
5845  */
5846 double
xmlXPathCastStringToNumber(const xmlChar * val)5847 xmlXPathCastStringToNumber(const xmlChar * val) {
5848     return(xmlXPathStringEvalNumber(val));
5849 }
5850 
5851 /**
5852  * xmlXPathCastNodeToNumber:
5853  * @node:  a node
5854  *
5855  * Converts a node to its number value
5856  *
5857  * Returns the number value
5858  */
5859 double
xmlXPathCastNodeToNumber(xmlNodePtr node)5860 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5861     xmlChar *strval;
5862     double ret;
5863 
5864     if (node == NULL)
5865 	return(xmlXPathNAN);
5866     strval = xmlXPathCastNodeToString(node);
5867     if (strval == NULL)
5868 	return(xmlXPathNAN);
5869     ret = xmlXPathCastStringToNumber(strval);
5870     xmlFree(strval);
5871 
5872     return(ret);
5873 }
5874 
5875 /**
5876  * xmlXPathCastNodeSetToNumber:
5877  * @ns:  a node-set
5878  *
5879  * Converts a node-set to its number value
5880  *
5881  * Returns the number value
5882  */
5883 double
xmlXPathCastNodeSetToNumber(xmlNodeSetPtr ns)5884 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5885     xmlChar *str;
5886     double ret;
5887 
5888     if (ns == NULL)
5889 	return(xmlXPathNAN);
5890     str = xmlXPathCastNodeSetToString(ns);
5891     ret = xmlXPathCastStringToNumber(str);
5892     xmlFree(str);
5893     return(ret);
5894 }
5895 
5896 /**
5897  * xmlXPathCastToNumber:
5898  * @val:  an XPath object
5899  *
5900  * Converts an XPath object to its number value
5901  *
5902  * Returns the number value
5903  */
5904 double
xmlXPathCastToNumber(xmlXPathObjectPtr val)5905 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5906     double ret = 0.0;
5907 
5908     if (val == NULL)
5909 	return(xmlXPathNAN);
5910     switch (val->type) {
5911     case XPATH_UNDEFINED:
5912 #ifdef DEBUG_EXPR
5913 	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5914 #endif
5915 	ret = xmlXPathNAN;
5916 	break;
5917     case XPATH_NODESET:
5918     case XPATH_XSLT_TREE:
5919 	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5920 	break;
5921     case XPATH_STRING:
5922 	ret = xmlXPathCastStringToNumber(val->stringval);
5923 	break;
5924     case XPATH_NUMBER:
5925 	ret = val->floatval;
5926 	break;
5927     case XPATH_BOOLEAN:
5928 	ret = xmlXPathCastBooleanToNumber(val->boolval);
5929 	break;
5930     case XPATH_USERS:
5931 #ifdef LIBXML_XPTR_LOCS_ENABLED
5932     case XPATH_POINT:
5933     case XPATH_RANGE:
5934     case XPATH_LOCATIONSET:
5935 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5936 	TODO;
5937 	ret = xmlXPathNAN;
5938 	break;
5939     }
5940     return(ret);
5941 }
5942 
5943 /**
5944  * xmlXPathConvertNumber:
5945  * @val:  an XPath object
5946  *
5947  * Converts an existing object to its number() equivalent
5948  *
5949  * Returns the new object, the old one is freed (or the operation
5950  *         is done directly on @val)
5951  */
5952 xmlXPathObjectPtr
xmlXPathConvertNumber(xmlXPathObjectPtr val)5953 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5954     xmlXPathObjectPtr ret;
5955 
5956     if (val == NULL)
5957 	return(xmlXPathNewFloat(0.0));
5958     if (val->type == XPATH_NUMBER)
5959 	return(val);
5960     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5961     xmlXPathFreeObject(val);
5962     return(ret);
5963 }
5964 
5965 /**
5966  * xmlXPathCastNumberToBoolean:
5967  * @val:  a number
5968  *
5969  * Converts a number to its boolean value
5970  *
5971  * Returns the boolean value
5972  */
5973 int
xmlXPathCastNumberToBoolean(double val)5974 xmlXPathCastNumberToBoolean (double val) {
5975      if (xmlXPathIsNaN(val) || (val == 0.0))
5976 	 return(0);
5977      return(1);
5978 }
5979 
5980 /**
5981  * xmlXPathCastStringToBoolean:
5982  * @val:  a string
5983  *
5984  * Converts a string to its boolean value
5985  *
5986  * Returns the boolean value
5987  */
5988 int
xmlXPathCastStringToBoolean(const xmlChar * val)5989 xmlXPathCastStringToBoolean (const xmlChar *val) {
5990     if ((val == NULL) || (xmlStrlen(val) == 0))
5991 	return(0);
5992     return(1);
5993 }
5994 
5995 /**
5996  * xmlXPathCastNodeSetToBoolean:
5997  * @ns:  a node-set
5998  *
5999  * Converts a node-set to its boolean value
6000  *
6001  * Returns the boolean value
6002  */
6003 int
xmlXPathCastNodeSetToBoolean(xmlNodeSetPtr ns)6004 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6005     if ((ns == NULL) || (ns->nodeNr == 0))
6006 	return(0);
6007     return(1);
6008 }
6009 
6010 /**
6011  * xmlXPathCastToBoolean:
6012  * @val:  an XPath object
6013  *
6014  * Converts an XPath object to its boolean value
6015  *
6016  * Returns the boolean value
6017  */
6018 int
xmlXPathCastToBoolean(xmlXPathObjectPtr val)6019 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6020     int ret = 0;
6021 
6022     if (val == NULL)
6023 	return(0);
6024     switch (val->type) {
6025     case XPATH_UNDEFINED:
6026 #ifdef DEBUG_EXPR
6027 	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6028 #endif
6029 	ret = 0;
6030 	break;
6031     case XPATH_NODESET:
6032     case XPATH_XSLT_TREE:
6033 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6034 	break;
6035     case XPATH_STRING:
6036 	ret = xmlXPathCastStringToBoolean(val->stringval);
6037 	break;
6038     case XPATH_NUMBER:
6039 	ret = xmlXPathCastNumberToBoolean(val->floatval);
6040 	break;
6041     case XPATH_BOOLEAN:
6042 	ret = val->boolval;
6043 	break;
6044     case XPATH_USERS:
6045 #ifdef LIBXML_XPTR_LOCS_ENABLED
6046     case XPATH_POINT:
6047     case XPATH_RANGE:
6048     case XPATH_LOCATIONSET:
6049 #endif /* LIBXML_XPTR_LOCS_ENABLED */
6050 	TODO;
6051 	ret = 0;
6052 	break;
6053     }
6054     return(ret);
6055 }
6056 
6057 
6058 /**
6059  * xmlXPathConvertBoolean:
6060  * @val:  an XPath object
6061  *
6062  * Converts an existing object to its boolean() equivalent
6063  *
6064  * Returns the new object, the old one is freed (or the operation
6065  *         is done directly on @val)
6066  */
6067 xmlXPathObjectPtr
xmlXPathConvertBoolean(xmlXPathObjectPtr val)6068 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6069     xmlXPathObjectPtr ret;
6070 
6071     if (val == NULL)
6072 	return(xmlXPathNewBoolean(0));
6073     if (val->type == XPATH_BOOLEAN)
6074 	return(val);
6075     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6076     xmlXPathFreeObject(val);
6077     return(ret);
6078 }
6079 
6080 /************************************************************************
6081  *									*
6082  *		Routines to handle XPath contexts			*
6083  *									*
6084  ************************************************************************/
6085 
6086 /**
6087  * xmlXPathNewContext:
6088  * @doc:  the XML document
6089  *
6090  * Create a new xmlXPathContext
6091  *
6092  * Returns the xmlXPathContext just allocated. The caller will need to free it.
6093  */
6094 xmlXPathContextPtr
xmlXPathNewContext(xmlDocPtr doc)6095 xmlXPathNewContext(xmlDocPtr doc) {
6096     xmlXPathContextPtr ret;
6097 
6098     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6099     if (ret == NULL) {
6100         xmlXPathErrMemory(NULL, "creating context\n");
6101 	return(NULL);
6102     }
6103     memset(ret, 0 , sizeof(xmlXPathContext));
6104     ret->doc = doc;
6105     ret->node = NULL;
6106 
6107     ret->varHash = NULL;
6108 
6109     ret->nb_types = 0;
6110     ret->max_types = 0;
6111     ret->types = NULL;
6112 
6113     ret->funcHash = xmlHashCreate(0);
6114 
6115     ret->nb_axis = 0;
6116     ret->max_axis = 0;
6117     ret->axis = NULL;
6118 
6119     ret->nsHash = NULL;
6120     ret->user = NULL;
6121 
6122     ret->contextSize = -1;
6123     ret->proximityPosition = -1;
6124 
6125 #ifdef XP_DEFAULT_CACHE_ON
6126     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6127 	xmlXPathFreeContext(ret);
6128 	return(NULL);
6129     }
6130 #endif
6131 
6132     xmlXPathRegisterAllFunctions(ret);
6133 
6134     return(ret);
6135 }
6136 
6137 /**
6138  * xmlXPathFreeContext:
6139  * @ctxt:  the context to free
6140  *
6141  * Free up an xmlXPathContext
6142  */
6143 void
xmlXPathFreeContext(xmlXPathContextPtr ctxt)6144 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6145     if (ctxt == NULL) return;
6146 
6147     if (ctxt->cache != NULL)
6148 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6149     xmlXPathRegisteredNsCleanup(ctxt);
6150     xmlXPathRegisteredFuncsCleanup(ctxt);
6151     xmlXPathRegisteredVariablesCleanup(ctxt);
6152     xmlResetError(&ctxt->lastError);
6153     xmlFree(ctxt);
6154 }
6155 
6156 /************************************************************************
6157  *									*
6158  *		Routines to handle XPath parser contexts		*
6159  *									*
6160  ************************************************************************/
6161 
6162 #define CHECK_CTXT(ctxt)						\
6163     if (ctxt == NULL) {						\
6164 	__xmlRaiseError(NULL, NULL, NULL,				\
6165 		NULL, NULL, XML_FROM_XPATH,				\
6166 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6167 		__FILE__, __LINE__,					\
6168 		NULL, NULL, NULL, 0, 0,					\
6169 		"NULL context pointer\n");				\
6170 	return(NULL);							\
6171     }									\
6172 
6173 #define CHECK_CTXT_NEG(ctxt)						\
6174     if (ctxt == NULL) {						\
6175 	__xmlRaiseError(NULL, NULL, NULL,				\
6176 		NULL, NULL, XML_FROM_XPATH,				\
6177 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6178 		__FILE__, __LINE__,					\
6179 		NULL, NULL, NULL, 0, 0,					\
6180 		"NULL context pointer\n");				\
6181 	return(-1);							\
6182     }									\
6183 
6184 
6185 #define CHECK_CONTEXT(ctxt)						\
6186     if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
6187         (ctxt->doc->children == NULL)) {				\
6188 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
6189 	return(NULL);							\
6190     }
6191 
6192 
6193 /**
6194  * xmlXPathNewParserContext:
6195  * @str:  the XPath expression
6196  * @ctxt:  the XPath context
6197  *
6198  * Create a new xmlXPathParserContext
6199  *
6200  * Returns the xmlXPathParserContext just allocated.
6201  */
6202 xmlXPathParserContextPtr
xmlXPathNewParserContext(const xmlChar * str,xmlXPathContextPtr ctxt)6203 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6204     xmlXPathParserContextPtr ret;
6205 
6206     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6207     if (ret == NULL) {
6208         xmlXPathErrMemory(ctxt, "creating parser context\n");
6209 	return(NULL);
6210     }
6211     memset(ret, 0 , sizeof(xmlXPathParserContext));
6212     ret->cur = ret->base = str;
6213     ret->context = ctxt;
6214 
6215     ret->comp = xmlXPathNewCompExpr();
6216     if (ret->comp == NULL) {
6217 	xmlFree(ret->valueTab);
6218 	xmlFree(ret);
6219 	return(NULL);
6220     }
6221     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6222         ret->comp->dict = ctxt->dict;
6223 	xmlDictReference(ret->comp->dict);
6224     }
6225 
6226     return(ret);
6227 }
6228 
6229 /**
6230  * xmlXPathCompParserContext:
6231  * @comp:  the XPath compiled expression
6232  * @ctxt:  the XPath context
6233  *
6234  * Create a new xmlXPathParserContext when processing a compiled expression
6235  *
6236  * Returns the xmlXPathParserContext just allocated.
6237  */
6238 static xmlXPathParserContextPtr
xmlXPathCompParserContext(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)6239 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6240     xmlXPathParserContextPtr ret;
6241 
6242     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6243     if (ret == NULL) {
6244         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6245 	return(NULL);
6246     }
6247     memset(ret, 0 , sizeof(xmlXPathParserContext));
6248 
6249     /* Allocate the value stack */
6250     ret->valueTab = (xmlXPathObjectPtr *)
6251                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6252     if (ret->valueTab == NULL) {
6253 	xmlFree(ret);
6254 	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6255 	return(NULL);
6256     }
6257     ret->valueNr = 0;
6258     ret->valueMax = 10;
6259     ret->value = NULL;
6260 
6261     ret->context = ctxt;
6262     ret->comp = comp;
6263 
6264     return(ret);
6265 }
6266 
6267 /**
6268  * xmlXPathFreeParserContext:
6269  * @ctxt:  the context to free
6270  *
6271  * Free up an xmlXPathParserContext
6272  */
6273 void
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt)6274 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6275     int i;
6276 
6277     if (ctxt->valueTab != NULL) {
6278         for (i = 0; i < ctxt->valueNr; i++) {
6279             if (ctxt->context)
6280                 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6281             else
6282                 xmlXPathFreeObject(ctxt->valueTab[i]);
6283         }
6284         xmlFree(ctxt->valueTab);
6285     }
6286     if (ctxt->comp != NULL) {
6287 #ifdef XPATH_STREAMING
6288 	if (ctxt->comp->stream != NULL) {
6289 	    xmlFreePatternList(ctxt->comp->stream);
6290 	    ctxt->comp->stream = NULL;
6291 	}
6292 #endif
6293 	xmlXPathFreeCompExpr(ctxt->comp);
6294     }
6295     xmlFree(ctxt);
6296 }
6297 
6298 /************************************************************************
6299  *									*
6300  *		The implicit core function library			*
6301  *									*
6302  ************************************************************************/
6303 
6304 /**
6305  * xmlXPathNodeValHash:
6306  * @node:  a node pointer
6307  *
6308  * Function computing the beginning of the string value of the node,
6309  * used to speed up comparisons
6310  *
6311  * Returns an int usable as a hash
6312  */
6313 static unsigned int
xmlXPathNodeValHash(xmlNodePtr node)6314 xmlXPathNodeValHash(xmlNodePtr node) {
6315     int len = 2;
6316     const xmlChar * string = NULL;
6317     xmlNodePtr tmp = NULL;
6318     unsigned int ret = 0;
6319 
6320     if (node == NULL)
6321 	return(0);
6322 
6323     if (node->type == XML_DOCUMENT_NODE) {
6324 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
6325 	if (tmp == NULL)
6326 	    node = node->children;
6327 	else
6328 	    node = tmp;
6329 
6330 	if (node == NULL)
6331 	    return(0);
6332     }
6333 
6334     switch (node->type) {
6335 	case XML_COMMENT_NODE:
6336 	case XML_PI_NODE:
6337 	case XML_CDATA_SECTION_NODE:
6338 	case XML_TEXT_NODE:
6339 	    string = node->content;
6340 	    if (string == NULL)
6341 		return(0);
6342 	    if (string[0] == 0)
6343 		return(0);
6344 	    return(string[0] + (string[1] << 8));
6345 	case XML_NAMESPACE_DECL:
6346 	    string = ((xmlNsPtr)node)->href;
6347 	    if (string == NULL)
6348 		return(0);
6349 	    if (string[0] == 0)
6350 		return(0);
6351 	    return(string[0] + (string[1] << 8));
6352 	case XML_ATTRIBUTE_NODE:
6353 	    tmp = ((xmlAttrPtr) node)->children;
6354 	    break;
6355 	case XML_ELEMENT_NODE:
6356 	    tmp = node->children;
6357 	    break;
6358 	default:
6359 	    return(0);
6360     }
6361     while (tmp != NULL) {
6362 	switch (tmp->type) {
6363 	    case XML_CDATA_SECTION_NODE:
6364 	    case XML_TEXT_NODE:
6365 		string = tmp->content;
6366 		break;
6367 	    default:
6368                 string = NULL;
6369 		break;
6370 	}
6371 	if ((string != NULL) && (string[0] != 0)) {
6372 	    if (len == 1) {
6373 		return(ret + (string[0] << 8));
6374 	    }
6375 	    if (string[1] == 0) {
6376 		len = 1;
6377 		ret = string[0];
6378 	    } else {
6379 		return(string[0] + (string[1] << 8));
6380 	    }
6381 	}
6382 	/*
6383 	 * Skip to next node
6384 	 */
6385 	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6386 	    if (tmp->children->type != XML_ENTITY_DECL) {
6387 		tmp = tmp->children;
6388 		continue;
6389 	    }
6390 	}
6391 	if (tmp == node)
6392 	    break;
6393 
6394 	if (tmp->next != NULL) {
6395 	    tmp = tmp->next;
6396 	    continue;
6397 	}
6398 
6399 	do {
6400 	    tmp = tmp->parent;
6401 	    if (tmp == NULL)
6402 		break;
6403 	    if (tmp == node) {
6404 		tmp = NULL;
6405 		break;
6406 	    }
6407 	    if (tmp->next != NULL) {
6408 		tmp = tmp->next;
6409 		break;
6410 	    }
6411 	} while (tmp != NULL);
6412     }
6413     return(ret);
6414 }
6415 
6416 /**
6417  * xmlXPathStringHash:
6418  * @string:  a string
6419  *
6420  * Function computing the beginning of the string value of the node,
6421  * used to speed up comparisons
6422  *
6423  * Returns an int usable as a hash
6424  */
6425 static unsigned int
xmlXPathStringHash(const xmlChar * string)6426 xmlXPathStringHash(const xmlChar * string) {
6427     if (string == NULL)
6428 	return(0);
6429     if (string[0] == 0)
6430 	return(0);
6431     return(string[0] + (string[1] << 8));
6432 }
6433 
6434 /**
6435  * xmlXPathCompareNodeSetFloat:
6436  * @ctxt:  the XPath Parser context
6437  * @inf:  less than (1) or greater than (0)
6438  * @strict:  is the comparison strict
6439  * @arg:  the node set
6440  * @f:  the value
6441  *
6442  * Implement the compare operation between a nodeset and a number
6443  *     @ns < @val    (1, 1, ...
6444  *     @ns <= @val   (1, 0, ...
6445  *     @ns > @val    (0, 1, ...
6446  *     @ns >= @val   (0, 0, ...
6447  *
6448  * If one object to be compared is a node-set and the other is a number,
6449  * then the comparison will be true if and only if there is a node in the
6450  * node-set such that the result of performing the comparison on the number
6451  * to be compared and on the result of converting the string-value of that
6452  * node to a number using the number function is true.
6453  *
6454  * Returns 0 or 1 depending on the results of the test.
6455  */
6456 static int
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr f)6457 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6458 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6459     int i, ret = 0;
6460     xmlNodeSetPtr ns;
6461     xmlChar *str2;
6462 
6463     if ((f == NULL) || (arg == NULL) ||
6464 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6465 	xmlXPathReleaseObject(ctxt->context, arg);
6466 	xmlXPathReleaseObject(ctxt->context, f);
6467         return(0);
6468     }
6469     ns = arg->nodesetval;
6470     if (ns != NULL) {
6471 	for (i = 0;i < ns->nodeNr;i++) {
6472 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6473 	     if (str2 != NULL) {
6474 		 valuePush(ctxt,
6475 			   xmlXPathCacheNewString(ctxt->context, str2));
6476 		 xmlFree(str2);
6477 		 xmlXPathNumberFunction(ctxt, 1);
6478 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6479 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6480 		 if (ret)
6481 		     break;
6482 	     }
6483 	}
6484     }
6485     xmlXPathReleaseObject(ctxt->context, arg);
6486     xmlXPathReleaseObject(ctxt->context, f);
6487     return(ret);
6488 }
6489 
6490 /**
6491  * xmlXPathCompareNodeSetString:
6492  * @ctxt:  the XPath Parser context
6493  * @inf:  less than (1) or greater than (0)
6494  * @strict:  is the comparison strict
6495  * @arg:  the node set
6496  * @s:  the value
6497  *
6498  * Implement the compare operation between a nodeset and a string
6499  *     @ns < @val    (1, 1, ...
6500  *     @ns <= @val   (1, 0, ...
6501  *     @ns > @val    (0, 1, ...
6502  *     @ns >= @val   (0, 0, ...
6503  *
6504  * If one object to be compared is a node-set and the other is a string,
6505  * then the comparison will be true if and only if there is a node in
6506  * the node-set such that the result of performing the comparison on the
6507  * string-value of the node and the other string is true.
6508  *
6509  * Returns 0 or 1 depending on the results of the test.
6510  */
6511 static int
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr s)6512 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6513 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6514     int i, ret = 0;
6515     xmlNodeSetPtr ns;
6516     xmlChar *str2;
6517 
6518     if ((s == NULL) || (arg == NULL) ||
6519 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6520 	xmlXPathReleaseObject(ctxt->context, arg);
6521 	xmlXPathReleaseObject(ctxt->context, s);
6522         return(0);
6523     }
6524     ns = arg->nodesetval;
6525     if (ns != NULL) {
6526 	for (i = 0;i < ns->nodeNr;i++) {
6527 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6528 	     if (str2 != NULL) {
6529 		 valuePush(ctxt,
6530 			   xmlXPathCacheNewString(ctxt->context, str2));
6531 		 xmlFree(str2);
6532 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6533 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6534 		 if (ret)
6535 		     break;
6536 	     }
6537 	}
6538     }
6539     xmlXPathReleaseObject(ctxt->context, arg);
6540     xmlXPathReleaseObject(ctxt->context, s);
6541     return(ret);
6542 }
6543 
6544 /**
6545  * xmlXPathCompareNodeSets:
6546  * @inf:  less than (1) or greater than (0)
6547  * @strict:  is the comparison strict
6548  * @arg1:  the first node set object
6549  * @arg2:  the second node set object
6550  *
6551  * Implement the compare operation on nodesets:
6552  *
6553  * If both objects to be compared are node-sets, then the comparison
6554  * will be true if and only if there is a node in the first node-set
6555  * and a node in the second node-set such that the result of performing
6556  * the comparison on the string-values of the two nodes is true.
6557  * ....
6558  * When neither object to be compared is a node-set and the operator
6559  * is <=, <, >= or >, then the objects are compared by converting both
6560  * objects to numbers and comparing the numbers according to IEEE 754.
6561  * ....
6562  * The number function converts its argument to a number as follows:
6563  *  - a string that consists of optional whitespace followed by an
6564  *    optional minus sign followed by a Number followed by whitespace
6565  *    is converted to the IEEE 754 number that is nearest (according
6566  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6567  *    represented by the string; any other string is converted to NaN
6568  *
6569  * Conclusion all nodes need to be converted first to their string value
6570  * and then the comparison must be done when possible
6571  */
6572 static int
xmlXPathCompareNodeSets(int inf,int strict,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6573 xmlXPathCompareNodeSets(int inf, int strict,
6574 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6575     int i, j, init = 0;
6576     double val1;
6577     double *values2;
6578     int ret = 0;
6579     xmlNodeSetPtr ns1;
6580     xmlNodeSetPtr ns2;
6581 
6582     if ((arg1 == NULL) ||
6583 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6584 	xmlXPathFreeObject(arg2);
6585         return(0);
6586     }
6587     if ((arg2 == NULL) ||
6588 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6589 	xmlXPathFreeObject(arg1);
6590 	xmlXPathFreeObject(arg2);
6591         return(0);
6592     }
6593 
6594     ns1 = arg1->nodesetval;
6595     ns2 = arg2->nodesetval;
6596 
6597     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6598 	xmlXPathFreeObject(arg1);
6599 	xmlXPathFreeObject(arg2);
6600 	return(0);
6601     }
6602     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6603 	xmlXPathFreeObject(arg1);
6604 	xmlXPathFreeObject(arg2);
6605 	return(0);
6606     }
6607 
6608     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6609     if (values2 == NULL) {
6610         /* TODO: Propagate memory error. */
6611         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6612 	xmlXPathFreeObject(arg1);
6613 	xmlXPathFreeObject(arg2);
6614 	return(0);
6615     }
6616     for (i = 0;i < ns1->nodeNr;i++) {
6617 	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6618 	if (xmlXPathIsNaN(val1))
6619 	    continue;
6620 	for (j = 0;j < ns2->nodeNr;j++) {
6621 	    if (init == 0) {
6622 		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6623 	    }
6624 	    if (xmlXPathIsNaN(values2[j]))
6625 		continue;
6626 	    if (inf && strict)
6627 		ret = (val1 < values2[j]);
6628 	    else if (inf && !strict)
6629 		ret = (val1 <= values2[j]);
6630 	    else if (!inf && strict)
6631 		ret = (val1 > values2[j]);
6632 	    else if (!inf && !strict)
6633 		ret = (val1 >= values2[j]);
6634 	    if (ret)
6635 		break;
6636 	}
6637 	if (ret)
6638 	    break;
6639 	init = 1;
6640     }
6641     xmlFree(values2);
6642     xmlXPathFreeObject(arg1);
6643     xmlXPathFreeObject(arg2);
6644     return(ret);
6645 }
6646 
6647 /**
6648  * xmlXPathCompareNodeSetValue:
6649  * @ctxt:  the XPath Parser context
6650  * @inf:  less than (1) or greater than (0)
6651  * @strict:  is the comparison strict
6652  * @arg:  the node set
6653  * @val:  the value
6654  *
6655  * Implement the compare operation between a nodeset and a value
6656  *     @ns < @val    (1, 1, ...
6657  *     @ns <= @val   (1, 0, ...
6658  *     @ns > @val    (0, 1, ...
6659  *     @ns >= @val   (0, 0, ...
6660  *
6661  * If one object to be compared is a node-set and the other is a boolean,
6662  * then the comparison will be true if and only if the result of performing
6663  * the comparison on the boolean and on the result of converting
6664  * the node-set to a boolean using the boolean function is true.
6665  *
6666  * Returns 0 or 1 depending on the results of the test.
6667  */
6668 static int
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr val)6669 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6670 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6671     if ((val == NULL) || (arg == NULL) ||
6672 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6673         return(0);
6674 
6675     switch(val->type) {
6676         case XPATH_NUMBER:
6677 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6678         case XPATH_NODESET:
6679         case XPATH_XSLT_TREE:
6680 	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6681         case XPATH_STRING:
6682 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6683         case XPATH_BOOLEAN:
6684 	    valuePush(ctxt, arg);
6685 	    xmlXPathBooleanFunction(ctxt, 1);
6686 	    valuePush(ctxt, val);
6687 	    return(xmlXPathCompareValues(ctxt, inf, strict));
6688 	default:
6689             xmlGenericError(xmlGenericErrorContext,
6690                     "xmlXPathCompareNodeSetValue: Can't compare node set "
6691                     "and object of type %d\n",
6692                     val->type);
6693             xmlXPathReleaseObject(ctxt->context, arg);
6694             xmlXPathReleaseObject(ctxt->context, val);
6695             XP_ERROR0(XPATH_INVALID_TYPE);
6696     }
6697     return(0);
6698 }
6699 
6700 /**
6701  * xmlXPathEqualNodeSetString:
6702  * @arg:  the nodeset object argument
6703  * @str:  the string to compare to.
6704  * @neq:  flag to show whether for '=' (0) or '!=' (1)
6705  *
6706  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6707  * If one object to be compared is a node-set and the other is a string,
6708  * then the comparison will be true if and only if there is a node in
6709  * the node-set such that the result of performing the comparison on the
6710  * string-value of the node and the other string is true.
6711  *
6712  * Returns 0 or 1 depending on the results of the test.
6713  */
6714 static int
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg,const xmlChar * str,int neq)6715 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6716 {
6717     int i;
6718     xmlNodeSetPtr ns;
6719     xmlChar *str2;
6720     unsigned int hash;
6721 
6722     if ((str == NULL) || (arg == NULL) ||
6723         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6724         return (0);
6725     ns = arg->nodesetval;
6726     /*
6727      * A NULL nodeset compared with a string is always false
6728      * (since there is no node equal, and no node not equal)
6729      */
6730     if ((ns == NULL) || (ns->nodeNr <= 0) )
6731         return (0);
6732     hash = xmlXPathStringHash(str);
6733     for (i = 0; i < ns->nodeNr; i++) {
6734         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6735             str2 = xmlNodeGetContent(ns->nodeTab[i]);
6736             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6737                 xmlFree(str2);
6738 		if (neq)
6739 		    continue;
6740                 return (1);
6741 	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6742 		if (neq)
6743 		    continue;
6744                 return (1);
6745             } else if (neq) {
6746 		if (str2 != NULL)
6747 		    xmlFree(str2);
6748 		return (1);
6749 	    }
6750             if (str2 != NULL)
6751                 xmlFree(str2);
6752         } else if (neq)
6753 	    return (1);
6754     }
6755     return (0);
6756 }
6757 
6758 /**
6759  * xmlXPathEqualNodeSetFloat:
6760  * @arg:  the nodeset object argument
6761  * @f:  the float to compare to
6762  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6763  *
6764  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6765  * If one object to be compared is a node-set and the other is a number,
6766  * then the comparison will be true if and only if there is a node in
6767  * the node-set such that the result of performing the comparison on the
6768  * number to be compared and on the result of converting the string-value
6769  * of that node to a number using the number function is true.
6770  *
6771  * Returns 0 or 1 depending on the results of the test.
6772  */
6773 static int
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,double f,int neq)6774 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6775     xmlXPathObjectPtr arg, double f, int neq) {
6776   int i, ret=0;
6777   xmlNodeSetPtr ns;
6778   xmlChar *str2;
6779   xmlXPathObjectPtr val;
6780   double v;
6781 
6782     if ((arg == NULL) ||
6783 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6784         return(0);
6785 
6786     ns = arg->nodesetval;
6787     if (ns != NULL) {
6788 	for (i=0;i<ns->nodeNr;i++) {
6789 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6790 	    if (str2 != NULL) {
6791 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6792 		xmlFree(str2);
6793 		xmlXPathNumberFunction(ctxt, 1);
6794                 CHECK_ERROR0;
6795 		val = valuePop(ctxt);
6796 		v = val->floatval;
6797 		xmlXPathReleaseObject(ctxt->context, val);
6798 		if (!xmlXPathIsNaN(v)) {
6799 		    if ((!neq) && (v==f)) {
6800 			ret = 1;
6801 			break;
6802 		    } else if ((neq) && (v!=f)) {
6803 			ret = 1;
6804 			break;
6805 		    }
6806 		} else {	/* NaN is unequal to any value */
6807 		    if (neq)
6808 			ret = 1;
6809 		}
6810 	    }
6811 	}
6812     }
6813 
6814     return(ret);
6815 }
6816 
6817 
6818 /**
6819  * xmlXPathEqualNodeSets:
6820  * @arg1:  first nodeset object argument
6821  * @arg2:  second nodeset object argument
6822  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6823  *
6824  * Implement the equal / not equal operation on XPath nodesets:
6825  * @arg1 == @arg2  or  @arg1 != @arg2
6826  * If both objects to be compared are node-sets, then the comparison
6827  * will be true if and only if there is a node in the first node-set and
6828  * a node in the second node-set such that the result of performing the
6829  * comparison on the string-values of the two nodes is true.
6830  *
6831  * (needless to say, this is a costly operation)
6832  *
6833  * Returns 0 or 1 depending on the results of the test.
6834  */
6835 static int
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2,int neq)6836 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6837     int i, j;
6838     unsigned int *hashs1;
6839     unsigned int *hashs2;
6840     xmlChar **values1;
6841     xmlChar **values2;
6842     int ret = 0;
6843     xmlNodeSetPtr ns1;
6844     xmlNodeSetPtr ns2;
6845 
6846     if ((arg1 == NULL) ||
6847 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6848         return(0);
6849     if ((arg2 == NULL) ||
6850 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6851         return(0);
6852 
6853     ns1 = arg1->nodesetval;
6854     ns2 = arg2->nodesetval;
6855 
6856     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6857 	return(0);
6858     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6859 	return(0);
6860 
6861     /*
6862      * for equal, check if there is a node pertaining to both sets
6863      */
6864     if (neq == 0)
6865 	for (i = 0;i < ns1->nodeNr;i++)
6866 	    for (j = 0;j < ns2->nodeNr;j++)
6867 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
6868 		    return(1);
6869 
6870     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6871     if (values1 == NULL) {
6872         /* TODO: Propagate memory error. */
6873         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6874 	return(0);
6875     }
6876     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6877     if (hashs1 == NULL) {
6878         /* TODO: Propagate memory error. */
6879         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6880 	xmlFree(values1);
6881 	return(0);
6882     }
6883     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6884     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6885     if (values2 == NULL) {
6886         /* TODO: Propagate memory error. */
6887         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6888 	xmlFree(hashs1);
6889 	xmlFree(values1);
6890 	return(0);
6891     }
6892     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6893     if (hashs2 == NULL) {
6894         /* TODO: Propagate memory error. */
6895         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6896 	xmlFree(hashs1);
6897 	xmlFree(values1);
6898 	xmlFree(values2);
6899 	return(0);
6900     }
6901     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6902     for (i = 0;i < ns1->nodeNr;i++) {
6903 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6904 	for (j = 0;j < ns2->nodeNr;j++) {
6905 	    if (i == 0)
6906 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6907 	    if (hashs1[i] != hashs2[j]) {
6908 		if (neq) {
6909 		    ret = 1;
6910 		    break;
6911 		}
6912 	    }
6913 	    else {
6914 		if (values1[i] == NULL)
6915 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6916 		if (values2[j] == NULL)
6917 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6918 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6919 		if (ret)
6920 		    break;
6921 	    }
6922 	}
6923 	if (ret)
6924 	    break;
6925     }
6926     for (i = 0;i < ns1->nodeNr;i++)
6927 	if (values1[i] != NULL)
6928 	    xmlFree(values1[i]);
6929     for (j = 0;j < ns2->nodeNr;j++)
6930 	if (values2[j] != NULL)
6931 	    xmlFree(values2[j]);
6932     xmlFree(values1);
6933     xmlFree(values2);
6934     xmlFree(hashs1);
6935     xmlFree(hashs2);
6936     return(ret);
6937 }
6938 
6939 static int
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6940 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6941   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6942     int ret = 0;
6943     /*
6944      *At this point we are assured neither arg1 nor arg2
6945      *is a nodeset, so we can just pick the appropriate routine.
6946      */
6947     switch (arg1->type) {
6948         case XPATH_UNDEFINED:
6949 #ifdef DEBUG_EXPR
6950 	    xmlGenericError(xmlGenericErrorContext,
6951 		    "Equal: undefined\n");
6952 #endif
6953 	    break;
6954         case XPATH_BOOLEAN:
6955 	    switch (arg2->type) {
6956 	        case XPATH_UNDEFINED:
6957 #ifdef DEBUG_EXPR
6958 		    xmlGenericError(xmlGenericErrorContext,
6959 			    "Equal: undefined\n");
6960 #endif
6961 		    break;
6962 		case XPATH_BOOLEAN:
6963 #ifdef DEBUG_EXPR
6964 		    xmlGenericError(xmlGenericErrorContext,
6965 			    "Equal: %d boolean %d \n",
6966 			    arg1->boolval, arg2->boolval);
6967 #endif
6968 		    ret = (arg1->boolval == arg2->boolval);
6969 		    break;
6970 		case XPATH_NUMBER:
6971 		    ret = (arg1->boolval ==
6972 			   xmlXPathCastNumberToBoolean(arg2->floatval));
6973 		    break;
6974 		case XPATH_STRING:
6975 		    if ((arg2->stringval == NULL) ||
6976 			(arg2->stringval[0] == 0)) ret = 0;
6977 		    else
6978 			ret = 1;
6979 		    ret = (arg1->boolval == ret);
6980 		    break;
6981 		case XPATH_USERS:
6982 #ifdef LIBXML_XPTR_LOCS_ENABLED
6983 		case XPATH_POINT:
6984 		case XPATH_RANGE:
6985 		case XPATH_LOCATIONSET:
6986 #endif /* LIBXML_XPTR_LOCS_ENABLED */
6987 		    TODO
6988 		    break;
6989 		case XPATH_NODESET:
6990 		case XPATH_XSLT_TREE:
6991 		    break;
6992 	    }
6993 	    break;
6994         case XPATH_NUMBER:
6995 	    switch (arg2->type) {
6996 	        case XPATH_UNDEFINED:
6997 #ifdef DEBUG_EXPR
6998 		    xmlGenericError(xmlGenericErrorContext,
6999 			    "Equal: undefined\n");
7000 #endif
7001 		    break;
7002 		case XPATH_BOOLEAN:
7003 		    ret = (arg2->boolval==
7004 			   xmlXPathCastNumberToBoolean(arg1->floatval));
7005 		    break;
7006 		case XPATH_STRING:
7007 		    valuePush(ctxt, arg2);
7008 		    xmlXPathNumberFunction(ctxt, 1);
7009 		    arg2 = valuePop(ctxt);
7010                     if (ctxt->error)
7011                         break;
7012                     /* Falls through. */
7013 		case XPATH_NUMBER:
7014 		    /* Hand check NaN and Infinity equalities */
7015 		    if (xmlXPathIsNaN(arg1->floatval) ||
7016 			    xmlXPathIsNaN(arg2->floatval)) {
7017 		        ret = 0;
7018 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7019 		        if (xmlXPathIsInf(arg2->floatval) == 1)
7020 			    ret = 1;
7021 			else
7022 			    ret = 0;
7023 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7024 			if (xmlXPathIsInf(arg2->floatval) == -1)
7025 			    ret = 1;
7026 			else
7027 			    ret = 0;
7028 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7029 			if (xmlXPathIsInf(arg1->floatval) == 1)
7030 			    ret = 1;
7031 			else
7032 			    ret = 0;
7033 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7034 			if (xmlXPathIsInf(arg1->floatval) == -1)
7035 			    ret = 1;
7036 			else
7037 			    ret = 0;
7038 		    } else {
7039 		        ret = (arg1->floatval == arg2->floatval);
7040 		    }
7041 		    break;
7042 		case XPATH_USERS:
7043 #ifdef LIBXML_XPTR_LOCS_ENABLED
7044 		case XPATH_POINT:
7045 		case XPATH_RANGE:
7046 		case XPATH_LOCATIONSET:
7047 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7048 		    TODO
7049 		    break;
7050 		case XPATH_NODESET:
7051 		case XPATH_XSLT_TREE:
7052 		    break;
7053 	    }
7054 	    break;
7055         case XPATH_STRING:
7056 	    switch (arg2->type) {
7057 	        case XPATH_UNDEFINED:
7058 #ifdef DEBUG_EXPR
7059 		    xmlGenericError(xmlGenericErrorContext,
7060 			    "Equal: undefined\n");
7061 #endif
7062 		    break;
7063 		case XPATH_BOOLEAN:
7064 		    if ((arg1->stringval == NULL) ||
7065 			(arg1->stringval[0] == 0)) ret = 0;
7066 		    else
7067 			ret = 1;
7068 		    ret = (arg2->boolval == ret);
7069 		    break;
7070 		case XPATH_STRING:
7071 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7072 		    break;
7073 		case XPATH_NUMBER:
7074 		    valuePush(ctxt, arg1);
7075 		    xmlXPathNumberFunction(ctxt, 1);
7076 		    arg1 = valuePop(ctxt);
7077                     if (ctxt->error)
7078                         break;
7079 		    /* Hand check NaN and Infinity equalities */
7080 		    if (xmlXPathIsNaN(arg1->floatval) ||
7081 			    xmlXPathIsNaN(arg2->floatval)) {
7082 		        ret = 0;
7083 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7084 			if (xmlXPathIsInf(arg2->floatval) == 1)
7085 			    ret = 1;
7086 			else
7087 			    ret = 0;
7088 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7089 			if (xmlXPathIsInf(arg2->floatval) == -1)
7090 			    ret = 1;
7091 			else
7092 			    ret = 0;
7093 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7094 			if (xmlXPathIsInf(arg1->floatval) == 1)
7095 			    ret = 1;
7096 			else
7097 			    ret = 0;
7098 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7099 			if (xmlXPathIsInf(arg1->floatval) == -1)
7100 			    ret = 1;
7101 			else
7102 			    ret = 0;
7103 		    } else {
7104 		        ret = (arg1->floatval == arg2->floatval);
7105 		    }
7106 		    break;
7107 		case XPATH_USERS:
7108 #ifdef LIBXML_XPTR_LOCS_ENABLED
7109 		case XPATH_POINT:
7110 		case XPATH_RANGE:
7111 		case XPATH_LOCATIONSET:
7112 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7113 		    TODO
7114 		    break;
7115 		case XPATH_NODESET:
7116 		case XPATH_XSLT_TREE:
7117 		    break;
7118 	    }
7119 	    break;
7120         case XPATH_USERS:
7121 #ifdef LIBXML_XPTR_LOCS_ENABLED
7122 	case XPATH_POINT:
7123 	case XPATH_RANGE:
7124 	case XPATH_LOCATIONSET:
7125 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7126 	    TODO
7127 	    break;
7128 	case XPATH_NODESET:
7129 	case XPATH_XSLT_TREE:
7130 	    break;
7131     }
7132     xmlXPathReleaseObject(ctxt->context, arg1);
7133     xmlXPathReleaseObject(ctxt->context, arg2);
7134     return(ret);
7135 }
7136 
7137 /**
7138  * xmlXPathEqualValues:
7139  * @ctxt:  the XPath Parser context
7140  *
7141  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7142  *
7143  * Returns 0 or 1 depending on the results of the test.
7144  */
7145 int
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt)7146 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7147     xmlXPathObjectPtr arg1, arg2, argtmp;
7148     int ret = 0;
7149 
7150     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7151     arg2 = valuePop(ctxt);
7152     arg1 = valuePop(ctxt);
7153     if ((arg1 == NULL) || (arg2 == NULL)) {
7154 	if (arg1 != NULL)
7155 	    xmlXPathReleaseObject(ctxt->context, arg1);
7156 	else
7157 	    xmlXPathReleaseObject(ctxt->context, arg2);
7158 	XP_ERROR0(XPATH_INVALID_OPERAND);
7159     }
7160 
7161     if (arg1 == arg2) {
7162 #ifdef DEBUG_EXPR
7163         xmlGenericError(xmlGenericErrorContext,
7164 		"Equal: by pointer\n");
7165 #endif
7166 	xmlXPathFreeObject(arg1);
7167         return(1);
7168     }
7169 
7170     /*
7171      *If either argument is a nodeset, it's a 'special case'
7172      */
7173     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7174       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7175 	/*
7176 	 *Hack it to assure arg1 is the nodeset
7177 	 */
7178 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7179 		argtmp = arg2;
7180 		arg2 = arg1;
7181 		arg1 = argtmp;
7182 	}
7183 	switch (arg2->type) {
7184 	    case XPATH_UNDEFINED:
7185 #ifdef DEBUG_EXPR
7186 		xmlGenericError(xmlGenericErrorContext,
7187 			"Equal: undefined\n");
7188 #endif
7189 		break;
7190 	    case XPATH_NODESET:
7191 	    case XPATH_XSLT_TREE:
7192 		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7193 		break;
7194 	    case XPATH_BOOLEAN:
7195 		if ((arg1->nodesetval == NULL) ||
7196 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7197 		else
7198 		    ret = 1;
7199 		ret = (ret == arg2->boolval);
7200 		break;
7201 	    case XPATH_NUMBER:
7202 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7203 		break;
7204 	    case XPATH_STRING:
7205 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7206 		break;
7207 	    case XPATH_USERS:
7208 #ifdef LIBXML_XPTR_LOCS_ENABLED
7209 	    case XPATH_POINT:
7210 	    case XPATH_RANGE:
7211 	    case XPATH_LOCATIONSET:
7212 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7213 		TODO
7214 		break;
7215 	}
7216 	xmlXPathReleaseObject(ctxt->context, arg1);
7217 	xmlXPathReleaseObject(ctxt->context, arg2);
7218 	return(ret);
7219     }
7220 
7221     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7222 }
7223 
7224 /**
7225  * xmlXPathNotEqualValues:
7226  * @ctxt:  the XPath Parser context
7227  *
7228  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7229  *
7230  * Returns 0 or 1 depending on the results of the test.
7231  */
7232 int
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt)7233 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7234     xmlXPathObjectPtr arg1, arg2, argtmp;
7235     int ret = 0;
7236 
7237     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7238     arg2 = valuePop(ctxt);
7239     arg1 = valuePop(ctxt);
7240     if ((arg1 == NULL) || (arg2 == NULL)) {
7241 	if (arg1 != NULL)
7242 	    xmlXPathReleaseObject(ctxt->context, arg1);
7243 	else
7244 	    xmlXPathReleaseObject(ctxt->context, arg2);
7245 	XP_ERROR0(XPATH_INVALID_OPERAND);
7246     }
7247 
7248     if (arg1 == arg2) {
7249 #ifdef DEBUG_EXPR
7250         xmlGenericError(xmlGenericErrorContext,
7251 		"NotEqual: by pointer\n");
7252 #endif
7253 	xmlXPathReleaseObject(ctxt->context, arg1);
7254         return(0);
7255     }
7256 
7257     /*
7258      *If either argument is a nodeset, it's a 'special case'
7259      */
7260     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7261       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7262 	/*
7263 	 *Hack it to assure arg1 is the nodeset
7264 	 */
7265 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7266 		argtmp = arg2;
7267 		arg2 = arg1;
7268 		arg1 = argtmp;
7269 	}
7270 	switch (arg2->type) {
7271 	    case XPATH_UNDEFINED:
7272 #ifdef DEBUG_EXPR
7273 		xmlGenericError(xmlGenericErrorContext,
7274 			"NotEqual: undefined\n");
7275 #endif
7276 		break;
7277 	    case XPATH_NODESET:
7278 	    case XPATH_XSLT_TREE:
7279 		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7280 		break;
7281 	    case XPATH_BOOLEAN:
7282 		if ((arg1->nodesetval == NULL) ||
7283 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7284 		else
7285 		    ret = 1;
7286 		ret = (ret != arg2->boolval);
7287 		break;
7288 	    case XPATH_NUMBER:
7289 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7290 		break;
7291 	    case XPATH_STRING:
7292 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7293 		break;
7294 	    case XPATH_USERS:
7295 #ifdef LIBXML_XPTR_LOCS_ENABLED
7296 	    case XPATH_POINT:
7297 	    case XPATH_RANGE:
7298 	    case XPATH_LOCATIONSET:
7299 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7300 		TODO
7301 		break;
7302 	}
7303 	xmlXPathReleaseObject(ctxt->context, arg1);
7304 	xmlXPathReleaseObject(ctxt->context, arg2);
7305 	return(ret);
7306     }
7307 
7308     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7309 }
7310 
7311 /**
7312  * xmlXPathCompareValues:
7313  * @ctxt:  the XPath Parser context
7314  * @inf:  less than (1) or greater than (0)
7315  * @strict:  is the comparison strict
7316  *
7317  * Implement the compare operation on XPath objects:
7318  *     @arg1 < @arg2    (1, 1, ...
7319  *     @arg1 <= @arg2   (1, 0, ...
7320  *     @arg1 > @arg2    (0, 1, ...
7321  *     @arg1 >= @arg2   (0, 0, ...
7322  *
7323  * When neither object to be compared is a node-set and the operator is
7324  * <=, <, >=, >, then the objects are compared by converted both objects
7325  * to numbers and comparing the numbers according to IEEE 754. The <
7326  * comparison will be true if and only if the first number is less than the
7327  * second number. The <= comparison will be true if and only if the first
7328  * number is less than or equal to the second number. The > comparison
7329  * will be true if and only if the first number is greater than the second
7330  * number. The >= comparison will be true if and only if the first number
7331  * is greater than or equal to the second number.
7332  *
7333  * Returns 1 if the comparison succeeded, 0 if it failed
7334  */
7335 int
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt,int inf,int strict)7336 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7337     int ret = 0, arg1i = 0, arg2i = 0;
7338     xmlXPathObjectPtr arg1, arg2;
7339 
7340     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7341     arg2 = valuePop(ctxt);
7342     arg1 = valuePop(ctxt);
7343     if ((arg1 == NULL) || (arg2 == NULL)) {
7344 	if (arg1 != NULL)
7345 	    xmlXPathReleaseObject(ctxt->context, arg1);
7346 	else
7347 	    xmlXPathReleaseObject(ctxt->context, arg2);
7348 	XP_ERROR0(XPATH_INVALID_OPERAND);
7349     }
7350 
7351     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7352       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7353 	/*
7354 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7355 	 * are not freed from within this routine; they will be freed from the
7356 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7357 	 */
7358 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7359 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7360 	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7361 	} else {
7362 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7363 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7364 			                          arg1, arg2);
7365 	    } else {
7366 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7367 			                          arg2, arg1);
7368 	    }
7369 	}
7370 	return(ret);
7371     }
7372 
7373     if (arg1->type != XPATH_NUMBER) {
7374 	valuePush(ctxt, arg1);
7375 	xmlXPathNumberFunction(ctxt, 1);
7376 	arg1 = valuePop(ctxt);
7377     }
7378     if (arg2->type != XPATH_NUMBER) {
7379 	valuePush(ctxt, arg2);
7380 	xmlXPathNumberFunction(ctxt, 1);
7381 	arg2 = valuePop(ctxt);
7382     }
7383     if (ctxt->error)
7384         goto error;
7385     /*
7386      * Add tests for infinity and nan
7387      * => feedback on 3.4 for Inf and NaN
7388      */
7389     /* Hand check NaN and Infinity comparisons */
7390     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7391 	ret=0;
7392     } else {
7393 	arg1i=xmlXPathIsInf(arg1->floatval);
7394 	arg2i=xmlXPathIsInf(arg2->floatval);
7395 	if (inf && strict) {
7396 	    if ((arg1i == -1 && arg2i != -1) ||
7397 		(arg2i == 1 && arg1i != 1)) {
7398 		ret = 1;
7399 	    } else if (arg1i == 0 && arg2i == 0) {
7400 		ret = (arg1->floatval < arg2->floatval);
7401 	    } else {
7402 		ret = 0;
7403 	    }
7404 	}
7405 	else if (inf && !strict) {
7406 	    if (arg1i == -1 || arg2i == 1) {
7407 		ret = 1;
7408 	    } else if (arg1i == 0 && arg2i == 0) {
7409 		ret = (arg1->floatval <= arg2->floatval);
7410 	    } else {
7411 		ret = 0;
7412 	    }
7413 	}
7414 	else if (!inf && strict) {
7415 	    if ((arg1i == 1 && arg2i != 1) ||
7416 		(arg2i == -1 && arg1i != -1)) {
7417 		ret = 1;
7418 	    } else if (arg1i == 0 && arg2i == 0) {
7419 		ret = (arg1->floatval > arg2->floatval);
7420 	    } else {
7421 		ret = 0;
7422 	    }
7423 	}
7424 	else if (!inf && !strict) {
7425 	    if (arg1i == 1 || arg2i == -1) {
7426 		ret = 1;
7427 	    } else if (arg1i == 0 && arg2i == 0) {
7428 		ret = (arg1->floatval >= arg2->floatval);
7429 	    } else {
7430 		ret = 0;
7431 	    }
7432 	}
7433     }
7434 error:
7435     xmlXPathReleaseObject(ctxt->context, arg1);
7436     xmlXPathReleaseObject(ctxt->context, arg2);
7437     return(ret);
7438 }
7439 
7440 /**
7441  * xmlXPathValueFlipSign:
7442  * @ctxt:  the XPath Parser context
7443  *
7444  * Implement the unary - operation on an XPath object
7445  * The numeric operators convert their operands to numbers as if
7446  * by calling the number function.
7447  */
7448 void
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt)7449 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7450     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7451     CAST_TO_NUMBER;
7452     CHECK_TYPE(XPATH_NUMBER);
7453     ctxt->value->floatval = -ctxt->value->floatval;
7454 }
7455 
7456 /**
7457  * xmlXPathAddValues:
7458  * @ctxt:  the XPath Parser context
7459  *
7460  * Implement the add operation on XPath objects:
7461  * The numeric operators convert their operands to numbers as if
7462  * by calling the number function.
7463  */
7464 void
xmlXPathAddValues(xmlXPathParserContextPtr ctxt)7465 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7466     xmlXPathObjectPtr arg;
7467     double val;
7468 
7469     arg = valuePop(ctxt);
7470     if (arg == NULL)
7471 	XP_ERROR(XPATH_INVALID_OPERAND);
7472     val = xmlXPathCastToNumber(arg);
7473     xmlXPathReleaseObject(ctxt->context, arg);
7474     CAST_TO_NUMBER;
7475     CHECK_TYPE(XPATH_NUMBER);
7476     ctxt->value->floatval += val;
7477 }
7478 
7479 /**
7480  * xmlXPathSubValues:
7481  * @ctxt:  the XPath Parser context
7482  *
7483  * Implement the subtraction operation on XPath objects:
7484  * The numeric operators convert their operands to numbers as if
7485  * by calling the number function.
7486  */
7487 void
xmlXPathSubValues(xmlXPathParserContextPtr ctxt)7488 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7489     xmlXPathObjectPtr arg;
7490     double val;
7491 
7492     arg = valuePop(ctxt);
7493     if (arg == NULL)
7494 	XP_ERROR(XPATH_INVALID_OPERAND);
7495     val = xmlXPathCastToNumber(arg);
7496     xmlXPathReleaseObject(ctxt->context, arg);
7497     CAST_TO_NUMBER;
7498     CHECK_TYPE(XPATH_NUMBER);
7499     ctxt->value->floatval -= val;
7500 }
7501 
7502 /**
7503  * xmlXPathMultValues:
7504  * @ctxt:  the XPath Parser context
7505  *
7506  * Implement the multiply operation on XPath objects:
7507  * The numeric operators convert their operands to numbers as if
7508  * by calling the number function.
7509  */
7510 void
xmlXPathMultValues(xmlXPathParserContextPtr ctxt)7511 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7512     xmlXPathObjectPtr arg;
7513     double val;
7514 
7515     arg = valuePop(ctxt);
7516     if (arg == NULL)
7517 	XP_ERROR(XPATH_INVALID_OPERAND);
7518     val = xmlXPathCastToNumber(arg);
7519     xmlXPathReleaseObject(ctxt->context, arg);
7520     CAST_TO_NUMBER;
7521     CHECK_TYPE(XPATH_NUMBER);
7522     ctxt->value->floatval *= val;
7523 }
7524 
7525 /**
7526  * xmlXPathDivValues:
7527  * @ctxt:  the XPath Parser context
7528  *
7529  * Implement the div operation on XPath objects @arg1 / @arg2:
7530  * The numeric operators convert their operands to numbers as if
7531  * by calling the number function.
7532  */
7533 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
7534 void
xmlXPathDivValues(xmlXPathParserContextPtr ctxt)7535 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7536     xmlXPathObjectPtr arg;
7537     double val;
7538 
7539     arg = valuePop(ctxt);
7540     if (arg == NULL)
7541 	XP_ERROR(XPATH_INVALID_OPERAND);
7542     val = xmlXPathCastToNumber(arg);
7543     xmlXPathReleaseObject(ctxt->context, arg);
7544     CAST_TO_NUMBER;
7545     CHECK_TYPE(XPATH_NUMBER);
7546     ctxt->value->floatval /= val;
7547 }
7548 
7549 /**
7550  * xmlXPathModValues:
7551  * @ctxt:  the XPath Parser context
7552  *
7553  * Implement the mod operation on XPath objects: @arg1 / @arg2
7554  * The numeric operators convert their operands to numbers as if
7555  * by calling the number function.
7556  */
7557 void
xmlXPathModValues(xmlXPathParserContextPtr ctxt)7558 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7559     xmlXPathObjectPtr arg;
7560     double arg1, arg2;
7561 
7562     arg = valuePop(ctxt);
7563     if (arg == NULL)
7564 	XP_ERROR(XPATH_INVALID_OPERAND);
7565     arg2 = xmlXPathCastToNumber(arg);
7566     xmlXPathReleaseObject(ctxt->context, arg);
7567     CAST_TO_NUMBER;
7568     CHECK_TYPE(XPATH_NUMBER);
7569     arg1 = ctxt->value->floatval;
7570     if (arg2 == 0)
7571 	ctxt->value->floatval = xmlXPathNAN;
7572     else {
7573 	ctxt->value->floatval = fmod(arg1, arg2);
7574     }
7575 }
7576 
7577 /************************************************************************
7578  *									*
7579  *		The traversal functions					*
7580  *									*
7581  ************************************************************************/
7582 
7583 /*
7584  * A traversal function enumerates nodes along an axis.
7585  * Initially it must be called with NULL, and it indicates
7586  * termination on the axis by returning NULL.
7587  */
7588 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7589                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7590 
7591 /*
7592  * xmlXPathTraversalFunctionExt:
7593  * A traversal function enumerates nodes along an axis.
7594  * Initially it must be called with NULL, and it indicates
7595  * termination on the axis by returning NULL.
7596  * The context node of the traversal is specified via @contextNode.
7597  */
7598 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7599                     (xmlNodePtr cur, xmlNodePtr contextNode);
7600 
7601 /*
7602  * xmlXPathNodeSetMergeFunction:
7603  * Used for merging node sets in xmlXPathCollectAndTest().
7604  */
7605 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7606 		    (xmlNodeSetPtr, xmlNodeSetPtr);
7607 
7608 
7609 /**
7610  * xmlXPathNextSelf:
7611  * @ctxt:  the XPath Parser context
7612  * @cur:  the current node in the traversal
7613  *
7614  * Traversal function for the "self" direction
7615  * The self axis contains just the context node itself
7616  *
7617  * Returns the next element following that axis
7618  */
7619 xmlNodePtr
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7620 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7621     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7622     if (cur == NULL)
7623         return(ctxt->context->node);
7624     return(NULL);
7625 }
7626 
7627 /**
7628  * xmlXPathNextChild:
7629  * @ctxt:  the XPath Parser context
7630  * @cur:  the current node in the traversal
7631  *
7632  * Traversal function for the "child" direction
7633  * The child axis contains the children of the context node in document order.
7634  *
7635  * Returns the next element following that axis
7636  */
7637 xmlNodePtr
xmlXPathNextChild(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7638 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7639     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7640     if (cur == NULL) {
7641 	if (ctxt->context->node == NULL) return(NULL);
7642 	switch (ctxt->context->node->type) {
7643             case XML_ELEMENT_NODE:
7644             case XML_TEXT_NODE:
7645             case XML_CDATA_SECTION_NODE:
7646             case XML_ENTITY_REF_NODE:
7647             case XML_ENTITY_NODE:
7648             case XML_PI_NODE:
7649             case XML_COMMENT_NODE:
7650             case XML_NOTATION_NODE:
7651             case XML_DTD_NODE:
7652 		return(ctxt->context->node->children);
7653             case XML_DOCUMENT_NODE:
7654             case XML_DOCUMENT_TYPE_NODE:
7655             case XML_DOCUMENT_FRAG_NODE:
7656             case XML_HTML_DOCUMENT_NODE:
7657 		return(((xmlDocPtr) ctxt->context->node)->children);
7658 	    case XML_ELEMENT_DECL:
7659 	    case XML_ATTRIBUTE_DECL:
7660 	    case XML_ENTITY_DECL:
7661             case XML_ATTRIBUTE_NODE:
7662 	    case XML_NAMESPACE_DECL:
7663 	    case XML_XINCLUDE_START:
7664 	    case XML_XINCLUDE_END:
7665 		return(NULL);
7666 	}
7667 	return(NULL);
7668     }
7669     if ((cur->type == XML_DOCUMENT_NODE) ||
7670         (cur->type == XML_HTML_DOCUMENT_NODE))
7671 	return(NULL);
7672     return(cur->next);
7673 }
7674 
7675 /**
7676  * xmlXPathNextChildElement:
7677  * @ctxt:  the XPath Parser context
7678  * @cur:  the current node in the traversal
7679  *
7680  * Traversal function for the "child" direction and nodes of type element.
7681  * The child axis contains the children of the context node in document order.
7682  *
7683  * Returns the next element following that axis
7684  */
7685 static xmlNodePtr
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7686 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7687     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7688     if (cur == NULL) {
7689 	cur = ctxt->context->node;
7690 	if (cur == NULL) return(NULL);
7691 	/*
7692 	* Get the first element child.
7693 	*/
7694 	switch (cur->type) {
7695             case XML_ELEMENT_NODE:
7696 	    case XML_DOCUMENT_FRAG_NODE:
7697 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7698             case XML_ENTITY_NODE:
7699 		cur = cur->children;
7700 		if (cur != NULL) {
7701 		    if (cur->type == XML_ELEMENT_NODE)
7702 			return(cur);
7703 		    do {
7704 			cur = cur->next;
7705 		    } while ((cur != NULL) &&
7706 			(cur->type != XML_ELEMENT_NODE));
7707 		    return(cur);
7708 		}
7709 		return(NULL);
7710             case XML_DOCUMENT_NODE:
7711             case XML_HTML_DOCUMENT_NODE:
7712 		return(xmlDocGetRootElement((xmlDocPtr) cur));
7713 	    default:
7714 		return(NULL);
7715 	}
7716 	return(NULL);
7717     }
7718     /*
7719     * Get the next sibling element node.
7720     */
7721     switch (cur->type) {
7722 	case XML_ELEMENT_NODE:
7723 	case XML_TEXT_NODE:
7724 	case XML_ENTITY_REF_NODE:
7725 	case XML_ENTITY_NODE:
7726 	case XML_CDATA_SECTION_NODE:
7727 	case XML_PI_NODE:
7728 	case XML_COMMENT_NODE:
7729 	case XML_XINCLUDE_END:
7730 	    break;
7731 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7732 	default:
7733 	    return(NULL);
7734     }
7735     if (cur->next != NULL) {
7736 	if (cur->next->type == XML_ELEMENT_NODE)
7737 	    return(cur->next);
7738 	cur = cur->next;
7739 	do {
7740 	    cur = cur->next;
7741 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7742 	return(cur);
7743     }
7744     return(NULL);
7745 }
7746 
7747 #if 0
7748 /**
7749  * xmlXPathNextDescendantOrSelfElemParent:
7750  * @ctxt:  the XPath Parser context
7751  * @cur:  the current node in the traversal
7752  *
7753  * Traversal function for the "descendant-or-self" axis.
7754  * Additionally it returns only nodes which can be parents of
7755  * element nodes.
7756  *
7757  *
7758  * Returns the next element following that axis
7759  */
7760 static xmlNodePtr
7761 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7762 				       xmlNodePtr contextNode)
7763 {
7764     if (cur == NULL) {
7765 	if (contextNode == NULL)
7766 	    return(NULL);
7767 	switch (contextNode->type) {
7768 	    case XML_ELEMENT_NODE:
7769 	    case XML_XINCLUDE_START:
7770 	    case XML_DOCUMENT_FRAG_NODE:
7771 	    case XML_DOCUMENT_NODE:
7772 	    case XML_HTML_DOCUMENT_NODE:
7773 		return(contextNode);
7774 	    default:
7775 		return(NULL);
7776 	}
7777 	return(NULL);
7778     } else {
7779 	xmlNodePtr start = cur;
7780 
7781 	while (cur != NULL) {
7782 	    switch (cur->type) {
7783 		case XML_ELEMENT_NODE:
7784 		/* TODO: OK to have XInclude here? */
7785 		case XML_XINCLUDE_START:
7786 		case XML_DOCUMENT_FRAG_NODE:
7787 		    if (cur != start)
7788 			return(cur);
7789 		    if (cur->children != NULL) {
7790 			cur = cur->children;
7791 			continue;
7792 		    }
7793 		    break;
7794 		/* Not sure if we need those here. */
7795 		case XML_DOCUMENT_NODE:
7796 		case XML_HTML_DOCUMENT_NODE:
7797 		    if (cur != start)
7798 			return(cur);
7799 		    return(xmlDocGetRootElement((xmlDocPtr) cur));
7800 		default:
7801 		    break;
7802 	    }
7803 
7804 next_sibling:
7805 	    if ((cur == NULL) || (cur == contextNode))
7806 		return(NULL);
7807 	    if (cur->next != NULL) {
7808 		cur = cur->next;
7809 	    } else {
7810 		cur = cur->parent;
7811 		goto next_sibling;
7812 	    }
7813 	}
7814     }
7815     return(NULL);
7816 }
7817 #endif
7818 
7819 /**
7820  * xmlXPathNextDescendant:
7821  * @ctxt:  the XPath Parser context
7822  * @cur:  the current node in the traversal
7823  *
7824  * Traversal function for the "descendant" direction
7825  * the descendant axis contains the descendants of the context node in document
7826  * order; a descendant is a child or a child of a child and so on.
7827  *
7828  * Returns the next element following that axis
7829  */
7830 xmlNodePtr
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7831 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7832     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7833     if (cur == NULL) {
7834 	if (ctxt->context->node == NULL)
7835 	    return(NULL);
7836 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7837 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7838 	    return(NULL);
7839 
7840         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7841 	    return(ctxt->context->doc->children);
7842         return(ctxt->context->node->children);
7843     }
7844 
7845     if (cur->type == XML_NAMESPACE_DECL)
7846         return(NULL);
7847     if (cur->children != NULL) {
7848 	/*
7849 	 * Do not descend on entities declarations
7850 	 */
7851 	if (cur->children->type != XML_ENTITY_DECL) {
7852 	    cur = cur->children;
7853 	    /*
7854 	     * Skip DTDs
7855 	     */
7856 	    if (cur->type != XML_DTD_NODE)
7857 		return(cur);
7858 	}
7859     }
7860 
7861     if (cur == ctxt->context->node) return(NULL);
7862 
7863     while (cur->next != NULL) {
7864 	cur = cur->next;
7865 	if ((cur->type != XML_ENTITY_DECL) &&
7866 	    (cur->type != XML_DTD_NODE))
7867 	    return(cur);
7868     }
7869 
7870     do {
7871         cur = cur->parent;
7872 	if (cur == NULL) break;
7873 	if (cur == ctxt->context->node) return(NULL);
7874 	if (cur->next != NULL) {
7875 	    cur = cur->next;
7876 	    return(cur);
7877 	}
7878     } while (cur != NULL);
7879     return(cur);
7880 }
7881 
7882 /**
7883  * xmlXPathNextDescendantOrSelf:
7884  * @ctxt:  the XPath Parser context
7885  * @cur:  the current node in the traversal
7886  *
7887  * Traversal function for the "descendant-or-self" direction
7888  * the descendant-or-self axis contains the context node and the descendants
7889  * of the context node in document order; thus the context node is the first
7890  * node on the axis, and the first child of the context node is the second node
7891  * on the axis
7892  *
7893  * Returns the next element following that axis
7894  */
7895 xmlNodePtr
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7896 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7897     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7898     if (cur == NULL)
7899         return(ctxt->context->node);
7900 
7901     if (ctxt->context->node == NULL)
7902         return(NULL);
7903     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7904         (ctxt->context->node->type == XML_NAMESPACE_DECL))
7905         return(NULL);
7906 
7907     return(xmlXPathNextDescendant(ctxt, cur));
7908 }
7909 
7910 /**
7911  * xmlXPathNextParent:
7912  * @ctxt:  the XPath Parser context
7913  * @cur:  the current node in the traversal
7914  *
7915  * Traversal function for the "parent" direction
7916  * The parent axis contains the parent of the context node, if there is one.
7917  *
7918  * Returns the next element following that axis
7919  */
7920 xmlNodePtr
xmlXPathNextParent(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7921 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7922     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7923     /*
7924      * the parent of an attribute or namespace node is the element
7925      * to which the attribute or namespace node is attached
7926      * Namespace handling !!!
7927      */
7928     if (cur == NULL) {
7929 	if (ctxt->context->node == NULL) return(NULL);
7930 	switch (ctxt->context->node->type) {
7931             case XML_ELEMENT_NODE:
7932             case XML_TEXT_NODE:
7933             case XML_CDATA_SECTION_NODE:
7934             case XML_ENTITY_REF_NODE:
7935             case XML_ENTITY_NODE:
7936             case XML_PI_NODE:
7937             case XML_COMMENT_NODE:
7938             case XML_NOTATION_NODE:
7939             case XML_DTD_NODE:
7940 	    case XML_ELEMENT_DECL:
7941 	    case XML_ATTRIBUTE_DECL:
7942 	    case XML_XINCLUDE_START:
7943 	    case XML_XINCLUDE_END:
7944 	    case XML_ENTITY_DECL:
7945 		if (ctxt->context->node->parent == NULL)
7946 		    return((xmlNodePtr) ctxt->context->doc);
7947 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7948 		    ((ctxt->context->node->parent->name[0] == ' ') ||
7949 		     (xmlStrEqual(ctxt->context->node->parent->name,
7950 				 BAD_CAST "fake node libxslt"))))
7951 		    return(NULL);
7952 		return(ctxt->context->node->parent);
7953             case XML_ATTRIBUTE_NODE: {
7954 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7955 
7956 		return(att->parent);
7957 	    }
7958             case XML_DOCUMENT_NODE:
7959             case XML_DOCUMENT_TYPE_NODE:
7960             case XML_DOCUMENT_FRAG_NODE:
7961             case XML_HTML_DOCUMENT_NODE:
7962                 return(NULL);
7963 	    case XML_NAMESPACE_DECL: {
7964 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7965 
7966 		if ((ns->next != NULL) &&
7967 		    (ns->next->type != XML_NAMESPACE_DECL))
7968 		    return((xmlNodePtr) ns->next);
7969                 return(NULL);
7970 	    }
7971 	}
7972     }
7973     return(NULL);
7974 }
7975 
7976 /**
7977  * xmlXPathNextAncestor:
7978  * @ctxt:  the XPath Parser context
7979  * @cur:  the current node in the traversal
7980  *
7981  * Traversal function for the "ancestor" direction
7982  * the ancestor axis contains the ancestors of the context node; the ancestors
7983  * of the context node consist of the parent of context node and the parent's
7984  * parent and so on; the nodes are ordered in reverse document order; thus the
7985  * parent is the first node on the axis, and the parent's parent is the second
7986  * node on the axis
7987  *
7988  * Returns the next element following that axis
7989  */
7990 xmlNodePtr
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7991 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7992     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7993     /*
7994      * the parent of an attribute or namespace node is the element
7995      * to which the attribute or namespace node is attached
7996      * !!!!!!!!!!!!!
7997      */
7998     if (cur == NULL) {
7999 	if (ctxt->context->node == NULL) return(NULL);
8000 	switch (ctxt->context->node->type) {
8001             case XML_ELEMENT_NODE:
8002             case XML_TEXT_NODE:
8003             case XML_CDATA_SECTION_NODE:
8004             case XML_ENTITY_REF_NODE:
8005             case XML_ENTITY_NODE:
8006             case XML_PI_NODE:
8007             case XML_COMMENT_NODE:
8008 	    case XML_DTD_NODE:
8009 	    case XML_ELEMENT_DECL:
8010 	    case XML_ATTRIBUTE_DECL:
8011 	    case XML_ENTITY_DECL:
8012             case XML_NOTATION_NODE:
8013 	    case XML_XINCLUDE_START:
8014 	    case XML_XINCLUDE_END:
8015 		if (ctxt->context->node->parent == NULL)
8016 		    return((xmlNodePtr) ctxt->context->doc);
8017 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8018 		    ((ctxt->context->node->parent->name[0] == ' ') ||
8019 		     (xmlStrEqual(ctxt->context->node->parent->name,
8020 				 BAD_CAST "fake node libxslt"))))
8021 		    return(NULL);
8022 		return(ctxt->context->node->parent);
8023             case XML_ATTRIBUTE_NODE: {
8024 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8025 
8026 		return(tmp->parent);
8027 	    }
8028             case XML_DOCUMENT_NODE:
8029             case XML_DOCUMENT_TYPE_NODE:
8030             case XML_DOCUMENT_FRAG_NODE:
8031             case XML_HTML_DOCUMENT_NODE:
8032                 return(NULL);
8033 	    case XML_NAMESPACE_DECL: {
8034 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8035 
8036 		if ((ns->next != NULL) &&
8037 		    (ns->next->type != XML_NAMESPACE_DECL))
8038 		    return((xmlNodePtr) ns->next);
8039 		/* Bad, how did that namespace end up here ? */
8040                 return(NULL);
8041 	    }
8042 	}
8043 	return(NULL);
8044     }
8045     if (cur == ctxt->context->doc->children)
8046 	return((xmlNodePtr) ctxt->context->doc);
8047     if (cur == (xmlNodePtr) ctxt->context->doc)
8048 	return(NULL);
8049     switch (cur->type) {
8050 	case XML_ELEMENT_NODE:
8051 	case XML_TEXT_NODE:
8052 	case XML_CDATA_SECTION_NODE:
8053 	case XML_ENTITY_REF_NODE:
8054 	case XML_ENTITY_NODE:
8055 	case XML_PI_NODE:
8056 	case XML_COMMENT_NODE:
8057 	case XML_NOTATION_NODE:
8058 	case XML_DTD_NODE:
8059         case XML_ELEMENT_DECL:
8060         case XML_ATTRIBUTE_DECL:
8061         case XML_ENTITY_DECL:
8062 	case XML_XINCLUDE_START:
8063 	case XML_XINCLUDE_END:
8064 	    if (cur->parent == NULL)
8065 		return(NULL);
8066 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
8067 		((cur->parent->name[0] == ' ') ||
8068 		 (xmlStrEqual(cur->parent->name,
8069 			      BAD_CAST "fake node libxslt"))))
8070 		return(NULL);
8071 	    return(cur->parent);
8072 	case XML_ATTRIBUTE_NODE: {
8073 	    xmlAttrPtr att = (xmlAttrPtr) cur;
8074 
8075 	    return(att->parent);
8076 	}
8077 	case XML_NAMESPACE_DECL: {
8078 	    xmlNsPtr ns = (xmlNsPtr) cur;
8079 
8080 	    if ((ns->next != NULL) &&
8081 	        (ns->next->type != XML_NAMESPACE_DECL))
8082 	        return((xmlNodePtr) ns->next);
8083 	    /* Bad, how did that namespace end up here ? */
8084             return(NULL);
8085 	}
8086 	case XML_DOCUMENT_NODE:
8087 	case XML_DOCUMENT_TYPE_NODE:
8088 	case XML_DOCUMENT_FRAG_NODE:
8089 	case XML_HTML_DOCUMENT_NODE:
8090 	    return(NULL);
8091     }
8092     return(NULL);
8093 }
8094 
8095 /**
8096  * xmlXPathNextAncestorOrSelf:
8097  * @ctxt:  the XPath Parser context
8098  * @cur:  the current node in the traversal
8099  *
8100  * Traversal function for the "ancestor-or-self" direction
8101  * he ancestor-or-self axis contains the context node and ancestors of
8102  * the context node in reverse document order; thus the context node is
8103  * the first node on the axis, and the context node's parent the second;
8104  * parent here is defined the same as with the parent axis.
8105  *
8106  * Returns the next element following that axis
8107  */
8108 xmlNodePtr
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8109 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8110     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8111     if (cur == NULL)
8112         return(ctxt->context->node);
8113     return(xmlXPathNextAncestor(ctxt, cur));
8114 }
8115 
8116 /**
8117  * xmlXPathNextFollowingSibling:
8118  * @ctxt:  the XPath Parser context
8119  * @cur:  the current node in the traversal
8120  *
8121  * Traversal function for the "following-sibling" direction
8122  * The following-sibling axis contains the following siblings of the context
8123  * node in document order.
8124  *
8125  * Returns the next element following that axis
8126  */
8127 xmlNodePtr
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8128 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8129     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8130     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8131 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8132 	return(NULL);
8133     if (cur == (xmlNodePtr) ctxt->context->doc)
8134         return(NULL);
8135     if (cur == NULL)
8136         return(ctxt->context->node->next);
8137     return(cur->next);
8138 }
8139 
8140 /**
8141  * xmlXPathNextPrecedingSibling:
8142  * @ctxt:  the XPath Parser context
8143  * @cur:  the current node in the traversal
8144  *
8145  * Traversal function for the "preceding-sibling" direction
8146  * The preceding-sibling axis contains the preceding siblings of the context
8147  * node in reverse document order; the first preceding sibling is first on the
8148  * axis; the sibling preceding that node is the second on the axis and so on.
8149  *
8150  * Returns the next element following that axis
8151  */
8152 xmlNodePtr
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8153 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8154     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8155     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8156 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8157 	return(NULL);
8158     if (cur == (xmlNodePtr) ctxt->context->doc)
8159         return(NULL);
8160     if (cur == NULL)
8161         return(ctxt->context->node->prev);
8162     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8163 	cur = cur->prev;
8164 	if (cur == NULL)
8165 	    return(ctxt->context->node->prev);
8166     }
8167     return(cur->prev);
8168 }
8169 
8170 /**
8171  * xmlXPathNextFollowing:
8172  * @ctxt:  the XPath Parser context
8173  * @cur:  the current node in the traversal
8174  *
8175  * Traversal function for the "following" direction
8176  * The following axis contains all nodes in the same document as the context
8177  * node that are after the context node in document order, excluding any
8178  * descendants and excluding attribute nodes and namespace nodes; the nodes
8179  * are ordered in document order
8180  *
8181  * Returns the next element following that axis
8182  */
8183 xmlNodePtr
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8184 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8185     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8186     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8187         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8188         return(cur->children);
8189 
8190     if (cur == NULL) {
8191         cur = ctxt->context->node;
8192         if (cur->type == XML_ATTRIBUTE_NODE) {
8193             cur = cur->parent;
8194         } else if (cur->type == XML_NAMESPACE_DECL) {
8195             xmlNsPtr ns = (xmlNsPtr) cur;
8196 
8197             if ((ns->next == NULL) ||
8198                 (ns->next->type == XML_NAMESPACE_DECL))
8199                 return (NULL);
8200             cur = (xmlNodePtr) ns->next;
8201         }
8202     }
8203     if (cur == NULL) return(NULL) ; /* ERROR */
8204     if (cur->next != NULL) return(cur->next) ;
8205     do {
8206         cur = cur->parent;
8207         if (cur == NULL) break;
8208         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8209         if (cur->next != NULL) return(cur->next);
8210     } while (cur != NULL);
8211     return(cur);
8212 }
8213 
8214 /*
8215  * xmlXPathIsAncestor:
8216  * @ancestor:  the ancestor node
8217  * @node:  the current node
8218  *
8219  * Check that @ancestor is a @node's ancestor
8220  *
8221  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8222  */
8223 static int
xmlXPathIsAncestor(xmlNodePtr ancestor,xmlNodePtr node)8224 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8225     if ((ancestor == NULL) || (node == NULL)) return(0);
8226     if (node->type == XML_NAMESPACE_DECL)
8227         return(0);
8228     if (ancestor->type == XML_NAMESPACE_DECL)
8229         return(0);
8230     /* nodes need to be in the same document */
8231     if (ancestor->doc != node->doc) return(0);
8232     /* avoid searching if ancestor or node is the root node */
8233     if (ancestor == (xmlNodePtr) node->doc) return(1);
8234     if (node == (xmlNodePtr) ancestor->doc) return(0);
8235     while (node->parent != NULL) {
8236         if (node->parent == ancestor)
8237             return(1);
8238 	node = node->parent;
8239     }
8240     return(0);
8241 }
8242 
8243 /**
8244  * xmlXPathNextPreceding:
8245  * @ctxt:  the XPath Parser context
8246  * @cur:  the current node in the traversal
8247  *
8248  * Traversal function for the "preceding" direction
8249  * the preceding axis contains all nodes in the same document as the context
8250  * node that are before the context node in document order, excluding any
8251  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8252  * ordered in reverse document order
8253  *
8254  * Returns the next element following that axis
8255  */
8256 xmlNodePtr
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8257 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8258 {
8259     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8260     if (cur == NULL) {
8261         cur = ctxt->context->node;
8262         if (cur->type == XML_ATTRIBUTE_NODE) {
8263             cur = cur->parent;
8264         } else if (cur->type == XML_NAMESPACE_DECL) {
8265             xmlNsPtr ns = (xmlNsPtr) cur;
8266 
8267             if ((ns->next == NULL) ||
8268                 (ns->next->type == XML_NAMESPACE_DECL))
8269                 return (NULL);
8270             cur = (xmlNodePtr) ns->next;
8271         }
8272     }
8273     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8274 	return (NULL);
8275     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8276 	cur = cur->prev;
8277     do {
8278         if (cur->prev != NULL) {
8279             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8280             return (cur);
8281         }
8282 
8283         cur = cur->parent;
8284         if (cur == NULL)
8285             return (NULL);
8286         if (cur == ctxt->context->doc->children)
8287             return (NULL);
8288     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8289     return (cur);
8290 }
8291 
8292 /**
8293  * xmlXPathNextPrecedingInternal:
8294  * @ctxt:  the XPath Parser context
8295  * @cur:  the current node in the traversal
8296  *
8297  * Traversal function for the "preceding" direction
8298  * the preceding axis contains all nodes in the same document as the context
8299  * node that are before the context node in document order, excluding any
8300  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8301  * ordered in reverse document order
8302  * This is a faster implementation but internal only since it requires a
8303  * state kept in the parser context: ctxt->ancestor.
8304  *
8305  * Returns the next element following that axis
8306  */
8307 static xmlNodePtr
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8308 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8309                               xmlNodePtr cur)
8310 {
8311     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8312     if (cur == NULL) {
8313         cur = ctxt->context->node;
8314         if (cur == NULL)
8315             return (NULL);
8316         if (cur->type == XML_ATTRIBUTE_NODE) {
8317             cur = cur->parent;
8318         } else if (cur->type == XML_NAMESPACE_DECL) {
8319             xmlNsPtr ns = (xmlNsPtr) cur;
8320 
8321             if ((ns->next == NULL) ||
8322                 (ns->next->type == XML_NAMESPACE_DECL))
8323                 return (NULL);
8324             cur = (xmlNodePtr) ns->next;
8325         }
8326         ctxt->ancestor = cur->parent;
8327     }
8328     if (cur->type == XML_NAMESPACE_DECL)
8329         return(NULL);
8330     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8331 	cur = cur->prev;
8332     while (cur->prev == NULL) {
8333         cur = cur->parent;
8334         if (cur == NULL)
8335             return (NULL);
8336         if (cur == ctxt->context->doc->children)
8337             return (NULL);
8338         if (cur != ctxt->ancestor)
8339             return (cur);
8340         ctxt->ancestor = cur->parent;
8341     }
8342     cur = cur->prev;
8343     while (cur->last != NULL)
8344         cur = cur->last;
8345     return (cur);
8346 }
8347 
8348 /**
8349  * xmlXPathNextNamespace:
8350  * @ctxt:  the XPath Parser context
8351  * @cur:  the current attribute in the traversal
8352  *
8353  * Traversal function for the "namespace" direction
8354  * the namespace axis contains the namespace nodes of the context node;
8355  * the order of nodes on this axis is implementation-defined; the axis will
8356  * be empty unless the context node is an element
8357  *
8358  * We keep the XML namespace node at the end of the list.
8359  *
8360  * Returns the next element following that axis
8361  */
8362 xmlNodePtr
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8363 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8364     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8365     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8366     if (cur == NULL) {
8367         if (ctxt->context->tmpNsList != NULL)
8368 	    xmlFree(ctxt->context->tmpNsList);
8369 	ctxt->context->tmpNsList =
8370 	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8371 	ctxt->context->tmpNsNr = 0;
8372 	if (ctxt->context->tmpNsList != NULL) {
8373 	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8374 		ctxt->context->tmpNsNr++;
8375 	    }
8376 	}
8377 	return((xmlNodePtr) xmlXPathXMLNamespace);
8378     }
8379     if (ctxt->context->tmpNsNr > 0) {
8380 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8381     } else {
8382 	if (ctxt->context->tmpNsList != NULL)
8383 	    xmlFree(ctxt->context->tmpNsList);
8384 	ctxt->context->tmpNsList = NULL;
8385 	return(NULL);
8386     }
8387 }
8388 
8389 /**
8390  * xmlXPathNextAttribute:
8391  * @ctxt:  the XPath Parser context
8392  * @cur:  the current attribute in the traversal
8393  *
8394  * Traversal function for the "attribute" direction
8395  * TODO: support DTD inherited default attributes
8396  *
8397  * Returns the next element following that axis
8398  */
8399 xmlNodePtr
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8400 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8401     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8402     if (ctxt->context->node == NULL)
8403 	return(NULL);
8404     if (ctxt->context->node->type != XML_ELEMENT_NODE)
8405 	return(NULL);
8406     if (cur == NULL) {
8407         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8408 	    return(NULL);
8409         return((xmlNodePtr)ctxt->context->node->properties);
8410     }
8411     return((xmlNodePtr)cur->next);
8412 }
8413 
8414 /************************************************************************
8415  *									*
8416  *		NodeTest Functions					*
8417  *									*
8418  ************************************************************************/
8419 
8420 #define IS_FUNCTION			200
8421 
8422 
8423 /************************************************************************
8424  *									*
8425  *		Implicit tree core function library			*
8426  *									*
8427  ************************************************************************/
8428 
8429 /**
8430  * xmlXPathRoot:
8431  * @ctxt:  the XPath Parser context
8432  *
8433  * Initialize the context to the root of the document
8434  */
8435 void
xmlXPathRoot(xmlXPathParserContextPtr ctxt)8436 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8437     if ((ctxt == NULL) || (ctxt->context == NULL))
8438 	return;
8439     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8440 	(xmlNodePtr) ctxt->context->doc));
8441 }
8442 
8443 /************************************************************************
8444  *									*
8445  *		The explicit core function library			*
8446  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
8447  *									*
8448  ************************************************************************/
8449 
8450 
8451 /**
8452  * xmlXPathLastFunction:
8453  * @ctxt:  the XPath Parser context
8454  * @nargs:  the number of arguments
8455  *
8456  * Implement the last() XPath function
8457  *    number last()
8458  * The last function returns the number of nodes in the context node list.
8459  */
8460 void
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt,int nargs)8461 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8462     CHECK_ARITY(0);
8463     if (ctxt->context->contextSize >= 0) {
8464 	valuePush(ctxt,
8465 	    xmlXPathCacheNewFloat(ctxt->context,
8466 		(double) ctxt->context->contextSize));
8467 #ifdef DEBUG_EXPR
8468 	xmlGenericError(xmlGenericErrorContext,
8469 		"last() : %d\n", ctxt->context->contextSize);
8470 #endif
8471     } else {
8472 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8473     }
8474 }
8475 
8476 /**
8477  * xmlXPathPositionFunction:
8478  * @ctxt:  the XPath Parser context
8479  * @nargs:  the number of arguments
8480  *
8481  * Implement the position() XPath function
8482  *    number position()
8483  * The position function returns the position of the context node in the
8484  * context node list. The first position is 1, and so the last position
8485  * will be equal to last().
8486  */
8487 void
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt,int nargs)8488 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8489     CHECK_ARITY(0);
8490     if (ctxt->context->proximityPosition >= 0) {
8491 	valuePush(ctxt,
8492 	      xmlXPathCacheNewFloat(ctxt->context,
8493 		(double) ctxt->context->proximityPosition));
8494 #ifdef DEBUG_EXPR
8495 	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8496 		ctxt->context->proximityPosition);
8497 #endif
8498     } else {
8499 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8500     }
8501 }
8502 
8503 /**
8504  * xmlXPathCountFunction:
8505  * @ctxt:  the XPath Parser context
8506  * @nargs:  the number of arguments
8507  *
8508  * Implement the count() XPath function
8509  *    number count(node-set)
8510  */
8511 void
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt,int nargs)8512 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8513     xmlXPathObjectPtr cur;
8514 
8515     CHECK_ARITY(1);
8516     if ((ctxt->value == NULL) ||
8517 	((ctxt->value->type != XPATH_NODESET) &&
8518 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8519 	XP_ERROR(XPATH_INVALID_TYPE);
8520     cur = valuePop(ctxt);
8521 
8522     if ((cur == NULL) || (cur->nodesetval == NULL))
8523 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8524     else
8525 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8526 	    (double) cur->nodesetval->nodeNr));
8527     xmlXPathReleaseObject(ctxt->context, cur);
8528 }
8529 
8530 /**
8531  * xmlXPathGetElementsByIds:
8532  * @doc:  the document
8533  * @ids:  a whitespace separated list of IDs
8534  *
8535  * Selects elements by their unique ID.
8536  *
8537  * Returns a node-set of selected elements.
8538  */
8539 static xmlNodeSetPtr
xmlXPathGetElementsByIds(xmlDocPtr doc,const xmlChar * ids)8540 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8541     xmlNodeSetPtr ret;
8542     const xmlChar *cur = ids;
8543     xmlChar *ID;
8544     xmlAttrPtr attr;
8545     xmlNodePtr elem = NULL;
8546 
8547     if (ids == NULL) return(NULL);
8548 
8549     ret = xmlXPathNodeSetCreate(NULL);
8550     if (ret == NULL)
8551         return(ret);
8552 
8553     while (IS_BLANK_CH(*cur)) cur++;
8554     while (*cur != 0) {
8555 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8556 	    cur++;
8557 
8558         ID = xmlStrndup(ids, cur - ids);
8559 	if (ID != NULL) {
8560 	    /*
8561 	     * We used to check the fact that the value passed
8562 	     * was an NCName, but this generated much troubles for
8563 	     * me and Aleksey Sanin, people blatantly violated that
8564 	     * constraint, like Visa3D spec.
8565 	     * if (xmlValidateNCName(ID, 1) == 0)
8566 	     */
8567 	    attr = xmlGetID(doc, ID);
8568 	    if (attr != NULL) {
8569 		if (attr->type == XML_ATTRIBUTE_NODE)
8570 		    elem = attr->parent;
8571 		else if (attr->type == XML_ELEMENT_NODE)
8572 		    elem = (xmlNodePtr) attr;
8573 		else
8574 		    elem = NULL;
8575                 /* TODO: Check memory error. */
8576 		if (elem != NULL)
8577 		    xmlXPathNodeSetAdd(ret, elem);
8578 	    }
8579 	    xmlFree(ID);
8580 	}
8581 
8582 	while (IS_BLANK_CH(*cur)) cur++;
8583 	ids = cur;
8584     }
8585     return(ret);
8586 }
8587 
8588 /**
8589  * xmlXPathIdFunction:
8590  * @ctxt:  the XPath Parser context
8591  * @nargs:  the number of arguments
8592  *
8593  * Implement the id() XPath function
8594  *    node-set id(object)
8595  * The id function selects elements by their unique ID
8596  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8597  * then the result is the union of the result of applying id to the
8598  * string value of each of the nodes in the argument node-set. When the
8599  * argument to id is of any other type, the argument is converted to a
8600  * string as if by a call to the string function; the string is split
8601  * into a whitespace-separated list of tokens (whitespace is any sequence
8602  * of characters matching the production S); the result is a node-set
8603  * containing the elements in the same document as the context node that
8604  * have a unique ID equal to any of the tokens in the list.
8605  */
8606 void
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt,int nargs)8607 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8608     xmlChar *tokens;
8609     xmlNodeSetPtr ret;
8610     xmlXPathObjectPtr obj;
8611 
8612     CHECK_ARITY(1);
8613     obj = valuePop(ctxt);
8614     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8615     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8616 	xmlNodeSetPtr ns;
8617 	int i;
8618 
8619         /* TODO: Check memory error. */
8620 	ret = xmlXPathNodeSetCreate(NULL);
8621 
8622 	if (obj->nodesetval != NULL) {
8623 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8624 		tokens =
8625 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8626 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8627                 /* TODO: Check memory error. */
8628 		ret = xmlXPathNodeSetMerge(ret, ns);
8629 		xmlXPathFreeNodeSet(ns);
8630 		if (tokens != NULL)
8631 		    xmlFree(tokens);
8632 	    }
8633 	}
8634 	xmlXPathReleaseObject(ctxt->context, obj);
8635 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8636 	return;
8637     }
8638     obj = xmlXPathCacheConvertString(ctxt->context, obj);
8639     if (obj == NULL) return;
8640     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8641     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8642     xmlXPathReleaseObject(ctxt->context, obj);
8643     return;
8644 }
8645 
8646 /**
8647  * xmlXPathLocalNameFunction:
8648  * @ctxt:  the XPath Parser context
8649  * @nargs:  the number of arguments
8650  *
8651  * Implement the local-name() XPath function
8652  *    string local-name(node-set?)
8653  * The local-name function returns a string containing the local part
8654  * of the name of the node in the argument node-set that is first in
8655  * document order. If the node-set is empty or the first node has no
8656  * name, an empty string is returned. If the argument is omitted it
8657  * defaults to the context node.
8658  */
8659 void
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8660 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8661     xmlXPathObjectPtr cur;
8662 
8663     if (ctxt == NULL) return;
8664 
8665     if (nargs == 0) {
8666 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8667 	    ctxt->context->node));
8668 	nargs = 1;
8669     }
8670 
8671     CHECK_ARITY(1);
8672     if ((ctxt->value == NULL) ||
8673 	((ctxt->value->type != XPATH_NODESET) &&
8674 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8675 	XP_ERROR(XPATH_INVALID_TYPE);
8676     cur = valuePop(ctxt);
8677 
8678     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8679 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8680     } else {
8681 	int i = 0; /* Should be first in document order !!!!! */
8682 	switch (cur->nodesetval->nodeTab[i]->type) {
8683 	case XML_ELEMENT_NODE:
8684 	case XML_ATTRIBUTE_NODE:
8685 	case XML_PI_NODE:
8686 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8687 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8688 	    else
8689 		valuePush(ctxt,
8690 		      xmlXPathCacheNewString(ctxt->context,
8691 			cur->nodesetval->nodeTab[i]->name));
8692 	    break;
8693 	case XML_NAMESPACE_DECL:
8694 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8695 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8696 	    break;
8697 	default:
8698 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8699 	}
8700     }
8701     xmlXPathReleaseObject(ctxt->context, cur);
8702 }
8703 
8704 /**
8705  * xmlXPathNamespaceURIFunction:
8706  * @ctxt:  the XPath Parser context
8707  * @nargs:  the number of arguments
8708  *
8709  * Implement the namespace-uri() XPath function
8710  *    string namespace-uri(node-set?)
8711  * The namespace-uri function returns a string containing the
8712  * namespace URI of the expanded name of the node in the argument
8713  * node-set that is first in document order. If the node-set is empty,
8714  * the first node has no name, or the expanded name has no namespace
8715  * URI, an empty string is returned. If the argument is omitted it
8716  * defaults to the context node.
8717  */
8718 void
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt,int nargs)8719 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8720     xmlXPathObjectPtr cur;
8721 
8722     if (ctxt == NULL) return;
8723 
8724     if (nargs == 0) {
8725 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8726 	    ctxt->context->node));
8727 	nargs = 1;
8728     }
8729     CHECK_ARITY(1);
8730     if ((ctxt->value == NULL) ||
8731 	((ctxt->value->type != XPATH_NODESET) &&
8732 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8733 	XP_ERROR(XPATH_INVALID_TYPE);
8734     cur = valuePop(ctxt);
8735 
8736     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8737 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8738     } else {
8739 	int i = 0; /* Should be first in document order !!!!! */
8740 	switch (cur->nodesetval->nodeTab[i]->type) {
8741 	case XML_ELEMENT_NODE:
8742 	case XML_ATTRIBUTE_NODE:
8743 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
8744 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8745 	    else
8746 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8747 			  cur->nodesetval->nodeTab[i]->ns->href));
8748 	    break;
8749 	default:
8750 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8751 	}
8752     }
8753     xmlXPathReleaseObject(ctxt->context, cur);
8754 }
8755 
8756 /**
8757  * xmlXPathNameFunction:
8758  * @ctxt:  the XPath Parser context
8759  * @nargs:  the number of arguments
8760  *
8761  * Implement the name() XPath function
8762  *    string name(node-set?)
8763  * The name function returns a string containing a QName representing
8764  * the name of the node in the argument node-set that is first in document
8765  * order. The QName must represent the name with respect to the namespace
8766  * declarations in effect on the node whose name is being represented.
8767  * Typically, this will be the form in which the name occurred in the XML
8768  * source. This need not be the case if there are namespace declarations
8769  * in effect on the node that associate multiple prefixes with the same
8770  * namespace. However, an implementation may include information about
8771  * the original prefix in its representation of nodes; in this case, an
8772  * implementation can ensure that the returned string is always the same
8773  * as the QName used in the XML source. If the argument it omitted it
8774  * defaults to the context node.
8775  * Libxml keep the original prefix so the "real qualified name" used is
8776  * returned.
8777  */
8778 static void
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8779 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8780 {
8781     xmlXPathObjectPtr cur;
8782 
8783     if (nargs == 0) {
8784 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8785 	    ctxt->context->node));
8786         nargs = 1;
8787     }
8788 
8789     CHECK_ARITY(1);
8790     if ((ctxt->value == NULL) ||
8791         ((ctxt->value->type != XPATH_NODESET) &&
8792          (ctxt->value->type != XPATH_XSLT_TREE)))
8793         XP_ERROR(XPATH_INVALID_TYPE);
8794     cur = valuePop(ctxt);
8795 
8796     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8797         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8798     } else {
8799         int i = 0;              /* Should be first in document order !!!!! */
8800 
8801         switch (cur->nodesetval->nodeTab[i]->type) {
8802             case XML_ELEMENT_NODE:
8803             case XML_ATTRIBUTE_NODE:
8804 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8805 		    valuePush(ctxt,
8806 			xmlXPathCacheNewCString(ctxt->context, ""));
8807 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8808                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8809 		    valuePush(ctxt,
8810 		        xmlXPathCacheNewString(ctxt->context,
8811 			    cur->nodesetval->nodeTab[i]->name));
8812 		} else {
8813 		    xmlChar *fullname;
8814 
8815 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8816 				     cur->nodesetval->nodeTab[i]->ns->prefix,
8817 				     NULL, 0);
8818 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
8819 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8820 		    if (fullname == NULL)
8821                         xmlXPathPErrMemory(ctxt, NULL);
8822 		    valuePush(ctxt, xmlXPathCacheWrapString(
8823 			ctxt->context, fullname));
8824                 }
8825                 break;
8826             default:
8827 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8828 		    cur->nodesetval->nodeTab[i]));
8829                 xmlXPathLocalNameFunction(ctxt, 1);
8830         }
8831     }
8832     xmlXPathReleaseObject(ctxt->context, cur);
8833 }
8834 
8835 
8836 /**
8837  * xmlXPathStringFunction:
8838  * @ctxt:  the XPath Parser context
8839  * @nargs:  the number of arguments
8840  *
8841  * Implement the string() XPath function
8842  *    string string(object?)
8843  * The string function converts an object to a string as follows:
8844  *    - A node-set is converted to a string by returning the value of
8845  *      the node in the node-set that is first in document order.
8846  *      If the node-set is empty, an empty string is returned.
8847  *    - A number is converted to a string as follows
8848  *      + NaN is converted to the string NaN
8849  *      + positive zero is converted to the string 0
8850  *      + negative zero is converted to the string 0
8851  *      + positive infinity is converted to the string Infinity
8852  *      + negative infinity is converted to the string -Infinity
8853  *      + if the number is an integer, the number is represented in
8854  *        decimal form as a Number with no decimal point and no leading
8855  *        zeros, preceded by a minus sign (-) if the number is negative
8856  *      + otherwise, the number is represented in decimal form as a
8857  *        Number including a decimal point with at least one digit
8858  *        before the decimal point and at least one digit after the
8859  *        decimal point, preceded by a minus sign (-) if the number
8860  *        is negative; there must be no leading zeros before the decimal
8861  *        point apart possibly from the one required digit immediately
8862  *        before the decimal point; beyond the one required digit
8863  *        after the decimal point there must be as many, but only as
8864  *        many, more digits as are needed to uniquely distinguish the
8865  *        number from all other IEEE 754 numeric values.
8866  *    - The boolean false value is converted to the string false.
8867  *      The boolean true value is converted to the string true.
8868  *
8869  * If the argument is omitted, it defaults to a node-set with the
8870  * context node as its only member.
8871  */
8872 void
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt,int nargs)8873 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8874     xmlXPathObjectPtr cur;
8875 
8876     if (ctxt == NULL) return;
8877     if (nargs == 0) {
8878     valuePush(ctxt,
8879 	xmlXPathCacheWrapString(ctxt->context,
8880 	    xmlXPathCastNodeToString(ctxt->context->node)));
8881 	return;
8882     }
8883 
8884     CHECK_ARITY(1);
8885     cur = valuePop(ctxt);
8886     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8887     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8888 }
8889 
8890 /**
8891  * xmlXPathStringLengthFunction:
8892  * @ctxt:  the XPath Parser context
8893  * @nargs:  the number of arguments
8894  *
8895  * Implement the string-length() XPath function
8896  *    number string-length(string?)
8897  * The string-length returns the number of characters in the string
8898  * (see [3.6 Strings]). If the argument is omitted, it defaults to
8899  * the context node converted to a string, in other words the value
8900  * of the context node.
8901  */
8902 void
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt,int nargs)8903 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8904     xmlXPathObjectPtr cur;
8905 
8906     if (nargs == 0) {
8907         if ((ctxt == NULL) || (ctxt->context == NULL))
8908 	    return;
8909 	if (ctxt->context->node == NULL) {
8910 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8911 	} else {
8912 	    xmlChar *content;
8913 
8914 	    content = xmlXPathCastNodeToString(ctxt->context->node);
8915 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8916 		xmlUTF8Strlen(content)));
8917 	    xmlFree(content);
8918 	}
8919 	return;
8920     }
8921     CHECK_ARITY(1);
8922     CAST_TO_STRING;
8923     CHECK_TYPE(XPATH_STRING);
8924     cur = valuePop(ctxt);
8925     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8926 	xmlUTF8Strlen(cur->stringval)));
8927     xmlXPathReleaseObject(ctxt->context, cur);
8928 }
8929 
8930 /**
8931  * xmlXPathConcatFunction:
8932  * @ctxt:  the XPath Parser context
8933  * @nargs:  the number of arguments
8934  *
8935  * Implement the concat() XPath function
8936  *    string concat(string, string, string*)
8937  * The concat function returns the concatenation of its arguments.
8938  */
8939 void
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt,int nargs)8940 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8941     xmlXPathObjectPtr cur, newobj;
8942     xmlChar *tmp;
8943 
8944     if (ctxt == NULL) return;
8945     if (nargs < 2) {
8946 	CHECK_ARITY(2);
8947     }
8948 
8949     CAST_TO_STRING;
8950     cur = valuePop(ctxt);
8951     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8952 	xmlXPathReleaseObject(ctxt->context, cur);
8953 	return;
8954     }
8955     nargs--;
8956 
8957     while (nargs > 0) {
8958 	CAST_TO_STRING;
8959 	newobj = valuePop(ctxt);
8960 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8961 	    xmlXPathReleaseObject(ctxt->context, newobj);
8962 	    xmlXPathReleaseObject(ctxt->context, cur);
8963 	    XP_ERROR(XPATH_INVALID_TYPE);
8964 	}
8965 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
8966 	newobj->stringval = cur->stringval;
8967 	cur->stringval = tmp;
8968 	xmlXPathReleaseObject(ctxt->context, newobj);
8969 	nargs--;
8970     }
8971     valuePush(ctxt, cur);
8972 }
8973 
8974 /**
8975  * xmlXPathContainsFunction:
8976  * @ctxt:  the XPath Parser context
8977  * @nargs:  the number of arguments
8978  *
8979  * Implement the contains() XPath function
8980  *    boolean contains(string, string)
8981  * The contains function returns true if the first argument string
8982  * contains the second argument string, and otherwise returns false.
8983  */
8984 void
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt,int nargs)8985 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8986     xmlXPathObjectPtr hay, needle;
8987 
8988     CHECK_ARITY(2);
8989     CAST_TO_STRING;
8990     CHECK_TYPE(XPATH_STRING);
8991     needle = valuePop(ctxt);
8992     CAST_TO_STRING;
8993     hay = valuePop(ctxt);
8994 
8995     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8996 	xmlXPathReleaseObject(ctxt->context, hay);
8997 	xmlXPathReleaseObject(ctxt->context, needle);
8998 	XP_ERROR(XPATH_INVALID_TYPE);
8999     }
9000     if (xmlStrstr(hay->stringval, needle->stringval))
9001 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9002     else
9003 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9004     xmlXPathReleaseObject(ctxt->context, hay);
9005     xmlXPathReleaseObject(ctxt->context, needle);
9006 }
9007 
9008 /**
9009  * xmlXPathStartsWithFunction:
9010  * @ctxt:  the XPath Parser context
9011  * @nargs:  the number of arguments
9012  *
9013  * Implement the starts-with() XPath function
9014  *    boolean starts-with(string, string)
9015  * The starts-with function returns true if the first argument string
9016  * starts with the second argument string, and otherwise returns false.
9017  */
9018 void
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt,int nargs)9019 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9020     xmlXPathObjectPtr hay, needle;
9021     int n;
9022 
9023     CHECK_ARITY(2);
9024     CAST_TO_STRING;
9025     CHECK_TYPE(XPATH_STRING);
9026     needle = valuePop(ctxt);
9027     CAST_TO_STRING;
9028     hay = valuePop(ctxt);
9029 
9030     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9031 	xmlXPathReleaseObject(ctxt->context, hay);
9032 	xmlXPathReleaseObject(ctxt->context, needle);
9033 	XP_ERROR(XPATH_INVALID_TYPE);
9034     }
9035     n = xmlStrlen(needle->stringval);
9036     if (xmlStrncmp(hay->stringval, needle->stringval, n))
9037         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9038     else
9039         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9040     xmlXPathReleaseObject(ctxt->context, hay);
9041     xmlXPathReleaseObject(ctxt->context, needle);
9042 }
9043 
9044 /**
9045  * xmlXPathSubstringFunction:
9046  * @ctxt:  the XPath Parser context
9047  * @nargs:  the number of arguments
9048  *
9049  * Implement the substring() XPath function
9050  *    string substring(string, number, number?)
9051  * The substring function returns the substring of the first argument
9052  * starting at the position specified in the second argument with
9053  * length specified in the third argument. For example,
9054  * substring("12345",2,3) returns "234". If the third argument is not
9055  * specified, it returns the substring starting at the position specified
9056  * in the second argument and continuing to the end of the string. For
9057  * example, substring("12345",2) returns "2345".  More precisely, each
9058  * character in the string (see [3.6 Strings]) is considered to have a
9059  * numeric position: the position of the first character is 1, the position
9060  * of the second character is 2 and so on. The returned substring contains
9061  * those characters for which the position of the character is greater than
9062  * or equal to the second argument and, if the third argument is specified,
9063  * less than the sum of the second and third arguments; the comparisons
9064  * and addition used for the above follow the standard IEEE 754 rules. Thus:
9065  *  - substring("12345", 1.5, 2.6) returns "234"
9066  *  - substring("12345", 0, 3) returns "12"
9067  *  - substring("12345", 0 div 0, 3) returns ""
9068  *  - substring("12345", 1, 0 div 0) returns ""
9069  *  - substring("12345", -42, 1 div 0) returns "12345"
9070  *  - substring("12345", -1 div 0, 1 div 0) returns ""
9071  */
9072 void
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt,int nargs)9073 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9074     xmlXPathObjectPtr str, start, len;
9075     double le=0, in;
9076     int i = 1, j = INT_MAX;
9077 
9078     if (nargs < 2) {
9079 	CHECK_ARITY(2);
9080     }
9081     if (nargs > 3) {
9082 	CHECK_ARITY(3);
9083     }
9084     /*
9085      * take care of possible last (position) argument
9086     */
9087     if (nargs == 3) {
9088 	CAST_TO_NUMBER;
9089 	CHECK_TYPE(XPATH_NUMBER);
9090 	len = valuePop(ctxt);
9091 	le = len->floatval;
9092 	xmlXPathReleaseObject(ctxt->context, len);
9093     }
9094 
9095     CAST_TO_NUMBER;
9096     CHECK_TYPE(XPATH_NUMBER);
9097     start = valuePop(ctxt);
9098     in = start->floatval;
9099     xmlXPathReleaseObject(ctxt->context, start);
9100     CAST_TO_STRING;
9101     CHECK_TYPE(XPATH_STRING);
9102     str = valuePop(ctxt);
9103 
9104     if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9105         i = INT_MAX;
9106     } else if (in >= 1.0) {
9107         i = (int)in;
9108         if (in - floor(in) >= 0.5)
9109             i += 1;
9110     }
9111 
9112     if (nargs == 3) {
9113         double rin, rle, end;
9114 
9115         rin = floor(in);
9116         if (in - rin >= 0.5)
9117             rin += 1.0;
9118 
9119         rle = floor(le);
9120         if (le - rle >= 0.5)
9121             rle += 1.0;
9122 
9123         end = rin + rle;
9124         if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9125             j = 1;
9126         } else if (end < INT_MAX) {
9127             j = (int)end;
9128         }
9129     }
9130 
9131     if (i < j) {
9132         xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
9133 	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9134 	xmlFree(ret);
9135     } else {
9136 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9137     }
9138 
9139     xmlXPathReleaseObject(ctxt->context, str);
9140 }
9141 
9142 /**
9143  * xmlXPathSubstringBeforeFunction:
9144  * @ctxt:  the XPath Parser context
9145  * @nargs:  the number of arguments
9146  *
9147  * Implement the substring-before() XPath function
9148  *    string substring-before(string, string)
9149  * The substring-before function returns the substring of the first
9150  * argument string that precedes the first occurrence of the second
9151  * argument string in the first argument string, or the empty string
9152  * if the first argument string does not contain the second argument
9153  * string. For example, substring-before("1999/04/01","/") returns 1999.
9154  */
9155 void
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt,int nargs)9156 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9157   xmlXPathObjectPtr str;
9158   xmlXPathObjectPtr find;
9159   xmlBufPtr target;
9160   const xmlChar *point;
9161   int offset;
9162 
9163   CHECK_ARITY(2);
9164   CAST_TO_STRING;
9165   find = valuePop(ctxt);
9166   CAST_TO_STRING;
9167   str = valuePop(ctxt);
9168 
9169   target = xmlBufCreate();
9170   if (target) {
9171     point = xmlStrstr(str->stringval, find->stringval);
9172     if (point) {
9173       offset = point - str->stringval;
9174       xmlBufAdd(target, str->stringval, offset);
9175     }
9176     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9177 	xmlBufContent(target)));
9178     xmlBufFree(target);
9179   }
9180   xmlXPathReleaseObject(ctxt->context, str);
9181   xmlXPathReleaseObject(ctxt->context, find);
9182 }
9183 
9184 /**
9185  * xmlXPathSubstringAfterFunction:
9186  * @ctxt:  the XPath Parser context
9187  * @nargs:  the number of arguments
9188  *
9189  * Implement the substring-after() XPath function
9190  *    string substring-after(string, string)
9191  * The substring-after function returns the substring of the first
9192  * argument string that follows the first occurrence of the second
9193  * argument string in the first argument string, or the empty stringi
9194  * if the first argument string does not contain the second argument
9195  * string. For example, substring-after("1999/04/01","/") returns 04/01,
9196  * and substring-after("1999/04/01","19") returns 99/04/01.
9197  */
9198 void
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt,int nargs)9199 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9200   xmlXPathObjectPtr str;
9201   xmlXPathObjectPtr find;
9202   xmlBufPtr target;
9203   const xmlChar *point;
9204   int offset;
9205 
9206   CHECK_ARITY(2);
9207   CAST_TO_STRING;
9208   find = valuePop(ctxt);
9209   CAST_TO_STRING;
9210   str = valuePop(ctxt);
9211 
9212   target = xmlBufCreate();
9213   if (target) {
9214     point = xmlStrstr(str->stringval, find->stringval);
9215     if (point) {
9216       offset = point - str->stringval + xmlStrlen(find->stringval);
9217       xmlBufAdd(target, &str->stringval[offset],
9218 		   xmlStrlen(str->stringval) - offset);
9219     }
9220     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9221 	xmlBufContent(target)));
9222     xmlBufFree(target);
9223   }
9224   xmlXPathReleaseObject(ctxt->context, str);
9225   xmlXPathReleaseObject(ctxt->context, find);
9226 }
9227 
9228 /**
9229  * xmlXPathNormalizeFunction:
9230  * @ctxt:  the XPath Parser context
9231  * @nargs:  the number of arguments
9232  *
9233  * Implement the normalize-space() XPath function
9234  *    string normalize-space(string?)
9235  * The normalize-space function returns the argument string with white
9236  * space normalized by stripping leading and trailing whitespace
9237  * and replacing sequences of whitespace characters by a single
9238  * space. Whitespace characters are the same allowed by the S production
9239  * in XML. If the argument is omitted, it defaults to the context
9240  * node converted to a string, in other words the value of the context node.
9241  */
9242 void
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt,int nargs)9243 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9244     xmlChar *source, *target;
9245     int blank;
9246 
9247     if (ctxt == NULL) return;
9248     if (nargs == 0) {
9249         /* Use current context node */
9250         valuePush(ctxt,
9251             xmlXPathCacheWrapString(ctxt->context,
9252                 xmlXPathCastNodeToString(ctxt->context->node)));
9253         nargs = 1;
9254     }
9255 
9256     CHECK_ARITY(1);
9257     CAST_TO_STRING;
9258     CHECK_TYPE(XPATH_STRING);
9259     source = ctxt->value->stringval;
9260     if (source == NULL)
9261         return;
9262     target = source;
9263 
9264     /* Skip leading whitespaces */
9265     while (IS_BLANK_CH(*source))
9266         source++;
9267 
9268     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9269     blank = 0;
9270     while (*source) {
9271         if (IS_BLANK_CH(*source)) {
9272 	    blank = 1;
9273         } else {
9274             if (blank) {
9275                 *target++ = 0x20;
9276                 blank = 0;
9277             }
9278             *target++ = *source;
9279         }
9280         source++;
9281     }
9282     *target = 0;
9283 }
9284 
9285 /**
9286  * xmlXPathTranslateFunction:
9287  * @ctxt:  the XPath Parser context
9288  * @nargs:  the number of arguments
9289  *
9290  * Implement the translate() XPath function
9291  *    string translate(string, string, string)
9292  * The translate function returns the first argument string with
9293  * occurrences of characters in the second argument string replaced
9294  * by the character at the corresponding position in the third argument
9295  * string. For example, translate("bar","abc","ABC") returns the string
9296  * BAr. If there is a character in the second argument string with no
9297  * character at a corresponding position in the third argument string
9298  * (because the second argument string is longer than the third argument
9299  * string), then occurrences of that character in the first argument
9300  * string are removed. For example, translate("--aaa--","abc-","ABC")
9301  * returns "AAA". If a character occurs more than once in second
9302  * argument string, then the first occurrence determines the replacement
9303  * character. If the third argument string is longer than the second
9304  * argument string, then excess characters are ignored.
9305  */
9306 void
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt,int nargs)9307 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9308     xmlXPathObjectPtr str;
9309     xmlXPathObjectPtr from;
9310     xmlXPathObjectPtr to;
9311     xmlBufPtr target;
9312     int offset, max;
9313     int ch;
9314     const xmlChar *point;
9315     xmlChar *cptr;
9316 
9317     CHECK_ARITY(3);
9318 
9319     CAST_TO_STRING;
9320     to = valuePop(ctxt);
9321     CAST_TO_STRING;
9322     from = valuePop(ctxt);
9323     CAST_TO_STRING;
9324     str = valuePop(ctxt);
9325 
9326     target = xmlBufCreate();
9327     if (target) {
9328 	max = xmlUTF8Strlen(to->stringval);
9329 	for (cptr = str->stringval; (ch=*cptr); ) {
9330 	    offset = xmlUTF8Strloc(from->stringval, cptr);
9331 	    if (offset >= 0) {
9332 		if (offset < max) {
9333 		    point = xmlUTF8Strpos(to->stringval, offset);
9334 		    if (point)
9335 			xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9336 		}
9337 	    } else
9338 		xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9339 
9340 	    /* Step to next character in input */
9341 	    cptr++;
9342 	    if ( ch & 0x80 ) {
9343 		/* if not simple ascii, verify proper format */
9344 		if ( (ch & 0xc0) != 0xc0 ) {
9345 		    xmlGenericError(xmlGenericErrorContext,
9346 			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
9347                     /* not asserting an XPath error is probably better */
9348 		    break;
9349 		}
9350 		/* then skip over remaining bytes for this char */
9351 		while ( (ch <<= 1) & 0x80 )
9352 		    if ( (*cptr++ & 0xc0) != 0x80 ) {
9353 			xmlGenericError(xmlGenericErrorContext,
9354 			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9355                         /* not asserting an XPath error is probably better */
9356 			break;
9357 		    }
9358 		if (ch & 0x80) /* must have had error encountered */
9359 		    break;
9360 	    }
9361 	}
9362     }
9363     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9364 	xmlBufContent(target)));
9365     xmlBufFree(target);
9366     xmlXPathReleaseObject(ctxt->context, str);
9367     xmlXPathReleaseObject(ctxt->context, from);
9368     xmlXPathReleaseObject(ctxt->context, to);
9369 }
9370 
9371 /**
9372  * xmlXPathBooleanFunction:
9373  * @ctxt:  the XPath Parser context
9374  * @nargs:  the number of arguments
9375  *
9376  * Implement the boolean() XPath function
9377  *    boolean boolean(object)
9378  * The boolean function converts its argument to a boolean as follows:
9379  *    - a number is true if and only if it is neither positive or
9380  *      negative zero nor NaN
9381  *    - a node-set is true if and only if it is non-empty
9382  *    - a string is true if and only if its length is non-zero
9383  */
9384 void
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt,int nargs)9385 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9386     xmlXPathObjectPtr cur;
9387 
9388     CHECK_ARITY(1);
9389     cur = valuePop(ctxt);
9390     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9391     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9392     valuePush(ctxt, cur);
9393 }
9394 
9395 /**
9396  * xmlXPathNotFunction:
9397  * @ctxt:  the XPath Parser context
9398  * @nargs:  the number of arguments
9399  *
9400  * Implement the not() XPath function
9401  *    boolean not(boolean)
9402  * The not function returns true if its argument is false,
9403  * and false otherwise.
9404  */
9405 void
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt,int nargs)9406 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9407     CHECK_ARITY(1);
9408     CAST_TO_BOOLEAN;
9409     CHECK_TYPE(XPATH_BOOLEAN);
9410     ctxt->value->boolval = ! ctxt->value->boolval;
9411 }
9412 
9413 /**
9414  * xmlXPathTrueFunction:
9415  * @ctxt:  the XPath Parser context
9416  * @nargs:  the number of arguments
9417  *
9418  * Implement the true() XPath function
9419  *    boolean true()
9420  */
9421 void
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt,int nargs)9422 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9423     CHECK_ARITY(0);
9424     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9425 }
9426 
9427 /**
9428  * xmlXPathFalseFunction:
9429  * @ctxt:  the XPath Parser context
9430  * @nargs:  the number of arguments
9431  *
9432  * Implement the false() XPath function
9433  *    boolean false()
9434  */
9435 void
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt,int nargs)9436 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9437     CHECK_ARITY(0);
9438     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9439 }
9440 
9441 /**
9442  * xmlXPathLangFunction:
9443  * @ctxt:  the XPath Parser context
9444  * @nargs:  the number of arguments
9445  *
9446  * Implement the lang() XPath function
9447  *    boolean lang(string)
9448  * The lang function returns true or false depending on whether the
9449  * language of the context node as specified by xml:lang attributes
9450  * is the same as or is a sublanguage of the language specified by
9451  * the argument string. The language of the context node is determined
9452  * by the value of the xml:lang attribute on the context node, or, if
9453  * the context node has no xml:lang attribute, by the value of the
9454  * xml:lang attribute on the nearest ancestor of the context node that
9455  * has an xml:lang attribute. If there is no such attribute, then lang
9456  * returns false. If there is such an attribute, then lang returns
9457  * true if the attribute value is equal to the argument ignoring case,
9458  * or if there is some suffix starting with - such that the attribute
9459  * value is equal to the argument ignoring that suffix of the attribute
9460  * value and ignoring case.
9461  */
9462 void
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt,int nargs)9463 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9464     xmlXPathObjectPtr val = NULL;
9465     const xmlChar *theLang = NULL;
9466     const xmlChar *lang;
9467     int ret = 0;
9468     int i;
9469 
9470     CHECK_ARITY(1);
9471     CAST_TO_STRING;
9472     CHECK_TYPE(XPATH_STRING);
9473     val = valuePop(ctxt);
9474     lang = val->stringval;
9475     theLang = xmlNodeGetLang(ctxt->context->node);
9476     if ((theLang != NULL) && (lang != NULL)) {
9477         for (i = 0;lang[i] != 0;i++)
9478 	    if (toupper(lang[i]) != toupper(theLang[i]))
9479 	        goto not_equal;
9480 	if ((theLang[i] == 0) || (theLang[i] == '-'))
9481 	    ret = 1;
9482     }
9483 not_equal:
9484     if (theLang != NULL)
9485 	xmlFree((void *)theLang);
9486 
9487     xmlXPathReleaseObject(ctxt->context, val);
9488     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9489 }
9490 
9491 /**
9492  * xmlXPathNumberFunction:
9493  * @ctxt:  the XPath Parser context
9494  * @nargs:  the number of arguments
9495  *
9496  * Implement the number() XPath function
9497  *    number number(object?)
9498  */
9499 void
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt,int nargs)9500 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9501     xmlXPathObjectPtr cur;
9502     double res;
9503 
9504     if (ctxt == NULL) return;
9505     if (nargs == 0) {
9506 	if (ctxt->context->node == NULL) {
9507 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9508 	} else {
9509 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9510 
9511 	    res = xmlXPathStringEvalNumber(content);
9512 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9513 	    xmlFree(content);
9514 	}
9515 	return;
9516     }
9517 
9518     CHECK_ARITY(1);
9519     cur = valuePop(ctxt);
9520     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9521 }
9522 
9523 /**
9524  * xmlXPathSumFunction:
9525  * @ctxt:  the XPath Parser context
9526  * @nargs:  the number of arguments
9527  *
9528  * Implement the sum() XPath function
9529  *    number sum(node-set)
9530  * The sum function returns the sum of the values of the nodes in
9531  * the argument node-set.
9532  */
9533 void
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt,int nargs)9534 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9535     xmlXPathObjectPtr cur;
9536     int i;
9537     double res = 0.0;
9538 
9539     CHECK_ARITY(1);
9540     if ((ctxt->value == NULL) ||
9541 	((ctxt->value->type != XPATH_NODESET) &&
9542 	 (ctxt->value->type != XPATH_XSLT_TREE)))
9543 	XP_ERROR(XPATH_INVALID_TYPE);
9544     cur = valuePop(ctxt);
9545 
9546     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9547 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9548 	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9549 	}
9550     }
9551     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9552     xmlXPathReleaseObject(ctxt->context, cur);
9553 }
9554 
9555 /**
9556  * xmlXPathFloorFunction:
9557  * @ctxt:  the XPath Parser context
9558  * @nargs:  the number of arguments
9559  *
9560  * Implement the floor() XPath function
9561  *    number floor(number)
9562  * The floor function returns the largest (closest to positive infinity)
9563  * number that is not greater than the argument and that is an integer.
9564  */
9565 void
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt,int nargs)9566 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9567     CHECK_ARITY(1);
9568     CAST_TO_NUMBER;
9569     CHECK_TYPE(XPATH_NUMBER);
9570 
9571     ctxt->value->floatval = floor(ctxt->value->floatval);
9572 }
9573 
9574 /**
9575  * xmlXPathCeilingFunction:
9576  * @ctxt:  the XPath Parser context
9577  * @nargs:  the number of arguments
9578  *
9579  * Implement the ceiling() XPath function
9580  *    number ceiling(number)
9581  * The ceiling function returns the smallest (closest to negative infinity)
9582  * number that is not less than the argument and that is an integer.
9583  */
9584 void
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt,int nargs)9585 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9586     CHECK_ARITY(1);
9587     CAST_TO_NUMBER;
9588     CHECK_TYPE(XPATH_NUMBER);
9589 
9590 #ifdef _AIX
9591     /* Work around buggy ceil() function on AIX */
9592     ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
9593 #else
9594     ctxt->value->floatval = ceil(ctxt->value->floatval);
9595 #endif
9596 }
9597 
9598 /**
9599  * xmlXPathRoundFunction:
9600  * @ctxt:  the XPath Parser context
9601  * @nargs:  the number of arguments
9602  *
9603  * Implement the round() XPath function
9604  *    number round(number)
9605  * The round function returns the number that is closest to the
9606  * argument and that is an integer. If there are two such numbers,
9607  * then the one that is closest to positive infinity is returned.
9608  */
9609 void
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt,int nargs)9610 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9611     double f;
9612 
9613     CHECK_ARITY(1);
9614     CAST_TO_NUMBER;
9615     CHECK_TYPE(XPATH_NUMBER);
9616 
9617     f = ctxt->value->floatval;
9618 
9619     if ((f >= -0.5) && (f < 0.5)) {
9620         /* Handles negative zero. */
9621         ctxt->value->floatval *= 0.0;
9622     }
9623     else {
9624         double rounded = floor(f);
9625         if (f - rounded >= 0.5)
9626             rounded += 1.0;
9627         ctxt->value->floatval = rounded;
9628     }
9629 }
9630 
9631 /************************************************************************
9632  *									*
9633  *			The Parser					*
9634  *									*
9635  ************************************************************************/
9636 
9637 /*
9638  * a few forward declarations since we use a recursive call based
9639  * implementation.
9640  */
9641 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9642 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9643 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9644 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9645 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9646 	                                  int qualified);
9647 
9648 /**
9649  * xmlXPathCurrentChar:
9650  * @ctxt:  the XPath parser context
9651  * @cur:  pointer to the beginning of the char
9652  * @len:  pointer to the length of the char read
9653  *
9654  * The current char value, if using UTF-8 this may actually span multiple
9655  * bytes in the input buffer.
9656  *
9657  * Returns the current char value and its length
9658  */
9659 
9660 static int
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt,int * len)9661 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9662     unsigned char c;
9663     unsigned int val;
9664     const xmlChar *cur;
9665 
9666     if (ctxt == NULL)
9667 	return(0);
9668     cur = ctxt->cur;
9669 
9670     /*
9671      * We are supposed to handle UTF8, check it's valid
9672      * From rfc2044: encoding of the Unicode values on UTF-8:
9673      *
9674      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9675      * 0000 0000-0000 007F   0xxxxxxx
9676      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9677      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9678      *
9679      * Check for the 0x110000 limit too
9680      */
9681     c = *cur;
9682     if (c & 0x80) {
9683 	if ((cur[1] & 0xc0) != 0x80)
9684 	    goto encoding_error;
9685 	if ((c & 0xe0) == 0xe0) {
9686 
9687 	    if ((cur[2] & 0xc0) != 0x80)
9688 		goto encoding_error;
9689 	    if ((c & 0xf0) == 0xf0) {
9690 		if (((c & 0xf8) != 0xf0) ||
9691 		    ((cur[3] & 0xc0) != 0x80))
9692 		    goto encoding_error;
9693 		/* 4-byte code */
9694 		*len = 4;
9695 		val = (cur[0] & 0x7) << 18;
9696 		val |= (cur[1] & 0x3f) << 12;
9697 		val |= (cur[2] & 0x3f) << 6;
9698 		val |= cur[3] & 0x3f;
9699 	    } else {
9700 	      /* 3-byte code */
9701 		*len = 3;
9702 		val = (cur[0] & 0xf) << 12;
9703 		val |= (cur[1] & 0x3f) << 6;
9704 		val |= cur[2] & 0x3f;
9705 	    }
9706 	} else {
9707 	  /* 2-byte code */
9708 	    *len = 2;
9709 	    val = (cur[0] & 0x1f) << 6;
9710 	    val |= cur[1] & 0x3f;
9711 	}
9712 	if (!IS_CHAR(val)) {
9713 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9714 	}
9715 	return(val);
9716     } else {
9717 	/* 1-byte code */
9718 	*len = 1;
9719 	return(*cur);
9720     }
9721 encoding_error:
9722     /*
9723      * If we detect an UTF8 error that probably means that the
9724      * input encoding didn't get properly advertised in the
9725      * declaration header. Report the error and switch the encoding
9726      * to ISO-Latin-1 (if you don't like this policy, just declare the
9727      * encoding !)
9728      */
9729     *len = 0;
9730     XP_ERROR0(XPATH_ENCODING_ERROR);
9731 }
9732 
9733 /**
9734  * xmlXPathParseNCName:
9735  * @ctxt:  the XPath Parser context
9736  *
9737  * parse an XML namespace non qualified name.
9738  *
9739  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9740  *
9741  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9742  *                       CombiningChar | Extender
9743  *
9744  * Returns the namespace name or NULL
9745  */
9746 
9747 xmlChar *
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt)9748 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9749     const xmlChar *in;
9750     xmlChar *ret;
9751     int count = 0;
9752 
9753     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9754     /*
9755      * Accelerator for simple ASCII names
9756      */
9757     in = ctxt->cur;
9758     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9759 	((*in >= 0x41) && (*in <= 0x5A)) ||
9760 	(*in == '_')) {
9761 	in++;
9762 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9763 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9764 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9765 	       (*in == '_') || (*in == '.') ||
9766 	       (*in == '-'))
9767 	    in++;
9768 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9769             (*in == '[') || (*in == ']') || (*in == ':') ||
9770             (*in == '@') || (*in == '*')) {
9771 	    count = in - ctxt->cur;
9772 	    if (count == 0)
9773 		return(NULL);
9774 	    ret = xmlStrndup(ctxt->cur, count);
9775 	    ctxt->cur = in;
9776 	    return(ret);
9777 	}
9778     }
9779     return(xmlXPathParseNameComplex(ctxt, 0));
9780 }
9781 
9782 
9783 /**
9784  * xmlXPathParseQName:
9785  * @ctxt:  the XPath Parser context
9786  * @prefix:  a xmlChar **
9787  *
9788  * parse an XML qualified name
9789  *
9790  * [NS 5] QName ::= (Prefix ':')? LocalPart
9791  *
9792  * [NS 6] Prefix ::= NCName
9793  *
9794  * [NS 7] LocalPart ::= NCName
9795  *
9796  * Returns the function returns the local part, and prefix is updated
9797  *   to get the Prefix if any.
9798  */
9799 
9800 static xmlChar *
xmlXPathParseQName(xmlXPathParserContextPtr ctxt,xmlChar ** prefix)9801 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9802     xmlChar *ret = NULL;
9803 
9804     *prefix = NULL;
9805     ret = xmlXPathParseNCName(ctxt);
9806     if (ret && CUR == ':') {
9807         *prefix = ret;
9808 	NEXT;
9809 	ret = xmlXPathParseNCName(ctxt);
9810     }
9811     return(ret);
9812 }
9813 
9814 /**
9815  * xmlXPathParseName:
9816  * @ctxt:  the XPath Parser context
9817  *
9818  * parse an XML name
9819  *
9820  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9821  *                  CombiningChar | Extender
9822  *
9823  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9824  *
9825  * Returns the namespace name or NULL
9826  */
9827 
9828 xmlChar *
xmlXPathParseName(xmlXPathParserContextPtr ctxt)9829 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9830     const xmlChar *in;
9831     xmlChar *ret;
9832     size_t count = 0;
9833 
9834     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9835     /*
9836      * Accelerator for simple ASCII names
9837      */
9838     in = ctxt->cur;
9839     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9840 	((*in >= 0x41) && (*in <= 0x5A)) ||
9841 	(*in == '_') || (*in == ':')) {
9842 	in++;
9843 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9844 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9845 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9846 	       (*in == '_') || (*in == '-') ||
9847 	       (*in == ':') || (*in == '.'))
9848 	    in++;
9849 	if ((*in > 0) && (*in < 0x80)) {
9850 	    count = in - ctxt->cur;
9851             if (count > XML_MAX_NAME_LENGTH) {
9852                 ctxt->cur = in;
9853                 XP_ERRORNULL(XPATH_EXPR_ERROR);
9854             }
9855 	    ret = xmlStrndup(ctxt->cur, count);
9856 	    ctxt->cur = in;
9857 	    return(ret);
9858 	}
9859     }
9860     return(xmlXPathParseNameComplex(ctxt, 1));
9861 }
9862 
9863 static xmlChar *
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,int qualified)9864 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9865     xmlChar buf[XML_MAX_NAMELEN + 5];
9866     int len = 0, l;
9867     int c;
9868 
9869     /*
9870      * Handler for more complex cases
9871      */
9872     c = CUR_CHAR(l);
9873     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9874         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9875         (c == '*') || /* accelerators */
9876 	(!IS_LETTER(c) && (c != '_') &&
9877          ((!qualified) || (c != ':')))) {
9878 	return(NULL);
9879     }
9880 
9881     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9882 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9883             (c == '.') || (c == '-') ||
9884 	    (c == '_') || ((qualified) && (c == ':')) ||
9885 	    (IS_COMBINING(c)) ||
9886 	    (IS_EXTENDER(c)))) {
9887 	COPY_BUF(l,buf,len,c);
9888 	NEXTL(l);
9889 	c = CUR_CHAR(l);
9890 	if (len >= XML_MAX_NAMELEN) {
9891 	    /*
9892 	     * Okay someone managed to make a huge name, so he's ready to pay
9893 	     * for the processing speed.
9894 	     */
9895 	    xmlChar *buffer;
9896 	    int max = len * 2;
9897 
9898             if (len > XML_MAX_NAME_LENGTH) {
9899                 XP_ERRORNULL(XPATH_EXPR_ERROR);
9900             }
9901 	    buffer = (xmlChar *) xmlMallocAtomic(max);
9902 	    if (buffer == NULL) {
9903 		XP_ERRORNULL(XPATH_MEMORY_ERROR);
9904 	    }
9905 	    memcpy(buffer, buf, len);
9906 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9907 		   (c == '.') || (c == '-') ||
9908 		   (c == '_') || ((qualified) && (c == ':')) ||
9909 		   (IS_COMBINING(c)) ||
9910 		   (IS_EXTENDER(c))) {
9911 		if (len + 10 > max) {
9912                     xmlChar *tmp;
9913                     if (max > XML_MAX_NAME_LENGTH) {
9914                         xmlFree(buffer);
9915                         XP_ERRORNULL(XPATH_EXPR_ERROR);
9916                     }
9917 		    max *= 2;
9918 		    tmp = (xmlChar *) xmlRealloc(buffer, max);
9919 		    if (tmp == NULL) {
9920                         xmlFree(buffer);
9921 			XP_ERRORNULL(XPATH_MEMORY_ERROR);
9922 		    }
9923                     buffer = tmp;
9924 		}
9925 		COPY_BUF(l,buffer,len,c);
9926 		NEXTL(l);
9927 		c = CUR_CHAR(l);
9928 	    }
9929 	    buffer[len] = 0;
9930 	    return(buffer);
9931 	}
9932     }
9933     if (len == 0)
9934 	return(NULL);
9935     return(xmlStrndup(buf, len));
9936 }
9937 
9938 #define MAX_FRAC 20
9939 
9940 /**
9941  * xmlXPathStringEvalNumber:
9942  * @str:  A string to scan
9943  *
9944  *  [30a]  Float  ::= Number ('e' Digits?)?
9945  *
9946  *  [30]   Number ::=   Digits ('.' Digits?)?
9947  *                    | '.' Digits
9948  *  [31]   Digits ::=   [0-9]+
9949  *
9950  * Compile a Number in the string
9951  * In complement of the Number expression, this function also handles
9952  * negative values : '-' Number.
9953  *
9954  * Returns the double value.
9955  */
9956 double
xmlXPathStringEvalNumber(const xmlChar * str)9957 xmlXPathStringEvalNumber(const xmlChar *str) {
9958     const xmlChar *cur = str;
9959     double ret;
9960     int ok = 0;
9961     int isneg = 0;
9962     int exponent = 0;
9963     int is_exponent_negative = 0;
9964 #ifdef __GNUC__
9965     unsigned long tmp = 0;
9966     double temp;
9967 #endif
9968     if (cur == NULL) return(0);
9969     while (IS_BLANK_CH(*cur)) cur++;
9970     if (*cur == '-') {
9971 	isneg = 1;
9972 	cur++;
9973     }
9974     if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
9975         return(xmlXPathNAN);
9976     }
9977 
9978 #ifdef __GNUC__
9979     /*
9980      * tmp/temp is a workaround against a gcc compiler bug
9981      * http://veillard.com/gcc.bug
9982      */
9983     ret = 0;
9984     while ((*cur >= '0') && (*cur <= '9')) {
9985 	ret = ret * 10;
9986 	tmp = (*cur - '0');
9987 	ok = 1;
9988 	cur++;
9989 	temp = (double) tmp;
9990 	ret = ret + temp;
9991     }
9992 #else
9993     ret = 0;
9994     while ((*cur >= '0') && (*cur <= '9')) {
9995 	ret = ret * 10 + (*cur - '0');
9996 	ok = 1;
9997 	cur++;
9998     }
9999 #endif
10000 
10001     if (*cur == '.') {
10002 	int v, frac = 0, max;
10003 	double fraction = 0;
10004 
10005         cur++;
10006 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10007 	    return(xmlXPathNAN);
10008 	}
10009         while (*cur == '0') {
10010 	    frac = frac + 1;
10011 	    cur++;
10012         }
10013         max = frac + MAX_FRAC;
10014 	while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10015 	    v = (*cur - '0');
10016 	    fraction = fraction * 10 + v;
10017 	    frac = frac + 1;
10018 	    cur++;
10019 	}
10020 	fraction /= pow(10.0, frac);
10021 	ret = ret + fraction;
10022 	while ((*cur >= '0') && (*cur <= '9'))
10023 	    cur++;
10024     }
10025     if ((*cur == 'e') || (*cur == 'E')) {
10026       cur++;
10027       if (*cur == '-') {
10028 	is_exponent_negative = 1;
10029 	cur++;
10030       } else if (*cur == '+') {
10031         cur++;
10032       }
10033       while ((*cur >= '0') && (*cur <= '9')) {
10034         if (exponent < 1000000)
10035 	  exponent = exponent * 10 + (*cur - '0');
10036 	cur++;
10037       }
10038     }
10039     while (IS_BLANK_CH(*cur)) cur++;
10040     if (*cur != 0) return(xmlXPathNAN);
10041     if (isneg) ret = -ret;
10042     if (is_exponent_negative) exponent = -exponent;
10043     ret *= pow(10.0, (double)exponent);
10044     return(ret);
10045 }
10046 
10047 /**
10048  * xmlXPathCompNumber:
10049  * @ctxt:  the XPath Parser context
10050  *
10051  *  [30]   Number ::=   Digits ('.' Digits?)?
10052  *                    | '.' Digits
10053  *  [31]   Digits ::=   [0-9]+
10054  *
10055  * Compile a Number, then push it on the stack
10056  *
10057  */
10058 static void
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)10059 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10060 {
10061     double ret = 0.0;
10062     int ok = 0;
10063     int exponent = 0;
10064     int is_exponent_negative = 0;
10065     xmlXPathObjectPtr num;
10066 #ifdef __GNUC__
10067     unsigned long tmp = 0;
10068     double temp;
10069 #endif
10070 
10071     CHECK_ERROR;
10072     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10073         XP_ERROR(XPATH_NUMBER_ERROR);
10074     }
10075 #ifdef __GNUC__
10076     /*
10077      * tmp/temp is a workaround against a gcc compiler bug
10078      * http://veillard.com/gcc.bug
10079      */
10080     ret = 0;
10081     while ((CUR >= '0') && (CUR <= '9')) {
10082 	ret = ret * 10;
10083 	tmp = (CUR - '0');
10084         ok = 1;
10085         NEXT;
10086 	temp = (double) tmp;
10087 	ret = ret + temp;
10088     }
10089 #else
10090     ret = 0;
10091     while ((CUR >= '0') && (CUR <= '9')) {
10092 	ret = ret * 10 + (CUR - '0');
10093 	ok = 1;
10094 	NEXT;
10095     }
10096 #endif
10097     if (CUR == '.') {
10098 	int v, frac = 0, max;
10099 	double fraction = 0;
10100 
10101         NEXT;
10102         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10103             XP_ERROR(XPATH_NUMBER_ERROR);
10104         }
10105         while (CUR == '0') {
10106             frac = frac + 1;
10107             NEXT;
10108         }
10109         max = frac + MAX_FRAC;
10110         while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10111 	    v = (CUR - '0');
10112 	    fraction = fraction * 10 + v;
10113 	    frac = frac + 1;
10114             NEXT;
10115         }
10116         fraction /= pow(10.0, frac);
10117         ret = ret + fraction;
10118         while ((CUR >= '0') && (CUR <= '9'))
10119             NEXT;
10120     }
10121     if ((CUR == 'e') || (CUR == 'E')) {
10122         NEXT;
10123         if (CUR == '-') {
10124             is_exponent_negative = 1;
10125             NEXT;
10126         } else if (CUR == '+') {
10127 	    NEXT;
10128 	}
10129         while ((CUR >= '0') && (CUR <= '9')) {
10130             if (exponent < 1000000)
10131                 exponent = exponent * 10 + (CUR - '0');
10132             NEXT;
10133         }
10134         if (is_exponent_negative)
10135             exponent = -exponent;
10136         ret *= pow(10.0, (double) exponent);
10137     }
10138     num = xmlXPathCacheNewFloat(ctxt->context, ret);
10139     if (num == NULL) {
10140 	ctxt->error = XPATH_MEMORY_ERROR;
10141     } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
10142                               NULL) == -1) {
10143         xmlXPathReleaseObject(ctxt->context, num);
10144     }
10145 }
10146 
10147 /**
10148  * xmlXPathParseLiteral:
10149  * @ctxt:  the XPath Parser context
10150  *
10151  * Parse a Literal
10152  *
10153  *  [29]   Literal ::=   '"' [^"]* '"'
10154  *                    | "'" [^']* "'"
10155  *
10156  * Returns the value found or NULL in case of error
10157  */
10158 static xmlChar *
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt)10159 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10160     const xmlChar *q;
10161     xmlChar *ret = NULL;
10162 
10163     if (CUR == '"') {
10164         NEXT;
10165 	q = CUR_PTR;
10166 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10167 	    NEXT;
10168 	if (!IS_CHAR_CH(CUR)) {
10169 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10170 	} else {
10171 	    ret = xmlStrndup(q, CUR_PTR - q);
10172 	    NEXT;
10173         }
10174     } else if (CUR == '\'') {
10175         NEXT;
10176 	q = CUR_PTR;
10177 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10178 	    NEXT;
10179 	if (!IS_CHAR_CH(CUR)) {
10180 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10181 	} else {
10182 	    ret = xmlStrndup(q, CUR_PTR - q);
10183 	    NEXT;
10184         }
10185     } else {
10186 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10187     }
10188     return(ret);
10189 }
10190 
10191 /**
10192  * xmlXPathCompLiteral:
10193  * @ctxt:  the XPath Parser context
10194  *
10195  * Parse a Literal and push it on the stack.
10196  *
10197  *  [29]   Literal ::=   '"' [^"]* '"'
10198  *                    | "'" [^']* "'"
10199  *
10200  * TODO: xmlXPathCompLiteral memory allocation could be improved.
10201  */
10202 static void
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt)10203 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10204     const xmlChar *q;
10205     xmlChar *ret = NULL;
10206     xmlXPathObjectPtr lit;
10207 
10208     if (CUR == '"') {
10209         NEXT;
10210 	q = CUR_PTR;
10211 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10212 	    NEXT;
10213 	if (!IS_CHAR_CH(CUR)) {
10214 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10215 	} else {
10216 	    ret = xmlStrndup(q, CUR_PTR - q);
10217 	    NEXT;
10218         }
10219     } else if (CUR == '\'') {
10220         NEXT;
10221 	q = CUR_PTR;
10222 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10223 	    NEXT;
10224 	if (!IS_CHAR_CH(CUR)) {
10225 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10226 	} else {
10227 	    ret = xmlStrndup(q, CUR_PTR - q);
10228 	    NEXT;
10229         }
10230     } else {
10231 	XP_ERROR(XPATH_START_LITERAL_ERROR);
10232     }
10233     if (ret == NULL) {
10234         xmlXPathPErrMemory(ctxt, NULL);
10235         return;
10236     }
10237     lit = xmlXPathCacheNewString(ctxt->context, ret);
10238     if (lit == NULL) {
10239 	ctxt->error = XPATH_MEMORY_ERROR;
10240     } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10241                               NULL) == -1) {
10242         xmlXPathReleaseObject(ctxt->context, lit);
10243     }
10244     xmlFree(ret);
10245 }
10246 
10247 /**
10248  * xmlXPathCompVariableReference:
10249  * @ctxt:  the XPath Parser context
10250  *
10251  * Parse a VariableReference, evaluate it and push it on the stack.
10252  *
10253  * The variable bindings consist of a mapping from variable names
10254  * to variable values. The value of a variable is an object, which can be
10255  * of any of the types that are possible for the value of an expression,
10256  * and may also be of additional types not specified here.
10257  *
10258  * Early evaluation is possible since:
10259  * The variable bindings [...] used to evaluate a subexpression are
10260  * always the same as those used to evaluate the containing expression.
10261  *
10262  *  [36]   VariableReference ::=   '$' QName
10263  */
10264 static void
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt)10265 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10266     xmlChar *name;
10267     xmlChar *prefix;
10268 
10269     SKIP_BLANKS;
10270     if (CUR != '$') {
10271 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10272     }
10273     NEXT;
10274     name = xmlXPathParseQName(ctxt, &prefix);
10275     if (name == NULL) {
10276         xmlFree(prefix);
10277 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10278     }
10279     ctxt->comp->last = -1;
10280     if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
10281         xmlFree(prefix);
10282         xmlFree(name);
10283     }
10284     SKIP_BLANKS;
10285     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10286 	XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10287     }
10288 }
10289 
10290 /**
10291  * xmlXPathIsNodeType:
10292  * @name:  a name string
10293  *
10294  * Is the name given a NodeType one.
10295  *
10296  *  [38]   NodeType ::=   'comment'
10297  *                    | 'text'
10298  *                    | 'processing-instruction'
10299  *                    | 'node'
10300  *
10301  * Returns 1 if true 0 otherwise
10302  */
10303 int
xmlXPathIsNodeType(const xmlChar * name)10304 xmlXPathIsNodeType(const xmlChar *name) {
10305     if (name == NULL)
10306 	return(0);
10307 
10308     if (xmlStrEqual(name, BAD_CAST "node"))
10309 	return(1);
10310     if (xmlStrEqual(name, BAD_CAST "text"))
10311 	return(1);
10312     if (xmlStrEqual(name, BAD_CAST "comment"))
10313 	return(1);
10314     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10315 	return(1);
10316     return(0);
10317 }
10318 
10319 /**
10320  * xmlXPathCompFunctionCall:
10321  * @ctxt:  the XPath Parser context
10322  *
10323  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10324  *  [17]   Argument ::=   Expr
10325  *
10326  * Compile a function call, the evaluation of all arguments are
10327  * pushed on the stack
10328  */
10329 static void
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt)10330 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10331     xmlChar *name;
10332     xmlChar *prefix;
10333     int nbargs = 0;
10334     int sort = 1;
10335 
10336     name = xmlXPathParseQName(ctxt, &prefix);
10337     if (name == NULL) {
10338 	xmlFree(prefix);
10339 	XP_ERROR(XPATH_EXPR_ERROR);
10340     }
10341     SKIP_BLANKS;
10342 #ifdef DEBUG_EXPR
10343     if (prefix == NULL)
10344 	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10345 			name);
10346     else
10347 	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10348 			prefix, name);
10349 #endif
10350 
10351     if (CUR != '(') {
10352 	xmlFree(name);
10353 	xmlFree(prefix);
10354 	XP_ERROR(XPATH_EXPR_ERROR);
10355     }
10356     NEXT;
10357     SKIP_BLANKS;
10358 
10359     /*
10360     * Optimization for count(): we don't need the node-set to be sorted.
10361     */
10362     if ((prefix == NULL) && (name[0] == 'c') &&
10363 	xmlStrEqual(name, BAD_CAST "count"))
10364     {
10365 	sort = 0;
10366     }
10367     ctxt->comp->last = -1;
10368     if (CUR != ')') {
10369 	while (CUR != 0) {
10370 	    int op1 = ctxt->comp->last;
10371 	    ctxt->comp->last = -1;
10372 	    xmlXPathCompileExpr(ctxt, sort);
10373 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
10374 		xmlFree(name);
10375 		xmlFree(prefix);
10376 		return;
10377 	    }
10378 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10379 	    nbargs++;
10380 	    if (CUR == ')') break;
10381 	    if (CUR != ',') {
10382 		xmlFree(name);
10383 		xmlFree(prefix);
10384 		XP_ERROR(XPATH_EXPR_ERROR);
10385 	    }
10386 	    NEXT;
10387 	    SKIP_BLANKS;
10388 	}
10389     }
10390     if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
10391         xmlFree(prefix);
10392         xmlFree(name);
10393     }
10394     NEXT;
10395     SKIP_BLANKS;
10396 }
10397 
10398 /**
10399  * xmlXPathCompPrimaryExpr:
10400  * @ctxt:  the XPath Parser context
10401  *
10402  *  [15]   PrimaryExpr ::=   VariableReference
10403  *                | '(' Expr ')'
10404  *                | Literal
10405  *                | Number
10406  *                | FunctionCall
10407  *
10408  * Compile a primary expression.
10409  */
10410 static void
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt)10411 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10412     SKIP_BLANKS;
10413     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10414     else if (CUR == '(') {
10415 	NEXT;
10416 	SKIP_BLANKS;
10417 	xmlXPathCompileExpr(ctxt, 1);
10418 	CHECK_ERROR;
10419 	if (CUR != ')') {
10420 	    XP_ERROR(XPATH_EXPR_ERROR);
10421 	}
10422 	NEXT;
10423 	SKIP_BLANKS;
10424     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10425 	xmlXPathCompNumber(ctxt);
10426     } else if ((CUR == '\'') || (CUR == '"')) {
10427 	xmlXPathCompLiteral(ctxt);
10428     } else {
10429 	xmlXPathCompFunctionCall(ctxt);
10430     }
10431     SKIP_BLANKS;
10432 }
10433 
10434 /**
10435  * xmlXPathCompFilterExpr:
10436  * @ctxt:  the XPath Parser context
10437  *
10438  *  [20]   FilterExpr ::=   PrimaryExpr
10439  *               | FilterExpr Predicate
10440  *
10441  * Compile a filter expression.
10442  * Square brackets are used to filter expressions in the same way that
10443  * they are used in location paths. It is an error if the expression to
10444  * be filtered does not evaluate to a node-set. The context node list
10445  * used for evaluating the expression in square brackets is the node-set
10446  * to be filtered listed in document order.
10447  */
10448 
10449 static void
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt)10450 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10451     xmlXPathCompPrimaryExpr(ctxt);
10452     CHECK_ERROR;
10453     SKIP_BLANKS;
10454 
10455     while (CUR == '[') {
10456 	xmlXPathCompPredicate(ctxt, 1);
10457 	SKIP_BLANKS;
10458     }
10459 
10460 
10461 }
10462 
10463 /**
10464  * xmlXPathScanName:
10465  * @ctxt:  the XPath Parser context
10466  *
10467  * Trickery: parse an XML name but without consuming the input flow
10468  * Needed to avoid insanity in the parser state.
10469  *
10470  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10471  *                  CombiningChar | Extender
10472  *
10473  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10474  *
10475  * [6] Names ::= Name (S Name)*
10476  *
10477  * Returns the Name parsed or NULL
10478  */
10479 
10480 static xmlChar *
xmlXPathScanName(xmlXPathParserContextPtr ctxt)10481 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10482     int l;
10483     int c;
10484     const xmlChar *cur;
10485     xmlChar *ret;
10486 
10487     cur = ctxt->cur;
10488 
10489     c = CUR_CHAR(l);
10490     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10491 	(!IS_LETTER(c) && (c != '_') &&
10492          (c != ':'))) {
10493 	return(NULL);
10494     }
10495 
10496     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10497 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10498             (c == '.') || (c == '-') ||
10499 	    (c == '_') || (c == ':') ||
10500 	    (IS_COMBINING(c)) ||
10501 	    (IS_EXTENDER(c)))) {
10502 	NEXTL(l);
10503 	c = CUR_CHAR(l);
10504     }
10505     ret = xmlStrndup(cur, ctxt->cur - cur);
10506     ctxt->cur = cur;
10507     return(ret);
10508 }
10509 
10510 /**
10511  * xmlXPathCompPathExpr:
10512  * @ctxt:  the XPath Parser context
10513  *
10514  *  [19]   PathExpr ::=   LocationPath
10515  *               | FilterExpr
10516  *               | FilterExpr '/' RelativeLocationPath
10517  *               | FilterExpr '//' RelativeLocationPath
10518  *
10519  * Compile a path expression.
10520  * The / operator and // operators combine an arbitrary expression
10521  * and a relative location path. It is an error if the expression
10522  * does not evaluate to a node-set.
10523  * The / operator does composition in the same way as when / is
10524  * used in a location path. As in location paths, // is short for
10525  * /descendant-or-self::node()/.
10526  */
10527 
10528 static void
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt)10529 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10530     int lc = 1;           /* Should we branch to LocationPath ?         */
10531     xmlChar *name = NULL; /* we may have to preparse a name to find out */
10532 
10533     SKIP_BLANKS;
10534     if ((CUR == '$') || (CUR == '(') ||
10535 	(IS_ASCII_DIGIT(CUR)) ||
10536         (CUR == '\'') || (CUR == '"') ||
10537 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10538 	lc = 0;
10539     } else if (CUR == '*') {
10540 	/* relative or absolute location path */
10541 	lc = 1;
10542     } else if (CUR == '/') {
10543 	/* relative or absolute location path */
10544 	lc = 1;
10545     } else if (CUR == '@') {
10546 	/* relative abbreviated attribute location path */
10547 	lc = 1;
10548     } else if (CUR == '.') {
10549 	/* relative abbreviated attribute location path */
10550 	lc = 1;
10551     } else {
10552 	/*
10553 	 * Problem is finding if we have a name here whether it's:
10554 	 *   - a nodetype
10555 	 *   - a function call in which case it's followed by '('
10556 	 *   - an axis in which case it's followed by ':'
10557 	 *   - a element name
10558 	 * We do an a priori analysis here rather than having to
10559 	 * maintain parsed token content through the recursive function
10560 	 * calls. This looks uglier but makes the code easier to
10561 	 * read/write/debug.
10562 	 */
10563 	SKIP_BLANKS;
10564 	name = xmlXPathScanName(ctxt);
10565 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10566 #ifdef DEBUG_STEP
10567 	    xmlGenericError(xmlGenericErrorContext,
10568 		    "PathExpr: Axis\n");
10569 #endif
10570 	    lc = 1;
10571 	    xmlFree(name);
10572 	} else if (name != NULL) {
10573 	    int len =xmlStrlen(name);
10574 
10575 
10576 	    while (NXT(len) != 0) {
10577 		if (NXT(len) == '/') {
10578 		    /* element name */
10579 #ifdef DEBUG_STEP
10580 		    xmlGenericError(xmlGenericErrorContext,
10581 			    "PathExpr: AbbrRelLocation\n");
10582 #endif
10583 		    lc = 1;
10584 		    break;
10585 		} else if (IS_BLANK_CH(NXT(len))) {
10586 		    /* ignore blanks */
10587 		    ;
10588 		} else if (NXT(len) == ':') {
10589 #ifdef DEBUG_STEP
10590 		    xmlGenericError(xmlGenericErrorContext,
10591 			    "PathExpr: AbbrRelLocation\n");
10592 #endif
10593 		    lc = 1;
10594 		    break;
10595 		} else if ((NXT(len) == '(')) {
10596 		    /* Node Type or Function */
10597 		    if (xmlXPathIsNodeType(name)) {
10598 #ifdef DEBUG_STEP
10599 		        xmlGenericError(xmlGenericErrorContext,
10600 				"PathExpr: Type search\n");
10601 #endif
10602 			lc = 1;
10603 #ifdef LIBXML_XPTR_LOCS_ENABLED
10604                     } else if (ctxt->xptr &&
10605                                xmlStrEqual(name, BAD_CAST "range-to")) {
10606                         lc = 1;
10607 #endif
10608 		    } else {
10609 #ifdef DEBUG_STEP
10610 		        xmlGenericError(xmlGenericErrorContext,
10611 				"PathExpr: function call\n");
10612 #endif
10613 			lc = 0;
10614 		    }
10615                     break;
10616 		} else if ((NXT(len) == '[')) {
10617 		    /* element name */
10618 #ifdef DEBUG_STEP
10619 		    xmlGenericError(xmlGenericErrorContext,
10620 			    "PathExpr: AbbrRelLocation\n");
10621 #endif
10622 		    lc = 1;
10623 		    break;
10624 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10625 			   (NXT(len) == '=')) {
10626 		    lc = 1;
10627 		    break;
10628 		} else {
10629 		    lc = 1;
10630 		    break;
10631 		}
10632 		len++;
10633 	    }
10634 	    if (NXT(len) == 0) {
10635 #ifdef DEBUG_STEP
10636 		xmlGenericError(xmlGenericErrorContext,
10637 			"PathExpr: AbbrRelLocation\n");
10638 #endif
10639 		/* element name */
10640 		lc = 1;
10641 	    }
10642 	    xmlFree(name);
10643 	} else {
10644 	    /* make sure all cases are covered explicitly */
10645 	    XP_ERROR(XPATH_EXPR_ERROR);
10646 	}
10647     }
10648 
10649     if (lc) {
10650 	if (CUR == '/') {
10651 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10652 	} else {
10653 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10654 	}
10655 	xmlXPathCompLocationPath(ctxt);
10656     } else {
10657 	xmlXPathCompFilterExpr(ctxt);
10658 	CHECK_ERROR;
10659 	if ((CUR == '/') && (NXT(1) == '/')) {
10660 	    SKIP(2);
10661 	    SKIP_BLANKS;
10662 
10663 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10664 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10665 
10666 	    xmlXPathCompRelativeLocationPath(ctxt);
10667 	} else if (CUR == '/') {
10668 	    xmlXPathCompRelativeLocationPath(ctxt);
10669 	}
10670     }
10671     SKIP_BLANKS;
10672 }
10673 
10674 /**
10675  * xmlXPathCompUnionExpr:
10676  * @ctxt:  the XPath Parser context
10677  *
10678  *  [18]   UnionExpr ::=   PathExpr
10679  *               | UnionExpr '|' PathExpr
10680  *
10681  * Compile an union expression.
10682  */
10683 
10684 static void
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt)10685 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10686     xmlXPathCompPathExpr(ctxt);
10687     CHECK_ERROR;
10688     SKIP_BLANKS;
10689     while (CUR == '|') {
10690 	int op1 = ctxt->comp->last;
10691 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10692 
10693 	NEXT;
10694 	SKIP_BLANKS;
10695 	xmlXPathCompPathExpr(ctxt);
10696 
10697 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10698 
10699 	SKIP_BLANKS;
10700     }
10701 }
10702 
10703 /**
10704  * xmlXPathCompUnaryExpr:
10705  * @ctxt:  the XPath Parser context
10706  *
10707  *  [27]   UnaryExpr ::=   UnionExpr
10708  *                   | '-' UnaryExpr
10709  *
10710  * Compile an unary expression.
10711  */
10712 
10713 static void
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt)10714 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10715     int minus = 0;
10716     int found = 0;
10717 
10718     SKIP_BLANKS;
10719     while (CUR == '-') {
10720         minus = 1 - minus;
10721 	found = 1;
10722 	NEXT;
10723 	SKIP_BLANKS;
10724     }
10725 
10726     xmlXPathCompUnionExpr(ctxt);
10727     CHECK_ERROR;
10728     if (found) {
10729 	if (minus)
10730 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10731 	else
10732 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10733     }
10734 }
10735 
10736 /**
10737  * xmlXPathCompMultiplicativeExpr:
10738  * @ctxt:  the XPath Parser context
10739  *
10740  *  [26]   MultiplicativeExpr ::=   UnaryExpr
10741  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10742  *                   | MultiplicativeExpr 'div' UnaryExpr
10743  *                   | MultiplicativeExpr 'mod' UnaryExpr
10744  *  [34]   MultiplyOperator ::=   '*'
10745  *
10746  * Compile an Additive expression.
10747  */
10748 
10749 static void
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt)10750 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10751     xmlXPathCompUnaryExpr(ctxt);
10752     CHECK_ERROR;
10753     SKIP_BLANKS;
10754     while ((CUR == '*') ||
10755            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10756            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10757 	int op = -1;
10758 	int op1 = ctxt->comp->last;
10759 
10760         if (CUR == '*') {
10761 	    op = 0;
10762 	    NEXT;
10763 	} else if (CUR == 'd') {
10764 	    op = 1;
10765 	    SKIP(3);
10766 	} else if (CUR == 'm') {
10767 	    op = 2;
10768 	    SKIP(3);
10769 	}
10770 	SKIP_BLANKS;
10771         xmlXPathCompUnaryExpr(ctxt);
10772 	CHECK_ERROR;
10773 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10774 	SKIP_BLANKS;
10775     }
10776 }
10777 
10778 /**
10779  * xmlXPathCompAdditiveExpr:
10780  * @ctxt:  the XPath Parser context
10781  *
10782  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10783  *                   | AdditiveExpr '+' MultiplicativeExpr
10784  *                   | AdditiveExpr '-' MultiplicativeExpr
10785  *
10786  * Compile an Additive expression.
10787  */
10788 
10789 static void
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt)10790 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10791 
10792     xmlXPathCompMultiplicativeExpr(ctxt);
10793     CHECK_ERROR;
10794     SKIP_BLANKS;
10795     while ((CUR == '+') || (CUR == '-')) {
10796 	int plus;
10797 	int op1 = ctxt->comp->last;
10798 
10799         if (CUR == '+') plus = 1;
10800 	else plus = 0;
10801 	NEXT;
10802 	SKIP_BLANKS;
10803         xmlXPathCompMultiplicativeExpr(ctxt);
10804 	CHECK_ERROR;
10805 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10806 	SKIP_BLANKS;
10807     }
10808 }
10809 
10810 /**
10811  * xmlXPathCompRelationalExpr:
10812  * @ctxt:  the XPath Parser context
10813  *
10814  *  [24]   RelationalExpr ::=   AdditiveExpr
10815  *                 | RelationalExpr '<' AdditiveExpr
10816  *                 | RelationalExpr '>' AdditiveExpr
10817  *                 | RelationalExpr '<=' AdditiveExpr
10818  *                 | RelationalExpr '>=' AdditiveExpr
10819  *
10820  *  A <= B > C is allowed ? Answer from James, yes with
10821  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10822  *  which is basically what got implemented.
10823  *
10824  * Compile a Relational expression, then push the result
10825  * on the stack
10826  */
10827 
10828 static void
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt)10829 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10830     xmlXPathCompAdditiveExpr(ctxt);
10831     CHECK_ERROR;
10832     SKIP_BLANKS;
10833     while ((CUR == '<') || (CUR == '>')) {
10834 	int inf, strict;
10835 	int op1 = ctxt->comp->last;
10836 
10837         if (CUR == '<') inf = 1;
10838 	else inf = 0;
10839 	if (NXT(1) == '=') strict = 0;
10840 	else strict = 1;
10841 	NEXT;
10842 	if (!strict) NEXT;
10843 	SKIP_BLANKS;
10844         xmlXPathCompAdditiveExpr(ctxt);
10845 	CHECK_ERROR;
10846 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10847 	SKIP_BLANKS;
10848     }
10849 }
10850 
10851 /**
10852  * xmlXPathCompEqualityExpr:
10853  * @ctxt:  the XPath Parser context
10854  *
10855  *  [23]   EqualityExpr ::=   RelationalExpr
10856  *                 | EqualityExpr '=' RelationalExpr
10857  *                 | EqualityExpr '!=' RelationalExpr
10858  *
10859  *  A != B != C is allowed ? Answer from James, yes with
10860  *  (RelationalExpr = RelationalExpr) = RelationalExpr
10861  *  (RelationalExpr != RelationalExpr) != RelationalExpr
10862  *  which is basically what got implemented.
10863  *
10864  * Compile an Equality expression.
10865  *
10866  */
10867 static void
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt)10868 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10869     xmlXPathCompRelationalExpr(ctxt);
10870     CHECK_ERROR;
10871     SKIP_BLANKS;
10872     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10873 	int eq;
10874 	int op1 = ctxt->comp->last;
10875 
10876         if (CUR == '=') eq = 1;
10877 	else eq = 0;
10878 	NEXT;
10879 	if (!eq) NEXT;
10880 	SKIP_BLANKS;
10881         xmlXPathCompRelationalExpr(ctxt);
10882 	CHECK_ERROR;
10883 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10884 	SKIP_BLANKS;
10885     }
10886 }
10887 
10888 /**
10889  * xmlXPathCompAndExpr:
10890  * @ctxt:  the XPath Parser context
10891  *
10892  *  [22]   AndExpr ::=   EqualityExpr
10893  *                 | AndExpr 'and' EqualityExpr
10894  *
10895  * Compile an AND expression.
10896  *
10897  */
10898 static void
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt)10899 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10900     xmlXPathCompEqualityExpr(ctxt);
10901     CHECK_ERROR;
10902     SKIP_BLANKS;
10903     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10904 	int op1 = ctxt->comp->last;
10905         SKIP(3);
10906 	SKIP_BLANKS;
10907         xmlXPathCompEqualityExpr(ctxt);
10908 	CHECK_ERROR;
10909 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10910 	SKIP_BLANKS;
10911     }
10912 }
10913 
10914 /**
10915  * xmlXPathCompileExpr:
10916  * @ctxt:  the XPath Parser context
10917  *
10918  *  [14]   Expr ::=   OrExpr
10919  *  [21]   OrExpr ::=   AndExpr
10920  *                 | OrExpr 'or' AndExpr
10921  *
10922  * Parse and compile an expression
10923  */
10924 static void
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt,int sort)10925 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10926     xmlXPathContextPtr xpctxt = ctxt->context;
10927 
10928     if (xpctxt != NULL) {
10929         if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10930             XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10931         /*
10932          * Parsing a single '(' pushes about 10 functions on the call stack
10933          * before recursing!
10934          */
10935         xpctxt->depth += 10;
10936     }
10937 
10938     xmlXPathCompAndExpr(ctxt);
10939     CHECK_ERROR;
10940     SKIP_BLANKS;
10941     while ((CUR == 'o') && (NXT(1) == 'r')) {
10942 	int op1 = ctxt->comp->last;
10943         SKIP(2);
10944 	SKIP_BLANKS;
10945         xmlXPathCompAndExpr(ctxt);
10946 	CHECK_ERROR;
10947 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10948 	SKIP_BLANKS;
10949     }
10950     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10951 	/* more ops could be optimized too */
10952 	/*
10953 	* This is the main place to eliminate sorting for
10954 	* operations which don't require a sorted node-set.
10955 	* E.g. count().
10956 	*/
10957 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10958     }
10959 
10960     if (xpctxt != NULL)
10961         xpctxt->depth -= 10;
10962 }
10963 
10964 /**
10965  * xmlXPathCompPredicate:
10966  * @ctxt:  the XPath Parser context
10967  * @filter:  act as a filter
10968  *
10969  *  [8]   Predicate ::=   '[' PredicateExpr ']'
10970  *  [9]   PredicateExpr ::=   Expr
10971  *
10972  * Compile a predicate expression
10973  */
10974 static void
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt,int filter)10975 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10976     int op1 = ctxt->comp->last;
10977 
10978     SKIP_BLANKS;
10979     if (CUR != '[') {
10980 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10981     }
10982     NEXT;
10983     SKIP_BLANKS;
10984 
10985     ctxt->comp->last = -1;
10986     /*
10987     * This call to xmlXPathCompileExpr() will deactivate sorting
10988     * of the predicate result.
10989     * TODO: Sorting is still activated for filters, since I'm not
10990     *  sure if needed. Normally sorting should not be needed, since
10991     *  a filter can only diminish the number of items in a sequence,
10992     *  but won't change its order; so if the initial sequence is sorted,
10993     *  subsequent sorting is not needed.
10994     */
10995     if (! filter)
10996 	xmlXPathCompileExpr(ctxt, 0);
10997     else
10998 	xmlXPathCompileExpr(ctxt, 1);
10999     CHECK_ERROR;
11000 
11001     if (CUR != ']') {
11002 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11003     }
11004 
11005     if (filter)
11006 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11007     else
11008 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11009 
11010     NEXT;
11011     SKIP_BLANKS;
11012 }
11013 
11014 /**
11015  * xmlXPathCompNodeTest:
11016  * @ctxt:  the XPath Parser context
11017  * @test:  pointer to a xmlXPathTestVal
11018  * @type:  pointer to a xmlXPathTypeVal
11019  * @prefix:  placeholder for a possible name prefix
11020  *
11021  * [7] NodeTest ::=   NameTest
11022  *		    | NodeType '(' ')'
11023  *		    | 'processing-instruction' '(' Literal ')'
11024  *
11025  * [37] NameTest ::=  '*'
11026  *		    | NCName ':' '*'
11027  *		    | QName
11028  * [38] NodeType ::= 'comment'
11029  *		   | 'text'
11030  *		   | 'processing-instruction'
11031  *		   | 'node'
11032  *
11033  * Returns the name found and updates @test, @type and @prefix appropriately
11034  */
11035 static xmlChar *
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt,xmlXPathTestVal * test,xmlXPathTypeVal * type,xmlChar ** prefix,xmlChar * name)11036 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11037 	             xmlXPathTypeVal *type, xmlChar **prefix,
11038 		     xmlChar *name) {
11039     int blanks;
11040 
11041     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11042 	STRANGE;
11043 	return(NULL);
11044     }
11045     *type = (xmlXPathTypeVal) 0;
11046     *test = (xmlXPathTestVal) 0;
11047     *prefix = NULL;
11048     SKIP_BLANKS;
11049 
11050     if ((name == NULL) && (CUR == '*')) {
11051 	/*
11052 	 * All elements
11053 	 */
11054 	NEXT;
11055 	*test = NODE_TEST_ALL;
11056 	return(NULL);
11057     }
11058 
11059     if (name == NULL)
11060 	name = xmlXPathParseNCName(ctxt);
11061     if (name == NULL) {
11062 	XP_ERRORNULL(XPATH_EXPR_ERROR);
11063     }
11064 
11065     blanks = IS_BLANK_CH(CUR);
11066     SKIP_BLANKS;
11067     if (CUR == '(') {
11068 	NEXT;
11069 	/*
11070 	 * NodeType or PI search
11071 	 */
11072 	if (xmlStrEqual(name, BAD_CAST "comment"))
11073 	    *type = NODE_TYPE_COMMENT;
11074 	else if (xmlStrEqual(name, BAD_CAST "node"))
11075 	    *type = NODE_TYPE_NODE;
11076 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11077 	    *type = NODE_TYPE_PI;
11078 	else if (xmlStrEqual(name, BAD_CAST "text"))
11079 	    *type = NODE_TYPE_TEXT;
11080 	else {
11081 	    if (name != NULL)
11082 		xmlFree(name);
11083 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11084 	}
11085 
11086 	*test = NODE_TEST_TYPE;
11087 
11088 	SKIP_BLANKS;
11089 	if (*type == NODE_TYPE_PI) {
11090 	    /*
11091 	     * Specific case: search a PI by name.
11092 	     */
11093 	    if (name != NULL)
11094 		xmlFree(name);
11095 	    name = NULL;
11096 	    if (CUR != ')') {
11097 		name = xmlXPathParseLiteral(ctxt);
11098                 if (name == NULL) {
11099 	            XP_ERRORNULL(XPATH_EXPR_ERROR);
11100                 }
11101 		*test = NODE_TEST_PI;
11102 		SKIP_BLANKS;
11103 	    }
11104 	}
11105 	if (CUR != ')') {
11106 	    if (name != NULL)
11107 		xmlFree(name);
11108 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11109 	}
11110 	NEXT;
11111 	return(name);
11112     }
11113     *test = NODE_TEST_NAME;
11114     if ((!blanks) && (CUR == ':')) {
11115 	NEXT;
11116 
11117 	/*
11118 	 * Since currently the parser context don't have a
11119 	 * namespace list associated:
11120 	 * The namespace name for this prefix can be computed
11121 	 * only at evaluation time. The compilation is done
11122 	 * outside of any context.
11123 	 */
11124 #if 0
11125 	*prefix = xmlXPathNsLookup(ctxt->context, name);
11126 	if (name != NULL)
11127 	    xmlFree(name);
11128 	if (*prefix == NULL) {
11129 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11130 	}
11131 #else
11132 	*prefix = name;
11133 #endif
11134 
11135 	if (CUR == '*') {
11136 	    /*
11137 	     * All elements
11138 	     */
11139 	    NEXT;
11140 	    *test = NODE_TEST_ALL;
11141 	    return(NULL);
11142 	}
11143 
11144 	name = xmlXPathParseNCName(ctxt);
11145 	if (name == NULL) {
11146 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11147 	}
11148     }
11149     return(name);
11150 }
11151 
11152 /**
11153  * xmlXPathIsAxisName:
11154  * @name:  a preparsed name token
11155  *
11156  * [6] AxisName ::=   'ancestor'
11157  *                  | 'ancestor-or-self'
11158  *                  | 'attribute'
11159  *                  | 'child'
11160  *                  | 'descendant'
11161  *                  | 'descendant-or-self'
11162  *                  | 'following'
11163  *                  | 'following-sibling'
11164  *                  | 'namespace'
11165  *                  | 'parent'
11166  *                  | 'preceding'
11167  *                  | 'preceding-sibling'
11168  *                  | 'self'
11169  *
11170  * Returns the axis or 0
11171  */
11172 static xmlXPathAxisVal
xmlXPathIsAxisName(const xmlChar * name)11173 xmlXPathIsAxisName(const xmlChar *name) {
11174     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11175     switch (name[0]) {
11176 	case 'a':
11177 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
11178 		ret = AXIS_ANCESTOR;
11179 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11180 		ret = AXIS_ANCESTOR_OR_SELF;
11181 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
11182 		ret = AXIS_ATTRIBUTE;
11183 	    break;
11184 	case 'c':
11185 	    if (xmlStrEqual(name, BAD_CAST "child"))
11186 		ret = AXIS_CHILD;
11187 	    break;
11188 	case 'd':
11189 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
11190 		ret = AXIS_DESCENDANT;
11191 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11192 		ret = AXIS_DESCENDANT_OR_SELF;
11193 	    break;
11194 	case 'f':
11195 	    if (xmlStrEqual(name, BAD_CAST "following"))
11196 		ret = AXIS_FOLLOWING;
11197 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11198 		ret = AXIS_FOLLOWING_SIBLING;
11199 	    break;
11200 	case 'n':
11201 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
11202 		ret = AXIS_NAMESPACE;
11203 	    break;
11204 	case 'p':
11205 	    if (xmlStrEqual(name, BAD_CAST "parent"))
11206 		ret = AXIS_PARENT;
11207 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
11208 		ret = AXIS_PRECEDING;
11209 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11210 		ret = AXIS_PRECEDING_SIBLING;
11211 	    break;
11212 	case 's':
11213 	    if (xmlStrEqual(name, BAD_CAST "self"))
11214 		ret = AXIS_SELF;
11215 	    break;
11216     }
11217     return(ret);
11218 }
11219 
11220 /**
11221  * xmlXPathCompStep:
11222  * @ctxt:  the XPath Parser context
11223  *
11224  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11225  *                  | AbbreviatedStep
11226  *
11227  * [12] AbbreviatedStep ::=   '.' | '..'
11228  *
11229  * [5] AxisSpecifier ::= AxisName '::'
11230  *                  | AbbreviatedAxisSpecifier
11231  *
11232  * [13] AbbreviatedAxisSpecifier ::= '@'?
11233  *
11234  * Modified for XPtr range support as:
11235  *
11236  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11237  *                     | AbbreviatedStep
11238  *                     | 'range-to' '(' Expr ')' Predicate*
11239  *
11240  * Compile one step in a Location Path
11241  * A location step of . is short for self::node(). This is
11242  * particularly useful in conjunction with //. For example, the
11243  * location path .//para is short for
11244  * self::node()/descendant-or-self::node()/child::para
11245  * and so will select all para descendant elements of the context
11246  * node.
11247  * Similarly, a location step of .. is short for parent::node().
11248  * For example, ../title is short for parent::node()/child::title
11249  * and so will select the title children of the parent of the context
11250  * node.
11251  */
11252 static void
xmlXPathCompStep(xmlXPathParserContextPtr ctxt)11253 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11254 #ifdef LIBXML_XPTR_LOCS_ENABLED
11255     int rangeto = 0;
11256     int op2 = -1;
11257 #endif
11258 
11259     SKIP_BLANKS;
11260     if ((CUR == '.') && (NXT(1) == '.')) {
11261 	SKIP(2);
11262 	SKIP_BLANKS;
11263 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11264 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11265     } else if (CUR == '.') {
11266 	NEXT;
11267 	SKIP_BLANKS;
11268     } else {
11269 	xmlChar *name = NULL;
11270 	xmlChar *prefix = NULL;
11271 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
11272 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11273 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11274 	int op1;
11275 
11276 	/*
11277 	 * The modification needed for XPointer change to the production
11278 	 */
11279 #ifdef LIBXML_XPTR_LOCS_ENABLED
11280 	if (ctxt->xptr) {
11281 	    name = xmlXPathParseNCName(ctxt);
11282 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11283                 op2 = ctxt->comp->last;
11284 		xmlFree(name);
11285 		SKIP_BLANKS;
11286 		if (CUR != '(') {
11287 		    XP_ERROR(XPATH_EXPR_ERROR);
11288 		}
11289 		NEXT;
11290 		SKIP_BLANKS;
11291 
11292 		xmlXPathCompileExpr(ctxt, 1);
11293 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11294 		CHECK_ERROR;
11295 
11296 		SKIP_BLANKS;
11297 		if (CUR != ')') {
11298 		    XP_ERROR(XPATH_EXPR_ERROR);
11299 		}
11300 		NEXT;
11301 		rangeto = 1;
11302 		goto eval_predicates;
11303 	    }
11304 	}
11305 #endif
11306 	if (CUR == '*') {
11307 	    axis = AXIS_CHILD;
11308 	} else {
11309 	    if (name == NULL)
11310 		name = xmlXPathParseNCName(ctxt);
11311 	    if (name != NULL) {
11312 		axis = xmlXPathIsAxisName(name);
11313 		if (axis != 0) {
11314 		    SKIP_BLANKS;
11315 		    if ((CUR == ':') && (NXT(1) == ':')) {
11316 			SKIP(2);
11317 			xmlFree(name);
11318 			name = NULL;
11319 		    } else {
11320 			/* an element name can conflict with an axis one :-\ */
11321 			axis = AXIS_CHILD;
11322 		    }
11323 		} else {
11324 		    axis = AXIS_CHILD;
11325 		}
11326 	    } else if (CUR == '@') {
11327 		NEXT;
11328 		axis = AXIS_ATTRIBUTE;
11329 	    } else {
11330 		axis = AXIS_CHILD;
11331 	    }
11332 	}
11333 
11334         if (ctxt->error != XPATH_EXPRESSION_OK) {
11335             xmlFree(name);
11336             return;
11337         }
11338 
11339 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11340 	if (test == 0)
11341 	    return;
11342 
11343         if ((prefix != NULL) && (ctxt->context != NULL) &&
11344 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11345 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11346 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11347 	    }
11348 	}
11349 #ifdef DEBUG_STEP
11350 	xmlGenericError(xmlGenericErrorContext,
11351 		"Basis : computing new set\n");
11352 #endif
11353 
11354 #ifdef DEBUG_STEP
11355 	xmlGenericError(xmlGenericErrorContext, "Basis : ");
11356 	if (ctxt->value == NULL)
11357 	    xmlGenericError(xmlGenericErrorContext, "no value\n");
11358 	else if (ctxt->value->nodesetval == NULL)
11359 	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
11360 	else
11361 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11362 #endif
11363 
11364 #ifdef LIBXML_XPTR_LOCS_ENABLED
11365 eval_predicates:
11366 #endif
11367 	op1 = ctxt->comp->last;
11368 	ctxt->comp->last = -1;
11369 
11370 	SKIP_BLANKS;
11371 	while (CUR == '[') {
11372 	    xmlXPathCompPredicate(ctxt, 0);
11373 	}
11374 
11375 #ifdef LIBXML_XPTR_LOCS_ENABLED
11376 	if (rangeto) {
11377 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11378 	} else
11379 #endif
11380         if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11381                            test, type, (void *)prefix, (void *)name) == -1) {
11382             xmlFree(prefix);
11383             xmlFree(name);
11384         }
11385     }
11386 #ifdef DEBUG_STEP
11387     xmlGenericError(xmlGenericErrorContext, "Step : ");
11388     if (ctxt->value == NULL)
11389 	xmlGenericError(xmlGenericErrorContext, "no value\n");
11390     else if (ctxt->value->nodesetval == NULL)
11391 	xmlGenericError(xmlGenericErrorContext, "Empty\n");
11392     else
11393 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11394 		ctxt->value->nodesetval);
11395 #endif
11396 }
11397 
11398 /**
11399  * xmlXPathCompRelativeLocationPath:
11400  * @ctxt:  the XPath Parser context
11401  *
11402  *  [3]   RelativeLocationPath ::=   Step
11403  *                     | RelativeLocationPath '/' Step
11404  *                     | AbbreviatedRelativeLocationPath
11405  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11406  *
11407  * Compile a relative location path.
11408  */
11409 static void
xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt)11410 xmlXPathCompRelativeLocationPath
11411 (xmlXPathParserContextPtr ctxt) {
11412     SKIP_BLANKS;
11413     if ((CUR == '/') && (NXT(1) == '/')) {
11414 	SKIP(2);
11415 	SKIP_BLANKS;
11416 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11417 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11418     } else if (CUR == '/') {
11419 	    NEXT;
11420 	SKIP_BLANKS;
11421     }
11422     xmlXPathCompStep(ctxt);
11423     CHECK_ERROR;
11424     SKIP_BLANKS;
11425     while (CUR == '/') {
11426 	if ((CUR == '/') && (NXT(1) == '/')) {
11427 	    SKIP(2);
11428 	    SKIP_BLANKS;
11429 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11430 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11431 	    xmlXPathCompStep(ctxt);
11432 	} else if (CUR == '/') {
11433 	    NEXT;
11434 	    SKIP_BLANKS;
11435 	    xmlXPathCompStep(ctxt);
11436 	}
11437 	SKIP_BLANKS;
11438     }
11439 }
11440 
11441 /**
11442  * xmlXPathCompLocationPath:
11443  * @ctxt:  the XPath Parser context
11444  *
11445  *  [1]   LocationPath ::=   RelativeLocationPath
11446  *                     | AbsoluteLocationPath
11447  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11448  *                     | AbbreviatedAbsoluteLocationPath
11449  *  [10]   AbbreviatedAbsoluteLocationPath ::=
11450  *                           '//' RelativeLocationPath
11451  *
11452  * Compile a location path
11453  *
11454  * // is short for /descendant-or-self::node()/. For example,
11455  * //para is short for /descendant-or-self::node()/child::para and
11456  * so will select any para element in the document (even a para element
11457  * that is a document element will be selected by //para since the
11458  * document element node is a child of the root node); div//para is
11459  * short for div/descendant-or-self::node()/child::para and so will
11460  * select all para descendants of div children.
11461  */
11462 static void
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt)11463 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11464     SKIP_BLANKS;
11465     if (CUR != '/') {
11466         xmlXPathCompRelativeLocationPath(ctxt);
11467     } else {
11468 	while (CUR == '/') {
11469 	    if ((CUR == '/') && (NXT(1) == '/')) {
11470 		SKIP(2);
11471 		SKIP_BLANKS;
11472 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11473 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11474 		xmlXPathCompRelativeLocationPath(ctxt);
11475 	    } else if (CUR == '/') {
11476 		NEXT;
11477 		SKIP_BLANKS;
11478 		if ((CUR != 0 ) &&
11479 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11480 		     (CUR == '@') || (CUR == '*')))
11481 		    xmlXPathCompRelativeLocationPath(ctxt);
11482 	    }
11483 	    CHECK_ERROR;
11484 	}
11485     }
11486 }
11487 
11488 /************************************************************************
11489  *									*
11490  *		XPath precompiled expression evaluation			*
11491  *									*
11492  ************************************************************************/
11493 
11494 static int
11495 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11496 
11497 #ifdef DEBUG_STEP
11498 static void
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,int nbNodes)11499 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11500 			  int nbNodes)
11501 {
11502     xmlGenericError(xmlGenericErrorContext, "new step : ");
11503     switch (op->value) {
11504         case AXIS_ANCESTOR:
11505             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11506             break;
11507         case AXIS_ANCESTOR_OR_SELF:
11508             xmlGenericError(xmlGenericErrorContext,
11509                             "axis 'ancestors-or-self' ");
11510             break;
11511         case AXIS_ATTRIBUTE:
11512             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11513             break;
11514         case AXIS_CHILD:
11515             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11516             break;
11517         case AXIS_DESCENDANT:
11518             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11519             break;
11520         case AXIS_DESCENDANT_OR_SELF:
11521             xmlGenericError(xmlGenericErrorContext,
11522                             "axis 'descendant-or-self' ");
11523             break;
11524         case AXIS_FOLLOWING:
11525             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11526             break;
11527         case AXIS_FOLLOWING_SIBLING:
11528             xmlGenericError(xmlGenericErrorContext,
11529                             "axis 'following-siblings' ");
11530             break;
11531         case AXIS_NAMESPACE:
11532             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11533             break;
11534         case AXIS_PARENT:
11535             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11536             break;
11537         case AXIS_PRECEDING:
11538             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11539             break;
11540         case AXIS_PRECEDING_SIBLING:
11541             xmlGenericError(xmlGenericErrorContext,
11542                             "axis 'preceding-sibling' ");
11543             break;
11544         case AXIS_SELF:
11545             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11546             break;
11547     }
11548     xmlGenericError(xmlGenericErrorContext,
11549 	" context contains %d nodes\n", nbNodes);
11550     switch (op->value2) {
11551         case NODE_TEST_NONE:
11552             xmlGenericError(xmlGenericErrorContext,
11553                             "           searching for none !!!\n");
11554             break;
11555         case NODE_TEST_TYPE:
11556             xmlGenericError(xmlGenericErrorContext,
11557                             "           searching for type %d\n", op->value3);
11558             break;
11559         case NODE_TEST_PI:
11560             xmlGenericError(xmlGenericErrorContext,
11561                             "           searching for PI !!!\n");
11562             break;
11563         case NODE_TEST_ALL:
11564             xmlGenericError(xmlGenericErrorContext,
11565                             "           searching for *\n");
11566             break;
11567         case NODE_TEST_NS:
11568             xmlGenericError(xmlGenericErrorContext,
11569                             "           searching for namespace %s\n",
11570                             op->value5);
11571             break;
11572         case NODE_TEST_NAME:
11573             xmlGenericError(xmlGenericErrorContext,
11574                             "           searching for name %s\n", op->value5);
11575             if (op->value4)
11576                 xmlGenericError(xmlGenericErrorContext,
11577                                 "           with namespace %s\n", op->value4);
11578             break;
11579     }
11580     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11581 }
11582 #endif /* DEBUG_STEP */
11583 
11584 /**
11585  * xmlXPathNodeSetFilter:
11586  * @ctxt:  the XPath Parser context
11587  * @set: the node set to filter
11588  * @filterOpIndex: the index of the predicate/filter op
11589  * @minPos: minimum position in the filtered set (1-based)
11590  * @maxPos: maximum position in the filtered set (1-based)
11591  * @hasNsNodes: true if the node set may contain namespace nodes
11592  *
11593  * Filter a node set, keeping only nodes for which the predicate expression
11594  * matches. Afterwards, keep only nodes between minPos and maxPos in the
11595  * filtered result.
11596  */
11597 static void
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,xmlNodeSetPtr set,int filterOpIndex,int minPos,int maxPos,int hasNsNodes)11598 xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11599 		      xmlNodeSetPtr set,
11600 		      int filterOpIndex,
11601                       int minPos, int maxPos,
11602 		      int hasNsNodes)
11603 {
11604     xmlXPathContextPtr xpctxt;
11605     xmlNodePtr oldnode;
11606     xmlDocPtr olddoc;
11607     xmlXPathStepOpPtr filterOp;
11608     int oldcs, oldpp;
11609     int i, j, pos;
11610 
11611     if ((set == NULL) || (set->nodeNr == 0))
11612         return;
11613 
11614     /*
11615     * Check if the node set contains a sufficient number of nodes for
11616     * the requested range.
11617     */
11618     if (set->nodeNr < minPos) {
11619         xmlXPathNodeSetClear(set, hasNsNodes);
11620         return;
11621     }
11622 
11623     xpctxt = ctxt->context;
11624     oldnode = xpctxt->node;
11625     olddoc = xpctxt->doc;
11626     oldcs = xpctxt->contextSize;
11627     oldpp = xpctxt->proximityPosition;
11628     filterOp = &ctxt->comp->steps[filterOpIndex];
11629 
11630     xpctxt->contextSize = set->nodeNr;
11631 
11632     for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11633         xmlNodePtr node = set->nodeTab[i];
11634         int res;
11635 
11636         xpctxt->node = node;
11637         xpctxt->proximityPosition = i + 1;
11638 
11639         /*
11640         * Also set the xpath document in case things like
11641         * key() are evaluated in the predicate.
11642         *
11643         * TODO: Get real doc for namespace nodes.
11644         */
11645         if ((node->type != XML_NAMESPACE_DECL) &&
11646             (node->doc != NULL))
11647             xpctxt->doc = node->doc;
11648 
11649         res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11650 
11651         if (ctxt->error != XPATH_EXPRESSION_OK)
11652             break;
11653         if (res < 0) {
11654             /* Shouldn't happen */
11655             xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11656             break;
11657         }
11658 
11659         if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11660             if (i != j) {
11661                 set->nodeTab[j] = node;
11662                 set->nodeTab[i] = NULL;
11663             }
11664 
11665             j += 1;
11666         } else {
11667             /* Remove the entry from the initial node set. */
11668             set->nodeTab[i] = NULL;
11669             if (node->type == XML_NAMESPACE_DECL)
11670                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11671         }
11672 
11673         if (res != 0) {
11674             if (pos == maxPos) {
11675                 i += 1;
11676                 break;
11677             }
11678 
11679             pos += 1;
11680         }
11681     }
11682 
11683     /* Free remaining nodes. */
11684     if (hasNsNodes) {
11685         for (; i < set->nodeNr; i++) {
11686             xmlNodePtr node = set->nodeTab[i];
11687             if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11688                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11689         }
11690     }
11691 
11692     set->nodeNr = j;
11693 
11694     /* If too many elements were removed, shrink table to preserve memory. */
11695     if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11696         (set->nodeNr < set->nodeMax / 2)) {
11697         xmlNodePtr *tmp;
11698         int nodeMax = set->nodeNr;
11699 
11700         if (nodeMax < XML_NODESET_DEFAULT)
11701             nodeMax = XML_NODESET_DEFAULT;
11702         tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11703                 nodeMax * sizeof(xmlNodePtr));
11704         if (tmp == NULL) {
11705             xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11706         } else {
11707             set->nodeTab = tmp;
11708             set->nodeMax = nodeMax;
11709         }
11710     }
11711 
11712     xpctxt->node = oldnode;
11713     xpctxt->doc = olddoc;
11714     xpctxt->contextSize = oldcs;
11715     xpctxt->proximityPosition = oldpp;
11716 }
11717 
11718 #ifdef LIBXML_XPTR_LOCS_ENABLED
11719 /**
11720  * xmlXPathLocationSetFilter:
11721  * @ctxt:  the XPath Parser context
11722  * @locset: the location set to filter
11723  * @filterOpIndex: the index of the predicate/filter op
11724  * @minPos: minimum position in the filtered set (1-based)
11725  * @maxPos: maximum position in the filtered set (1-based)
11726  *
11727  * Filter a location set, keeping only nodes for which the predicate
11728  * expression matches. Afterwards, keep only nodes between minPos and maxPos
11729  * in the filtered result.
11730  */
11731 static void
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,xmlLocationSetPtr locset,int filterOpIndex,int minPos,int maxPos)11732 xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11733 		          xmlLocationSetPtr locset,
11734 		          int filterOpIndex,
11735                           int minPos, int maxPos)
11736 {
11737     xmlXPathContextPtr xpctxt;
11738     xmlNodePtr oldnode;
11739     xmlDocPtr olddoc;
11740     xmlXPathStepOpPtr filterOp;
11741     int oldcs, oldpp;
11742     int i, j, pos;
11743 
11744     if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11745         return;
11746 
11747     xpctxt = ctxt->context;
11748     oldnode = xpctxt->node;
11749     olddoc = xpctxt->doc;
11750     oldcs = xpctxt->contextSize;
11751     oldpp = xpctxt->proximityPosition;
11752     filterOp = &ctxt->comp->steps[filterOpIndex];
11753 
11754     xpctxt->contextSize = locset->locNr;
11755 
11756     for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11757         xmlNodePtr contextNode = locset->locTab[i]->user;
11758         int res;
11759 
11760         xpctxt->node = contextNode;
11761         xpctxt->proximityPosition = i + 1;
11762 
11763         /*
11764         * Also set the xpath document in case things like
11765         * key() are evaluated in the predicate.
11766         *
11767         * TODO: Get real doc for namespace nodes.
11768         */
11769         if ((contextNode->type != XML_NAMESPACE_DECL) &&
11770             (contextNode->doc != NULL))
11771             xpctxt->doc = contextNode->doc;
11772 
11773         res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11774 
11775         if (ctxt->error != XPATH_EXPRESSION_OK)
11776             break;
11777         if (res < 0) {
11778             /* Shouldn't happen */
11779             xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11780             break;
11781         }
11782 
11783         if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11784             if (i != j) {
11785                 locset->locTab[j] = locset->locTab[i];
11786                 locset->locTab[i] = NULL;
11787             }
11788 
11789             j += 1;
11790         } else {
11791             /* Remove the entry from the initial location set. */
11792             xmlXPathFreeObject(locset->locTab[i]);
11793             locset->locTab[i] = NULL;
11794         }
11795 
11796         if (res != 0) {
11797             if (pos == maxPos) {
11798                 i += 1;
11799                 break;
11800             }
11801 
11802             pos += 1;
11803         }
11804     }
11805 
11806     /* Free remaining nodes. */
11807     for (; i < locset->locNr; i++)
11808         xmlXPathFreeObject(locset->locTab[i]);
11809 
11810     locset->locNr = j;
11811 
11812     /* If too many elements were removed, shrink table to preserve memory. */
11813     if ((locset->locMax > XML_NODESET_DEFAULT) &&
11814         (locset->locNr < locset->locMax / 2)) {
11815         xmlXPathObjectPtr *tmp;
11816         int locMax = locset->locNr;
11817 
11818         if (locMax < XML_NODESET_DEFAULT)
11819             locMax = XML_NODESET_DEFAULT;
11820         tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11821                 locMax * sizeof(xmlXPathObjectPtr));
11822         if (tmp == NULL) {
11823             xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11824         } else {
11825             locset->locTab = tmp;
11826             locset->locMax = locMax;
11827         }
11828     }
11829 
11830     xpctxt->node = oldnode;
11831     xpctxt->doc = olddoc;
11832     xpctxt->contextSize = oldcs;
11833     xpctxt->proximityPosition = oldpp;
11834 }
11835 #endif /* LIBXML_XPTR_LOCS_ENABLED */
11836 
11837 /**
11838  * xmlXPathCompOpEvalPredicate:
11839  * @ctxt:  the XPath Parser context
11840  * @op: the predicate op
11841  * @set: the node set to filter
11842  * @minPos: minimum position in the filtered set (1-based)
11843  * @maxPos: maximum position in the filtered set (1-based)
11844  * @hasNsNodes: true if the node set may contain namespace nodes
11845  *
11846  * Filter a node set, keeping only nodes for which the sequence of predicate
11847  * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11848  * in the filtered result.
11849  */
11850 static void
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int minPos,int maxPos,int hasNsNodes)11851 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11852 			    xmlXPathStepOpPtr op,
11853 			    xmlNodeSetPtr set,
11854                             int minPos, int maxPos,
11855 			    int hasNsNodes)
11856 {
11857     if (op->ch1 != -1) {
11858 	xmlXPathCompExprPtr comp = ctxt->comp;
11859 	/*
11860 	* Process inner predicates first.
11861 	*/
11862 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11863             xmlGenericError(xmlGenericErrorContext,
11864                 "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11865             XP_ERROR(XPATH_INVALID_OPERAND);
11866 	}
11867         if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11868             XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11869         ctxt->context->depth += 1;
11870 	xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11871                                     1, set->nodeNr, hasNsNodes);
11872         ctxt->context->depth -= 1;
11873 	CHECK_ERROR;
11874     }
11875 
11876     if (op->ch2 != -1)
11877         xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11878 }
11879 
11880 static int
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int * maxPos)11881 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11882 			    xmlXPathStepOpPtr op,
11883 			    int *maxPos)
11884 {
11885 
11886     xmlXPathStepOpPtr exprOp;
11887 
11888     /*
11889     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11890     */
11891 
11892     /*
11893     * If not -1, then ch1 will point to:
11894     * 1) For predicates (XPATH_OP_PREDICATE):
11895     *    - an inner predicate operator
11896     * 2) For filters (XPATH_OP_FILTER):
11897     *    - an inner filter operator OR
11898     *    - an expression selecting the node set.
11899     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11900     */
11901     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11902 	return(0);
11903 
11904     if (op->ch2 != -1) {
11905 	exprOp = &ctxt->comp->steps[op->ch2];
11906     } else
11907 	return(0);
11908 
11909     if ((exprOp != NULL) &&
11910 	(exprOp->op == XPATH_OP_VALUE) &&
11911 	(exprOp->value4 != NULL) &&
11912 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11913     {
11914         double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11915 
11916 	/*
11917 	* We have a "[n]" predicate here.
11918 	* TODO: Unfortunately this simplistic test here is not
11919 	* able to detect a position() predicate in compound
11920 	* expressions like "[@attr = 'a" and position() = 1],
11921 	* and even not the usage of position() in
11922 	* "[position() = 1]"; thus - obviously - a position-range,
11923 	* like it "[position() < 5]", is also not detected.
11924 	* Maybe we could rewrite the AST to ease the optimization.
11925 	*/
11926 
11927         if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11928 	    *maxPos = (int) floatval;
11929             if (floatval == (double) *maxPos)
11930                 return(1);
11931         }
11932     }
11933     return(0);
11934 }
11935 
11936 static int
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first,xmlNodePtr * last,int toBool)11937 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11938                            xmlXPathStepOpPtr op,
11939 			   xmlNodePtr * first, xmlNodePtr * last,
11940 			   int toBool)
11941 {
11942 
11943 #define XP_TEST_HIT \
11944     if (hasAxisRange != 0) { \
11945 	if (++pos == maxPos) { \
11946 	    if (addNode(seq, cur) < 0) \
11947 	        ctxt->error = XPATH_MEMORY_ERROR; \
11948 	    goto axis_range_end; } \
11949     } else { \
11950 	if (addNode(seq, cur) < 0) \
11951 	    ctxt->error = XPATH_MEMORY_ERROR; \
11952 	if (breakOnFirstHit) goto first_hit; }
11953 
11954 #define XP_TEST_HIT_NS \
11955     if (hasAxisRange != 0) { \
11956 	if (++pos == maxPos) { \
11957 	    hasNsNodes = 1; \
11958 	    if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11959 	        ctxt->error = XPATH_MEMORY_ERROR; \
11960 	goto axis_range_end; } \
11961     } else { \
11962 	hasNsNodes = 1; \
11963 	if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11964 	    ctxt->error = XPATH_MEMORY_ERROR; \
11965 	if (breakOnFirstHit) goto first_hit; }
11966 
11967     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11968     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11969     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11970     const xmlChar *prefix = op->value4;
11971     const xmlChar *name = op->value5;
11972     const xmlChar *URI = NULL;
11973 
11974 #ifdef DEBUG_STEP
11975     int nbMatches = 0, prevMatches = 0;
11976 #endif
11977     int total = 0, hasNsNodes = 0;
11978     /* The popped object holding the context nodes */
11979     xmlXPathObjectPtr obj;
11980     /* The set of context nodes for the node tests */
11981     xmlNodeSetPtr contextSeq;
11982     int contextIdx;
11983     xmlNodePtr contextNode;
11984     /* The final resulting node set wrt to all context nodes */
11985     xmlNodeSetPtr outSeq;
11986     /*
11987     * The temporary resulting node set wrt 1 context node.
11988     * Used to feed predicate evaluation.
11989     */
11990     xmlNodeSetPtr seq;
11991     xmlNodePtr cur;
11992     /* First predicate operator */
11993     xmlXPathStepOpPtr predOp;
11994     int maxPos; /* The requested position() (when a "[n]" predicate) */
11995     int hasPredicateRange, hasAxisRange, pos;
11996     int breakOnFirstHit;
11997 
11998     xmlXPathTraversalFunction next = NULL;
11999     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12000     xmlXPathNodeSetMergeFunction mergeAndClear;
12001     xmlNodePtr oldContextNode;
12002     xmlXPathContextPtr xpctxt = ctxt->context;
12003 
12004 
12005     CHECK_TYPE0(XPATH_NODESET);
12006     obj = valuePop(ctxt);
12007     /*
12008     * Setup namespaces.
12009     */
12010     if (prefix != NULL) {
12011         URI = xmlXPathNsLookup(xpctxt, prefix);
12012         if (URI == NULL) {
12013 	    xmlXPathReleaseObject(xpctxt, obj);
12014             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12015 	}
12016     }
12017     /*
12018     * Setup axis.
12019     *
12020     * MAYBE FUTURE TODO: merging optimizations:
12021     * - If the nodes to be traversed wrt to the initial nodes and
12022     *   the current axis cannot overlap, then we could avoid searching
12023     *   for duplicates during the merge.
12024     *   But the question is how/when to evaluate if they cannot overlap.
12025     *   Example: if we know that for two initial nodes, the one is
12026     *   not in the ancestor-or-self axis of the other, then we could safely
12027     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12028     *   the descendant-or-self axis.
12029     */
12030     mergeAndClear = xmlXPathNodeSetMergeAndClear;
12031     switch (axis) {
12032         case AXIS_ANCESTOR:
12033             first = NULL;
12034             next = xmlXPathNextAncestor;
12035             break;
12036         case AXIS_ANCESTOR_OR_SELF:
12037             first = NULL;
12038             next = xmlXPathNextAncestorOrSelf;
12039             break;
12040         case AXIS_ATTRIBUTE:
12041             first = NULL;
12042 	    last = NULL;
12043             next = xmlXPathNextAttribute;
12044 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12045             break;
12046         case AXIS_CHILD:
12047 	    last = NULL;
12048 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12049 		(type == NODE_TYPE_NODE))
12050 	    {
12051 		/*
12052 		* Optimization if an element node type is 'element'.
12053 		*/
12054 		next = xmlXPathNextChildElement;
12055 	    } else
12056 		next = xmlXPathNextChild;
12057 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12058             break;
12059         case AXIS_DESCENDANT:
12060 	    last = NULL;
12061             next = xmlXPathNextDescendant;
12062             break;
12063         case AXIS_DESCENDANT_OR_SELF:
12064 	    last = NULL;
12065             next = xmlXPathNextDescendantOrSelf;
12066             break;
12067         case AXIS_FOLLOWING:
12068 	    last = NULL;
12069             next = xmlXPathNextFollowing;
12070             break;
12071         case AXIS_FOLLOWING_SIBLING:
12072 	    last = NULL;
12073             next = xmlXPathNextFollowingSibling;
12074             break;
12075         case AXIS_NAMESPACE:
12076             first = NULL;
12077 	    last = NULL;
12078             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12079 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12080             break;
12081         case AXIS_PARENT:
12082             first = NULL;
12083             next = xmlXPathNextParent;
12084             break;
12085         case AXIS_PRECEDING:
12086             first = NULL;
12087             next = xmlXPathNextPrecedingInternal;
12088             break;
12089         case AXIS_PRECEDING_SIBLING:
12090             first = NULL;
12091             next = xmlXPathNextPrecedingSibling;
12092             break;
12093         case AXIS_SELF:
12094             first = NULL;
12095 	    last = NULL;
12096             next = xmlXPathNextSelf;
12097 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12098             break;
12099     }
12100 
12101 #ifdef DEBUG_STEP
12102     xmlXPathDebugDumpStepAxis(op,
12103 	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12104 #endif
12105 
12106     if (next == NULL) {
12107 	xmlXPathReleaseObject(xpctxt, obj);
12108         return(0);
12109     }
12110     contextSeq = obj->nodesetval;
12111     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12112 	xmlXPathReleaseObject(xpctxt, obj);
12113         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12114         return(0);
12115     }
12116     /*
12117     * Predicate optimization ---------------------------------------------
12118     * If this step has a last predicate, which contains a position(),
12119     * then we'll optimize (although not exactly "position()", but only
12120     * the  short-hand form, i.e., "[n]".
12121     *
12122     * Example - expression "/foo[parent::bar][1]":
12123     *
12124     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12125     *   ROOT                               -- op->ch1
12126     *   PREDICATE                          -- op->ch2 (predOp)
12127     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12128     *       SORT
12129     *         COLLECT  'parent' 'name' 'node' bar
12130     *           NODE
12131     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12132     *
12133     */
12134     maxPos = 0;
12135     predOp = NULL;
12136     hasPredicateRange = 0;
12137     hasAxisRange = 0;
12138     if (op->ch2 != -1) {
12139 	/*
12140 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
12141 	*/
12142 	predOp = &ctxt->comp->steps[op->ch2];
12143 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12144 	    if (predOp->ch1 != -1) {
12145 		/*
12146 		* Use the next inner predicate operator.
12147 		*/
12148 		predOp = &ctxt->comp->steps[predOp->ch1];
12149 		hasPredicateRange = 1;
12150 	    } else {
12151 		/*
12152 		* There's no other predicate than the [n] predicate.
12153 		*/
12154 		predOp = NULL;
12155 		hasAxisRange = 1;
12156 	    }
12157 	}
12158     }
12159     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12160     /*
12161     * Axis traversal -----------------------------------------------------
12162     */
12163     /*
12164      * 2.3 Node Tests
12165      *  - For the attribute axis, the principal node type is attribute.
12166      *  - For the namespace axis, the principal node type is namespace.
12167      *  - For other axes, the principal node type is element.
12168      *
12169      * A node test * is true for any node of the
12170      * principal node type. For example, child::* will
12171      * select all element children of the context node
12172      */
12173     oldContextNode = xpctxt->node;
12174     addNode = xmlXPathNodeSetAddUnique;
12175     outSeq = NULL;
12176     seq = NULL;
12177     contextNode = NULL;
12178     contextIdx = 0;
12179 
12180 
12181     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12182            (ctxt->error == XPATH_EXPRESSION_OK)) {
12183 	xpctxt->node = contextSeq->nodeTab[contextIdx++];
12184 
12185 	if (seq == NULL) {
12186 	    seq = xmlXPathNodeSetCreate(NULL);
12187 	    if (seq == NULL) {
12188                 /* TODO: Propagate memory error. */
12189 		total = 0;
12190 		goto error;
12191 	    }
12192 	}
12193 	/*
12194 	* Traverse the axis and test the nodes.
12195 	*/
12196 	pos = 0;
12197 	cur = NULL;
12198 	hasNsNodes = 0;
12199         do {
12200             if (OP_LIMIT_EXCEEDED(ctxt, 1))
12201                 goto error;
12202 
12203             cur = next(ctxt, cur);
12204             if (cur == NULL)
12205                 break;
12206 
12207 	    /*
12208 	    * QUESTION TODO: What does the "first" and "last" stuff do?
12209 	    */
12210             if ((first != NULL) && (*first != NULL)) {
12211 		if (*first == cur)
12212 		    break;
12213 		if (((total % 256) == 0) &&
12214 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12215 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12216 #else
12217 		    (xmlXPathCmpNodes(*first, cur) >= 0))
12218 #endif
12219 		{
12220 		    break;
12221 		}
12222 	    }
12223 	    if ((last != NULL) && (*last != NULL)) {
12224 		if (*last == cur)
12225 		    break;
12226 		if (((total % 256) == 0) &&
12227 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12228 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12229 #else
12230 		    (xmlXPathCmpNodes(cur, *last) >= 0))
12231 #endif
12232 		{
12233 		    break;
12234 		}
12235 	    }
12236 
12237             total++;
12238 
12239 #ifdef DEBUG_STEP
12240             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12241 #endif
12242 
12243 	    switch (test) {
12244                 case NODE_TEST_NONE:
12245 		    total = 0;
12246                     STRANGE
12247 		    goto error;
12248                 case NODE_TEST_TYPE:
12249 		    if (type == NODE_TYPE_NODE) {
12250 			switch (cur->type) {
12251 			    case XML_DOCUMENT_NODE:
12252 			    case XML_HTML_DOCUMENT_NODE:
12253 			    case XML_ELEMENT_NODE:
12254 			    case XML_ATTRIBUTE_NODE:
12255 			    case XML_PI_NODE:
12256 			    case XML_COMMENT_NODE:
12257 			    case XML_CDATA_SECTION_NODE:
12258 			    case XML_TEXT_NODE:
12259 				XP_TEST_HIT
12260 				break;
12261 			    case XML_NAMESPACE_DECL: {
12262 				if (axis == AXIS_NAMESPACE) {
12263 				    XP_TEST_HIT_NS
12264 				} else {
12265 	                            hasNsNodes = 1;
12266 				    XP_TEST_HIT
12267 				}
12268 				break;
12269                             }
12270 			    default:
12271 				break;
12272 			}
12273 		    } else if (cur->type == (xmlElementType) type) {
12274 			if (cur->type == XML_NAMESPACE_DECL)
12275 			    XP_TEST_HIT_NS
12276 			else
12277 			    XP_TEST_HIT
12278 		    } else if ((type == NODE_TYPE_TEXT) &&
12279 			 (cur->type == XML_CDATA_SECTION_NODE))
12280 		    {
12281 			XP_TEST_HIT
12282 		    }
12283 		    break;
12284                 case NODE_TEST_PI:
12285                     if ((cur->type == XML_PI_NODE) &&
12286                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12287 		    {
12288 			XP_TEST_HIT
12289                     }
12290                     break;
12291                 case NODE_TEST_ALL:
12292                     if (axis == AXIS_ATTRIBUTE) {
12293                         if (cur->type == XML_ATTRIBUTE_NODE)
12294 			{
12295                             if (prefix == NULL)
12296 			    {
12297 				XP_TEST_HIT
12298                             } else if ((cur->ns != NULL) &&
12299 				(xmlStrEqual(URI, cur->ns->href)))
12300 			    {
12301 				XP_TEST_HIT
12302                             }
12303                         }
12304                     } else if (axis == AXIS_NAMESPACE) {
12305                         if (cur->type == XML_NAMESPACE_DECL)
12306 			{
12307 			    XP_TEST_HIT_NS
12308                         }
12309                     } else {
12310                         if (cur->type == XML_ELEMENT_NODE) {
12311                             if (prefix == NULL)
12312 			    {
12313 				XP_TEST_HIT
12314 
12315                             } else if ((cur->ns != NULL) &&
12316 				(xmlStrEqual(URI, cur->ns->href)))
12317 			    {
12318 				XP_TEST_HIT
12319                             }
12320                         }
12321                     }
12322                     break;
12323                 case NODE_TEST_NS:{
12324                         TODO;
12325                         break;
12326                     }
12327                 case NODE_TEST_NAME:
12328                     if (axis == AXIS_ATTRIBUTE) {
12329                         if (cur->type != XML_ATTRIBUTE_NODE)
12330 			    break;
12331 		    } else if (axis == AXIS_NAMESPACE) {
12332                         if (cur->type != XML_NAMESPACE_DECL)
12333 			    break;
12334 		    } else {
12335 		        if (cur->type != XML_ELEMENT_NODE)
12336 			    break;
12337 		    }
12338                     switch (cur->type) {
12339                         case XML_ELEMENT_NODE:
12340                             if (xmlStrEqual(name, cur->name)) {
12341                                 if (prefix == NULL) {
12342                                     if (cur->ns == NULL)
12343 				    {
12344 					XP_TEST_HIT
12345                                     }
12346                                 } else {
12347                                     if ((cur->ns != NULL) &&
12348                                         (xmlStrEqual(URI, cur->ns->href)))
12349 				    {
12350 					XP_TEST_HIT
12351                                     }
12352                                 }
12353                             }
12354                             break;
12355                         case XML_ATTRIBUTE_NODE:{
12356                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12357 
12358                                 if (xmlStrEqual(name, attr->name)) {
12359                                     if (prefix == NULL) {
12360                                         if ((attr->ns == NULL) ||
12361                                             (attr->ns->prefix == NULL))
12362 					{
12363 					    XP_TEST_HIT
12364                                         }
12365                                     } else {
12366                                         if ((attr->ns != NULL) &&
12367                                             (xmlStrEqual(URI,
12368 					      attr->ns->href)))
12369 					{
12370 					    XP_TEST_HIT
12371                                         }
12372                                     }
12373                                 }
12374                                 break;
12375                             }
12376                         case XML_NAMESPACE_DECL:
12377                             if (cur->type == XML_NAMESPACE_DECL) {
12378                                 xmlNsPtr ns = (xmlNsPtr) cur;
12379 
12380                                 if ((ns->prefix != NULL) && (name != NULL)
12381                                     && (xmlStrEqual(ns->prefix, name)))
12382 				{
12383 				    XP_TEST_HIT_NS
12384                                 }
12385                             }
12386                             break;
12387                         default:
12388                             break;
12389                     }
12390                     break;
12391 	    } /* switch(test) */
12392         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12393 
12394 	goto apply_predicates;
12395 
12396 axis_range_end: /* ----------------------------------------------------- */
12397 	/*
12398 	* We have a "/foo[n]", and position() = n was reached.
12399 	* Note that we can have as well "/foo/::parent::foo[1]", so
12400 	* a duplicate-aware merge is still needed.
12401 	* Merge with the result.
12402 	*/
12403 	if (outSeq == NULL) {
12404 	    outSeq = seq;
12405 	    seq = NULL;
12406 	} else
12407             /* TODO: Check memory error. */
12408 	    outSeq = mergeAndClear(outSeq, seq);
12409 	/*
12410 	* Break if only a true/false result was requested.
12411 	*/
12412 	if (toBool)
12413 	    break;
12414 	continue;
12415 
12416 first_hit: /* ---------------------------------------------------------- */
12417 	/*
12418 	* Break if only a true/false result was requested and
12419 	* no predicates existed and a node test succeeded.
12420 	*/
12421 	if (outSeq == NULL) {
12422 	    outSeq = seq;
12423 	    seq = NULL;
12424 	} else
12425             /* TODO: Check memory error. */
12426 	    outSeq = mergeAndClear(outSeq, seq);
12427 	break;
12428 
12429 #ifdef DEBUG_STEP
12430 	if (seq != NULL)
12431 	    nbMatches += seq->nodeNr;
12432 #endif
12433 
12434 apply_predicates: /* --------------------------------------------------- */
12435         if (ctxt->error != XPATH_EXPRESSION_OK)
12436 	    goto error;
12437 
12438         /*
12439 	* Apply predicates.
12440 	*/
12441         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12442 	    /*
12443 	    * E.g. when we have a "/foo[some expression][n]".
12444 	    */
12445 	    /*
12446 	    * QUESTION TODO: The old predicate evaluation took into
12447 	    *  account location-sets.
12448 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12449 	    *  Do we expect such a set here?
12450 	    *  All what I learned now from the evaluation semantics
12451 	    *  does not indicate that a location-set will be processed
12452 	    *  here, so this looks OK.
12453 	    */
12454 	    /*
12455 	    * Iterate over all predicates, starting with the outermost
12456 	    * predicate.
12457 	    * TODO: Problem: we cannot execute the inner predicates first
12458 	    *  since we cannot go back *up* the operator tree!
12459 	    *  Options we have:
12460 	    *  1) Use of recursive functions (like is it currently done
12461 	    *     via xmlXPathCompOpEval())
12462 	    *  2) Add a predicate evaluation information stack to the
12463 	    *     context struct
12464 	    *  3) Change the way the operators are linked; we need a
12465 	    *     "parent" field on xmlXPathStepOp
12466 	    *
12467 	    * For the moment, I'll try to solve this with a recursive
12468 	    * function: xmlXPathCompOpEvalPredicate().
12469 	    */
12470 	    if (hasPredicateRange != 0)
12471 		xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12472 					    hasNsNodes);
12473 	    else
12474 		xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12475 					    hasNsNodes);
12476 
12477 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12478 		total = 0;
12479 		goto error;
12480 	    }
12481         }
12482 
12483         if (seq->nodeNr > 0) {
12484 	    /*
12485 	    * Add to result set.
12486 	    */
12487 	    if (outSeq == NULL) {
12488 		outSeq = seq;
12489 		seq = NULL;
12490 	    } else {
12491                 /* TODO: Check memory error. */
12492 		outSeq = mergeAndClear(outSeq, seq);
12493 	    }
12494 
12495             if (toBool)
12496                 break;
12497 	}
12498     }
12499 
12500 error:
12501     if ((obj->boolval) && (obj->user != NULL)) {
12502 	/*
12503 	* QUESTION TODO: What does this do and why?
12504 	* TODO: Do we have to do this also for the "error"
12505 	* cleanup further down?
12506 	*/
12507 	ctxt->value->boolval = 1;
12508 	ctxt->value->user = obj->user;
12509 	obj->user = NULL;
12510 	obj->boolval = 0;
12511     }
12512     xmlXPathReleaseObject(xpctxt, obj);
12513 
12514     /*
12515     * Ensure we return at least an empty set.
12516     */
12517     if (outSeq == NULL) {
12518 	if ((seq != NULL) && (seq->nodeNr == 0))
12519 	    outSeq = seq;
12520 	else
12521             /* TODO: Check memory error. */
12522 	    outSeq = xmlXPathNodeSetCreate(NULL);
12523     }
12524     if ((seq != NULL) && (seq != outSeq)) {
12525 	 xmlXPathFreeNodeSet(seq);
12526     }
12527     /*
12528     * Hand over the result. Better to push the set also in
12529     * case of errors.
12530     */
12531     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12532     /*
12533     * Reset the context node.
12534     */
12535     xpctxt->node = oldContextNode;
12536     /*
12537     * When traversing the namespace axis in "toBool" mode, it's
12538     * possible that tmpNsList wasn't freed.
12539     */
12540     if (xpctxt->tmpNsList != NULL) {
12541         xmlFree(xpctxt->tmpNsList);
12542         xpctxt->tmpNsList = NULL;
12543     }
12544 
12545 #ifdef DEBUG_STEP
12546     xmlGenericError(xmlGenericErrorContext,
12547 	"\nExamined %d nodes, found %d nodes at that step\n",
12548 	total, nbMatches);
12549 #endif
12550 
12551     return(total);
12552 }
12553 
12554 static int
12555 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12556 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12557 
12558 /**
12559  * xmlXPathCompOpEvalFirst:
12560  * @ctxt:  the XPath parser context with the compiled expression
12561  * @op:  an XPath compiled operation
12562  * @first:  the first elem found so far
12563  *
12564  * Evaluate the Precompiled XPath operation searching only the first
12565  * element in document order
12566  *
12567  * Returns the number of examined objects.
12568  */
12569 static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12570 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12571                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12572 {
12573     int total = 0, cur;
12574     xmlXPathCompExprPtr comp;
12575     xmlXPathObjectPtr arg1, arg2;
12576 
12577     CHECK_ERROR0;
12578     if (OP_LIMIT_EXCEEDED(ctxt, 1))
12579         return(0);
12580     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12581         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12582     ctxt->context->depth += 1;
12583     comp = ctxt->comp;
12584     switch (op->op) {
12585         case XPATH_OP_END:
12586             break;
12587         case XPATH_OP_UNION:
12588             total =
12589                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12590                                         first);
12591 	    CHECK_ERROR0;
12592             if ((ctxt->value != NULL)
12593                 && (ctxt->value->type == XPATH_NODESET)
12594                 && (ctxt->value->nodesetval != NULL)
12595                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12596                 /*
12597                  * limit tree traversing to first node in the result
12598                  */
12599 		/*
12600 		* OPTIMIZE TODO: This implicitly sorts
12601 		*  the result, even if not needed. E.g. if the argument
12602 		*  of the count() function, no sorting is needed.
12603 		* OPTIMIZE TODO: How do we know if the node-list wasn't
12604 		*  already sorted?
12605 		*/
12606 		if (ctxt->value->nodesetval->nodeNr > 1)
12607 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12608                 *first = ctxt->value->nodesetval->nodeTab[0];
12609             }
12610             cur =
12611                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12612                                         first);
12613 	    CHECK_ERROR0;
12614 
12615             arg2 = valuePop(ctxt);
12616             arg1 = valuePop(ctxt);
12617             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12618                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12619 	        xmlXPathReleaseObject(ctxt->context, arg1);
12620 	        xmlXPathReleaseObject(ctxt->context, arg2);
12621                 XP_ERROR0(XPATH_INVALID_TYPE);
12622             }
12623             if ((ctxt->context->opLimit != 0) &&
12624                 (((arg1->nodesetval != NULL) &&
12625                   (xmlXPathCheckOpLimit(ctxt,
12626                                         arg1->nodesetval->nodeNr) < 0)) ||
12627                  ((arg2->nodesetval != NULL) &&
12628                   (xmlXPathCheckOpLimit(ctxt,
12629                                         arg2->nodesetval->nodeNr) < 0)))) {
12630 	        xmlXPathReleaseObject(ctxt->context, arg1);
12631 	        xmlXPathReleaseObject(ctxt->context, arg2);
12632                 break;
12633             }
12634 
12635             /* TODO: Check memory error. */
12636             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12637                                                     arg2->nodesetval);
12638             valuePush(ctxt, arg1);
12639 	    xmlXPathReleaseObject(ctxt->context, arg2);
12640             /* optimizer */
12641 	    if (total > cur)
12642 		xmlXPathCompSwap(op);
12643             total += cur;
12644             break;
12645         case XPATH_OP_ROOT:
12646             xmlXPathRoot(ctxt);
12647             break;
12648         case XPATH_OP_NODE:
12649             if (op->ch1 != -1)
12650                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12651 	    CHECK_ERROR0;
12652             if (op->ch2 != -1)
12653                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12654 	    CHECK_ERROR0;
12655 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12656 		ctxt->context->node));
12657             break;
12658         case XPATH_OP_COLLECT:{
12659                 if (op->ch1 == -1)
12660                     break;
12661 
12662                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12663 		CHECK_ERROR0;
12664 
12665                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12666                 break;
12667             }
12668         case XPATH_OP_VALUE:
12669             valuePush(ctxt,
12670                       xmlXPathCacheObjectCopy(ctxt->context,
12671 			(xmlXPathObjectPtr) op->value4));
12672             break;
12673         case XPATH_OP_SORT:
12674             if (op->ch1 != -1)
12675                 total +=
12676                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12677                                             first);
12678 	    CHECK_ERROR0;
12679             if ((ctxt->value != NULL)
12680                 && (ctxt->value->type == XPATH_NODESET)
12681                 && (ctxt->value->nodesetval != NULL)
12682 		&& (ctxt->value->nodesetval->nodeNr > 1))
12683                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12684             break;
12685 #ifdef XP_OPTIMIZED_FILTER_FIRST
12686 	case XPATH_OP_FILTER:
12687                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12688             break;
12689 #endif
12690         default:
12691             total += xmlXPathCompOpEval(ctxt, op);
12692             break;
12693     }
12694 
12695     ctxt->context->depth -= 1;
12696     return(total);
12697 }
12698 
12699 /**
12700  * xmlXPathCompOpEvalLast:
12701  * @ctxt:  the XPath parser context with the compiled expression
12702  * @op:  an XPath compiled operation
12703  * @last:  the last elem found so far
12704  *
12705  * Evaluate the Precompiled XPath operation searching only the last
12706  * element in document order
12707  *
12708  * Returns the number of nodes traversed
12709  */
12710 static int
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * last)12711 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12712                        xmlNodePtr * last)
12713 {
12714     int total = 0, cur;
12715     xmlXPathCompExprPtr comp;
12716     xmlXPathObjectPtr arg1, arg2;
12717 
12718     CHECK_ERROR0;
12719     if (OP_LIMIT_EXCEEDED(ctxt, 1))
12720         return(0);
12721     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12722         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12723     ctxt->context->depth += 1;
12724     comp = ctxt->comp;
12725     switch (op->op) {
12726         case XPATH_OP_END:
12727             break;
12728         case XPATH_OP_UNION:
12729             total =
12730                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12731 	    CHECK_ERROR0;
12732             if ((ctxt->value != NULL)
12733                 && (ctxt->value->type == XPATH_NODESET)
12734                 && (ctxt->value->nodesetval != NULL)
12735                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12736                 /*
12737                  * limit tree traversing to first node in the result
12738                  */
12739 		if (ctxt->value->nodesetval->nodeNr > 1)
12740 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12741                 *last =
12742                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12743                                                      nodesetval->nodeNr -
12744                                                      1];
12745             }
12746             cur =
12747                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12748 	    CHECK_ERROR0;
12749             if ((ctxt->value != NULL)
12750                 && (ctxt->value->type == XPATH_NODESET)
12751                 && (ctxt->value->nodesetval != NULL)
12752                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12753             }
12754 
12755             arg2 = valuePop(ctxt);
12756             arg1 = valuePop(ctxt);
12757             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12758                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12759 	        xmlXPathReleaseObject(ctxt->context, arg1);
12760 	        xmlXPathReleaseObject(ctxt->context, arg2);
12761                 XP_ERROR0(XPATH_INVALID_TYPE);
12762             }
12763             if ((ctxt->context->opLimit != 0) &&
12764                 (((arg1->nodesetval != NULL) &&
12765                   (xmlXPathCheckOpLimit(ctxt,
12766                                         arg1->nodesetval->nodeNr) < 0)) ||
12767                  ((arg2->nodesetval != NULL) &&
12768                   (xmlXPathCheckOpLimit(ctxt,
12769                                         arg2->nodesetval->nodeNr) < 0)))) {
12770 	        xmlXPathReleaseObject(ctxt->context, arg1);
12771 	        xmlXPathReleaseObject(ctxt->context, arg2);
12772                 break;
12773             }
12774 
12775             /* TODO: Check memory error. */
12776             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12777                                                     arg2->nodesetval);
12778             valuePush(ctxt, arg1);
12779 	    xmlXPathReleaseObject(ctxt->context, arg2);
12780             /* optimizer */
12781 	    if (total > cur)
12782 		xmlXPathCompSwap(op);
12783             total += cur;
12784             break;
12785         case XPATH_OP_ROOT:
12786             xmlXPathRoot(ctxt);
12787             break;
12788         case XPATH_OP_NODE:
12789             if (op->ch1 != -1)
12790                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12791 	    CHECK_ERROR0;
12792             if (op->ch2 != -1)
12793                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12794 	    CHECK_ERROR0;
12795 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12796 		ctxt->context->node));
12797             break;
12798         case XPATH_OP_COLLECT:{
12799                 if (op->ch1 == -1)
12800                     break;
12801 
12802                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12803 		CHECK_ERROR0;
12804 
12805                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12806                 break;
12807             }
12808         case XPATH_OP_VALUE:
12809             valuePush(ctxt,
12810                       xmlXPathCacheObjectCopy(ctxt->context,
12811 			(xmlXPathObjectPtr) op->value4));
12812             break;
12813         case XPATH_OP_SORT:
12814             if (op->ch1 != -1)
12815                 total +=
12816                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12817                                            last);
12818 	    CHECK_ERROR0;
12819             if ((ctxt->value != NULL)
12820                 && (ctxt->value->type == XPATH_NODESET)
12821                 && (ctxt->value->nodesetval != NULL)
12822 		&& (ctxt->value->nodesetval->nodeNr > 1))
12823                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12824             break;
12825         default:
12826             total += xmlXPathCompOpEval(ctxt, op);
12827             break;
12828     }
12829 
12830     ctxt->context->depth -= 1;
12831     return (total);
12832 }
12833 
12834 #ifdef XP_OPTIMIZED_FILTER_FIRST
12835 static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12836 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12837 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
12838 {
12839     int total = 0;
12840     xmlXPathCompExprPtr comp;
12841     xmlXPathObjectPtr obj;
12842     xmlNodeSetPtr set;
12843 
12844     CHECK_ERROR0;
12845     comp = ctxt->comp;
12846     /*
12847     * Optimization for ()[last()] selection i.e. the last elem
12848     */
12849     if ((op->ch1 != -1) && (op->ch2 != -1) &&
12850 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12851 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12852 	int f = comp->steps[op->ch2].ch1;
12853 
12854 	if ((f != -1) &&
12855 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12856 	    (comp->steps[f].value5 == NULL) &&
12857 	    (comp->steps[f].value == 0) &&
12858 	    (comp->steps[f].value4 != NULL) &&
12859 	    (xmlStrEqual
12860 	    (comp->steps[f].value4, BAD_CAST "last"))) {
12861 	    xmlNodePtr last = NULL;
12862 
12863 	    total +=
12864 		xmlXPathCompOpEvalLast(ctxt,
12865 		    &comp->steps[op->ch1],
12866 		    &last);
12867 	    CHECK_ERROR0;
12868 	    /*
12869 	    * The nodeset should be in document order,
12870 	    * Keep only the last value
12871 	    */
12872 	    if ((ctxt->value != NULL) &&
12873 		(ctxt->value->type == XPATH_NODESET) &&
12874 		(ctxt->value->nodesetval != NULL) &&
12875 		(ctxt->value->nodesetval->nodeTab != NULL) &&
12876 		(ctxt->value->nodesetval->nodeNr > 1)) {
12877                 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12878 		*first = *(ctxt->value->nodesetval->nodeTab);
12879 	    }
12880 	    return (total);
12881 	}
12882     }
12883 
12884     if (op->ch1 != -1)
12885 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12886     CHECK_ERROR0;
12887     if (op->ch2 == -1)
12888 	return (total);
12889     if (ctxt->value == NULL)
12890 	return (total);
12891 
12892 #ifdef LIBXML_XPTR_LOCS_ENABLED
12893     /*
12894     * Hum are we filtering the result of an XPointer expression
12895     */
12896     if (ctxt->value->type == XPATH_LOCATIONSET) {
12897         xmlLocationSetPtr locset = ctxt->value->user;
12898 
12899         if (locset != NULL) {
12900             xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12901             if (locset->locNr > 0)
12902                 *first = (xmlNodePtr) locset->locTab[0]->user;
12903         }
12904 
12905 	return (total);
12906     }
12907 #endif /* LIBXML_XPTR_LOCS_ENABLED */
12908 
12909     /*
12910      * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
12911      * the stack. We have to temporarily remove the nodeset object from the
12912      * stack to avoid freeing it prematurely.
12913      */
12914     CHECK_TYPE0(XPATH_NODESET);
12915     obj = valuePop(ctxt);
12916     set = obj->nodesetval;
12917     if (set != NULL) {
12918         xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12919         if (set->nodeNr > 0)
12920             *first = set->nodeTab[0];
12921     }
12922     valuePush(ctxt, obj);
12923 
12924     return (total);
12925 }
12926 #endif /* XP_OPTIMIZED_FILTER_FIRST */
12927 
12928 /**
12929  * xmlXPathCompOpEval:
12930  * @ctxt:  the XPath parser context with the compiled expression
12931  * @op:  an XPath compiled operation
12932  *
12933  * Evaluate the Precompiled XPath operation
12934  * Returns the number of nodes traversed
12935  */
12936 static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op)12937 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12938 {
12939     int total = 0;
12940     int equal, ret;
12941     xmlXPathCompExprPtr comp;
12942     xmlXPathObjectPtr arg1, arg2;
12943 
12944     CHECK_ERROR0;
12945     if (OP_LIMIT_EXCEEDED(ctxt, 1))
12946         return(0);
12947     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12948         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12949     ctxt->context->depth += 1;
12950     comp = ctxt->comp;
12951     switch (op->op) {
12952         case XPATH_OP_END:
12953             break;
12954         case XPATH_OP_AND:
12955             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12956 	    CHECK_ERROR0;
12957             xmlXPathBooleanFunction(ctxt, 1);
12958             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12959                 break;
12960             arg2 = valuePop(ctxt);
12961             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12962 	    if (ctxt->error) {
12963 		xmlXPathFreeObject(arg2);
12964 		break;
12965 	    }
12966             xmlXPathBooleanFunction(ctxt, 1);
12967             if (ctxt->value != NULL)
12968                 ctxt->value->boolval &= arg2->boolval;
12969 	    xmlXPathReleaseObject(ctxt->context, arg2);
12970             break;
12971         case XPATH_OP_OR:
12972             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12973 	    CHECK_ERROR0;
12974             xmlXPathBooleanFunction(ctxt, 1);
12975             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12976                 break;
12977             arg2 = valuePop(ctxt);
12978             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12979 	    if (ctxt->error) {
12980 		xmlXPathFreeObject(arg2);
12981 		break;
12982 	    }
12983             xmlXPathBooleanFunction(ctxt, 1);
12984             if (ctxt->value != NULL)
12985                 ctxt->value->boolval |= arg2->boolval;
12986 	    xmlXPathReleaseObject(ctxt->context, arg2);
12987             break;
12988         case XPATH_OP_EQUAL:
12989             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12990 	    CHECK_ERROR0;
12991             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12992 	    CHECK_ERROR0;
12993 	    if (op->value)
12994 		equal = xmlXPathEqualValues(ctxt);
12995 	    else
12996 		equal = xmlXPathNotEqualValues(ctxt);
12997 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
12998             break;
12999         case XPATH_OP_CMP:
13000             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13001 	    CHECK_ERROR0;
13002             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13003 	    CHECK_ERROR0;
13004             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13005 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13006             break;
13007         case XPATH_OP_PLUS:
13008             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13009 	    CHECK_ERROR0;
13010             if (op->ch2 != -1) {
13011                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13012 	    }
13013 	    CHECK_ERROR0;
13014             if (op->value == 0)
13015                 xmlXPathSubValues(ctxt);
13016             else if (op->value == 1)
13017                 xmlXPathAddValues(ctxt);
13018             else if (op->value == 2)
13019                 xmlXPathValueFlipSign(ctxt);
13020             else if (op->value == 3) {
13021                 CAST_TO_NUMBER;
13022                 CHECK_TYPE0(XPATH_NUMBER);
13023             }
13024             break;
13025         case XPATH_OP_MULT:
13026             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13027 	    CHECK_ERROR0;
13028             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13029 	    CHECK_ERROR0;
13030             if (op->value == 0)
13031                 xmlXPathMultValues(ctxt);
13032             else if (op->value == 1)
13033                 xmlXPathDivValues(ctxt);
13034             else if (op->value == 2)
13035                 xmlXPathModValues(ctxt);
13036             break;
13037         case XPATH_OP_UNION:
13038             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13039 	    CHECK_ERROR0;
13040             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13041 	    CHECK_ERROR0;
13042 
13043             arg2 = valuePop(ctxt);
13044             arg1 = valuePop(ctxt);
13045             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13046                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13047 	        xmlXPathReleaseObject(ctxt->context, arg1);
13048 	        xmlXPathReleaseObject(ctxt->context, arg2);
13049                 XP_ERROR0(XPATH_INVALID_TYPE);
13050             }
13051             if ((ctxt->context->opLimit != 0) &&
13052                 (((arg1->nodesetval != NULL) &&
13053                   (xmlXPathCheckOpLimit(ctxt,
13054                                         arg1->nodesetval->nodeNr) < 0)) ||
13055                  ((arg2->nodesetval != NULL) &&
13056                   (xmlXPathCheckOpLimit(ctxt,
13057                                         arg2->nodesetval->nodeNr) < 0)))) {
13058 	        xmlXPathReleaseObject(ctxt->context, arg1);
13059 	        xmlXPathReleaseObject(ctxt->context, arg2);
13060                 break;
13061             }
13062 
13063 	    if ((arg1->nodesetval == NULL) ||
13064 		((arg2->nodesetval != NULL) &&
13065 		 (arg2->nodesetval->nodeNr != 0)))
13066 	    {
13067                 /* TODO: Check memory error. */
13068 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13069 							arg2->nodesetval);
13070 	    }
13071 
13072             valuePush(ctxt, arg1);
13073 	    xmlXPathReleaseObject(ctxt->context, arg2);
13074             break;
13075         case XPATH_OP_ROOT:
13076             xmlXPathRoot(ctxt);
13077             break;
13078         case XPATH_OP_NODE:
13079             if (op->ch1 != -1)
13080                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13081 	    CHECK_ERROR0;
13082             if (op->ch2 != -1)
13083                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13084 	    CHECK_ERROR0;
13085 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13086 		ctxt->context->node));
13087             break;
13088         case XPATH_OP_COLLECT:{
13089                 if (op->ch1 == -1)
13090                     break;
13091 
13092                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13093 		CHECK_ERROR0;
13094 
13095                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13096                 break;
13097             }
13098         case XPATH_OP_VALUE:
13099             valuePush(ctxt,
13100                       xmlXPathCacheObjectCopy(ctxt->context,
13101 			(xmlXPathObjectPtr) op->value4));
13102             break;
13103         case XPATH_OP_VARIABLE:{
13104 		xmlXPathObjectPtr val;
13105 
13106                 if (op->ch1 != -1)
13107                     total +=
13108                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13109                 if (op->value5 == NULL) {
13110 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13111 		    if (val == NULL)
13112 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13113                     valuePush(ctxt, val);
13114 		} else {
13115                     const xmlChar *URI;
13116 
13117                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13118                     if (URI == NULL) {
13119                         xmlGenericError(xmlGenericErrorContext,
13120             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13121                                     (char *) op->value4, (char *)op->value5);
13122                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13123                         break;
13124                     }
13125 		    val = xmlXPathVariableLookupNS(ctxt->context,
13126                                                        op->value4, URI);
13127 		    if (val == NULL)
13128 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13129                     valuePush(ctxt, val);
13130                 }
13131                 break;
13132             }
13133         case XPATH_OP_FUNCTION:{
13134                 xmlXPathFunction func;
13135                 const xmlChar *oldFunc, *oldFuncURI;
13136 		int i;
13137                 int frame;
13138 
13139                 frame = ctxt->valueNr;
13140                 if (op->ch1 != -1) {
13141                     total +=
13142                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13143                     if (ctxt->error != XPATH_EXPRESSION_OK)
13144                         break;
13145                 }
13146 		if (ctxt->valueNr < frame + op->value) {
13147 		    xmlGenericError(xmlGenericErrorContext,
13148 			    "xmlXPathCompOpEval: parameter error\n");
13149 		    ctxt->error = XPATH_INVALID_OPERAND;
13150 		    break;
13151 		}
13152 		for (i = 0; i < op->value; i++) {
13153 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13154 			xmlGenericError(xmlGenericErrorContext,
13155 				"xmlXPathCompOpEval: parameter error\n");
13156 			ctxt->error = XPATH_INVALID_OPERAND;
13157 			break;
13158 		    }
13159                 }
13160                 if (op->cache != NULL)
13161                     func = op->cache;
13162                 else {
13163                     const xmlChar *URI = NULL;
13164 
13165                     if (op->value5 == NULL)
13166                         func =
13167                             xmlXPathFunctionLookup(ctxt->context,
13168                                                    op->value4);
13169                     else {
13170                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
13171                         if (URI == NULL) {
13172                             xmlGenericError(xmlGenericErrorContext,
13173             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13174                                     (char *)op->value4, (char *)op->value5);
13175                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13176                             break;
13177                         }
13178                         func = xmlXPathFunctionLookupNS(ctxt->context,
13179                                                         op->value4, URI);
13180                     }
13181                     if (func == NULL) {
13182                         xmlGenericError(xmlGenericErrorContext,
13183                                 "xmlXPathCompOpEval: function %s not found\n",
13184                                         (char *)op->value4);
13185                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13186                     }
13187                     op->cache = func;
13188                     op->cacheURI = (void *) URI;
13189                 }
13190                 oldFunc = ctxt->context->function;
13191                 oldFuncURI = ctxt->context->functionURI;
13192                 ctxt->context->function = op->value4;
13193                 ctxt->context->functionURI = op->cacheURI;
13194                 func(ctxt, op->value);
13195                 ctxt->context->function = oldFunc;
13196                 ctxt->context->functionURI = oldFuncURI;
13197                 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13198                     (ctxt->valueNr != frame + 1))
13199                     XP_ERROR0(XPATH_STACK_ERROR);
13200                 break;
13201             }
13202         case XPATH_OP_ARG:
13203             if (op->ch1 != -1) {
13204                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13205 	        CHECK_ERROR0;
13206             }
13207             if (op->ch2 != -1) {
13208                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13209 	        CHECK_ERROR0;
13210 	    }
13211             break;
13212         case XPATH_OP_PREDICATE:
13213         case XPATH_OP_FILTER:{
13214                 xmlXPathObjectPtr obj;
13215                 xmlNodeSetPtr set;
13216 
13217                 /*
13218                  * Optimization for ()[1] selection i.e. the first elem
13219                  */
13220                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13221 #ifdef XP_OPTIMIZED_FILTER_FIRST
13222 		    /*
13223 		    * FILTER TODO: Can we assume that the inner processing
13224 		    *  will result in an ordered list if we have an
13225 		    *  XPATH_OP_FILTER?
13226 		    *  What about an additional field or flag on
13227 		    *  xmlXPathObject like @sorted ? This way we wouldn't need
13228 		    *  to assume anything, so it would be more robust and
13229 		    *  easier to optimize.
13230 		    */
13231                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13232 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13233 #else
13234 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13235 #endif
13236                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13237                     xmlXPathObjectPtr val;
13238 
13239                     val = comp->steps[op->ch2].value4;
13240                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13241                         (val->floatval == 1.0)) {
13242                         xmlNodePtr first = NULL;
13243 
13244                         total +=
13245                             xmlXPathCompOpEvalFirst(ctxt,
13246                                                     &comp->steps[op->ch1],
13247                                                     &first);
13248 			CHECK_ERROR0;
13249                         /*
13250                          * The nodeset should be in document order,
13251                          * Keep only the first value
13252                          */
13253                         if ((ctxt->value != NULL) &&
13254                             (ctxt->value->type == XPATH_NODESET) &&
13255                             (ctxt->value->nodesetval != NULL) &&
13256                             (ctxt->value->nodesetval->nodeNr > 1))
13257                             xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13258                                                         1, 1);
13259                         break;
13260                     }
13261                 }
13262                 /*
13263                  * Optimization for ()[last()] selection i.e. the last elem
13264                  */
13265                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13266                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13267                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13268                     int f = comp->steps[op->ch2].ch1;
13269 
13270                     if ((f != -1) &&
13271                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13272                         (comp->steps[f].value5 == NULL) &&
13273                         (comp->steps[f].value == 0) &&
13274                         (comp->steps[f].value4 != NULL) &&
13275                         (xmlStrEqual
13276                          (comp->steps[f].value4, BAD_CAST "last"))) {
13277                         xmlNodePtr last = NULL;
13278 
13279                         total +=
13280                             xmlXPathCompOpEvalLast(ctxt,
13281                                                    &comp->steps[op->ch1],
13282                                                    &last);
13283 			CHECK_ERROR0;
13284                         /*
13285                          * The nodeset should be in document order,
13286                          * Keep only the last value
13287                          */
13288                         if ((ctxt->value != NULL) &&
13289                             (ctxt->value->type == XPATH_NODESET) &&
13290                             (ctxt->value->nodesetval != NULL) &&
13291                             (ctxt->value->nodesetval->nodeTab != NULL) &&
13292                             (ctxt->value->nodesetval->nodeNr > 1))
13293                             xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13294                         break;
13295                     }
13296                 }
13297 		/*
13298 		* Process inner predicates first.
13299 		* Example "index[parent::book][1]":
13300 		* ...
13301 		*   PREDICATE   <-- we are here "[1]"
13302 		*     PREDICATE <-- process "[parent::book]" first
13303 		*       SORT
13304 		*         COLLECT  'parent' 'name' 'node' book
13305 		*           NODE
13306 		*     ELEM Object is a number : 1
13307 		*/
13308                 if (op->ch1 != -1)
13309                     total +=
13310                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13311 		CHECK_ERROR0;
13312                 if (op->ch2 == -1)
13313                     break;
13314                 if (ctxt->value == NULL)
13315                     break;
13316 
13317 #ifdef LIBXML_XPTR_LOCS_ENABLED
13318                 /*
13319                  * Hum are we filtering the result of an XPointer expression
13320                  */
13321                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13322                     xmlLocationSetPtr locset = ctxt->value->user;
13323                     xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13324                                               1, locset->locNr);
13325                     break;
13326                 }
13327 #endif /* LIBXML_XPTR_LOCS_ENABLED */
13328 
13329                 /*
13330                  * In case of errors, xmlXPathNodeSetFilter can pop additional
13331                  * nodes from the stack. We have to temporarily remove the
13332                  * nodeset object from the stack to avoid freeing it
13333                  * prematurely.
13334                  */
13335                 CHECK_TYPE0(XPATH_NODESET);
13336                 obj = valuePop(ctxt);
13337                 set = obj->nodesetval;
13338                 if (set != NULL)
13339                     xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13340                                           1, set->nodeNr, 1);
13341                 valuePush(ctxt, obj);
13342                 break;
13343             }
13344         case XPATH_OP_SORT:
13345             if (op->ch1 != -1)
13346                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13347 	    CHECK_ERROR0;
13348             if ((ctxt->value != NULL) &&
13349                 (ctxt->value->type == XPATH_NODESET) &&
13350                 (ctxt->value->nodesetval != NULL) &&
13351 		(ctxt->value->nodesetval->nodeNr > 1))
13352 	    {
13353                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13354 	    }
13355             break;
13356 #ifdef LIBXML_XPTR_LOCS_ENABLED
13357         case XPATH_OP_RANGETO:{
13358                 xmlXPathObjectPtr range;
13359                 xmlXPathObjectPtr res, obj;
13360                 xmlXPathObjectPtr tmp;
13361                 xmlLocationSetPtr newlocset = NULL;
13362 		    xmlLocationSetPtr oldlocset;
13363                 xmlNodeSetPtr oldset;
13364                 xmlNodePtr oldnode = ctxt->context->node;
13365                 int oldcs = ctxt->context->contextSize;
13366                 int oldpp = ctxt->context->proximityPosition;
13367                 int i, j;
13368 
13369                 if (op->ch1 != -1) {
13370                     total +=
13371                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13372                     CHECK_ERROR0;
13373                 }
13374                 if (ctxt->value == NULL) {
13375                     XP_ERROR0(XPATH_INVALID_OPERAND);
13376                 }
13377                 if (op->ch2 == -1)
13378                     break;
13379 
13380                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13381                     /*
13382                      * Extract the old locset, and then evaluate the result of the
13383                      * expression for all the element in the locset. use it to grow
13384                      * up a new locset.
13385                      */
13386                     CHECK_TYPE0(XPATH_LOCATIONSET);
13387 
13388                     if ((ctxt->value->user == NULL) ||
13389                         (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13390                         break;
13391 
13392                     obj = valuePop(ctxt);
13393                     oldlocset = obj->user;
13394 
13395                     newlocset = xmlXPtrLocationSetCreate(NULL);
13396 
13397                     for (i = 0; i < oldlocset->locNr; i++) {
13398                         /*
13399                          * Run the evaluation with a node list made of a
13400                          * single item in the nodelocset.
13401                          */
13402                         ctxt->context->node = oldlocset->locTab[i]->user;
13403                         ctxt->context->contextSize = oldlocset->locNr;
13404                         ctxt->context->proximityPosition = i + 1;
13405 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13406 			    ctxt->context->node);
13407                         valuePush(ctxt, tmp);
13408 
13409                         if (op->ch2 != -1)
13410                             total +=
13411                                 xmlXPathCompOpEval(ctxt,
13412                                                    &comp->steps[op->ch2]);
13413 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13414                             xmlXPtrFreeLocationSet(newlocset);
13415                             goto rangeto_error;
13416 			}
13417 
13418                         res = valuePop(ctxt);
13419 			if (res->type == XPATH_LOCATIONSET) {
13420 			    xmlLocationSetPtr rloc =
13421 			        (xmlLocationSetPtr)res->user;
13422 			    for (j=0; j<rloc->locNr; j++) {
13423 			        range = xmlXPtrNewRange(
13424 				  oldlocset->locTab[i]->user,
13425 				  oldlocset->locTab[i]->index,
13426 				  rloc->locTab[j]->user2,
13427 				  rloc->locTab[j]->index2);
13428 				if (range != NULL) {
13429 				    xmlXPtrLocationSetAdd(newlocset, range);
13430 				}
13431 			    }
13432 			} else {
13433 			    range = xmlXPtrNewRangeNodeObject(
13434 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
13435                             if (range != NULL) {
13436                                 xmlXPtrLocationSetAdd(newlocset,range);
13437 			    }
13438                         }
13439 
13440                         /*
13441                          * Cleanup
13442                          */
13443                         if (res != NULL) {
13444 			    xmlXPathReleaseObject(ctxt->context, res);
13445 			}
13446                         if (ctxt->value == tmp) {
13447                             res = valuePop(ctxt);
13448 			    xmlXPathReleaseObject(ctxt->context, res);
13449                         }
13450                     }
13451 		} else {	/* Not a location set */
13452                     CHECK_TYPE0(XPATH_NODESET);
13453                     obj = valuePop(ctxt);
13454                     oldset = obj->nodesetval;
13455 
13456                     newlocset = xmlXPtrLocationSetCreate(NULL);
13457 
13458                     if (oldset != NULL) {
13459                         for (i = 0; i < oldset->nodeNr; i++) {
13460                             /*
13461                              * Run the evaluation with a node list made of a single item
13462                              * in the nodeset.
13463                              */
13464                             ctxt->context->node = oldset->nodeTab[i];
13465 			    /*
13466 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
13467 			    */
13468 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13469 				ctxt->context->node);
13470                             valuePush(ctxt, tmp);
13471 
13472                             if (op->ch2 != -1)
13473                                 total +=
13474                                     xmlXPathCompOpEval(ctxt,
13475                                                    &comp->steps[op->ch2]);
13476 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
13477                                 xmlXPtrFreeLocationSet(newlocset);
13478                                 goto rangeto_error;
13479 			    }
13480 
13481                             res = valuePop(ctxt);
13482                             range =
13483                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13484                                                       res);
13485                             if (range != NULL) {
13486                                 xmlXPtrLocationSetAdd(newlocset, range);
13487                             }
13488 
13489                             /*
13490                              * Cleanup
13491                              */
13492                             if (res != NULL) {
13493 				xmlXPathReleaseObject(ctxt->context, res);
13494 			    }
13495                             if (ctxt->value == tmp) {
13496                                 res = valuePop(ctxt);
13497 				xmlXPathReleaseObject(ctxt->context, res);
13498                             }
13499                         }
13500                     }
13501                 }
13502 
13503                 /*
13504                  * The result is used as the new evaluation set.
13505                  */
13506                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13507 rangeto_error:
13508 		xmlXPathReleaseObject(ctxt->context, obj);
13509                 ctxt->context->node = oldnode;
13510                 ctxt->context->contextSize = oldcs;
13511                 ctxt->context->proximityPosition = oldpp;
13512                 break;
13513             }
13514 #endif /* LIBXML_XPTR_LOCS_ENABLED */
13515         default:
13516             xmlGenericError(xmlGenericErrorContext,
13517                             "XPath: unknown precompiled operation %d\n", op->op);
13518             ctxt->error = XPATH_INVALID_OPERAND;
13519             break;
13520     }
13521 
13522     ctxt->context->depth -= 1;
13523     return (total);
13524 }
13525 
13526 /**
13527  * xmlXPathCompOpEvalToBoolean:
13528  * @ctxt:  the XPath parser context
13529  *
13530  * Evaluates if the expression evaluates to true.
13531  *
13532  * Returns 1 if true, 0 if false and -1 on API or internal errors.
13533  */
13534 static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int isPredicate)13535 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13536 			    xmlXPathStepOpPtr op,
13537 			    int isPredicate)
13538 {
13539     xmlXPathObjectPtr resObj = NULL;
13540 
13541 start:
13542     if (OP_LIMIT_EXCEEDED(ctxt, 1))
13543         return(0);
13544     /* comp = ctxt->comp; */
13545     switch (op->op) {
13546         case XPATH_OP_END:
13547             return (0);
13548 	case XPATH_OP_VALUE:
13549 	    resObj = (xmlXPathObjectPtr) op->value4;
13550 	    if (isPredicate)
13551 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13552 	    return(xmlXPathCastToBoolean(resObj));
13553 	case XPATH_OP_SORT:
13554 	    /*
13555 	    * We don't need sorting for boolean results. Skip this one.
13556 	    */
13557             if (op->ch1 != -1) {
13558 		op = &ctxt->comp->steps[op->ch1];
13559 		goto start;
13560 	    }
13561 	    return(0);
13562 	case XPATH_OP_COLLECT:
13563 	    if (op->ch1 == -1)
13564 		return(0);
13565 
13566             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13567 	    if (ctxt->error != XPATH_EXPRESSION_OK)
13568 		return(-1);
13569 
13570             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13571 	    if (ctxt->error != XPATH_EXPRESSION_OK)
13572 		return(-1);
13573 
13574 	    resObj = valuePop(ctxt);
13575 	    if (resObj == NULL)
13576 		return(-1);
13577 	    break;
13578 	default:
13579 	    /*
13580 	    * Fallback to call xmlXPathCompOpEval().
13581 	    */
13582 	    xmlXPathCompOpEval(ctxt, op);
13583 	    if (ctxt->error != XPATH_EXPRESSION_OK)
13584 		return(-1);
13585 
13586 	    resObj = valuePop(ctxt);
13587 	    if (resObj == NULL)
13588 		return(-1);
13589 	    break;
13590     }
13591 
13592     if (resObj) {
13593 	int res;
13594 
13595 	if (resObj->type == XPATH_BOOLEAN) {
13596 	    res = resObj->boolval;
13597 	} else if (isPredicate) {
13598 	    /*
13599 	    * For predicates a result of type "number" is handled
13600 	    * differently:
13601 	    * SPEC XPath 1.0:
13602 	    * "If the result is a number, the result will be converted
13603 	    *  to true if the number is equal to the context position
13604 	    *  and will be converted to false otherwise;"
13605 	    */
13606 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13607 	} else {
13608 	    res = xmlXPathCastToBoolean(resObj);
13609 	}
13610 	xmlXPathReleaseObject(ctxt->context, resObj);
13611 	return(res);
13612     }
13613 
13614     return(0);
13615 }
13616 
13617 #ifdef XPATH_STREAMING
13618 /**
13619  * xmlXPathRunStreamEval:
13620  * @ctxt:  the XPath parser context with the compiled expression
13621  *
13622  * Evaluate the Precompiled Streamable XPath expression in the given context.
13623  */
13624 static int
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt,xmlPatternPtr comp,xmlXPathObjectPtr * resultSeq,int toBool)13625 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13626 		      xmlXPathObjectPtr *resultSeq, int toBool)
13627 {
13628     int max_depth, min_depth;
13629     int from_root;
13630     int ret, depth;
13631     int eval_all_nodes;
13632     xmlNodePtr cur = NULL, limit = NULL;
13633     xmlStreamCtxtPtr patstream = NULL;
13634 
13635     if ((ctxt == NULL) || (comp == NULL))
13636         return(-1);
13637     max_depth = xmlPatternMaxDepth(comp);
13638     if (max_depth == -1)
13639         return(-1);
13640     if (max_depth == -2)
13641         max_depth = 10000;
13642     min_depth = xmlPatternMinDepth(comp);
13643     if (min_depth == -1)
13644         return(-1);
13645     from_root = xmlPatternFromRoot(comp);
13646     if (from_root < 0)
13647         return(-1);
13648 #if 0
13649     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13650 #endif
13651 
13652     if (! toBool) {
13653 	if (resultSeq == NULL)
13654 	    return(-1);
13655 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13656 	if (*resultSeq == NULL)
13657 	    return(-1);
13658     }
13659 
13660     /*
13661      * handle the special cases of "/" amd "." being matched
13662      */
13663     if (min_depth == 0) {
13664 	if (from_root) {
13665 	    /* Select "/" */
13666 	    if (toBool)
13667 		return(1);
13668             /* TODO: Check memory error. */
13669 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
13670 		                     (xmlNodePtr) ctxt->doc);
13671 	} else {
13672 	    /* Select "self::node()" */
13673 	    if (toBool)
13674 		return(1);
13675             /* TODO: Check memory error. */
13676 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13677 	}
13678     }
13679     if (max_depth == 0) {
13680 	return(0);
13681     }
13682 
13683     if (from_root) {
13684         cur = (xmlNodePtr)ctxt->doc;
13685     } else if (ctxt->node != NULL) {
13686         switch (ctxt->node->type) {
13687             case XML_ELEMENT_NODE:
13688             case XML_DOCUMENT_NODE:
13689             case XML_DOCUMENT_FRAG_NODE:
13690             case XML_HTML_DOCUMENT_NODE:
13691 	        cur = ctxt->node;
13692 		break;
13693             case XML_ATTRIBUTE_NODE:
13694             case XML_TEXT_NODE:
13695             case XML_CDATA_SECTION_NODE:
13696             case XML_ENTITY_REF_NODE:
13697             case XML_ENTITY_NODE:
13698             case XML_PI_NODE:
13699             case XML_COMMENT_NODE:
13700             case XML_NOTATION_NODE:
13701             case XML_DTD_NODE:
13702             case XML_DOCUMENT_TYPE_NODE:
13703             case XML_ELEMENT_DECL:
13704             case XML_ATTRIBUTE_DECL:
13705             case XML_ENTITY_DECL:
13706             case XML_NAMESPACE_DECL:
13707             case XML_XINCLUDE_START:
13708             case XML_XINCLUDE_END:
13709 		break;
13710 	}
13711 	limit = cur;
13712     }
13713     if (cur == NULL) {
13714         return(0);
13715     }
13716 
13717     patstream = xmlPatternGetStreamCtxt(comp);
13718     if (patstream == NULL) {
13719 	/*
13720 	* QUESTION TODO: Is this an error?
13721 	*/
13722 	return(0);
13723     }
13724 
13725     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13726 
13727     if (from_root) {
13728 	ret = xmlStreamPush(patstream, NULL, NULL);
13729 	if (ret < 0) {
13730 	} else if (ret == 1) {
13731 	    if (toBool)
13732 		goto return_1;
13733             /* TODO: Check memory error. */
13734 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13735 	}
13736     }
13737     depth = 0;
13738     goto scan_children;
13739 next_node:
13740     do {
13741         if (ctxt->opLimit != 0) {
13742             if (ctxt->opCount >= ctxt->opLimit) {
13743                 xmlGenericError(xmlGenericErrorContext,
13744                         "XPath operation limit exceeded\n");
13745                 xmlFreeStreamCtxt(patstream);
13746                 return(-1);
13747             }
13748             ctxt->opCount++;
13749         }
13750 
13751 	switch (cur->type) {
13752 	    case XML_ELEMENT_NODE:
13753 	    case XML_TEXT_NODE:
13754 	    case XML_CDATA_SECTION_NODE:
13755 	    case XML_COMMENT_NODE:
13756 	    case XML_PI_NODE:
13757 		if (cur->type == XML_ELEMENT_NODE) {
13758 		    ret = xmlStreamPush(patstream, cur->name,
13759 				(cur->ns ? cur->ns->href : NULL));
13760 		} else if (eval_all_nodes)
13761 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13762 		else
13763 		    break;
13764 
13765 		if (ret < 0) {
13766 		    /* NOP. */
13767 		} else if (ret == 1) {
13768 		    if (toBool)
13769 			goto return_1;
13770 		    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13771 		        < 0) {
13772 			ctxt->lastError.domain = XML_FROM_XPATH;
13773 			ctxt->lastError.code = XML_ERR_NO_MEMORY;
13774 		    }
13775 		}
13776 		if ((cur->children == NULL) || (depth >= max_depth)) {
13777 		    ret = xmlStreamPop(patstream);
13778 		    while (cur->next != NULL) {
13779 			cur = cur->next;
13780 			if ((cur->type != XML_ENTITY_DECL) &&
13781 			    (cur->type != XML_DTD_NODE))
13782 			    goto next_node;
13783 		    }
13784 		}
13785 	    default:
13786 		break;
13787 	}
13788 
13789 scan_children:
13790 	if (cur->type == XML_NAMESPACE_DECL) break;
13791 	if ((cur->children != NULL) && (depth < max_depth)) {
13792 	    /*
13793 	     * Do not descend on entities declarations
13794 	     */
13795 	    if (cur->children->type != XML_ENTITY_DECL) {
13796 		cur = cur->children;
13797 		depth++;
13798 		/*
13799 		 * Skip DTDs
13800 		 */
13801 		if (cur->type != XML_DTD_NODE)
13802 		    continue;
13803 	    }
13804 	}
13805 
13806 	if (cur == limit)
13807 	    break;
13808 
13809 	while (cur->next != NULL) {
13810 	    cur = cur->next;
13811 	    if ((cur->type != XML_ENTITY_DECL) &&
13812 		(cur->type != XML_DTD_NODE))
13813 		goto next_node;
13814 	}
13815 
13816 	do {
13817 	    cur = cur->parent;
13818 	    depth--;
13819 	    if ((cur == NULL) || (cur == limit) ||
13820                 (cur->type == XML_DOCUMENT_NODE))
13821 	        goto done;
13822 	    if (cur->type == XML_ELEMENT_NODE) {
13823 		ret = xmlStreamPop(patstream);
13824 	    } else if ((eval_all_nodes) &&
13825 		((cur->type == XML_TEXT_NODE) ||
13826 		 (cur->type == XML_CDATA_SECTION_NODE) ||
13827 		 (cur->type == XML_COMMENT_NODE) ||
13828 		 (cur->type == XML_PI_NODE)))
13829 	    {
13830 		ret = xmlStreamPop(patstream);
13831 	    }
13832 	    if (cur->next != NULL) {
13833 		cur = cur->next;
13834 		break;
13835 	    }
13836 	} while (cur != NULL);
13837 
13838     } while ((cur != NULL) && (depth >= 0));
13839 
13840 done:
13841 
13842     if (patstream)
13843 	xmlFreeStreamCtxt(patstream);
13844     return(0);
13845 
13846 return_1:
13847     if (patstream)
13848 	xmlFreeStreamCtxt(patstream);
13849     return(1);
13850 }
13851 #endif /* XPATH_STREAMING */
13852 
13853 /**
13854  * xmlXPathRunEval:
13855  * @ctxt:  the XPath parser context with the compiled expression
13856  * @toBool:  evaluate to a boolean result
13857  *
13858  * Evaluate the Precompiled XPath expression in the given context.
13859  */
13860 static int
xmlXPathRunEval(xmlXPathParserContextPtr ctxt,int toBool)13861 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13862 {
13863     xmlXPathCompExprPtr comp;
13864     int oldDepth;
13865 
13866     if ((ctxt == NULL) || (ctxt->comp == NULL))
13867 	return(-1);
13868 
13869     if (ctxt->valueTab == NULL) {
13870 	/* Allocate the value stack */
13871 	ctxt->valueTab = (xmlXPathObjectPtr *)
13872 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13873 	if (ctxt->valueTab == NULL) {
13874 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13875 	    return(-1);
13876 	}
13877 	ctxt->valueNr = 0;
13878 	ctxt->valueMax = 10;
13879 	ctxt->value = NULL;
13880     }
13881 #ifdef XPATH_STREAMING
13882     if (ctxt->comp->stream) {
13883 	int res;
13884 
13885 	if (toBool) {
13886 	    /*
13887 	    * Evaluation to boolean result.
13888 	    */
13889 	    res = xmlXPathRunStreamEval(ctxt->context,
13890 		ctxt->comp->stream, NULL, 1);
13891 	    if (res != -1)
13892 		return(res);
13893 	} else {
13894 	    xmlXPathObjectPtr resObj = NULL;
13895 
13896 	    /*
13897 	    * Evaluation to a sequence.
13898 	    */
13899 	    res = xmlXPathRunStreamEval(ctxt->context,
13900 		ctxt->comp->stream, &resObj, 0);
13901 
13902 	    if ((res != -1) && (resObj != NULL)) {
13903 		valuePush(ctxt, resObj);
13904 		return(0);
13905 	    }
13906 	    if (resObj != NULL)
13907 		xmlXPathReleaseObject(ctxt->context, resObj);
13908 	}
13909 	/*
13910 	* QUESTION TODO: This falls back to normal XPath evaluation
13911 	* if res == -1. Is this intended?
13912 	*/
13913     }
13914 #endif
13915     comp = ctxt->comp;
13916     if (comp->last < 0) {
13917 	xmlGenericError(xmlGenericErrorContext,
13918 	    "xmlXPathRunEval: last is less than zero\n");
13919 	return(-1);
13920     }
13921     oldDepth = ctxt->context->depth;
13922     if (toBool)
13923 	return(xmlXPathCompOpEvalToBoolean(ctxt,
13924 	    &comp->steps[comp->last], 0));
13925     else
13926 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13927     ctxt->context->depth = oldDepth;
13928 
13929     return(0);
13930 }
13931 
13932 /************************************************************************
13933  *									*
13934  *			Public interfaces				*
13935  *									*
13936  ************************************************************************/
13937 
13938 /**
13939  * xmlXPathEvalPredicate:
13940  * @ctxt:  the XPath context
13941  * @res:  the Predicate Expression evaluation result
13942  *
13943  * Evaluate a predicate result for the current node.
13944  * A PredicateExpr is evaluated by evaluating the Expr and converting
13945  * the result to a boolean. If the result is a number, the result will
13946  * be converted to true if the number is equal to the position of the
13947  * context node in the context node list (as returned by the position
13948  * function) and will be converted to false otherwise; if the result
13949  * is not a number, then the result will be converted as if by a call
13950  * to the boolean function.
13951  *
13952  * Returns 1 if predicate is true, 0 otherwise
13953  */
13954 int
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt,xmlXPathObjectPtr res)13955 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13956     if ((ctxt == NULL) || (res == NULL)) return(0);
13957     switch (res->type) {
13958         case XPATH_BOOLEAN:
13959 	    return(res->boolval);
13960         case XPATH_NUMBER:
13961 	    return(res->floatval == ctxt->proximityPosition);
13962         case XPATH_NODESET:
13963         case XPATH_XSLT_TREE:
13964 	    if (res->nodesetval == NULL)
13965 		return(0);
13966 	    return(res->nodesetval->nodeNr != 0);
13967         case XPATH_STRING:
13968 	    return((res->stringval != NULL) &&
13969 	           (xmlStrlen(res->stringval) != 0));
13970         default:
13971 	    STRANGE
13972     }
13973     return(0);
13974 }
13975 
13976 /**
13977  * xmlXPathEvaluatePredicateResult:
13978  * @ctxt:  the XPath Parser context
13979  * @res:  the Predicate Expression evaluation result
13980  *
13981  * Evaluate a predicate result for the current node.
13982  * A PredicateExpr is evaluated by evaluating the Expr and converting
13983  * the result to a boolean. If the result is a number, the result will
13984  * be converted to true if the number is equal to the position of the
13985  * context node in the context node list (as returned by the position
13986  * function) and will be converted to false otherwise; if the result
13987  * is not a number, then the result will be converted as if by a call
13988  * to the boolean function.
13989  *
13990  * Returns 1 if predicate is true, 0 otherwise
13991  */
13992 int
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr res)13993 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
13994                                 xmlXPathObjectPtr res) {
13995     if ((ctxt == NULL) || (res == NULL)) return(0);
13996     switch (res->type) {
13997         case XPATH_BOOLEAN:
13998 	    return(res->boolval);
13999         case XPATH_NUMBER:
14000 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14001 	    return((res->floatval == ctxt->context->proximityPosition) &&
14002 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14003 #else
14004 	    return(res->floatval == ctxt->context->proximityPosition);
14005 #endif
14006         case XPATH_NODESET:
14007         case XPATH_XSLT_TREE:
14008 	    if (res->nodesetval == NULL)
14009 		return(0);
14010 	    return(res->nodesetval->nodeNr != 0);
14011         case XPATH_STRING:
14012 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
14013 #ifdef LIBXML_XPTR_LOCS_ENABLED
14014 	case XPATH_LOCATIONSET:{
14015 	    xmlLocationSetPtr ptr = res->user;
14016 	    if (ptr == NULL)
14017 	        return(0);
14018 	    return (ptr->locNr != 0);
14019 	    }
14020 #endif
14021         default:
14022 	    STRANGE
14023     }
14024     return(0);
14025 }
14026 
14027 #ifdef XPATH_STREAMING
14028 /**
14029  * xmlXPathTryStreamCompile:
14030  * @ctxt: an XPath context
14031  * @str:  the XPath expression
14032  *
14033  * Try to compile the XPath expression as a streamable subset.
14034  *
14035  * Returns the compiled expression or NULL if failed to compile.
14036  */
14037 static xmlXPathCompExprPtr
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14038 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14039     /*
14040      * Optimization: use streaming patterns when the XPath expression can
14041      * be compiled to a stream lookup
14042      */
14043     xmlPatternPtr stream;
14044     xmlXPathCompExprPtr comp;
14045     xmlDictPtr dict = NULL;
14046     const xmlChar **namespaces = NULL;
14047     xmlNsPtr ns;
14048     int i, j;
14049 
14050     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14051         (!xmlStrchr(str, '@'))) {
14052 	const xmlChar *tmp;
14053 
14054 	/*
14055 	 * We don't try to handle expressions using the verbose axis
14056 	 * specifiers ("::"), just the simplified form at this point.
14057 	 * Additionally, if there is no list of namespaces available and
14058 	 *  there's a ":" in the expression, indicating a prefixed QName,
14059 	 *  then we won't try to compile either. xmlPatterncompile() needs
14060 	 *  to have a list of namespaces at compilation time in order to
14061 	 *  compile prefixed name tests.
14062 	 */
14063 	tmp = xmlStrchr(str, ':');
14064 	if ((tmp != NULL) &&
14065 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14066 	    return(NULL);
14067 
14068 	if (ctxt != NULL) {
14069 	    dict = ctxt->dict;
14070 	    if (ctxt->nsNr > 0) {
14071 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14072 		if (namespaces == NULL) {
14073 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14074 		    return(NULL);
14075 		}
14076 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14077 		    ns = ctxt->namespaces[j];
14078 		    namespaces[i++] = ns->href;
14079 		    namespaces[i++] = ns->prefix;
14080 		}
14081 		namespaces[i++] = NULL;
14082 		namespaces[i] = NULL;
14083 	    }
14084 	}
14085 
14086 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14087 	if (namespaces != NULL) {
14088 	    xmlFree((xmlChar **)namespaces);
14089 	}
14090 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14091 	    comp = xmlXPathNewCompExpr();
14092 	    if (comp == NULL) {
14093 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14094 	        xmlFreePattern(stream);
14095 		return(NULL);
14096 	    }
14097 	    comp->stream = stream;
14098 	    comp->dict = dict;
14099 	    if (comp->dict)
14100 		xmlDictReference(comp->dict);
14101 	    return(comp);
14102 	}
14103 	xmlFreePattern(stream);
14104     }
14105     return(NULL);
14106 }
14107 #endif /* XPATH_STREAMING */
14108 
14109 static void
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,xmlXPathStepOpPtr op)14110 xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14111                            xmlXPathStepOpPtr op)
14112 {
14113     xmlXPathCompExprPtr comp = pctxt->comp;
14114     xmlXPathContextPtr ctxt;
14115 
14116     /*
14117     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14118     * internal representation.
14119     */
14120 
14121     if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14122         (op->ch1 != -1) &&
14123         (op->ch2 == -1 /* no predicate */))
14124     {
14125         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14126 
14127         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14128             ((xmlXPathAxisVal) prevop->value ==
14129                 AXIS_DESCENDANT_OR_SELF) &&
14130             (prevop->ch2 == -1) &&
14131             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14132             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14133         {
14134             /*
14135             * This is a "descendant-or-self::node()" without predicates.
14136             * Try to eliminate it.
14137             */
14138 
14139             switch ((xmlXPathAxisVal) op->value) {
14140                 case AXIS_CHILD:
14141                 case AXIS_DESCENDANT:
14142                     /*
14143                     * Convert "descendant-or-self::node()/child::" or
14144                     * "descendant-or-self::node()/descendant::" to
14145                     * "descendant::"
14146                     */
14147                     op->ch1   = prevop->ch1;
14148                     op->value = AXIS_DESCENDANT;
14149                     break;
14150                 case AXIS_SELF:
14151                 case AXIS_DESCENDANT_OR_SELF:
14152                     /*
14153                     * Convert "descendant-or-self::node()/self::" or
14154                     * "descendant-or-self::node()/descendant-or-self::" to
14155                     * to "descendant-or-self::"
14156                     */
14157                     op->ch1   = prevop->ch1;
14158                     op->value = AXIS_DESCENDANT_OR_SELF;
14159                     break;
14160                 default:
14161                     break;
14162             }
14163 	}
14164     }
14165 
14166     /* OP_VALUE has invalid ch1. */
14167     if (op->op == XPATH_OP_VALUE)
14168         return;
14169 
14170     /* Recurse */
14171     ctxt = pctxt->context;
14172     if (ctxt != NULL) {
14173         if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14174             return;
14175         ctxt->depth += 1;
14176     }
14177     if (op->ch1 != -1)
14178         xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14179     if (op->ch2 != -1)
14180 	xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14181     if (ctxt != NULL)
14182         ctxt->depth -= 1;
14183 }
14184 
14185 /**
14186  * xmlXPathCtxtCompile:
14187  * @ctxt: an XPath context
14188  * @str:  the XPath expression
14189  *
14190  * Compile an XPath expression
14191  *
14192  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14193  *         the caller has to free the object.
14194  */
14195 xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14196 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14197     xmlXPathParserContextPtr pctxt;
14198     xmlXPathCompExprPtr comp;
14199     int oldDepth = 0;
14200 
14201 #ifdef XPATH_STREAMING
14202     comp = xmlXPathTryStreamCompile(ctxt, str);
14203     if (comp != NULL)
14204         return(comp);
14205 #endif
14206 
14207     xmlInitParser();
14208 
14209     pctxt = xmlXPathNewParserContext(str, ctxt);
14210     if (pctxt == NULL)
14211         return NULL;
14212     if (ctxt != NULL)
14213         oldDepth = ctxt->depth;
14214     xmlXPathCompileExpr(pctxt, 1);
14215     if (ctxt != NULL)
14216         ctxt->depth = oldDepth;
14217 
14218     if( pctxt->error != XPATH_EXPRESSION_OK )
14219     {
14220         xmlXPathFreeParserContext(pctxt);
14221         return(NULL);
14222     }
14223 
14224     if (*pctxt->cur != 0) {
14225 	/*
14226 	 * aleksey: in some cases this line prints *second* error message
14227 	 * (see bug #78858) and probably this should be fixed.
14228 	 * However, we are not sure that all error messages are printed
14229 	 * out in other places. It's not critical so we leave it as-is for now
14230 	 */
14231 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14232 	comp = NULL;
14233     } else {
14234 	comp = pctxt->comp;
14235 	if ((comp->nbStep > 1) && (comp->last >= 0)) {
14236             if (ctxt != NULL)
14237                 oldDepth = ctxt->depth;
14238 	    xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14239             if (ctxt != NULL)
14240                 ctxt->depth = oldDepth;
14241 	}
14242 	pctxt->comp = NULL;
14243     }
14244     xmlXPathFreeParserContext(pctxt);
14245 
14246     if (comp != NULL) {
14247 	comp->expr = xmlStrdup(str);
14248 #ifdef DEBUG_EVAL_COUNTS
14249 	comp->string = xmlStrdup(str);
14250 	comp->nb = 0;
14251 #endif
14252     }
14253     return(comp);
14254 }
14255 
14256 /**
14257  * xmlXPathCompile:
14258  * @str:  the XPath expression
14259  *
14260  * Compile an XPath expression
14261  *
14262  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14263  *         the caller has to free the object.
14264  */
14265 xmlXPathCompExprPtr
xmlXPathCompile(const xmlChar * str)14266 xmlXPathCompile(const xmlChar *str) {
14267     return(xmlXPathCtxtCompile(NULL, str));
14268 }
14269 
14270 /**
14271  * xmlXPathCompiledEvalInternal:
14272  * @comp:  the compiled XPath expression
14273  * @ctxt:  the XPath context
14274  * @resObj: the resulting XPath object or NULL
14275  * @toBool: 1 if only a boolean result is requested
14276  *
14277  * Evaluate the Precompiled XPath expression in the given context.
14278  * The caller has to free @resObj.
14279  *
14280  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14281  *         the caller has to free the object.
14282  */
14283 static int
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt,xmlXPathObjectPtr * resObjPtr,int toBool)14284 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14285 			     xmlXPathContextPtr ctxt,
14286 			     xmlXPathObjectPtr *resObjPtr,
14287 			     int toBool)
14288 {
14289     xmlXPathParserContextPtr pctxt;
14290     xmlXPathObjectPtr resObj;
14291 #ifndef LIBXML_THREAD_ENABLED
14292     static int reentance = 0;
14293 #endif
14294     int res;
14295 
14296     CHECK_CTXT_NEG(ctxt)
14297 
14298     if (comp == NULL)
14299 	return(-1);
14300     xmlInitParser();
14301 
14302 #ifndef LIBXML_THREAD_ENABLED
14303     reentance++;
14304     if (reentance > 1)
14305 	xmlXPathDisableOptimizer = 1;
14306 #endif
14307 
14308 #ifdef DEBUG_EVAL_COUNTS
14309     comp->nb++;
14310     if ((comp->string != NULL) && (comp->nb > 100)) {
14311 	fprintf(stderr, "100 x %s\n", comp->string);
14312 	comp->nb = 0;
14313     }
14314 #endif
14315     pctxt = xmlXPathCompParserContext(comp, ctxt);
14316     if (pctxt == NULL)
14317         return(-1);
14318     res = xmlXPathRunEval(pctxt, toBool);
14319 
14320     if (pctxt->error != XPATH_EXPRESSION_OK) {
14321         resObj = NULL;
14322     } else {
14323         resObj = valuePop(pctxt);
14324         if (resObj == NULL) {
14325             if (!toBool)
14326                 xmlGenericError(xmlGenericErrorContext,
14327                     "xmlXPathCompiledEval: No result on the stack.\n");
14328         } else if (pctxt->valueNr > 0) {
14329             xmlGenericError(xmlGenericErrorContext,
14330                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14331                 pctxt->valueNr);
14332         }
14333     }
14334 
14335     if (resObjPtr)
14336         *resObjPtr = resObj;
14337     else
14338         xmlXPathReleaseObject(ctxt, resObj);
14339 
14340     pctxt->comp = NULL;
14341     xmlXPathFreeParserContext(pctxt);
14342 #ifndef LIBXML_THREAD_ENABLED
14343     reentance--;
14344 #endif
14345 
14346     return(res);
14347 }
14348 
14349 /**
14350  * xmlXPathCompiledEval:
14351  * @comp:  the compiled XPath expression
14352  * @ctx:  the XPath context
14353  *
14354  * Evaluate the Precompiled XPath expression in the given context.
14355  *
14356  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14357  *         the caller has to free the object.
14358  */
14359 xmlXPathObjectPtr
xmlXPathCompiledEval(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctx)14360 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14361 {
14362     xmlXPathObjectPtr res = NULL;
14363 
14364     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14365     return(res);
14366 }
14367 
14368 /**
14369  * xmlXPathCompiledEvalToBoolean:
14370  * @comp:  the compiled XPath expression
14371  * @ctxt:  the XPath context
14372  *
14373  * Applies the XPath boolean() function on the result of the given
14374  * compiled expression.
14375  *
14376  * Returns 1 if the expression evaluated to true, 0 if to false and
14377  *         -1 in API and internal errors.
14378  */
14379 int
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)14380 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14381 			      xmlXPathContextPtr ctxt)
14382 {
14383     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14384 }
14385 
14386 /**
14387  * xmlXPathEvalExpr:
14388  * @ctxt:  the XPath Parser context
14389  *
14390  * Parse and evaluate an XPath expression in the given context,
14391  * then push the result on the context stack
14392  */
14393 void
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt)14394 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14395 #ifdef XPATH_STREAMING
14396     xmlXPathCompExprPtr comp;
14397 #endif
14398     int oldDepth = 0;
14399 
14400     if (ctxt == NULL) return;
14401 
14402 #ifdef XPATH_STREAMING
14403     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14404     if (comp != NULL) {
14405         if (ctxt->comp != NULL)
14406 	    xmlXPathFreeCompExpr(ctxt->comp);
14407         ctxt->comp = comp;
14408     } else
14409 #endif
14410     {
14411         if (ctxt->context != NULL)
14412             oldDepth = ctxt->context->depth;
14413 	xmlXPathCompileExpr(ctxt, 1);
14414         if (ctxt->context != NULL)
14415             ctxt->context->depth = oldDepth;
14416         CHECK_ERROR;
14417 
14418         /* Check for trailing characters. */
14419         if (*ctxt->cur != 0)
14420             XP_ERROR(XPATH_EXPR_ERROR);
14421 
14422 	if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14423             if (ctxt->context != NULL)
14424                 oldDepth = ctxt->context->depth;
14425 	    xmlXPathOptimizeExpression(ctxt,
14426 		&ctxt->comp->steps[ctxt->comp->last]);
14427             if (ctxt->context != NULL)
14428                 ctxt->context->depth = oldDepth;
14429         }
14430     }
14431 
14432     xmlXPathRunEval(ctxt, 0);
14433 }
14434 
14435 /**
14436  * xmlXPathEval:
14437  * @str:  the XPath expression
14438  * @ctx:  the XPath context
14439  *
14440  * Evaluate the XPath Location Path in the given context.
14441  *
14442  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14443  *         the caller has to free the object.
14444  */
14445 xmlXPathObjectPtr
xmlXPathEval(const xmlChar * str,xmlXPathContextPtr ctx)14446 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14447     xmlXPathParserContextPtr ctxt;
14448     xmlXPathObjectPtr res;
14449 
14450     CHECK_CTXT(ctx)
14451 
14452     xmlInitParser();
14453 
14454     ctxt = xmlXPathNewParserContext(str, ctx);
14455     if (ctxt == NULL)
14456         return NULL;
14457     xmlXPathEvalExpr(ctxt);
14458 
14459     if (ctxt->error != XPATH_EXPRESSION_OK) {
14460 	res = NULL;
14461     } else {
14462 	res = valuePop(ctxt);
14463         if (res == NULL) {
14464             xmlGenericError(xmlGenericErrorContext,
14465                 "xmlXPathCompiledEval: No result on the stack.\n");
14466         } else if (ctxt->valueNr > 0) {
14467             xmlGenericError(xmlGenericErrorContext,
14468                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14469                 ctxt->valueNr);
14470         }
14471     }
14472 
14473     xmlXPathFreeParserContext(ctxt);
14474     return(res);
14475 }
14476 
14477 /**
14478  * xmlXPathSetContextNode:
14479  * @node: the node to to use as the context node
14480  * @ctx:  the XPath context
14481  *
14482  * Sets 'node' as the context node. The node must be in the same
14483  * document as that associated with the context.
14484  *
14485  * Returns -1 in case of error or 0 if successful
14486  */
14487 int
xmlXPathSetContextNode(xmlNodePtr node,xmlXPathContextPtr ctx)14488 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14489     if ((node == NULL) || (ctx == NULL))
14490         return(-1);
14491 
14492     if (node->doc == ctx->doc) {
14493         ctx->node = node;
14494 	return(0);
14495     }
14496     return(-1);
14497 }
14498 
14499 /**
14500  * xmlXPathNodeEval:
14501  * @node: the node to to use as the context node
14502  * @str:  the XPath expression
14503  * @ctx:  the XPath context
14504  *
14505  * Evaluate the XPath Location Path in the given context. The node 'node'
14506  * is set as the context node. The context node is not restored.
14507  *
14508  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14509  *         the caller has to free the object.
14510  */
14511 xmlXPathObjectPtr
xmlXPathNodeEval(xmlNodePtr node,const xmlChar * str,xmlXPathContextPtr ctx)14512 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14513     if (str == NULL)
14514         return(NULL);
14515     if (xmlXPathSetContextNode(node, ctx) < 0)
14516         return(NULL);
14517     return(xmlXPathEval(str, ctx));
14518 }
14519 
14520 /**
14521  * xmlXPathEvalExpression:
14522  * @str:  the XPath expression
14523  * @ctxt:  the XPath context
14524  *
14525  * Alias for xmlXPathEval().
14526  *
14527  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14528  *         the caller has to free the object.
14529  */
14530 xmlXPathObjectPtr
xmlXPathEvalExpression(const xmlChar * str,xmlXPathContextPtr ctxt)14531 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14532     return(xmlXPathEval(str, ctxt));
14533 }
14534 
14535 /************************************************************************
14536  *									*
14537  *	Extra functions not pertaining to the XPath spec		*
14538  *									*
14539  ************************************************************************/
14540 /**
14541  * xmlXPathEscapeUriFunction:
14542  * @ctxt:  the XPath Parser context
14543  * @nargs:  the number of arguments
14544  *
14545  * Implement the escape-uri() XPath function
14546  *    string escape-uri(string $str, bool $escape-reserved)
14547  *
14548  * This function applies the URI escaping rules defined in section 2 of [RFC
14549  * 2396] to the string supplied as $uri-part, which typically represents all
14550  * or part of a URI. The effect of the function is to replace any special
14551  * character in the string by an escape sequence of the form %xx%yy...,
14552  * where xxyy... is the hexadecimal representation of the octets used to
14553  * represent the character in UTF-8.
14554  *
14555  * The set of characters that are escaped depends on the setting of the
14556  * boolean argument $escape-reserved.
14557  *
14558  * If $escape-reserved is true, all characters are escaped other than lower
14559  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14560  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14561  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14562  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14563  * A-F).
14564  *
14565  * If $escape-reserved is false, the behavior differs in that characters
14566  * referred to in [RFC 2396] as reserved characters are not escaped. These
14567  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14568  *
14569  * [RFC 2396] does not define whether escaped URIs should use lower case or
14570  * upper case for hexadecimal digits. To ensure that escaped URIs can be
14571  * compared using string comparison functions, this function must always use
14572  * the upper-case letters A-F.
14573  *
14574  * Generally, $escape-reserved should be set to true when escaping a string
14575  * that is to form a single part of a URI, and to false when escaping an
14576  * entire URI or URI reference.
14577  *
14578  * In the case of non-ascii characters, the string is encoded according to
14579  * utf-8 and then converted according to RFC 2396.
14580  *
14581  * Examples
14582  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14583  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14584  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14585  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14586  *
14587  */
14588 static void
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt,int nargs)14589 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14590     xmlXPathObjectPtr str;
14591     int escape_reserved;
14592     xmlBufPtr target;
14593     xmlChar *cptr;
14594     xmlChar escape[4];
14595 
14596     CHECK_ARITY(2);
14597 
14598     escape_reserved = xmlXPathPopBoolean(ctxt);
14599 
14600     CAST_TO_STRING;
14601     str = valuePop(ctxt);
14602 
14603     target = xmlBufCreate();
14604 
14605     escape[0] = '%';
14606     escape[3] = 0;
14607 
14608     if (target) {
14609 	for (cptr = str->stringval; *cptr; cptr++) {
14610 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
14611 		(*cptr >= 'a' && *cptr <= 'z') ||
14612 		(*cptr >= '0' && *cptr <= '9') ||
14613 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
14614 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
14615 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14616 		(*cptr == '%' &&
14617 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14618 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14619 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
14620 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14621 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14622 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14623 		(!escape_reserved &&
14624 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14625 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14626 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14627 		  *cptr == ','))) {
14628 		xmlBufAdd(target, cptr, 1);
14629 	    } else {
14630 		if ((*cptr >> 4) < 10)
14631 		    escape[1] = '0' + (*cptr >> 4);
14632 		else
14633 		    escape[1] = 'A' - 10 + (*cptr >> 4);
14634 		if ((*cptr & 0xF) < 10)
14635 		    escape[2] = '0' + (*cptr & 0xF);
14636 		else
14637 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
14638 
14639 		xmlBufAdd(target, &escape[0], 3);
14640 	    }
14641 	}
14642     }
14643     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14644 	xmlBufContent(target)));
14645     xmlBufFree(target);
14646     xmlXPathReleaseObject(ctxt->context, str);
14647 }
14648 
14649 /**
14650  * xmlXPathRegisterAllFunctions:
14651  * @ctxt:  the XPath context
14652  *
14653  * Registers all default XPath functions in this context
14654  */
14655 void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)14656 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14657 {
14658     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14659                          xmlXPathBooleanFunction);
14660     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14661                          xmlXPathCeilingFunction);
14662     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14663                          xmlXPathCountFunction);
14664     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14665                          xmlXPathConcatFunction);
14666     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14667                          xmlXPathContainsFunction);
14668     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14669                          xmlXPathIdFunction);
14670     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14671                          xmlXPathFalseFunction);
14672     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14673                          xmlXPathFloorFunction);
14674     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14675                          xmlXPathLastFunction);
14676     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14677                          xmlXPathLangFunction);
14678     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14679                          xmlXPathLocalNameFunction);
14680     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14681                          xmlXPathNotFunction);
14682     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14683                          xmlXPathNameFunction);
14684     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14685                          xmlXPathNamespaceURIFunction);
14686     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14687                          xmlXPathNormalizeFunction);
14688     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14689                          xmlXPathNumberFunction);
14690     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14691                          xmlXPathPositionFunction);
14692     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14693                          xmlXPathRoundFunction);
14694     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14695                          xmlXPathStringFunction);
14696     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14697                          xmlXPathStringLengthFunction);
14698     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14699                          xmlXPathStartsWithFunction);
14700     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14701                          xmlXPathSubstringFunction);
14702     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14703                          xmlXPathSubstringBeforeFunction);
14704     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14705                          xmlXPathSubstringAfterFunction);
14706     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14707                          xmlXPathSumFunction);
14708     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14709                          xmlXPathTrueFunction);
14710     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14711                          xmlXPathTranslateFunction);
14712 
14713     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14714 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14715                          xmlXPathEscapeUriFunction);
14716 }
14717 
14718 #endif /* LIBXML_XPATH_ENABLED */
14719