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  *f
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 #define IN_LIBXML
18 #include "libxml.h"
19 
20 #include <string.h>
21 
22 #ifdef HAVE_SYS_TYPES_H
23 #include <sys/types.h>
24 #endif
25 #ifdef HAVE_MATH_H
26 #include <math.h>
27 #endif
28 #ifdef HAVE_FLOAT_H
29 #include <float.h>
30 #endif
31 #ifdef HAVE_CTYPE_H
32 #include <ctype.h>
33 #endif
34 #ifdef HAVE_SIGNAL_H
35 #include <signal.h>
36 #endif
37 
38 #include <libxml/xmlmemory.h>
39 #include <libxml/tree.h>
40 #include <libxml/valid.h>
41 #include <libxml/xpath.h>
42 #include <libxml/xpathInternals.h>
43 #include <libxml/parserInternals.h>
44 #include <libxml/hash.h>
45 #ifdef LIBXML_XPTR_ENABLED
46 #include <libxml/xpointer.h>
47 #endif
48 #ifdef LIBXML_DEBUG_ENABLED
49 #include <libxml/debugXML.h>
50 #endif
51 #include <libxml/xmlerror.h>
52 #include <libxml/threads.h>
53 #include <libxml/globals.h>
54 #ifdef LIBXML_PATTERN_ENABLED
55 #include <libxml/pattern.h>
56 #endif
57 
58 #include "buf.h"
59 
60 #ifdef LIBXML_PATTERN_ENABLED
61 #define XPATH_STREAMING
62 #endif
63 
64 #define TODO								\
65     xmlGenericError(xmlGenericErrorContext,				\
66 	    "Unimplemented block at %s:%d\n",				\
67             __FILE__, __LINE__);
68 
69 /**
70  * WITH_TIM_SORT:
71  *
72  * Use the Timsort algorithm provided in timsort.h to sort
73  * nodeset as this is a great improvement over the old Shell sort
74  * used in xmlXPathNodeSetSort()
75  */
76 #define WITH_TIM_SORT
77 
78 /*
79 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
80 * If defined, this will use xmlXPathCmpNodesExt() instead of
81 * xmlXPathCmpNodes(). The new function is optimized comparison of
82 * non-element nodes; actually it will speed up comparison only if
83 * xmlXPathOrderDocElems() was called in order to index the elements of
84 * a tree in document order; Libxslt does such an indexing, thus it will
85 * benefit from this optimization.
86 */
87 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
88 
89 /*
90 * XP_OPTIMIZED_FILTER_FIRST:
91 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
92 * in a way, that it stop evaluation at the first node.
93 */
94 #define XP_OPTIMIZED_FILTER_FIRST
95 
96 /*
97 * XP_DEBUG_OBJ_USAGE:
98 * Internal flag to enable tracking of how much XPath objects have been
99 * created.
100 */
101 /* #define XP_DEBUG_OBJ_USAGE */
102 
103 /*
104  * XPATH_MAX_STEPS:
105  * when compiling an XPath expression we arbitrary limit the maximum
106  * number of step operation in the compiled expression. 1000000 is
107  * an insanely large value which should never be reached under normal
108  * circumstances
109  */
110 #define XPATH_MAX_STEPS 1000000
111 
112 /*
113  * XPATH_MAX_STACK_DEPTH:
114  * when evaluating an XPath expression we arbitrary limit the maximum
115  * number of object allowed to be pushed on the stack. 1000000 is
116  * an insanely large value which should never be reached under normal
117  * circumstances
118  */
119 #define XPATH_MAX_STACK_DEPTH 1000000
120 
121 /*
122  * XPATH_MAX_NODESET_LENGTH:
123  * when evaluating an XPath expression nodesets are created and we
124  * arbitrary limit the maximum length of those node set. 10000000 is
125  * an insanely large value which should never be reached under normal
126  * circumstances, one would first need to construct an in memory tree
127  * with more than 10 millions nodes.
128  */
129 #define XPATH_MAX_NODESET_LENGTH 10000000
130 
131 /*
132  * TODO:
133  * There are a few spots where some tests are done which depend upon ascii
134  * data.  These should be enhanced for full UTF8 support (see particularly
135  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
136  */
137 
138 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
139 /**
140  * xmlXPathCmpNodesExt:
141  * @node1:  the first node
142  * @node2:  the second node
143  *
144  * Compare two nodes w.r.t document order.
145  * This one is optimized for handling of non-element nodes.
146  *
147  * Returns -2 in case of error 1 if first point < second point, 0 if
148  *         it's the same node, -1 otherwise
149  */
150 static int
xmlXPathCmpNodesExt(xmlNodePtr node1,xmlNodePtr node2)151 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
152     int depth1, depth2;
153     int misc = 0, precedence1 = 0, precedence2 = 0;
154     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
155     xmlNodePtr cur, root;
156     long l1, l2;
157 
158     if ((node1 == NULL) || (node2 == NULL))
159 	return(-2);
160 
161     if (node1 == node2)
162 	return(0);
163 
164     /*
165      * a couple of optimizations which will avoid computations in most cases
166      */
167     switch (node1->type) {
168 	case XML_ELEMENT_NODE:
169 	    if (node2->type == XML_ELEMENT_NODE) {
170 		if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
171 		    (0 > (long) node2->content) &&
172 		    (node1->doc == node2->doc))
173 		{
174 		    l1 = -((long) node1->content);
175 		    l2 = -((long) node2->content);
176 		    if (l1 < l2)
177 			return(1);
178 		    if (l1 > l2)
179 			return(-1);
180 		} else
181 		    goto turtle_comparison;
182 	    }
183 	    break;
184 	case XML_ATTRIBUTE_NODE:
185 	    precedence1 = 1; /* element is owner */
186 	    miscNode1 = node1;
187 	    node1 = node1->parent;
188 	    misc = 1;
189 	    break;
190 	case XML_TEXT_NODE:
191 	case XML_CDATA_SECTION_NODE:
192 	case XML_COMMENT_NODE:
193 	case XML_PI_NODE: {
194 	    miscNode1 = node1;
195 	    /*
196 	    * Find nearest element node.
197 	    */
198 	    if (node1->prev != NULL) {
199 		do {
200 		    node1 = node1->prev;
201 		    if (node1->type == XML_ELEMENT_NODE) {
202 			precedence1 = 3; /* element in prev-sibl axis */
203 			break;
204 		    }
205 		    if (node1->prev == NULL) {
206 			precedence1 = 2; /* element is parent */
207 			/*
208 			* URGENT TODO: Are there any cases, where the
209 			* parent of such a node is not an element node?
210 			*/
211 			node1 = node1->parent;
212 			break;
213 		    }
214 		} while (1);
215 	    } else {
216 		precedence1 = 2; /* element is parent */
217 		node1 = node1->parent;
218 	    }
219 	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
220 		(0 <= (long) node1->content)) {
221 		/*
222 		* Fallback for whatever case.
223 		*/
224 		node1 = miscNode1;
225 		precedence1 = 0;
226 	    } else
227 		misc = 1;
228 	}
229 	    break;
230 	case XML_NAMESPACE_DECL:
231 	    /*
232 	    * TODO: why do we return 1 for namespace nodes?
233 	    */
234 	    return(1);
235 	default:
236 	    break;
237     }
238     switch (node2->type) {
239 	case XML_ELEMENT_NODE:
240 	    break;
241 	case XML_ATTRIBUTE_NODE:
242 	    precedence2 = 1; /* element is owner */
243 	    miscNode2 = node2;
244 	    node2 = node2->parent;
245 	    misc = 1;
246 	    break;
247 	case XML_TEXT_NODE:
248 	case XML_CDATA_SECTION_NODE:
249 	case XML_COMMENT_NODE:
250 	case XML_PI_NODE: {
251 	    miscNode2 = node2;
252 	    if (node2->prev != NULL) {
253 		do {
254 		    node2 = node2->prev;
255 		    if (node2->type == XML_ELEMENT_NODE) {
256 			precedence2 = 3; /* element in prev-sibl axis */
257 			break;
258 		    }
259 		    if (node2->prev == NULL) {
260 			precedence2 = 2; /* element is parent */
261 			node2 = node2->parent;
262 			break;
263 		    }
264 		} while (1);
265 	    } else {
266 		precedence2 = 2; /* element is parent */
267 		node2 = node2->parent;
268 	    }
269 	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
270 		(0 <= (long) node2->content))
271 	    {
272 		node2 = miscNode2;
273 		precedence2 = 0;
274 	    } else
275 		misc = 1;
276 	}
277 	    break;
278 	case XML_NAMESPACE_DECL:
279 	    return(1);
280 	default:
281 	    break;
282     }
283     if (misc) {
284 	if (node1 == node2) {
285 	    if (precedence1 == precedence2) {
286 		/*
287 		* The ugly case; but normally there aren't many
288 		* adjacent non-element nodes around.
289 		*/
290 		cur = miscNode2->prev;
291 		while (cur != NULL) {
292 		    if (cur == miscNode1)
293 			return(1);
294 		    if (cur->type == XML_ELEMENT_NODE)
295 			return(-1);
296 		    cur = cur->prev;
297 		}
298 		return (-1);
299 	    } else {
300 		/*
301 		* Evaluate based on higher precedence wrt to the element.
302 		* TODO: This assumes attributes are sorted before content.
303 		*   Is this 100% correct?
304 		*/
305 		if (precedence1 < precedence2)
306 		    return(1);
307 		else
308 		    return(-1);
309 	    }
310 	}
311 	/*
312 	* Special case: One of the helper-elements is contained by the other.
313 	* <foo>
314 	*   <node2>
315 	*     <node1>Text-1(precedence1 == 2)</node1>
316 	*   </node2>
317 	*   Text-6(precedence2 == 3)
318 	* </foo>
319 	*/
320 	if ((precedence2 == 3) && (precedence1 > 1)) {
321 	    cur = node1->parent;
322 	    while (cur) {
323 		if (cur == node2)
324 		    return(1);
325 		cur = cur->parent;
326 	    }
327 	}
328 	if ((precedence1 == 3) && (precedence2 > 1)) {
329 	    cur = node2->parent;
330 	    while (cur) {
331 		if (cur == node1)
332 		    return(-1);
333 		cur = cur->parent;
334 	    }
335 	}
336     }
337 
338     /*
339      * Speedup using document order if availble.
340      */
341     if ((node1->type == XML_ELEMENT_NODE) &&
342 	(node2->type == XML_ELEMENT_NODE) &&
343 	(0 > (long) node1->content) &&
344 	(0 > (long) node2->content) &&
345 	(node1->doc == node2->doc)) {
346 
347 	l1 = -((long) node1->content);
348 	l2 = -((long) node2->content);
349 	if (l1 < l2)
350 	    return(1);
351 	if (l1 > l2)
352 	    return(-1);
353     }
354 
355 turtle_comparison:
356 
357     if (node1 == node2->prev)
358 	return(1);
359     if (node1 == node2->next)
360 	return(-1);
361     /*
362      * compute depth to root
363      */
364     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
365 	if (cur == node1)
366 	    return(1);
367 	depth2++;
368     }
369     root = cur;
370     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
371 	if (cur == node2)
372 	    return(-1);
373 	depth1++;
374     }
375     /*
376      * Distinct document (or distinct entities :-( ) case.
377      */
378     if (root != cur) {
379 	return(-2);
380     }
381     /*
382      * get the nearest common ancestor.
383      */
384     while (depth1 > depth2) {
385 	depth1--;
386 	node1 = node1->parent;
387     }
388     while (depth2 > depth1) {
389 	depth2--;
390 	node2 = node2->parent;
391     }
392     while (node1->parent != node2->parent) {
393 	node1 = node1->parent;
394 	node2 = node2->parent;
395 	/* should not happen but just in case ... */
396 	if ((node1 == NULL) || (node2 == NULL))
397 	    return(-2);
398     }
399     /*
400      * Find who's first.
401      */
402     if (node1 == node2->prev)
403 	return(1);
404     if (node1 == node2->next)
405 	return(-1);
406     /*
407      * Speedup using document order if availble.
408      */
409     if ((node1->type == XML_ELEMENT_NODE) &&
410 	(node2->type == XML_ELEMENT_NODE) &&
411 	(0 > (long) node1->content) &&
412 	(0 > (long) node2->content) &&
413 	(node1->doc == node2->doc)) {
414 
415 	l1 = -((long) node1->content);
416 	l2 = -((long) node2->content);
417 	if (l1 < l2)
418 	    return(1);
419 	if (l1 > l2)
420 	    return(-1);
421     }
422 
423     for (cur = node1->next;cur != NULL;cur = cur->next)
424 	if (cur == node2)
425 	    return(1);
426     return(-1); /* assume there is no sibling list corruption */
427 }
428 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
429 
430 /*
431  * Wrapper for the Timsort argorithm from timsort.h
432  */
433 #ifdef WITH_TIM_SORT
434 #define SORT_NAME libxml_domnode
435 #define SORT_TYPE xmlNodePtr
436 /**
437  * wrap_cmp:
438  * @x: a node
439  * @y: another node
440  *
441  * Comparison function for the Timsort implementation
442  *
443  * Returns -2 in case of error -1 if first point < second point, 0 if
444  *         it's the same node, +1 otherwise
445  */
446 static
447 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
448 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
wrap_cmp(xmlNodePtr x,xmlNodePtr y)449     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
450     {
451         int res = xmlXPathCmpNodesExt(x, y);
452         return res == -2 ? res : -res;
453     }
454 #else
wrap_cmp(xmlNodePtr x,xmlNodePtr y)455     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
456     {
457         int res = xmlXPathCmpNodes(x, y);
458         return res == -2 ? res : -res;
459     }
460 #endif
461 #define SORT_CMP(x, y)  (wrap_cmp(x, y))
462 #include "timsort.h"
463 #endif /* WITH_TIM_SORT */
464 
465 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
466 
467 /************************************************************************
468  *									*
469  *			Floating point stuff				*
470  *									*
471  ************************************************************************/
472 
473 #ifndef TRIO_REPLACE_STDIO
474 #define TRIO_PUBLIC static
475 #endif
476 #include "trionan.c"
477 
478 /*
479  * The lack of portability of this section of the libc is annoying !
480  */
481 double xmlXPathNAN = 0;
482 double xmlXPathPINF = 1;
483 double xmlXPathNINF = -1;
484 static double xmlXPathNZERO = 0; /* not exported from headers */
485 static int xmlXPathInitialized = 0;
486 
487 /**
488  * xmlXPathInit:
489  *
490  * Initialize the XPath environment
491  */
492 void
xmlXPathInit(void)493 xmlXPathInit(void) {
494     if (xmlXPathInitialized) return;
495 
496     xmlXPathPINF = trio_pinf();
497     xmlXPathNINF = trio_ninf();
498     xmlXPathNAN = trio_nan();
499     xmlXPathNZERO = trio_nzero();
500 
501     xmlXPathInitialized = 1;
502 }
503 
504 /**
505  * xmlXPathIsNaN:
506  * @val:  a double value
507  *
508  * Provides a portable isnan() function to detect whether a double
509  * is a NotaNumber. Based on trio code
510  * http://sourceforge.net/projects/ctrio/
511  *
512  * Returns 1 if the value is a NaN, 0 otherwise
513  */
514 int
xmlXPathIsNaN(double val)515 xmlXPathIsNaN(double val) {
516     return(trio_isnan(val));
517 }
518 
519 /**
520  * xmlXPathIsInf:
521  * @val:  a double value
522  *
523  * Provides a portable isinf() function to detect whether a double
524  * is a +Infinite or -Infinite. Based on trio code
525  * http://sourceforge.net/projects/ctrio/
526  *
527  * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
528  */
529 int
xmlXPathIsInf(double val)530 xmlXPathIsInf(double val) {
531     return(trio_isinf(val));
532 }
533 
534 #endif /* SCHEMAS or XPATH */
535 #ifdef LIBXML_XPATH_ENABLED
536 /**
537  * xmlXPathGetSign:
538  * @val:  a double value
539  *
540  * Provides a portable function to detect the sign of a double
541  * Modified from trio code
542  * http://sourceforge.net/projects/ctrio/
543  *
544  * Returns 1 if the value is Negative, 0 if positive
545  */
546 static int
xmlXPathGetSign(double val)547 xmlXPathGetSign(double val) {
548     return(trio_signbit(val));
549 }
550 
551 
552 /*
553  * TODO: when compatibility allows remove all "fake node libxslt" strings
554  *       the test should just be name[0] = ' '
555  */
556 #ifdef DEBUG_XPATH_EXPRESSION
557 #define DEBUG_STEP
558 #define DEBUG_EXPR
559 #define DEBUG_EVAL_COUNTS
560 #endif
561 
562 static xmlNs xmlXPathXMLNamespaceStruct = {
563     NULL,
564     XML_NAMESPACE_DECL,
565     XML_XML_NAMESPACE,
566     BAD_CAST "xml",
567     NULL,
568     NULL
569 };
570 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
571 #ifndef LIBXML_THREAD_ENABLED
572 /*
573  * Optimizer is disabled only when threaded apps are detected while
574  * the library ain't compiled for thread safety.
575  */
576 static int xmlXPathDisableOptimizer = 0;
577 #endif
578 
579 /************************************************************************
580  *									*
581  *			Error handling routines				*
582  *									*
583  ************************************************************************/
584 
585 /**
586  * XP_ERRORNULL:
587  * @X:  the error code
588  *
589  * Macro to raise an XPath error and return NULL.
590  */
591 #define XP_ERRORNULL(X)							\
592     { xmlXPathErr(ctxt, X); return(NULL); }
593 
594 /*
595  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
596  */
597 static const char *xmlXPathErrorMessages[] = {
598     "Ok\n",
599     "Number encoding\n",
600     "Unfinished literal\n",
601     "Start of literal\n",
602     "Expected $ for variable reference\n",
603     "Undefined variable\n",
604     "Invalid predicate\n",
605     "Invalid expression\n",
606     "Missing closing curly brace\n",
607     "Unregistered function\n",
608     "Invalid operand\n",
609     "Invalid type\n",
610     "Invalid number of arguments\n",
611     "Invalid context size\n",
612     "Invalid context position\n",
613     "Memory allocation error\n",
614     "Syntax error\n",
615     "Resource error\n",
616     "Sub resource error\n",
617     "Undefined namespace prefix\n",
618     "Encoding error\n",
619     "Char out of XML range\n",
620     "Invalid or incomplete context\n",
621     "Stack usage error\n",
622     "Forbidden variable\n",
623     "?? Unknown error ??\n"	/* Must be last in the list! */
624 };
625 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
626 		   sizeof(xmlXPathErrorMessages[0])) - 1)
627 /**
628  * xmlXPathErrMemory:
629  * @ctxt:  an XPath context
630  * @extra:  extra informations
631  *
632  * Handle a redefinition of attribute error
633  */
634 static void
xmlXPathErrMemory(xmlXPathContextPtr ctxt,const char * extra)635 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
636 {
637     if (ctxt != NULL) {
638         if (extra) {
639             xmlChar buf[200];
640 
641             xmlStrPrintf(buf, 200,
642                          BAD_CAST "Memory allocation failed : %s\n",
643                          extra);
644             ctxt->lastError.message = (char *) xmlStrdup(buf);
645         } else {
646             ctxt->lastError.message = (char *)
647 	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
648         }
649         ctxt->lastError.domain = XML_FROM_XPATH;
650         ctxt->lastError.code = XML_ERR_NO_MEMORY;
651 	if (ctxt->error != NULL)
652 	    ctxt->error(ctxt->userData, &ctxt->lastError);
653     } else {
654         if (extra)
655             __xmlRaiseError(NULL, NULL, NULL,
656                             NULL, NULL, XML_FROM_XPATH,
657                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
658                             extra, NULL, NULL, 0, 0,
659                             "Memory allocation failed : %s\n", extra);
660         else
661             __xmlRaiseError(NULL, NULL, NULL,
662                             NULL, NULL, XML_FROM_XPATH,
663                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
664                             NULL, NULL, NULL, 0, 0,
665                             "Memory allocation failed\n");
666     }
667 }
668 
669 /**
670  * xmlXPathPErrMemory:
671  * @ctxt:  an XPath parser context
672  * @extra:  extra informations
673  *
674  * Handle a redefinition of attribute error
675  */
676 static void
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt,const char * extra)677 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
678 {
679     if (ctxt == NULL)
680 	xmlXPathErrMemory(NULL, extra);
681     else {
682 	ctxt->error = XPATH_MEMORY_ERROR;
683 	xmlXPathErrMemory(ctxt->context, extra);
684     }
685 }
686 
687 /**
688  * xmlXPathErr:
689  * @ctxt:  a XPath parser context
690  * @error:  the error code
691  *
692  * Handle an XPath error
693  */
694 void
xmlXPathErr(xmlXPathParserContextPtr ctxt,int error)695 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
696 {
697     if ((error < 0) || (error > MAXERRNO))
698 	error = MAXERRNO;
699     if (ctxt == NULL) {
700 	__xmlRaiseError(NULL, NULL, NULL,
701 			NULL, NULL, XML_FROM_XPATH,
702 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
703 			XML_ERR_ERROR, NULL, 0,
704 			NULL, NULL, NULL, 0, 0,
705 			"%s", xmlXPathErrorMessages[error]);
706 	return;
707     }
708     ctxt->error = error;
709     if (ctxt->context == 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 			(const char *) ctxt->base, NULL, NULL,
715 			ctxt->cur - ctxt->base, 0,
716 			"%s", xmlXPathErrorMessages[error]);
717 	return;
718     }
719 
720     /* cleanup current last error */
721     xmlResetError(&ctxt->context->lastError);
722 
723     ctxt->context->lastError.domain = XML_FROM_XPATH;
724     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
725                            XPATH_EXPRESSION_OK;
726     ctxt->context->lastError.level = XML_ERR_ERROR;
727     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
728     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
729     ctxt->context->lastError.node = ctxt->context->debugNode;
730     if (ctxt->context->error != NULL) {
731 	ctxt->context->error(ctxt->context->userData,
732 	                     &ctxt->context->lastError);
733     } else {
734 	__xmlRaiseError(NULL, NULL, NULL,
735 			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
736 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
737 			XML_ERR_ERROR, NULL, 0,
738 			(const char *) ctxt->base, NULL, NULL,
739 			ctxt->cur - ctxt->base, 0,
740 			"%s", xmlXPathErrorMessages[error]);
741     }
742 
743 }
744 
745 /**
746  * xmlXPatherror:
747  * @ctxt:  the XPath Parser context
748  * @file:  the file name
749  * @line:  the line number
750  * @no:  the error number
751  *
752  * Formats an error message.
753  */
754 void
xmlXPatherror(xmlXPathParserContextPtr ctxt,const char * file ATTRIBUTE_UNUSED,int line ATTRIBUTE_UNUSED,int no)755 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
756               int line ATTRIBUTE_UNUSED, int no) {
757     xmlXPathErr(ctxt, no);
758 }
759 
760 /************************************************************************
761  *									*
762  *			Utilities					*
763  *									*
764  ************************************************************************/
765 
766 /**
767  * xsltPointerList:
768  *
769  * Pointer-list for various purposes.
770  */
771 typedef struct _xmlPointerList xmlPointerList;
772 typedef xmlPointerList *xmlPointerListPtr;
773 struct _xmlPointerList {
774     void **items;
775     int number;
776     int size;
777 };
778 /*
779 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
780 * and here, we should make the functions public.
781 */
782 static int
xmlPointerListAddSize(xmlPointerListPtr list,void * item,int initialSize)783 xmlPointerListAddSize(xmlPointerListPtr list,
784 		       void *item,
785 		       int initialSize)
786 {
787     if (list->items == NULL) {
788 	if (initialSize <= 0)
789 	    initialSize = 1;
790 	list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
791 	if (list->items == NULL) {
792 	    xmlXPathErrMemory(NULL,
793 		"xmlPointerListCreate: allocating item\n");
794 	    return(-1);
795 	}
796 	list->number = 0;
797 	list->size = initialSize;
798     } else if (list->size <= list->number) {
799         if (list->size > 50000000) {
800 	    xmlXPathErrMemory(NULL,
801 		"xmlPointerListAddSize: re-allocating item\n");
802             return(-1);
803         }
804 	list->size *= 2;
805 	list->items = (void **) xmlRealloc(list->items,
806 	    list->size * sizeof(void *));
807 	if (list->items == NULL) {
808 	    xmlXPathErrMemory(NULL,
809 		"xmlPointerListAddSize: re-allocating item\n");
810 	    list->size = 0;
811 	    return(-1);
812 	}
813     }
814     list->items[list->number++] = item;
815     return(0);
816 }
817 
818 /**
819  * xsltPointerListCreate:
820  *
821  * Creates an xsltPointerList structure.
822  *
823  * Returns a xsltPointerList structure or NULL in case of an error.
824  */
825 static xmlPointerListPtr
xmlPointerListCreate(int initialSize)826 xmlPointerListCreate(int initialSize)
827 {
828     xmlPointerListPtr ret;
829 
830     ret = xmlMalloc(sizeof(xmlPointerList));
831     if (ret == NULL) {
832 	xmlXPathErrMemory(NULL,
833 	    "xmlPointerListCreate: allocating item\n");
834 	return (NULL);
835     }
836     memset(ret, 0, sizeof(xmlPointerList));
837     if (initialSize > 0) {
838 	xmlPointerListAddSize(ret, NULL, initialSize);
839 	ret->number = 0;
840     }
841     return (ret);
842 }
843 
844 /**
845  * xsltPointerListFree:
846  *
847  * Frees the xsltPointerList structure. This does not free
848  * the content of the list.
849  */
850 static void
xmlPointerListFree(xmlPointerListPtr list)851 xmlPointerListFree(xmlPointerListPtr list)
852 {
853     if (list == NULL)
854 	return;
855     if (list->items != NULL)
856 	xmlFree(list->items);
857     xmlFree(list);
858 }
859 
860 /************************************************************************
861  *									*
862  *			Parser Types					*
863  *									*
864  ************************************************************************/
865 
866 /*
867  * Types are private:
868  */
869 
870 typedef enum {
871     XPATH_OP_END=0,
872     XPATH_OP_AND,
873     XPATH_OP_OR,
874     XPATH_OP_EQUAL,
875     XPATH_OP_CMP,
876     XPATH_OP_PLUS,
877     XPATH_OP_MULT,
878     XPATH_OP_UNION,
879     XPATH_OP_ROOT,
880     XPATH_OP_NODE,
881     XPATH_OP_RESET, /* 10 */
882     XPATH_OP_COLLECT,
883     XPATH_OP_VALUE, /* 12 */
884     XPATH_OP_VARIABLE,
885     XPATH_OP_FUNCTION,
886     XPATH_OP_ARG,
887     XPATH_OP_PREDICATE,
888     XPATH_OP_FILTER, /* 17 */
889     XPATH_OP_SORT /* 18 */
890 #ifdef LIBXML_XPTR_ENABLED
891     ,XPATH_OP_RANGETO
892 #endif
893 } xmlXPathOp;
894 
895 typedef enum {
896     AXIS_ANCESTOR = 1,
897     AXIS_ANCESTOR_OR_SELF,
898     AXIS_ATTRIBUTE,
899     AXIS_CHILD,
900     AXIS_DESCENDANT,
901     AXIS_DESCENDANT_OR_SELF,
902     AXIS_FOLLOWING,
903     AXIS_FOLLOWING_SIBLING,
904     AXIS_NAMESPACE,
905     AXIS_PARENT,
906     AXIS_PRECEDING,
907     AXIS_PRECEDING_SIBLING,
908     AXIS_SELF
909 } xmlXPathAxisVal;
910 
911 typedef enum {
912     NODE_TEST_NONE = 0,
913     NODE_TEST_TYPE = 1,
914     NODE_TEST_PI = 2,
915     NODE_TEST_ALL = 3,
916     NODE_TEST_NS = 4,
917     NODE_TEST_NAME = 5
918 } xmlXPathTestVal;
919 
920 typedef enum {
921     NODE_TYPE_NODE = 0,
922     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
923     NODE_TYPE_TEXT = XML_TEXT_NODE,
924     NODE_TYPE_PI = XML_PI_NODE
925 } xmlXPathTypeVal;
926 
927 typedef struct _xmlXPathStepOp xmlXPathStepOp;
928 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
929 struct _xmlXPathStepOp {
930     xmlXPathOp op;		/* The identifier of the operation */
931     int ch1;			/* First child */
932     int ch2;			/* Second child */
933     int value;
934     int value2;
935     int value3;
936     void *value4;
937     void *value5;
938     void *cache;
939     void *cacheURI;
940 };
941 
942 struct _xmlXPathCompExpr {
943     int nbStep;			/* Number of steps in this expression */
944     int maxStep;		/* Maximum number of steps allocated */
945     xmlXPathStepOp *steps;	/* ops for computation of this expression */
946     int last;			/* index of last step in expression */
947     xmlChar *expr;		/* the expression being computed */
948     xmlDictPtr dict;		/* the dictionnary to use if any */
949 #ifdef DEBUG_EVAL_COUNTS
950     int nb;
951     xmlChar *string;
952 #endif
953 #ifdef XPATH_STREAMING
954     xmlPatternPtr stream;
955 #endif
956 };
957 
958 /************************************************************************
959  *									*
960  *			Forward declarations				*
961  *									*
962  ************************************************************************/
963 static void
964 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
965 static void
966 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
967 static int
968 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
969                         xmlXPathStepOpPtr op, xmlNodePtr *first);
970 static int
971 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
972 			    xmlXPathStepOpPtr op,
973 			    int isPredicate);
974 
975 /************************************************************************
976  *									*
977  *			Parser Type functions				*
978  *									*
979  ************************************************************************/
980 
981 /**
982  * xmlXPathNewCompExpr:
983  *
984  * Create a new Xpath component
985  *
986  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
987  */
988 static xmlXPathCompExprPtr
xmlXPathNewCompExpr(void)989 xmlXPathNewCompExpr(void) {
990     xmlXPathCompExprPtr cur;
991 
992     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
993     if (cur == NULL) {
994         xmlXPathErrMemory(NULL, "allocating component\n");
995 	return(NULL);
996     }
997     memset(cur, 0, sizeof(xmlXPathCompExpr));
998     cur->maxStep = 10;
999     cur->nbStep = 0;
1000     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1001 	                                   sizeof(xmlXPathStepOp));
1002     if (cur->steps == NULL) {
1003         xmlXPathErrMemory(NULL, "allocating steps\n");
1004 	xmlFree(cur);
1005 	return(NULL);
1006     }
1007     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1008     cur->last = -1;
1009 #ifdef DEBUG_EVAL_COUNTS
1010     cur->nb = 0;
1011 #endif
1012     return(cur);
1013 }
1014 
1015 /**
1016  * xmlXPathFreeCompExpr:
1017  * @comp:  an XPATH comp
1018  *
1019  * Free up the memory allocated by @comp
1020  */
1021 void
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)1022 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1023 {
1024     xmlXPathStepOpPtr op;
1025     int i;
1026 
1027     if (comp == NULL)
1028         return;
1029     if (comp->dict == NULL) {
1030 	for (i = 0; i < comp->nbStep; i++) {
1031 	    op = &comp->steps[i];
1032 	    if (op->value4 != NULL) {
1033 		if (op->op == XPATH_OP_VALUE)
1034 		    xmlXPathFreeObject(op->value4);
1035 		else
1036 		    xmlFree(op->value4);
1037 	    }
1038 	    if (op->value5 != NULL)
1039 		xmlFree(op->value5);
1040 	}
1041     } else {
1042 	for (i = 0; i < comp->nbStep; i++) {
1043 	    op = &comp->steps[i];
1044 	    if (op->value4 != NULL) {
1045 		if (op->op == XPATH_OP_VALUE)
1046 		    xmlXPathFreeObject(op->value4);
1047 	    }
1048 	}
1049         xmlDictFree(comp->dict);
1050     }
1051     if (comp->steps != NULL) {
1052         xmlFree(comp->steps);
1053     }
1054 #ifdef DEBUG_EVAL_COUNTS
1055     if (comp->string != NULL) {
1056         xmlFree(comp->string);
1057     }
1058 #endif
1059 #ifdef XPATH_STREAMING
1060     if (comp->stream != NULL) {
1061         xmlFreePatternList(comp->stream);
1062     }
1063 #endif
1064     if (comp->expr != NULL) {
1065         xmlFree(comp->expr);
1066     }
1067 
1068     xmlFree(comp);
1069 }
1070 
1071 /**
1072  * xmlXPathCompExprAdd:
1073  * @comp:  the compiled expression
1074  * @ch1: first child index
1075  * @ch2: second child index
1076  * @op:  an op
1077  * @value:  the first int value
1078  * @value2:  the second int value
1079  * @value3:  the third int value
1080  * @value4:  the first string value
1081  * @value5:  the second string value
1082  *
1083  * Add a step to an XPath Compiled Expression
1084  *
1085  * Returns -1 in case of failure, the index otherwise
1086  */
1087 static int
xmlXPathCompExprAdd(xmlXPathCompExprPtr comp,int ch1,int ch2,xmlXPathOp op,int value,int value2,int value3,void * value4,void * value5)1088 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
1089    xmlXPathOp op, int value,
1090    int value2, int value3, void *value4, void *value5) {
1091     if (comp->nbStep >= comp->maxStep) {
1092 	xmlXPathStepOp *real;
1093 
1094         if (comp->maxStep >= XPATH_MAX_STEPS) {
1095 	    xmlXPathErrMemory(NULL, "adding step\n");
1096 	    return(-1);
1097         }
1098 	comp->maxStep *= 2;
1099 	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1100 		                      comp->maxStep * sizeof(xmlXPathStepOp));
1101 	if (real == NULL) {
1102 	    comp->maxStep /= 2;
1103 	    xmlXPathErrMemory(NULL, "adding step\n");
1104 	    return(-1);
1105 	}
1106 	comp->steps = real;
1107     }
1108     comp->last = comp->nbStep;
1109     comp->steps[comp->nbStep].ch1 = ch1;
1110     comp->steps[comp->nbStep].ch2 = ch2;
1111     comp->steps[comp->nbStep].op = op;
1112     comp->steps[comp->nbStep].value = value;
1113     comp->steps[comp->nbStep].value2 = value2;
1114     comp->steps[comp->nbStep].value3 = value3;
1115     if ((comp->dict != NULL) &&
1116         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1117 	 (op == XPATH_OP_COLLECT))) {
1118         if (value4 != NULL) {
1119 	    comp->steps[comp->nbStep].value4 = (xmlChar *)
1120 	        (void *)xmlDictLookup(comp->dict, value4, -1);
1121 	    xmlFree(value4);
1122 	} else
1123 	    comp->steps[comp->nbStep].value4 = NULL;
1124         if (value5 != NULL) {
1125 	    comp->steps[comp->nbStep].value5 = (xmlChar *)
1126 	        (void *)xmlDictLookup(comp->dict, value5, -1);
1127 	    xmlFree(value5);
1128 	} else
1129 	    comp->steps[comp->nbStep].value5 = NULL;
1130     } else {
1131 	comp->steps[comp->nbStep].value4 = value4;
1132 	comp->steps[comp->nbStep].value5 = value5;
1133     }
1134     comp->steps[comp->nbStep].cache = NULL;
1135     return(comp->nbStep++);
1136 }
1137 
1138 /**
1139  * xmlXPathCompSwap:
1140  * @comp:  the compiled expression
1141  * @op: operation index
1142  *
1143  * Swaps 2 operations in the compiled expression
1144  */
1145 static void
xmlXPathCompSwap(xmlXPathStepOpPtr op)1146 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1147     int tmp;
1148 
1149 #ifndef LIBXML_THREAD_ENABLED
1150     /*
1151      * Since this manipulates possibly shared variables, this is
1152      * disabled if one detects that the library is used in a multithreaded
1153      * application
1154      */
1155     if (xmlXPathDisableOptimizer)
1156 	return;
1157 #endif
1158 
1159     tmp = op->ch1;
1160     op->ch1 = op->ch2;
1161     op->ch2 = tmp;
1162 }
1163 
1164 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
1165     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\
1166 	                (op), (val), (val2), (val3), (val4), (val5))
1167 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
1168     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\
1169 	                (op), (val), (val2), (val3), (val4), (val5))
1170 
1171 #define PUSH_LEAVE_EXPR(op, val, val2)					\
1172 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1173 
1174 #define PUSH_UNARY_EXPR(op, ch, val, val2)				\
1175 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1176 
1177 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
1178 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\
1179 			(val), (val2), 0 ,NULL ,NULL)
1180 
1181 /************************************************************************
1182  *									*
1183  *		XPath object cache structures				*
1184  *									*
1185  ************************************************************************/
1186 
1187 /* #define XP_DEFAULT_CACHE_ON */
1188 
1189 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1190 
1191 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1192 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1193 struct _xmlXPathContextCache {
1194     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1195     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1196     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1197     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1198     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1199     int maxNodeset;
1200     int maxString;
1201     int maxBoolean;
1202     int maxNumber;
1203     int maxMisc;
1204 #ifdef XP_DEBUG_OBJ_USAGE
1205     int dbgCachedAll;
1206     int dbgCachedNodeset;
1207     int dbgCachedString;
1208     int dbgCachedBool;
1209     int dbgCachedNumber;
1210     int dbgCachedPoint;
1211     int dbgCachedRange;
1212     int dbgCachedLocset;
1213     int dbgCachedUsers;
1214     int dbgCachedXSLTTree;
1215     int dbgCachedUndefined;
1216 
1217 
1218     int dbgReusedAll;
1219     int dbgReusedNodeset;
1220     int dbgReusedString;
1221     int dbgReusedBool;
1222     int dbgReusedNumber;
1223     int dbgReusedPoint;
1224     int dbgReusedRange;
1225     int dbgReusedLocset;
1226     int dbgReusedUsers;
1227     int dbgReusedXSLTTree;
1228     int dbgReusedUndefined;
1229 
1230 #endif
1231 };
1232 
1233 /************************************************************************
1234  *									*
1235  *		Debugging related functions				*
1236  *									*
1237  ************************************************************************/
1238 
1239 #define STRANGE							\
1240     xmlGenericError(xmlGenericErrorContext,				\
1241 	    "Internal error at %s:%d\n",				\
1242             __FILE__, __LINE__);
1243 
1244 #ifdef LIBXML_DEBUG_ENABLED
1245 static void
xmlXPathDebugDumpNode(FILE * output,xmlNodePtr cur,int depth)1246 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1247     int i;
1248     char shift[100];
1249 
1250     for (i = 0;((i < depth) && (i < 25));i++)
1251         shift[2 * i] = shift[2 * i + 1] = ' ';
1252     shift[2 * i] = shift[2 * i + 1] = 0;
1253     if (cur == NULL) {
1254 	fprintf(output, "%s", shift);
1255 	fprintf(output, "Node is NULL !\n");
1256 	return;
1257 
1258     }
1259 
1260     if ((cur->type == XML_DOCUMENT_NODE) ||
1261 	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
1262 	fprintf(output, "%s", shift);
1263 	fprintf(output, " /\n");
1264     } else if (cur->type == XML_ATTRIBUTE_NODE)
1265 	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1266     else
1267 	xmlDebugDumpOneNode(output, cur, depth);
1268 }
1269 static void
xmlXPathDebugDumpNodeList(FILE * output,xmlNodePtr cur,int depth)1270 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1271     xmlNodePtr tmp;
1272     int i;
1273     char shift[100];
1274 
1275     for (i = 0;((i < depth) && (i < 25));i++)
1276         shift[2 * i] = shift[2 * i + 1] = ' ';
1277     shift[2 * i] = shift[2 * i + 1] = 0;
1278     if (cur == NULL) {
1279 	fprintf(output, "%s", shift);
1280 	fprintf(output, "Node is NULL !\n");
1281 	return;
1282 
1283     }
1284 
1285     while (cur != NULL) {
1286 	tmp = cur;
1287 	cur = cur->next;
1288 	xmlDebugDumpOneNode(output, tmp, depth);
1289     }
1290 }
1291 
1292 static void
xmlXPathDebugDumpNodeSet(FILE * output,xmlNodeSetPtr cur,int depth)1293 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1294     int i;
1295     char shift[100];
1296 
1297     for (i = 0;((i < depth) && (i < 25));i++)
1298         shift[2 * i] = shift[2 * i + 1] = ' ';
1299     shift[2 * i] = shift[2 * i + 1] = 0;
1300 
1301     if (cur == NULL) {
1302 	fprintf(output, "%s", shift);
1303 	fprintf(output, "NodeSet is NULL !\n");
1304 	return;
1305 
1306     }
1307 
1308     if (cur != NULL) {
1309 	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1310 	for (i = 0;i < cur->nodeNr;i++) {
1311 	    fprintf(output, "%s", shift);
1312 	    fprintf(output, "%d", i + 1);
1313 	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1314 	}
1315     }
1316 }
1317 
1318 static void
xmlXPathDebugDumpValueTree(FILE * output,xmlNodeSetPtr cur,int depth)1319 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1320     int i;
1321     char shift[100];
1322 
1323     for (i = 0;((i < depth) && (i < 25));i++)
1324         shift[2 * i] = shift[2 * i + 1] = ' ';
1325     shift[2 * i] = shift[2 * i + 1] = 0;
1326 
1327     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1328 	fprintf(output, "%s", shift);
1329 	fprintf(output, "Value Tree is NULL !\n");
1330 	return;
1331 
1332     }
1333 
1334     fprintf(output, "%s", shift);
1335     fprintf(output, "%d", i + 1);
1336     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1337 }
1338 #if defined(LIBXML_XPTR_ENABLED)
1339 static void
xmlXPathDebugDumpLocationSet(FILE * output,xmlLocationSetPtr cur,int depth)1340 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1341     int i;
1342     char shift[100];
1343 
1344     for (i = 0;((i < depth) && (i < 25));i++)
1345         shift[2 * i] = shift[2 * i + 1] = ' ';
1346     shift[2 * i] = shift[2 * i + 1] = 0;
1347 
1348     if (cur == NULL) {
1349 	fprintf(output, "%s", shift);
1350 	fprintf(output, "LocationSet is NULL !\n");
1351 	return;
1352 
1353     }
1354 
1355     for (i = 0;i < cur->locNr;i++) {
1356 	fprintf(output, "%s", shift);
1357         fprintf(output, "%d : ", i + 1);
1358 	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1359     }
1360 }
1361 #endif /* LIBXML_XPTR_ENABLED */
1362 
1363 /**
1364  * xmlXPathDebugDumpObject:
1365  * @output:  the FILE * to dump the output
1366  * @cur:  the object to inspect
1367  * @depth:  indentation level
1368  *
1369  * Dump the content of the object for debugging purposes
1370  */
1371 void
xmlXPathDebugDumpObject(FILE * output,xmlXPathObjectPtr cur,int depth)1372 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1373     int i;
1374     char shift[100];
1375 
1376     if (output == NULL) return;
1377 
1378     for (i = 0;((i < depth) && (i < 25));i++)
1379         shift[2 * i] = shift[2 * i + 1] = ' ';
1380     shift[2 * i] = shift[2 * i + 1] = 0;
1381 
1382 
1383     fprintf(output, "%s", shift);
1384 
1385     if (cur == NULL) {
1386         fprintf(output, "Object is empty (NULL)\n");
1387 	return;
1388     }
1389     switch(cur->type) {
1390         case XPATH_UNDEFINED:
1391 	    fprintf(output, "Object is uninitialized\n");
1392 	    break;
1393         case XPATH_NODESET:
1394 	    fprintf(output, "Object is a Node Set :\n");
1395 	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1396 	    break;
1397 	case XPATH_XSLT_TREE:
1398 	    fprintf(output, "Object is an XSLT value tree :\n");
1399 	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1400 	    break;
1401         case XPATH_BOOLEAN:
1402 	    fprintf(output, "Object is a Boolean : ");
1403 	    if (cur->boolval) fprintf(output, "true\n");
1404 	    else fprintf(output, "false\n");
1405 	    break;
1406         case XPATH_NUMBER:
1407 	    switch (xmlXPathIsInf(cur->floatval)) {
1408 	    case 1:
1409 		fprintf(output, "Object is a number : Infinity\n");
1410 		break;
1411 	    case -1:
1412 		fprintf(output, "Object is a number : -Infinity\n");
1413 		break;
1414 	    default:
1415 		if (xmlXPathIsNaN(cur->floatval)) {
1416 		    fprintf(output, "Object is a number : NaN\n");
1417 		} else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1418 		    fprintf(output, "Object is a number : 0\n");
1419 		} else {
1420 		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
1421 		}
1422 	    }
1423 	    break;
1424         case XPATH_STRING:
1425 	    fprintf(output, "Object is a string : ");
1426 	    xmlDebugDumpString(output, cur->stringval);
1427 	    fprintf(output, "\n");
1428 	    break;
1429 	case XPATH_POINT:
1430 	    fprintf(output, "Object is a point : index %d in node", cur->index);
1431 	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1432 	    fprintf(output, "\n");
1433 	    break;
1434 	case XPATH_RANGE:
1435 	    if ((cur->user2 == NULL) ||
1436 		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1437 		fprintf(output, "Object is a collapsed range :\n");
1438 		fprintf(output, "%s", shift);
1439 		if (cur->index >= 0)
1440 		    fprintf(output, "index %d in ", cur->index);
1441 		fprintf(output, "node\n");
1442 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1443 			              depth + 1);
1444 	    } else  {
1445 		fprintf(output, "Object is a range :\n");
1446 		fprintf(output, "%s", shift);
1447 		fprintf(output, "From ");
1448 		if (cur->index >= 0)
1449 		    fprintf(output, "index %d in ", cur->index);
1450 		fprintf(output, "node\n");
1451 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1452 			              depth + 1);
1453 		fprintf(output, "%s", shift);
1454 		fprintf(output, "To ");
1455 		if (cur->index2 >= 0)
1456 		    fprintf(output, "index %d in ", cur->index2);
1457 		fprintf(output, "node\n");
1458 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1459 			              depth + 1);
1460 		fprintf(output, "\n");
1461 	    }
1462 	    break;
1463 	case XPATH_LOCATIONSET:
1464 #if defined(LIBXML_XPTR_ENABLED)
1465 	    fprintf(output, "Object is a Location Set:\n");
1466 	    xmlXPathDebugDumpLocationSet(output,
1467 		    (xmlLocationSetPtr) cur->user, depth);
1468 #endif
1469 	    break;
1470 	case XPATH_USERS:
1471 	    fprintf(output, "Object is user defined\n");
1472 	    break;
1473     }
1474 }
1475 
1476 static void
xmlXPathDebugDumpStepOp(FILE * output,xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op,int depth)1477 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1478 	                     xmlXPathStepOpPtr op, int depth) {
1479     int i;
1480     char shift[100];
1481 
1482     for (i = 0;((i < depth) && (i < 25));i++)
1483         shift[2 * i] = shift[2 * i + 1] = ' ';
1484     shift[2 * i] = shift[2 * i + 1] = 0;
1485 
1486     fprintf(output, "%s", shift);
1487     if (op == NULL) {
1488 	fprintf(output, "Step is NULL\n");
1489 	return;
1490     }
1491     switch (op->op) {
1492         case XPATH_OP_END:
1493 	    fprintf(output, "END"); break;
1494         case XPATH_OP_AND:
1495 	    fprintf(output, "AND"); break;
1496         case XPATH_OP_OR:
1497 	    fprintf(output, "OR"); break;
1498         case XPATH_OP_EQUAL:
1499 	     if (op->value)
1500 		 fprintf(output, "EQUAL =");
1501 	     else
1502 		 fprintf(output, "EQUAL !=");
1503 	     break;
1504         case XPATH_OP_CMP:
1505 	     if (op->value)
1506 		 fprintf(output, "CMP <");
1507 	     else
1508 		 fprintf(output, "CMP >");
1509 	     if (!op->value2)
1510 		 fprintf(output, "=");
1511 	     break;
1512         case XPATH_OP_PLUS:
1513 	     if (op->value == 0)
1514 		 fprintf(output, "PLUS -");
1515 	     else if (op->value == 1)
1516 		 fprintf(output, "PLUS +");
1517 	     else if (op->value == 2)
1518 		 fprintf(output, "PLUS unary -");
1519 	     else if (op->value == 3)
1520 		 fprintf(output, "PLUS unary - -");
1521 	     break;
1522         case XPATH_OP_MULT:
1523 	     if (op->value == 0)
1524 		 fprintf(output, "MULT *");
1525 	     else if (op->value == 1)
1526 		 fprintf(output, "MULT div");
1527 	     else
1528 		 fprintf(output, "MULT mod");
1529 	     break;
1530         case XPATH_OP_UNION:
1531 	     fprintf(output, "UNION"); break;
1532         case XPATH_OP_ROOT:
1533 	     fprintf(output, "ROOT"); break;
1534         case XPATH_OP_NODE:
1535 	     fprintf(output, "NODE"); break;
1536         case XPATH_OP_RESET:
1537 	     fprintf(output, "RESET"); break;
1538         case XPATH_OP_SORT:
1539 	     fprintf(output, "SORT"); break;
1540         case XPATH_OP_COLLECT: {
1541 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1542 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1543 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1544 	    const xmlChar *prefix = op->value4;
1545 	    const xmlChar *name = op->value5;
1546 
1547 	    fprintf(output, "COLLECT ");
1548 	    switch (axis) {
1549 		case AXIS_ANCESTOR:
1550 		    fprintf(output, " 'ancestors' "); break;
1551 		case AXIS_ANCESTOR_OR_SELF:
1552 		    fprintf(output, " 'ancestors-or-self' "); break;
1553 		case AXIS_ATTRIBUTE:
1554 		    fprintf(output, " 'attributes' "); break;
1555 		case AXIS_CHILD:
1556 		    fprintf(output, " 'child' "); break;
1557 		case AXIS_DESCENDANT:
1558 		    fprintf(output, " 'descendant' "); break;
1559 		case AXIS_DESCENDANT_OR_SELF:
1560 		    fprintf(output, " 'descendant-or-self' "); break;
1561 		case AXIS_FOLLOWING:
1562 		    fprintf(output, " 'following' "); break;
1563 		case AXIS_FOLLOWING_SIBLING:
1564 		    fprintf(output, " 'following-siblings' "); break;
1565 		case AXIS_NAMESPACE:
1566 		    fprintf(output, " 'namespace' "); break;
1567 		case AXIS_PARENT:
1568 		    fprintf(output, " 'parent' "); break;
1569 		case AXIS_PRECEDING:
1570 		    fprintf(output, " 'preceding' "); break;
1571 		case AXIS_PRECEDING_SIBLING:
1572 		    fprintf(output, " 'preceding-sibling' "); break;
1573 		case AXIS_SELF:
1574 		    fprintf(output, " 'self' "); break;
1575 	    }
1576 	    switch (test) {
1577                 case NODE_TEST_NONE:
1578 		    fprintf(output, "'none' "); break;
1579                 case NODE_TEST_TYPE:
1580 		    fprintf(output, "'type' "); break;
1581                 case NODE_TEST_PI:
1582 		    fprintf(output, "'PI' "); break;
1583                 case NODE_TEST_ALL:
1584 		    fprintf(output, "'all' "); break;
1585                 case NODE_TEST_NS:
1586 		    fprintf(output, "'namespace' "); break;
1587                 case NODE_TEST_NAME:
1588 		    fprintf(output, "'name' "); break;
1589 	    }
1590 	    switch (type) {
1591                 case NODE_TYPE_NODE:
1592 		    fprintf(output, "'node' "); break;
1593                 case NODE_TYPE_COMMENT:
1594 		    fprintf(output, "'comment' "); break;
1595                 case NODE_TYPE_TEXT:
1596 		    fprintf(output, "'text' "); break;
1597                 case NODE_TYPE_PI:
1598 		    fprintf(output, "'PI' "); break;
1599 	    }
1600 	    if (prefix != NULL)
1601 		fprintf(output, "%s:", prefix);
1602 	    if (name != NULL)
1603 		fprintf(output, "%s", (const char *) name);
1604 	    break;
1605 
1606         }
1607 	case XPATH_OP_VALUE: {
1608 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1609 
1610 	    fprintf(output, "ELEM ");
1611 	    xmlXPathDebugDumpObject(output, object, 0);
1612 	    goto finish;
1613 	}
1614 	case XPATH_OP_VARIABLE: {
1615 	    const xmlChar *prefix = op->value5;
1616 	    const xmlChar *name = op->value4;
1617 
1618 	    if (prefix != NULL)
1619 		fprintf(output, "VARIABLE %s:%s", prefix, name);
1620 	    else
1621 		fprintf(output, "VARIABLE %s", name);
1622 	    break;
1623 	}
1624 	case XPATH_OP_FUNCTION: {
1625 	    int nbargs = op->value;
1626 	    const xmlChar *prefix = op->value5;
1627 	    const xmlChar *name = op->value4;
1628 
1629 	    if (prefix != NULL)
1630 		fprintf(output, "FUNCTION %s:%s(%d args)",
1631 			prefix, name, nbargs);
1632 	    else
1633 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1634 	    break;
1635 	}
1636         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1637         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1638         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1639 #ifdef LIBXML_XPTR_ENABLED
1640         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1641 #endif
1642 	default:
1643         fprintf(output, "UNKNOWN %d\n", op->op); return;
1644     }
1645     fprintf(output, "\n");
1646 finish:
1647     if (op->ch1 >= 0)
1648 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1649     if (op->ch2 >= 0)
1650 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1651 }
1652 
1653 /**
1654  * xmlXPathDebugDumpCompExpr:
1655  * @output:  the FILE * for the output
1656  * @comp:  the precompiled XPath expression
1657  * @depth:  the indentation level.
1658  *
1659  * Dumps the tree of the compiled XPath expression.
1660  */
1661 void
xmlXPathDebugDumpCompExpr(FILE * output,xmlXPathCompExprPtr comp,int depth)1662 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1663 	                  int depth) {
1664     int i;
1665     char shift[100];
1666 
1667     if ((output == NULL) || (comp == NULL)) return;
1668 
1669     for (i = 0;((i < depth) && (i < 25));i++)
1670         shift[2 * i] = shift[2 * i + 1] = ' ';
1671     shift[2 * i] = shift[2 * i + 1] = 0;
1672 
1673     fprintf(output, "%s", shift);
1674 
1675     fprintf(output, "Compiled Expression : %d elements\n",
1676 	    comp->nbStep);
1677     i = comp->last;
1678     xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1679 }
1680 
1681 #ifdef XP_DEBUG_OBJ_USAGE
1682 
1683 /*
1684 * XPath object usage related debugging variables.
1685 */
1686 static int xmlXPathDebugObjCounterUndefined = 0;
1687 static int xmlXPathDebugObjCounterNodeset = 0;
1688 static int xmlXPathDebugObjCounterBool = 0;
1689 static int xmlXPathDebugObjCounterNumber = 0;
1690 static int xmlXPathDebugObjCounterString = 0;
1691 static int xmlXPathDebugObjCounterPoint = 0;
1692 static int xmlXPathDebugObjCounterRange = 0;
1693 static int xmlXPathDebugObjCounterLocset = 0;
1694 static int xmlXPathDebugObjCounterUsers = 0;
1695 static int xmlXPathDebugObjCounterXSLTTree = 0;
1696 static int xmlXPathDebugObjCounterAll = 0;
1697 
1698 static int xmlXPathDebugObjTotalUndefined = 0;
1699 static int xmlXPathDebugObjTotalNodeset = 0;
1700 static int xmlXPathDebugObjTotalBool = 0;
1701 static int xmlXPathDebugObjTotalNumber = 0;
1702 static int xmlXPathDebugObjTotalString = 0;
1703 static int xmlXPathDebugObjTotalPoint = 0;
1704 static int xmlXPathDebugObjTotalRange = 0;
1705 static int xmlXPathDebugObjTotalLocset = 0;
1706 static int xmlXPathDebugObjTotalUsers = 0;
1707 static int xmlXPathDebugObjTotalXSLTTree = 0;
1708 static int xmlXPathDebugObjTotalAll = 0;
1709 
1710 static int xmlXPathDebugObjMaxUndefined = 0;
1711 static int xmlXPathDebugObjMaxNodeset = 0;
1712 static int xmlXPathDebugObjMaxBool = 0;
1713 static int xmlXPathDebugObjMaxNumber = 0;
1714 static int xmlXPathDebugObjMaxString = 0;
1715 static int xmlXPathDebugObjMaxPoint = 0;
1716 static int xmlXPathDebugObjMaxRange = 0;
1717 static int xmlXPathDebugObjMaxLocset = 0;
1718 static int xmlXPathDebugObjMaxUsers = 0;
1719 static int xmlXPathDebugObjMaxXSLTTree = 0;
1720 static int xmlXPathDebugObjMaxAll = 0;
1721 
1722 /* REVISIT TODO: Make this static when committing */
1723 static void
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)1724 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1725 {
1726     if (ctxt != NULL) {
1727 	if (ctxt->cache != NULL) {
1728 	    xmlXPathContextCachePtr cache =
1729 		(xmlXPathContextCachePtr) ctxt->cache;
1730 
1731 	    cache->dbgCachedAll = 0;
1732 	    cache->dbgCachedNodeset = 0;
1733 	    cache->dbgCachedString = 0;
1734 	    cache->dbgCachedBool = 0;
1735 	    cache->dbgCachedNumber = 0;
1736 	    cache->dbgCachedPoint = 0;
1737 	    cache->dbgCachedRange = 0;
1738 	    cache->dbgCachedLocset = 0;
1739 	    cache->dbgCachedUsers = 0;
1740 	    cache->dbgCachedXSLTTree = 0;
1741 	    cache->dbgCachedUndefined = 0;
1742 
1743 	    cache->dbgReusedAll = 0;
1744 	    cache->dbgReusedNodeset = 0;
1745 	    cache->dbgReusedString = 0;
1746 	    cache->dbgReusedBool = 0;
1747 	    cache->dbgReusedNumber = 0;
1748 	    cache->dbgReusedPoint = 0;
1749 	    cache->dbgReusedRange = 0;
1750 	    cache->dbgReusedLocset = 0;
1751 	    cache->dbgReusedUsers = 0;
1752 	    cache->dbgReusedXSLTTree = 0;
1753 	    cache->dbgReusedUndefined = 0;
1754 	}
1755     }
1756 
1757     xmlXPathDebugObjCounterUndefined = 0;
1758     xmlXPathDebugObjCounterNodeset = 0;
1759     xmlXPathDebugObjCounterBool = 0;
1760     xmlXPathDebugObjCounterNumber = 0;
1761     xmlXPathDebugObjCounterString = 0;
1762     xmlXPathDebugObjCounterPoint = 0;
1763     xmlXPathDebugObjCounterRange = 0;
1764     xmlXPathDebugObjCounterLocset = 0;
1765     xmlXPathDebugObjCounterUsers = 0;
1766     xmlXPathDebugObjCounterXSLTTree = 0;
1767     xmlXPathDebugObjCounterAll = 0;
1768 
1769     xmlXPathDebugObjTotalUndefined = 0;
1770     xmlXPathDebugObjTotalNodeset = 0;
1771     xmlXPathDebugObjTotalBool = 0;
1772     xmlXPathDebugObjTotalNumber = 0;
1773     xmlXPathDebugObjTotalString = 0;
1774     xmlXPathDebugObjTotalPoint = 0;
1775     xmlXPathDebugObjTotalRange = 0;
1776     xmlXPathDebugObjTotalLocset = 0;
1777     xmlXPathDebugObjTotalUsers = 0;
1778     xmlXPathDebugObjTotalXSLTTree = 0;
1779     xmlXPathDebugObjTotalAll = 0;
1780 
1781     xmlXPathDebugObjMaxUndefined = 0;
1782     xmlXPathDebugObjMaxNodeset = 0;
1783     xmlXPathDebugObjMaxBool = 0;
1784     xmlXPathDebugObjMaxNumber = 0;
1785     xmlXPathDebugObjMaxString = 0;
1786     xmlXPathDebugObjMaxPoint = 0;
1787     xmlXPathDebugObjMaxRange = 0;
1788     xmlXPathDebugObjMaxLocset = 0;
1789     xmlXPathDebugObjMaxUsers = 0;
1790     xmlXPathDebugObjMaxXSLTTree = 0;
1791     xmlXPathDebugObjMaxAll = 0;
1792 
1793 }
1794 
1795 static void
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,xmlXPathObjectType objType)1796 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1797 			      xmlXPathObjectType objType)
1798 {
1799     int isCached = 0;
1800 
1801     if (ctxt != NULL) {
1802 	if (ctxt->cache != NULL) {
1803 	    xmlXPathContextCachePtr cache =
1804 		(xmlXPathContextCachePtr) ctxt->cache;
1805 
1806 	    isCached = 1;
1807 
1808 	    cache->dbgReusedAll++;
1809 	    switch (objType) {
1810 		case XPATH_UNDEFINED:
1811 		    cache->dbgReusedUndefined++;
1812 		    break;
1813 		case XPATH_NODESET:
1814 		    cache->dbgReusedNodeset++;
1815 		    break;
1816 		case XPATH_BOOLEAN:
1817 		    cache->dbgReusedBool++;
1818 		    break;
1819 		case XPATH_NUMBER:
1820 		    cache->dbgReusedNumber++;
1821 		    break;
1822 		case XPATH_STRING:
1823 		    cache->dbgReusedString++;
1824 		    break;
1825 		case XPATH_POINT:
1826 		    cache->dbgReusedPoint++;
1827 		    break;
1828 		case XPATH_RANGE:
1829 		    cache->dbgReusedRange++;
1830 		    break;
1831 		case XPATH_LOCATIONSET:
1832 		    cache->dbgReusedLocset++;
1833 		    break;
1834 		case XPATH_USERS:
1835 		    cache->dbgReusedUsers++;
1836 		    break;
1837 		case XPATH_XSLT_TREE:
1838 		    cache->dbgReusedXSLTTree++;
1839 		    break;
1840 		default:
1841 		    break;
1842 	    }
1843 	}
1844     }
1845 
1846     switch (objType) {
1847 	case XPATH_UNDEFINED:
1848 	    if (! isCached)
1849 		xmlXPathDebugObjTotalUndefined++;
1850 	    xmlXPathDebugObjCounterUndefined++;
1851 	    if (xmlXPathDebugObjCounterUndefined >
1852 		xmlXPathDebugObjMaxUndefined)
1853 		xmlXPathDebugObjMaxUndefined =
1854 		    xmlXPathDebugObjCounterUndefined;
1855 	    break;
1856 	case XPATH_NODESET:
1857 	    if (! isCached)
1858 		xmlXPathDebugObjTotalNodeset++;
1859 	    xmlXPathDebugObjCounterNodeset++;
1860 	    if (xmlXPathDebugObjCounterNodeset >
1861 		xmlXPathDebugObjMaxNodeset)
1862 		xmlXPathDebugObjMaxNodeset =
1863 		    xmlXPathDebugObjCounterNodeset;
1864 	    break;
1865 	case XPATH_BOOLEAN:
1866 	    if (! isCached)
1867 		xmlXPathDebugObjTotalBool++;
1868 	    xmlXPathDebugObjCounterBool++;
1869 	    if (xmlXPathDebugObjCounterBool >
1870 		xmlXPathDebugObjMaxBool)
1871 		xmlXPathDebugObjMaxBool =
1872 		    xmlXPathDebugObjCounterBool;
1873 	    break;
1874 	case XPATH_NUMBER:
1875 	    if (! isCached)
1876 		xmlXPathDebugObjTotalNumber++;
1877 	    xmlXPathDebugObjCounterNumber++;
1878 	    if (xmlXPathDebugObjCounterNumber >
1879 		xmlXPathDebugObjMaxNumber)
1880 		xmlXPathDebugObjMaxNumber =
1881 		    xmlXPathDebugObjCounterNumber;
1882 	    break;
1883 	case XPATH_STRING:
1884 	    if (! isCached)
1885 		xmlXPathDebugObjTotalString++;
1886 	    xmlXPathDebugObjCounterString++;
1887 	    if (xmlXPathDebugObjCounterString >
1888 		xmlXPathDebugObjMaxString)
1889 		xmlXPathDebugObjMaxString =
1890 		    xmlXPathDebugObjCounterString;
1891 	    break;
1892 	case XPATH_POINT:
1893 	    if (! isCached)
1894 		xmlXPathDebugObjTotalPoint++;
1895 	    xmlXPathDebugObjCounterPoint++;
1896 	    if (xmlXPathDebugObjCounterPoint >
1897 		xmlXPathDebugObjMaxPoint)
1898 		xmlXPathDebugObjMaxPoint =
1899 		    xmlXPathDebugObjCounterPoint;
1900 	    break;
1901 	case XPATH_RANGE:
1902 	    if (! isCached)
1903 		xmlXPathDebugObjTotalRange++;
1904 	    xmlXPathDebugObjCounterRange++;
1905 	    if (xmlXPathDebugObjCounterRange >
1906 		xmlXPathDebugObjMaxRange)
1907 		xmlXPathDebugObjMaxRange =
1908 		    xmlXPathDebugObjCounterRange;
1909 	    break;
1910 	case XPATH_LOCATIONSET:
1911 	    if (! isCached)
1912 		xmlXPathDebugObjTotalLocset++;
1913 	    xmlXPathDebugObjCounterLocset++;
1914 	    if (xmlXPathDebugObjCounterLocset >
1915 		xmlXPathDebugObjMaxLocset)
1916 		xmlXPathDebugObjMaxLocset =
1917 		    xmlXPathDebugObjCounterLocset;
1918 	    break;
1919 	case XPATH_USERS:
1920 	    if (! isCached)
1921 		xmlXPathDebugObjTotalUsers++;
1922 	    xmlXPathDebugObjCounterUsers++;
1923 	    if (xmlXPathDebugObjCounterUsers >
1924 		xmlXPathDebugObjMaxUsers)
1925 		xmlXPathDebugObjMaxUsers =
1926 		    xmlXPathDebugObjCounterUsers;
1927 	    break;
1928 	case XPATH_XSLT_TREE:
1929 	    if (! isCached)
1930 		xmlXPathDebugObjTotalXSLTTree++;
1931 	    xmlXPathDebugObjCounterXSLTTree++;
1932 	    if (xmlXPathDebugObjCounterXSLTTree >
1933 		xmlXPathDebugObjMaxXSLTTree)
1934 		xmlXPathDebugObjMaxXSLTTree =
1935 		    xmlXPathDebugObjCounterXSLTTree;
1936 	    break;
1937 	default:
1938 	    break;
1939     }
1940     if (! isCached)
1941 	xmlXPathDebugObjTotalAll++;
1942     xmlXPathDebugObjCounterAll++;
1943     if (xmlXPathDebugObjCounterAll >
1944 	xmlXPathDebugObjMaxAll)
1945 	xmlXPathDebugObjMaxAll =
1946 	    xmlXPathDebugObjCounterAll;
1947 }
1948 
1949 static void
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,xmlXPathObjectType objType)1950 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1951 			      xmlXPathObjectType objType)
1952 {
1953     int isCached = 0;
1954 
1955     if (ctxt != NULL) {
1956 	if (ctxt->cache != NULL) {
1957 	    xmlXPathContextCachePtr cache =
1958 		(xmlXPathContextCachePtr) ctxt->cache;
1959 
1960 	    isCached = 1;
1961 
1962 	    cache->dbgCachedAll++;
1963 	    switch (objType) {
1964 		case XPATH_UNDEFINED:
1965 		    cache->dbgCachedUndefined++;
1966 		    break;
1967 		case XPATH_NODESET:
1968 		    cache->dbgCachedNodeset++;
1969 		    break;
1970 		case XPATH_BOOLEAN:
1971 		    cache->dbgCachedBool++;
1972 		    break;
1973 		case XPATH_NUMBER:
1974 		    cache->dbgCachedNumber++;
1975 		    break;
1976 		case XPATH_STRING:
1977 		    cache->dbgCachedString++;
1978 		    break;
1979 		case XPATH_POINT:
1980 		    cache->dbgCachedPoint++;
1981 		    break;
1982 		case XPATH_RANGE:
1983 		    cache->dbgCachedRange++;
1984 		    break;
1985 		case XPATH_LOCATIONSET:
1986 		    cache->dbgCachedLocset++;
1987 		    break;
1988 		case XPATH_USERS:
1989 		    cache->dbgCachedUsers++;
1990 		    break;
1991 		case XPATH_XSLT_TREE:
1992 		    cache->dbgCachedXSLTTree++;
1993 		    break;
1994 		default:
1995 		    break;
1996 	    }
1997 
1998 	}
1999     }
2000     switch (objType) {
2001 	case XPATH_UNDEFINED:
2002 	    xmlXPathDebugObjCounterUndefined--;
2003 	    break;
2004 	case XPATH_NODESET:
2005 	    xmlXPathDebugObjCounterNodeset--;
2006 	    break;
2007 	case XPATH_BOOLEAN:
2008 	    xmlXPathDebugObjCounterBool--;
2009 	    break;
2010 	case XPATH_NUMBER:
2011 	    xmlXPathDebugObjCounterNumber--;
2012 	    break;
2013 	case XPATH_STRING:
2014 	    xmlXPathDebugObjCounterString--;
2015 	    break;
2016 	case XPATH_POINT:
2017 	    xmlXPathDebugObjCounterPoint--;
2018 	    break;
2019 	case XPATH_RANGE:
2020 	    xmlXPathDebugObjCounterRange--;
2021 	    break;
2022 	case XPATH_LOCATIONSET:
2023 	    xmlXPathDebugObjCounterLocset--;
2024 	    break;
2025 	case XPATH_USERS:
2026 	    xmlXPathDebugObjCounterUsers--;
2027 	    break;
2028 	case XPATH_XSLT_TREE:
2029 	    xmlXPathDebugObjCounterXSLTTree--;
2030 	    break;
2031 	default:
2032 	    break;
2033     }
2034     xmlXPathDebugObjCounterAll--;
2035 }
2036 
2037 /* REVISIT TODO: Make this static when committing */
2038 static void
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)2039 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2040 {
2041     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2042 	reqXSLTTree, reqUndefined;
2043     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2044 	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2045     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2046 	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2047     int leftObjs = xmlXPathDebugObjCounterAll;
2048 
2049     reqAll = xmlXPathDebugObjTotalAll;
2050     reqNodeset = xmlXPathDebugObjTotalNodeset;
2051     reqString = xmlXPathDebugObjTotalString;
2052     reqBool = xmlXPathDebugObjTotalBool;
2053     reqNumber = xmlXPathDebugObjTotalNumber;
2054     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2055     reqUndefined = xmlXPathDebugObjTotalUndefined;
2056 
2057     printf("# XPath object usage:\n");
2058 
2059     if (ctxt != NULL) {
2060 	if (ctxt->cache != NULL) {
2061 	    xmlXPathContextCachePtr cache =
2062 		(xmlXPathContextCachePtr) ctxt->cache;
2063 
2064 	    reAll = cache->dbgReusedAll;
2065 	    reqAll += reAll;
2066 	    reNodeset = cache->dbgReusedNodeset;
2067 	    reqNodeset += reNodeset;
2068 	    reString = cache->dbgReusedString;
2069 	    reqString += reString;
2070 	    reBool = cache->dbgReusedBool;
2071 	    reqBool += reBool;
2072 	    reNumber = cache->dbgReusedNumber;
2073 	    reqNumber += reNumber;
2074 	    reXSLTTree = cache->dbgReusedXSLTTree;
2075 	    reqXSLTTree += reXSLTTree;
2076 	    reUndefined = cache->dbgReusedUndefined;
2077 	    reqUndefined += reUndefined;
2078 
2079 	    caAll = cache->dbgCachedAll;
2080 	    caBool = cache->dbgCachedBool;
2081 	    caNodeset = cache->dbgCachedNodeset;
2082 	    caString = cache->dbgCachedString;
2083 	    caNumber = cache->dbgCachedNumber;
2084 	    caXSLTTree = cache->dbgCachedXSLTTree;
2085 	    caUndefined = cache->dbgCachedUndefined;
2086 
2087 	    if (cache->nodesetObjs)
2088 		leftObjs -= cache->nodesetObjs->number;
2089 	    if (cache->stringObjs)
2090 		leftObjs -= cache->stringObjs->number;
2091 	    if (cache->booleanObjs)
2092 		leftObjs -= cache->booleanObjs->number;
2093 	    if (cache->numberObjs)
2094 		leftObjs -= cache->numberObjs->number;
2095 	    if (cache->miscObjs)
2096 		leftObjs -= cache->miscObjs->number;
2097 	}
2098     }
2099 
2100     printf("# all\n");
2101     printf("#   total  : %d\n", reqAll);
2102     printf("#   left  : %d\n", leftObjs);
2103     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2104     printf("#   reused : %d\n", reAll);
2105     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2106 
2107     printf("# node-sets\n");
2108     printf("#   total  : %d\n", reqNodeset);
2109     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2110     printf("#   reused : %d\n", reNodeset);
2111     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2112 
2113     printf("# strings\n");
2114     printf("#   total  : %d\n", reqString);
2115     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2116     printf("#   reused : %d\n", reString);
2117     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2118 
2119     printf("# booleans\n");
2120     printf("#   total  : %d\n", reqBool);
2121     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2122     printf("#   reused : %d\n", reBool);
2123     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2124 
2125     printf("# numbers\n");
2126     printf("#   total  : %d\n", reqNumber);
2127     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2128     printf("#   reused : %d\n", reNumber);
2129     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2130 
2131     printf("# XSLT result tree fragments\n");
2132     printf("#   total  : %d\n", reqXSLTTree);
2133     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2134     printf("#   reused : %d\n", reXSLTTree);
2135     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2136 
2137     printf("# undefined\n");
2138     printf("#   total  : %d\n", reqUndefined);
2139     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2140     printf("#   reused : %d\n", reUndefined);
2141     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2142 
2143 }
2144 
2145 #endif /* XP_DEBUG_OBJ_USAGE */
2146 
2147 #endif /* LIBXML_DEBUG_ENABLED */
2148 
2149 /************************************************************************
2150  *									*
2151  *			XPath object caching				*
2152  *									*
2153  ************************************************************************/
2154 
2155 /**
2156  * xmlXPathNewCache:
2157  *
2158  * Create a new object cache
2159  *
2160  * Returns the xmlXPathCache just allocated.
2161  */
2162 static xmlXPathContextCachePtr
xmlXPathNewCache(void)2163 xmlXPathNewCache(void)
2164 {
2165     xmlXPathContextCachePtr ret;
2166 
2167     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2168     if (ret == NULL) {
2169         xmlXPathErrMemory(NULL, "creating object cache\n");
2170 	return(NULL);
2171     }
2172     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2173     ret->maxNodeset = 100;
2174     ret->maxString = 100;
2175     ret->maxBoolean = 100;
2176     ret->maxNumber = 100;
2177     ret->maxMisc = 100;
2178     return(ret);
2179 }
2180 
2181 static void
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)2182 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2183 {
2184     int i;
2185     xmlXPathObjectPtr obj;
2186 
2187     if (list == NULL)
2188 	return;
2189 
2190     for (i = 0; i < list->number; i++) {
2191 	obj = list->items[i];
2192 	/*
2193 	* Note that it is already assured that we don't need to
2194 	* look out for namespace nodes in the node-set.
2195 	*/
2196 	if (obj->nodesetval != NULL) {
2197 	    if (obj->nodesetval->nodeTab != NULL)
2198 		xmlFree(obj->nodesetval->nodeTab);
2199 	    xmlFree(obj->nodesetval);
2200 	}
2201 	xmlFree(obj);
2202 #ifdef XP_DEBUG_OBJ_USAGE
2203 	xmlXPathDebugObjCounterAll--;
2204 #endif
2205     }
2206     xmlPointerListFree(list);
2207 }
2208 
2209 static void
xmlXPathFreeCache(xmlXPathContextCachePtr cache)2210 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2211 {
2212     if (cache == NULL)
2213 	return;
2214     if (cache->nodesetObjs)
2215 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2216     if (cache->stringObjs)
2217 	xmlXPathCacheFreeObjectList(cache->stringObjs);
2218     if (cache->booleanObjs)
2219 	xmlXPathCacheFreeObjectList(cache->booleanObjs);
2220     if (cache->numberObjs)
2221 	xmlXPathCacheFreeObjectList(cache->numberObjs);
2222     if (cache->miscObjs)
2223 	xmlXPathCacheFreeObjectList(cache->miscObjs);
2224     xmlFree(cache);
2225 }
2226 
2227 /**
2228  * xmlXPathContextSetCache:
2229  *
2230  * @ctxt:  the XPath context
2231  * @active: enables/disables (creates/frees) the cache
2232  * @value: a value with semantics dependant on @options
2233  * @options: options (currently only the value 0 is used)
2234  *
2235  * Creates/frees an object cache on the XPath context.
2236  * If activates XPath objects (xmlXPathObject) will be cached internally
2237  * to be reused.
2238  * @options:
2239  *   0: This will set the XPath object caching:
2240  *      @value:
2241  *        This will set the maximum number of XPath objects
2242  *        to be cached per slot
2243  *        There are 5 slots for: node-set, string, number, boolean, and
2244  *        misc objects. Use <0 for the default number (100).
2245  *   Other values for @options have currently no effect.
2246  *
2247  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2248  */
2249 int
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,int active,int value,int options)2250 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2251 			int active,
2252 			int value,
2253 			int options)
2254 {
2255     if (ctxt == NULL)
2256 	return(-1);
2257     if (active) {
2258 	xmlXPathContextCachePtr cache;
2259 
2260 	if (ctxt->cache == NULL) {
2261 	    ctxt->cache = xmlXPathNewCache();
2262 	    if (ctxt->cache == NULL)
2263 		return(-1);
2264 	}
2265 	cache = (xmlXPathContextCachePtr) ctxt->cache;
2266 	if (options == 0) {
2267 	    if (value < 0)
2268 		value = 100;
2269 	    cache->maxNodeset = value;
2270 	    cache->maxString = value;
2271 	    cache->maxNumber = value;
2272 	    cache->maxBoolean = value;
2273 	    cache->maxMisc = value;
2274 	}
2275     } else if (ctxt->cache != NULL) {
2276 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2277 	ctxt->cache = NULL;
2278     }
2279     return(0);
2280 }
2281 
2282 /**
2283  * xmlXPathCacheWrapNodeSet:
2284  * @ctxt: the XPath context
2285  * @val:  the NodePtr value
2286  *
2287  * This is the cached version of xmlXPathWrapNodeSet().
2288  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2289  *
2290  * Returns the created or reused object.
2291  */
2292 static xmlXPathObjectPtr
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt,xmlNodeSetPtr val)2293 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2294 {
2295     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2296 	xmlXPathContextCachePtr cache =
2297 	    (xmlXPathContextCachePtr) ctxt->cache;
2298 
2299 	if ((cache->miscObjs != NULL) &&
2300 	    (cache->miscObjs->number != 0))
2301 	{
2302 	    xmlXPathObjectPtr ret;
2303 
2304 	    ret = (xmlXPathObjectPtr)
2305 		cache->miscObjs->items[--cache->miscObjs->number];
2306 	    ret->type = XPATH_NODESET;
2307 	    ret->nodesetval = val;
2308 #ifdef XP_DEBUG_OBJ_USAGE
2309 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2310 #endif
2311 	    return(ret);
2312 	}
2313     }
2314 
2315     return(xmlXPathWrapNodeSet(val));
2316 
2317 }
2318 
2319 /**
2320  * xmlXPathCacheWrapString:
2321  * @ctxt: the XPath context
2322  * @val:  the xmlChar * value
2323  *
2324  * This is the cached version of xmlXPathWrapString().
2325  * Wraps the @val string into an XPath object.
2326  *
2327  * Returns the created or reused object.
2328  */
2329 static xmlXPathObjectPtr
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt,xmlChar * val)2330 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2331 {
2332     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2333 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2334 
2335 	if ((cache->stringObjs != NULL) &&
2336 	    (cache->stringObjs->number != 0))
2337 	{
2338 
2339 	    xmlXPathObjectPtr ret;
2340 
2341 	    ret = (xmlXPathObjectPtr)
2342 		cache->stringObjs->items[--cache->stringObjs->number];
2343 	    ret->type = XPATH_STRING;
2344 	    ret->stringval = val;
2345 #ifdef XP_DEBUG_OBJ_USAGE
2346 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2347 #endif
2348 	    return(ret);
2349 	} else if ((cache->miscObjs != NULL) &&
2350 	    (cache->miscObjs->number != 0))
2351 	{
2352 	    xmlXPathObjectPtr ret;
2353 	    /*
2354 	    * Fallback to misc-cache.
2355 	    */
2356 	    ret = (xmlXPathObjectPtr)
2357 		cache->miscObjs->items[--cache->miscObjs->number];
2358 
2359 	    ret->type = XPATH_STRING;
2360 	    ret->stringval = val;
2361 #ifdef XP_DEBUG_OBJ_USAGE
2362 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2363 #endif
2364 	    return(ret);
2365 	}
2366     }
2367     return(xmlXPathWrapString(val));
2368 }
2369 
2370 /**
2371  * xmlXPathCacheNewNodeSet:
2372  * @ctxt: the XPath context
2373  * @val:  the NodePtr value
2374  *
2375  * This is the cached version of xmlXPathNewNodeSet().
2376  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2377  * it with the single Node @val
2378  *
2379  * Returns the created or reused object.
2380  */
2381 static xmlXPathObjectPtr
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt,xmlNodePtr val)2382 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2383 {
2384     if ((ctxt != NULL) && (ctxt->cache)) {
2385 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2386 
2387 	if ((cache->nodesetObjs != NULL) &&
2388 	    (cache->nodesetObjs->number != 0))
2389 	{
2390 	    xmlXPathObjectPtr ret;
2391 	    /*
2392 	    * Use the nodset-cache.
2393 	    */
2394 	    ret = (xmlXPathObjectPtr)
2395 		cache->nodesetObjs->items[--cache->nodesetObjs->number];
2396 	    ret->type = XPATH_NODESET;
2397 	    ret->boolval = 0;
2398 	    if (val) {
2399 		if ((ret->nodesetval->nodeMax == 0) ||
2400 		    (val->type == XML_NAMESPACE_DECL))
2401 		{
2402 		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2403 		} else {
2404 		    ret->nodesetval->nodeTab[0] = val;
2405 		    ret->nodesetval->nodeNr = 1;
2406 		}
2407 	    }
2408 #ifdef XP_DEBUG_OBJ_USAGE
2409 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2410 #endif
2411 	    return(ret);
2412 	} else if ((cache->miscObjs != NULL) &&
2413 	    (cache->miscObjs->number != 0))
2414 	{
2415 	    xmlXPathObjectPtr ret;
2416 	    /*
2417 	    * Fallback to misc-cache.
2418 	    */
2419 
2420 	    ret = (xmlXPathObjectPtr)
2421 		cache->miscObjs->items[--cache->miscObjs->number];
2422 
2423 	    ret->type = XPATH_NODESET;
2424 	    ret->boolval = 0;
2425 	    ret->nodesetval = xmlXPathNodeSetCreate(val);
2426 	    if (ret->nodesetval == NULL) {
2427 		ctxt->lastError.domain = XML_FROM_XPATH;
2428 		ctxt->lastError.code = XML_ERR_NO_MEMORY;
2429 		return(NULL);
2430 	    }
2431 #ifdef XP_DEBUG_OBJ_USAGE
2432 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2433 #endif
2434 	    return(ret);
2435 	}
2436     }
2437     return(xmlXPathNewNodeSet(val));
2438 }
2439 
2440 /**
2441  * xmlXPathCacheNewCString:
2442  * @ctxt: the XPath context
2443  * @val:  the char * value
2444  *
2445  * This is the cached version of xmlXPathNewCString().
2446  * Acquire an xmlXPathObjectPtr of type string and of value @val
2447  *
2448  * Returns the created or reused object.
2449  */
2450 static xmlXPathObjectPtr
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt,const char * val)2451 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2452 {
2453     if ((ctxt != NULL) && (ctxt->cache)) {
2454 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2455 
2456 	if ((cache->stringObjs != NULL) &&
2457 	    (cache->stringObjs->number != 0))
2458 	{
2459 	    xmlXPathObjectPtr ret;
2460 
2461 	    ret = (xmlXPathObjectPtr)
2462 		cache->stringObjs->items[--cache->stringObjs->number];
2463 
2464 	    ret->type = XPATH_STRING;
2465 	    ret->stringval = xmlStrdup(BAD_CAST val);
2466 #ifdef XP_DEBUG_OBJ_USAGE
2467 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2468 #endif
2469 	    return(ret);
2470 	} else if ((cache->miscObjs != NULL) &&
2471 	    (cache->miscObjs->number != 0))
2472 	{
2473 	    xmlXPathObjectPtr ret;
2474 
2475 	    ret = (xmlXPathObjectPtr)
2476 		cache->miscObjs->items[--cache->miscObjs->number];
2477 
2478 	    ret->type = XPATH_STRING;
2479 	    ret->stringval = xmlStrdup(BAD_CAST val);
2480 #ifdef XP_DEBUG_OBJ_USAGE
2481 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2482 #endif
2483 	    return(ret);
2484 	}
2485     }
2486     return(xmlXPathNewCString(val));
2487 }
2488 
2489 /**
2490  * xmlXPathCacheNewString:
2491  * @ctxt: the XPath context
2492  * @val:  the xmlChar * value
2493  *
2494  * This is the cached version of xmlXPathNewString().
2495  * Acquire an xmlXPathObjectPtr of type string and of value @val
2496  *
2497  * Returns the created or reused object.
2498  */
2499 static xmlXPathObjectPtr
xmlXPathCacheNewString(xmlXPathContextPtr ctxt,const xmlChar * val)2500 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2501 {
2502     if ((ctxt != NULL) && (ctxt->cache)) {
2503 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2504 
2505 	if ((cache->stringObjs != NULL) &&
2506 	    (cache->stringObjs->number != 0))
2507 	{
2508 	    xmlXPathObjectPtr ret;
2509 
2510 	    ret = (xmlXPathObjectPtr)
2511 		cache->stringObjs->items[--cache->stringObjs->number];
2512 	    ret->type = XPATH_STRING;
2513 	    if (val != NULL)
2514 		ret->stringval = xmlStrdup(val);
2515 	    else
2516 		ret->stringval = xmlStrdup((const xmlChar *)"");
2517 #ifdef XP_DEBUG_OBJ_USAGE
2518 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2519 #endif
2520 	    return(ret);
2521 	} else if ((cache->miscObjs != NULL) &&
2522 	    (cache->miscObjs->number != 0))
2523 	{
2524 	    xmlXPathObjectPtr ret;
2525 
2526 	    ret = (xmlXPathObjectPtr)
2527 		cache->miscObjs->items[--cache->miscObjs->number];
2528 
2529 	    ret->type = XPATH_STRING;
2530 	    if (val != NULL)
2531 		ret->stringval = xmlStrdup(val);
2532 	    else
2533 		ret->stringval = xmlStrdup((const xmlChar *)"");
2534 #ifdef XP_DEBUG_OBJ_USAGE
2535 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2536 #endif
2537 	    return(ret);
2538 	}
2539     }
2540     return(xmlXPathNewString(val));
2541 }
2542 
2543 /**
2544  * xmlXPathCacheNewBoolean:
2545  * @ctxt: the XPath context
2546  * @val:  the boolean value
2547  *
2548  * This is the cached version of xmlXPathNewBoolean().
2549  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2550  *
2551  * Returns the created or reused object.
2552  */
2553 static xmlXPathObjectPtr
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt,int val)2554 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2555 {
2556     if ((ctxt != NULL) && (ctxt->cache)) {
2557 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2558 
2559 	if ((cache->booleanObjs != NULL) &&
2560 	    (cache->booleanObjs->number != 0))
2561 	{
2562 	    xmlXPathObjectPtr ret;
2563 
2564 	    ret = (xmlXPathObjectPtr)
2565 		cache->booleanObjs->items[--cache->booleanObjs->number];
2566 	    ret->type = XPATH_BOOLEAN;
2567 	    ret->boolval = (val != 0);
2568 #ifdef XP_DEBUG_OBJ_USAGE
2569 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2570 #endif
2571 	    return(ret);
2572 	} else if ((cache->miscObjs != NULL) &&
2573 	    (cache->miscObjs->number != 0))
2574 	{
2575 	    xmlXPathObjectPtr ret;
2576 
2577 	    ret = (xmlXPathObjectPtr)
2578 		cache->miscObjs->items[--cache->miscObjs->number];
2579 
2580 	    ret->type = XPATH_BOOLEAN;
2581 	    ret->boolval = (val != 0);
2582 #ifdef XP_DEBUG_OBJ_USAGE
2583 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2584 #endif
2585 	    return(ret);
2586 	}
2587     }
2588     return(xmlXPathNewBoolean(val));
2589 }
2590 
2591 /**
2592  * xmlXPathCacheNewFloat:
2593  * @ctxt: the XPath context
2594  * @val:  the double value
2595  *
2596  * This is the cached version of xmlXPathNewFloat().
2597  * Acquires an xmlXPathObjectPtr of type double and of value @val
2598  *
2599  * Returns the created or reused object.
2600  */
2601 static xmlXPathObjectPtr
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt,double val)2602 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2603 {
2604      if ((ctxt != NULL) && (ctxt->cache)) {
2605 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2606 
2607 	if ((cache->numberObjs != NULL) &&
2608 	    (cache->numberObjs->number != 0))
2609 	{
2610 	    xmlXPathObjectPtr ret;
2611 
2612 	    ret = (xmlXPathObjectPtr)
2613 		cache->numberObjs->items[--cache->numberObjs->number];
2614 	    ret->type = XPATH_NUMBER;
2615 	    ret->floatval = val;
2616 #ifdef XP_DEBUG_OBJ_USAGE
2617 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2618 #endif
2619 	    return(ret);
2620 	} else if ((cache->miscObjs != NULL) &&
2621 	    (cache->miscObjs->number != 0))
2622 	{
2623 	    xmlXPathObjectPtr ret;
2624 
2625 	    ret = (xmlXPathObjectPtr)
2626 		cache->miscObjs->items[--cache->miscObjs->number];
2627 
2628 	    ret->type = XPATH_NUMBER;
2629 	    ret->floatval = val;
2630 #ifdef XP_DEBUG_OBJ_USAGE
2631 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2632 #endif
2633 	    return(ret);
2634 	}
2635     }
2636     return(xmlXPathNewFloat(val));
2637 }
2638 
2639 /**
2640  * xmlXPathCacheConvertString:
2641  * @ctxt: the XPath context
2642  * @val:  an XPath object
2643  *
2644  * This is the cached version of xmlXPathConvertString().
2645  * Converts an existing object to its string() equivalent
2646  *
2647  * Returns a created or reused object, the old one is freed (cached)
2648  *         (or the operation is done directly on @val)
2649  */
2650 
2651 static xmlXPathObjectPtr
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2652 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2653     xmlChar *res = NULL;
2654 
2655     if (val == NULL)
2656 	return(xmlXPathCacheNewCString(ctxt, ""));
2657 
2658     switch (val->type) {
2659     case XPATH_UNDEFINED:
2660 #ifdef DEBUG_EXPR
2661 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2662 #endif
2663 	break;
2664     case XPATH_NODESET:
2665     case XPATH_XSLT_TREE:
2666 	res = xmlXPathCastNodeSetToString(val->nodesetval);
2667 	break;
2668     case XPATH_STRING:
2669 	return(val);
2670     case XPATH_BOOLEAN:
2671 	res = xmlXPathCastBooleanToString(val->boolval);
2672 	break;
2673     case XPATH_NUMBER:
2674 	res = xmlXPathCastNumberToString(val->floatval);
2675 	break;
2676     case XPATH_USERS:
2677     case XPATH_POINT:
2678     case XPATH_RANGE:
2679     case XPATH_LOCATIONSET:
2680 	TODO;
2681 	break;
2682     }
2683     xmlXPathReleaseObject(ctxt, val);
2684     if (res == NULL)
2685 	return(xmlXPathCacheNewCString(ctxt, ""));
2686     return(xmlXPathCacheWrapString(ctxt, res));
2687 }
2688 
2689 /**
2690  * xmlXPathCacheObjectCopy:
2691  * @ctxt: the XPath context
2692  * @val:  the original object
2693  *
2694  * This is the cached version of xmlXPathObjectCopy().
2695  * Acquire a copy of a given object
2696  *
2697  * Returns a created or reused created object.
2698  */
2699 static xmlXPathObjectPtr
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2700 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2701 {
2702     if (val == NULL)
2703 	return(NULL);
2704 
2705     if (XP_HAS_CACHE(ctxt)) {
2706 	switch (val->type) {
2707 	    case XPATH_NODESET:
2708 		return(xmlXPathCacheWrapNodeSet(ctxt,
2709 		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2710 	    case XPATH_STRING:
2711 		return(xmlXPathCacheNewString(ctxt, val->stringval));
2712 	    case XPATH_BOOLEAN:
2713 		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2714 	    case XPATH_NUMBER:
2715 		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2716 	    default:
2717 		break;
2718 	}
2719     }
2720     return(xmlXPathObjectCopy(val));
2721 }
2722 
2723 /**
2724  * xmlXPathCacheConvertBoolean:
2725  * @ctxt: the XPath context
2726  * @val:  an XPath object
2727  *
2728  * This is the cached version of xmlXPathConvertBoolean().
2729  * Converts an existing object to its boolean() equivalent
2730  *
2731  * Returns a created or reused object, the old one is freed (or the operation
2732  *         is done directly on @val)
2733  */
2734 static xmlXPathObjectPtr
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2735 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2736     xmlXPathObjectPtr ret;
2737 
2738     if (val == NULL)
2739 	return(xmlXPathCacheNewBoolean(ctxt, 0));
2740     if (val->type == XPATH_BOOLEAN)
2741 	return(val);
2742     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2743     xmlXPathReleaseObject(ctxt, val);
2744     return(ret);
2745 }
2746 
2747 /**
2748  * xmlXPathCacheConvertNumber:
2749  * @ctxt: the XPath context
2750  * @val:  an XPath object
2751  *
2752  * This is the cached version of xmlXPathConvertNumber().
2753  * Converts an existing object to its number() equivalent
2754  *
2755  * Returns a created or reused object, the old one is freed (or the operation
2756  *         is done directly on @val)
2757  */
2758 static xmlXPathObjectPtr
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2759 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2760     xmlXPathObjectPtr ret;
2761 
2762     if (val == NULL)
2763 	return(xmlXPathCacheNewFloat(ctxt, 0.0));
2764     if (val->type == XPATH_NUMBER)
2765 	return(val);
2766     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2767     xmlXPathReleaseObject(ctxt, val);
2768     return(ret);
2769 }
2770 
2771 /************************************************************************
2772  *									*
2773  *		Parser stacks related functions and macros		*
2774  *									*
2775  ************************************************************************/
2776 
2777 /**
2778  * xmlXPathSetFrame:
2779  * @ctxt: an XPath parser context
2780  *
2781  * Set the callee evaluation frame
2782  *
2783  * Returns the previous frame value to be restored once done
2784  */
2785 static int
xmlXPathSetFrame(xmlXPathParserContextPtr ctxt)2786 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2787     int ret;
2788 
2789     if (ctxt == NULL)
2790         return(0);
2791     ret = ctxt->valueFrame;
2792     ctxt->valueFrame = ctxt->valueNr;
2793     return(ret);
2794 }
2795 
2796 /**
2797  * xmlXPathPopFrame:
2798  * @ctxt: an XPath parser context
2799  * @frame: the previous frame value
2800  *
2801  * Remove the callee evaluation frame
2802  */
2803 static void
xmlXPathPopFrame(xmlXPathParserContextPtr ctxt,int frame)2804 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2805     if (ctxt == NULL)
2806         return;
2807     if (ctxt->valueNr < ctxt->valueFrame) {
2808         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2809     }
2810     ctxt->valueFrame = frame;
2811 }
2812 
2813 /**
2814  * valuePop:
2815  * @ctxt: an XPath evaluation context
2816  *
2817  * Pops the top XPath object from the value stack
2818  *
2819  * Returns the XPath object just removed
2820  */
2821 xmlXPathObjectPtr
valuePop(xmlXPathParserContextPtr ctxt)2822 valuePop(xmlXPathParserContextPtr ctxt)
2823 {
2824     xmlXPathObjectPtr ret;
2825 
2826     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2827         return (NULL);
2828 
2829     if (ctxt->valueNr <= ctxt->valueFrame) {
2830         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2831         return (NULL);
2832     }
2833 
2834     ctxt->valueNr--;
2835     if (ctxt->valueNr > 0)
2836         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2837     else
2838         ctxt->value = NULL;
2839     ret = ctxt->valueTab[ctxt->valueNr];
2840     ctxt->valueTab[ctxt->valueNr] = NULL;
2841     return (ret);
2842 }
2843 /**
2844  * valuePush:
2845  * @ctxt:  an XPath evaluation context
2846  * @value:  the XPath object
2847  *
2848  * Pushes a new XPath object on top of the value stack
2849  *
2850  * returns the number of items on the value stack
2851  */
2852 int
valuePush(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr value)2853 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2854 {
2855     if ((ctxt == NULL) || (value == NULL)) return(-1);
2856     if (ctxt->valueNr >= ctxt->valueMax) {
2857         xmlXPathObjectPtr *tmp;
2858 
2859         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2860             xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2861             ctxt->error = XPATH_MEMORY_ERROR;
2862             return (0);
2863         }
2864         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2865                                              2 * ctxt->valueMax *
2866                                              sizeof(ctxt->valueTab[0]));
2867         if (tmp == NULL) {
2868             xmlXPathErrMemory(NULL, "pushing value\n");
2869             ctxt->error = XPATH_MEMORY_ERROR;
2870             return (0);
2871         }
2872         ctxt->valueMax *= 2;
2873 	ctxt->valueTab = tmp;
2874     }
2875     ctxt->valueTab[ctxt->valueNr] = value;
2876     ctxt->value = value;
2877     return (ctxt->valueNr++);
2878 }
2879 
2880 /**
2881  * xmlXPathPopBoolean:
2882  * @ctxt:  an XPath parser context
2883  *
2884  * Pops a boolean from the stack, handling conversion if needed.
2885  * Check error with #xmlXPathCheckError.
2886  *
2887  * Returns the boolean
2888  */
2889 int
xmlXPathPopBoolean(xmlXPathParserContextPtr ctxt)2890 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2891     xmlXPathObjectPtr obj;
2892     int ret;
2893 
2894     obj = valuePop(ctxt);
2895     if (obj == NULL) {
2896 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2897 	return(0);
2898     }
2899     if (obj->type != XPATH_BOOLEAN)
2900 	ret = xmlXPathCastToBoolean(obj);
2901     else
2902         ret = obj->boolval;
2903     xmlXPathReleaseObject(ctxt->context, obj);
2904     return(ret);
2905 }
2906 
2907 /**
2908  * xmlXPathPopNumber:
2909  * @ctxt:  an XPath parser context
2910  *
2911  * Pops a number from the stack, handling conversion if needed.
2912  * Check error with #xmlXPathCheckError.
2913  *
2914  * Returns the number
2915  */
2916 double
xmlXPathPopNumber(xmlXPathParserContextPtr ctxt)2917 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2918     xmlXPathObjectPtr obj;
2919     double ret;
2920 
2921     obj = valuePop(ctxt);
2922     if (obj == NULL) {
2923 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2924 	return(0);
2925     }
2926     if (obj->type != XPATH_NUMBER)
2927 	ret = xmlXPathCastToNumber(obj);
2928     else
2929         ret = obj->floatval;
2930     xmlXPathReleaseObject(ctxt->context, obj);
2931     return(ret);
2932 }
2933 
2934 /**
2935  * xmlXPathPopString:
2936  * @ctxt:  an XPath parser context
2937  *
2938  * Pops a string from the stack, handling conversion if needed.
2939  * Check error with #xmlXPathCheckError.
2940  *
2941  * Returns the string
2942  */
2943 xmlChar *
xmlXPathPopString(xmlXPathParserContextPtr ctxt)2944 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2945     xmlXPathObjectPtr obj;
2946     xmlChar * ret;
2947 
2948     obj = valuePop(ctxt);
2949     if (obj == NULL) {
2950 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2951 	return(NULL);
2952     }
2953     ret = xmlXPathCastToString(obj);	/* this does required strdup */
2954     /* TODO: needs refactoring somewhere else */
2955     if (obj->stringval == ret)
2956 	obj->stringval = NULL;
2957     xmlXPathReleaseObject(ctxt->context, obj);
2958     return(ret);
2959 }
2960 
2961 /**
2962  * xmlXPathPopNodeSet:
2963  * @ctxt:  an XPath parser context
2964  *
2965  * Pops a node-set from the stack, handling conversion if needed.
2966  * Check error with #xmlXPathCheckError.
2967  *
2968  * Returns the node-set
2969  */
2970 xmlNodeSetPtr
xmlXPathPopNodeSet(xmlXPathParserContextPtr ctxt)2971 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2972     xmlXPathObjectPtr obj;
2973     xmlNodeSetPtr ret;
2974 
2975     if (ctxt == NULL) return(NULL);
2976     if (ctxt->value == NULL) {
2977 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2978 	return(NULL);
2979     }
2980     if (!xmlXPathStackIsNodeSet(ctxt)) {
2981 	xmlXPathSetTypeError(ctxt);
2982 	return(NULL);
2983     }
2984     obj = valuePop(ctxt);
2985     ret = obj->nodesetval;
2986 #if 0
2987     /* to fix memory leak of not clearing obj->user */
2988     if (obj->boolval && obj->user != NULL)
2989         xmlFreeNodeList((xmlNodePtr) obj->user);
2990 #endif
2991     obj->nodesetval = NULL;
2992     xmlXPathReleaseObject(ctxt->context, obj);
2993     return(ret);
2994 }
2995 
2996 /**
2997  * xmlXPathPopExternal:
2998  * @ctxt:  an XPath parser context
2999  *
3000  * Pops an external object from the stack, handling conversion if needed.
3001  * Check error with #xmlXPathCheckError.
3002  *
3003  * Returns the object
3004  */
3005 void *
xmlXPathPopExternal(xmlXPathParserContextPtr ctxt)3006 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3007     xmlXPathObjectPtr obj;
3008     void * ret;
3009 
3010     if ((ctxt == NULL) || (ctxt->value == NULL)) {
3011 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3012 	return(NULL);
3013     }
3014     if (ctxt->value->type != XPATH_USERS) {
3015 	xmlXPathSetTypeError(ctxt);
3016 	return(NULL);
3017     }
3018     obj = valuePop(ctxt);
3019     ret = obj->user;
3020     obj->user = NULL;
3021     xmlXPathReleaseObject(ctxt->context, obj);
3022     return(ret);
3023 }
3024 
3025 /*
3026  * Macros for accessing the content. Those should be used only by the parser,
3027  * and not exported.
3028  *
3029  * Dirty macros, i.e. one need to make assumption on the context to use them
3030  *
3031  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3032  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3033  *           in ISO-Latin or UTF-8.
3034  *           This should be used internally by the parser
3035  *           only to compare to ASCII values otherwise it would break when
3036  *           running with UTF-8 encoding.
3037  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3038  *           to compare on ASCII based substring.
3039  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3040  *           strings within the parser.
3041  *   CURRENT Returns the current char value, with the full decoding of
3042  *           UTF-8 if we are using this mode. It returns an int.
3043  *   NEXT    Skip to the next character, this does the proper decoding
3044  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3045  *           It returns the pointer to the current xmlChar.
3046  */
3047 
3048 #define CUR (*ctxt->cur)
3049 #define SKIP(val) ctxt->cur += (val)
3050 #define NXT(val) ctxt->cur[(val)]
3051 #define CUR_PTR ctxt->cur
3052 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3053 
3054 #define COPY_BUF(l,b,i,v)                                              \
3055     if (l == 1) b[i++] = (xmlChar) v;                                  \
3056     else i += xmlCopyChar(l,&b[i],v)
3057 
3058 #define NEXTL(l)  ctxt->cur += l
3059 
3060 #define SKIP_BLANKS							\
3061     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3062 
3063 #define CURRENT (*ctxt->cur)
3064 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3065 
3066 
3067 #ifndef DBL_DIG
3068 #define DBL_DIG 16
3069 #endif
3070 #ifndef DBL_EPSILON
3071 #define DBL_EPSILON 1E-9
3072 #endif
3073 
3074 #define UPPER_DOUBLE 1E9
3075 #define LOWER_DOUBLE 1E-5
3076 #define	LOWER_DOUBLE_EXP 5
3077 
3078 #define INTEGER_DIGITS DBL_DIG
3079 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3080 #define EXPONENT_DIGITS (3 + 2)
3081 
3082 /**
3083  * xmlXPathFormatNumber:
3084  * @number:     number to format
3085  * @buffer:     output buffer
3086  * @buffersize: size of output buffer
3087  *
3088  * Convert the number into a string representation.
3089  */
3090 static void
xmlXPathFormatNumber(double number,char buffer[],int buffersize)3091 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3092 {
3093     switch (xmlXPathIsInf(number)) {
3094     case 1:
3095 	if (buffersize > (int)sizeof("Infinity"))
3096 	    snprintf(buffer, buffersize, "Infinity");
3097 	break;
3098     case -1:
3099 	if (buffersize > (int)sizeof("-Infinity"))
3100 	    snprintf(buffer, buffersize, "-Infinity");
3101 	break;
3102     default:
3103 	if (xmlXPathIsNaN(number)) {
3104 	    if (buffersize > (int)sizeof("NaN"))
3105 		snprintf(buffer, buffersize, "NaN");
3106 	} else if (number == 0 && xmlXPathGetSign(number) != 0) {
3107 	    snprintf(buffer, buffersize, "0");
3108 	} else if (number == ((int) number)) {
3109 	    char work[30];
3110 	    char *ptr, *cur;
3111 	    int value = (int) number;
3112 
3113             ptr = &buffer[0];
3114 	    if (value == 0) {
3115 		*ptr++ = '0';
3116 	    } else {
3117 		snprintf(work, 29, "%d", value);
3118 		cur = &work[0];
3119 		while ((*cur) && (ptr - buffer < buffersize)) {
3120 		    *ptr++ = *cur++;
3121 		}
3122 	    }
3123 	    if (ptr - buffer < buffersize) {
3124 		*ptr = 0;
3125 	    } else if (buffersize > 0) {
3126 		ptr--;
3127 		*ptr = 0;
3128 	    }
3129 	} else {
3130 	    /*
3131 	      For the dimension of work,
3132 	          DBL_DIG is number of significant digits
3133 		  EXPONENT is only needed for "scientific notation"
3134 	          3 is sign, decimal point, and terminating zero
3135 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3136 	      Note that this dimension is slightly (a few characters)
3137 	      larger than actually necessary.
3138 	    */
3139 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3140 	    int integer_place, fraction_place;
3141 	    char *ptr;
3142 	    char *after_fraction;
3143 	    double absolute_value;
3144 	    int size;
3145 
3146 	    absolute_value = fabs(number);
3147 
3148 	    /*
3149 	     * First choose format - scientific or regular floating point.
3150 	     * In either case, result is in work, and after_fraction points
3151 	     * just past the fractional part.
3152 	    */
3153 	    if ( ((absolute_value > UPPER_DOUBLE) ||
3154 		  (absolute_value < LOWER_DOUBLE)) &&
3155 		 (absolute_value != 0.0) ) {
3156 		/* Use scientific notation */
3157 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3158 		fraction_place = DBL_DIG - 1;
3159 		size = snprintf(work, sizeof(work),"%*.*e",
3160 			 integer_place, fraction_place, number);
3161 		while ((size > 0) && (work[size] != 'e')) size--;
3162 
3163 	    }
3164 	    else {
3165 		/* Use regular notation */
3166 		if (absolute_value > 0.0) {
3167 		    integer_place = (int)log10(absolute_value);
3168 		    if (integer_place > 0)
3169 		        fraction_place = DBL_DIG - integer_place - 1;
3170 		    else
3171 		        fraction_place = DBL_DIG - integer_place;
3172 		} else {
3173 		    fraction_place = 1;
3174 		}
3175 		size = snprintf(work, sizeof(work), "%0.*f",
3176 				fraction_place, number);
3177 	    }
3178 
3179 	    /* Remove leading spaces sometimes inserted by snprintf */
3180 	    while (work[0] == ' ') {
3181 	        for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3182 		size--;
3183 	    }
3184 
3185 	    /* Remove fractional trailing zeroes */
3186 	    after_fraction = work + size;
3187 	    ptr = after_fraction;
3188 	    while (*(--ptr) == '0')
3189 		;
3190 	    if (*ptr != '.')
3191 	        ptr++;
3192 	    while ((*ptr++ = *after_fraction++) != 0);
3193 
3194 	    /* Finally copy result back to caller */
3195 	    size = strlen(work) + 1;
3196 	    if (size > buffersize) {
3197 		work[buffersize - 1] = 0;
3198 		size = buffersize;
3199 	    }
3200 	    memmove(buffer, work, size);
3201 	}
3202 	break;
3203     }
3204 }
3205 
3206 
3207 /************************************************************************
3208  *									*
3209  *			Routines to handle NodeSets			*
3210  *									*
3211  ************************************************************************/
3212 
3213 /**
3214  * xmlXPathOrderDocElems:
3215  * @doc:  an input document
3216  *
3217  * Call this routine to speed up XPath computation on static documents.
3218  * This stamps all the element nodes with the document order
3219  * Like for line information, the order is kept in the element->content
3220  * field, the value stored is actually - the node number (starting at -1)
3221  * to be able to differentiate from line numbers.
3222  *
3223  * Returns the number of elements found in the document or -1 in case
3224  *    of error.
3225  */
3226 long
xmlXPathOrderDocElems(xmlDocPtr doc)3227 xmlXPathOrderDocElems(xmlDocPtr doc) {
3228     long count = 0;
3229     xmlNodePtr cur;
3230 
3231     if (doc == NULL)
3232 	return(-1);
3233     cur = doc->children;
3234     while (cur != NULL) {
3235 	if (cur->type == XML_ELEMENT_NODE) {
3236 	    cur->content = (void *) (-(++count));
3237 	    if (cur->children != NULL) {
3238 		cur = cur->children;
3239 		continue;
3240 	    }
3241 	}
3242 	if (cur->next != NULL) {
3243 	    cur = cur->next;
3244 	    continue;
3245 	}
3246 	do {
3247 	    cur = cur->parent;
3248 	    if (cur == NULL)
3249 		break;
3250 	    if (cur == (xmlNodePtr) doc) {
3251 		cur = NULL;
3252 		break;
3253 	    }
3254 	    if (cur->next != NULL) {
3255 		cur = cur->next;
3256 		break;
3257 	    }
3258 	} while (cur != NULL);
3259     }
3260     return(count);
3261 }
3262 
3263 /**
3264  * xmlXPathCmpNodes:
3265  * @node1:  the first node
3266  * @node2:  the second node
3267  *
3268  * Compare two nodes w.r.t document order
3269  *
3270  * Returns -2 in case of error 1 if first point < second point, 0 if
3271  *         it's the same node, -1 otherwise
3272  */
3273 int
xmlXPathCmpNodes(xmlNodePtr node1,xmlNodePtr node2)3274 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3275     int depth1, depth2;
3276     int attr1 = 0, attr2 = 0;
3277     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3278     xmlNodePtr cur, root;
3279 
3280     if ((node1 == NULL) || (node2 == NULL))
3281 	return(-2);
3282     /*
3283      * a couple of optimizations which will avoid computations in most cases
3284      */
3285     if (node1 == node2)		/* trivial case */
3286 	return(0);
3287     if (node1->type == XML_ATTRIBUTE_NODE) {
3288 	attr1 = 1;
3289 	attrNode1 = node1;
3290 	node1 = node1->parent;
3291     }
3292     if (node2->type == XML_ATTRIBUTE_NODE) {
3293 	attr2 = 1;
3294 	attrNode2 = node2;
3295 	node2 = node2->parent;
3296     }
3297     if (node1 == node2) {
3298 	if (attr1 == attr2) {
3299 	    /* not required, but we keep attributes in order */
3300 	    if (attr1 != 0) {
3301 	        cur = attrNode2->prev;
3302 		while (cur != NULL) {
3303 		    if (cur == attrNode1)
3304 		        return (1);
3305 		    cur = cur->prev;
3306 		}
3307 		return (-1);
3308 	    }
3309 	    return(0);
3310 	}
3311 	if (attr2 == 1)
3312 	    return(1);
3313 	return(-1);
3314     }
3315     if ((node1->type == XML_NAMESPACE_DECL) ||
3316         (node2->type == XML_NAMESPACE_DECL))
3317 	return(1);
3318     if (node1 == node2->prev)
3319 	return(1);
3320     if (node1 == node2->next)
3321 	return(-1);
3322 
3323     /*
3324      * Speedup using document order if availble.
3325      */
3326     if ((node1->type == XML_ELEMENT_NODE) &&
3327 	(node2->type == XML_ELEMENT_NODE) &&
3328 	(0 > (long) node1->content) &&
3329 	(0 > (long) node2->content) &&
3330 	(node1->doc == node2->doc)) {
3331 	long l1, l2;
3332 
3333 	l1 = -((long) node1->content);
3334 	l2 = -((long) node2->content);
3335 	if (l1 < l2)
3336 	    return(1);
3337 	if (l1 > l2)
3338 	    return(-1);
3339     }
3340 
3341     /*
3342      * compute depth to root
3343      */
3344     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3345 	if (cur == node1)
3346 	    return(1);
3347 	depth2++;
3348     }
3349     root = cur;
3350     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3351 	if (cur == node2)
3352 	    return(-1);
3353 	depth1++;
3354     }
3355     /*
3356      * Distinct document (or distinct entities :-( ) case.
3357      */
3358     if (root != cur) {
3359 	return(-2);
3360     }
3361     /*
3362      * get the nearest common ancestor.
3363      */
3364     while (depth1 > depth2) {
3365 	depth1--;
3366 	node1 = node1->parent;
3367     }
3368     while (depth2 > depth1) {
3369 	depth2--;
3370 	node2 = node2->parent;
3371     }
3372     while (node1->parent != node2->parent) {
3373 	node1 = node1->parent;
3374 	node2 = node2->parent;
3375 	/* should not happen but just in case ... */
3376 	if ((node1 == NULL) || (node2 == NULL))
3377 	    return(-2);
3378     }
3379     /*
3380      * Find who's first.
3381      */
3382     if (node1 == node2->prev)
3383 	return(1);
3384     if (node1 == node2->next)
3385 	return(-1);
3386     /*
3387      * Speedup using document order if availble.
3388      */
3389     if ((node1->type == XML_ELEMENT_NODE) &&
3390 	(node2->type == XML_ELEMENT_NODE) &&
3391 	(0 > (long) node1->content) &&
3392 	(0 > (long) node2->content) &&
3393 	(node1->doc == node2->doc)) {
3394 	long l1, l2;
3395 
3396 	l1 = -((long) node1->content);
3397 	l2 = -((long) node2->content);
3398 	if (l1 < l2)
3399 	    return(1);
3400 	if (l1 > l2)
3401 	    return(-1);
3402     }
3403 
3404     for (cur = node1->next;cur != NULL;cur = cur->next)
3405 	if (cur == node2)
3406 	    return(1);
3407     return(-1); /* assume there is no sibling list corruption */
3408 }
3409 
3410 /**
3411  * xmlXPathNodeSetSort:
3412  * @set:  the node set
3413  *
3414  * Sort the node set in document order
3415  */
3416 void
xmlXPathNodeSetSort(xmlNodeSetPtr set)3417 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3418 #ifndef WITH_TIM_SORT
3419     int i, j, incr, len;
3420     xmlNodePtr tmp;
3421 #endif
3422 
3423     if (set == NULL)
3424 	return;
3425 
3426 #ifndef WITH_TIM_SORT
3427     /*
3428      * Use the old Shell's sort implementation to sort the node-set
3429      * Timsort ought to be quite faster
3430      */
3431     len = set->nodeNr;
3432     for (incr = len / 2; incr > 0; incr /= 2) {
3433 	for (i = incr; i < len; i++) {
3434 	    j = i - incr;
3435 	    while (j >= 0) {
3436 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3437 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
3438 			set->nodeTab[j + incr]) == -1)
3439 #else
3440 		if (xmlXPathCmpNodes(set->nodeTab[j],
3441 			set->nodeTab[j + incr]) == -1)
3442 #endif
3443 		{
3444 		    tmp = set->nodeTab[j];
3445 		    set->nodeTab[j] = set->nodeTab[j + incr];
3446 		    set->nodeTab[j + incr] = tmp;
3447 		    j -= incr;
3448 		} else
3449 		    break;
3450 	    }
3451 	}
3452     }
3453 #else /* WITH_TIM_SORT */
3454     libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3455 #endif /* WITH_TIM_SORT */
3456 }
3457 
3458 #define XML_NODESET_DEFAULT	10
3459 /**
3460  * xmlXPathNodeSetDupNs:
3461  * @node:  the parent node of the namespace XPath node
3462  * @ns:  the libxml namespace declaration node.
3463  *
3464  * Namespace node in libxml don't match the XPath semantic. In a node set
3465  * the namespace nodes are duplicated and the next pointer is set to the
3466  * parent node in the XPath semantic.
3467  *
3468  * Returns the newly created object.
3469  */
3470 static xmlNodePtr
xmlXPathNodeSetDupNs(xmlNodePtr node,xmlNsPtr ns)3471 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3472     xmlNsPtr cur;
3473 
3474     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3475 	return(NULL);
3476     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3477 	return((xmlNodePtr) ns);
3478 
3479     /*
3480      * Allocate a new Namespace and fill the fields.
3481      */
3482     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3483     if (cur == NULL) {
3484         xmlXPathErrMemory(NULL, "duplicating namespace\n");
3485 	return(NULL);
3486     }
3487     memset(cur, 0, sizeof(xmlNs));
3488     cur->type = XML_NAMESPACE_DECL;
3489     if (ns->href != NULL)
3490 	cur->href = xmlStrdup(ns->href);
3491     if (ns->prefix != NULL)
3492 	cur->prefix = xmlStrdup(ns->prefix);
3493     cur->next = (xmlNsPtr) node;
3494     return((xmlNodePtr) cur);
3495 }
3496 
3497 /**
3498  * xmlXPathNodeSetFreeNs:
3499  * @ns:  the XPath namespace node found in a nodeset.
3500  *
3501  * Namespace nodes in libxml don't match the XPath semantic. In a node set
3502  * the namespace nodes are duplicated and the next pointer is set to the
3503  * parent node in the XPath semantic. Check if such a node needs to be freed
3504  */
3505 void
xmlXPathNodeSetFreeNs(xmlNsPtr ns)3506 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3507     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3508 	return;
3509 
3510     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3511 	if (ns->href != NULL)
3512 	    xmlFree((xmlChar *)ns->href);
3513 	if (ns->prefix != NULL)
3514 	    xmlFree((xmlChar *)ns->prefix);
3515 	xmlFree(ns);
3516     }
3517 }
3518 
3519 /**
3520  * xmlXPathNodeSetCreate:
3521  * @val:  an initial xmlNodePtr, or NULL
3522  *
3523  * Create a new xmlNodeSetPtr of type double and of value @val
3524  *
3525  * Returns the newly created object.
3526  */
3527 xmlNodeSetPtr
xmlXPathNodeSetCreate(xmlNodePtr val)3528 xmlXPathNodeSetCreate(xmlNodePtr val) {
3529     xmlNodeSetPtr ret;
3530 
3531     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3532     if (ret == NULL) {
3533         xmlXPathErrMemory(NULL, "creating nodeset\n");
3534 	return(NULL);
3535     }
3536     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3537     if (val != NULL) {
3538         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3539 					     sizeof(xmlNodePtr));
3540 	if (ret->nodeTab == NULL) {
3541 	    xmlXPathErrMemory(NULL, "creating nodeset\n");
3542 	    xmlFree(ret);
3543 	    return(NULL);
3544 	}
3545 	memset(ret->nodeTab, 0 ,
3546 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3547         ret->nodeMax = XML_NODESET_DEFAULT;
3548 	if (val->type == XML_NAMESPACE_DECL) {
3549 	    xmlNsPtr ns = (xmlNsPtr) val;
3550 
3551 	    ret->nodeTab[ret->nodeNr++] =
3552 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3553 	} else
3554 	    ret->nodeTab[ret->nodeNr++] = val;
3555     }
3556     return(ret);
3557 }
3558 
3559 /**
3560  * xmlXPathNodeSetCreateSize:
3561  * @size:  the initial size of the set
3562  *
3563  * Create a new xmlNodeSetPtr of type double and of value @val
3564  *
3565  * Returns the newly created object.
3566  */
3567 static xmlNodeSetPtr
xmlXPathNodeSetCreateSize(int size)3568 xmlXPathNodeSetCreateSize(int size) {
3569     xmlNodeSetPtr ret;
3570 
3571     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3572     if (ret == NULL) {
3573         xmlXPathErrMemory(NULL, "creating nodeset\n");
3574 	return(NULL);
3575     }
3576     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3577     if (size < XML_NODESET_DEFAULT)
3578 	size = XML_NODESET_DEFAULT;
3579     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3580     if (ret->nodeTab == NULL) {
3581 	xmlXPathErrMemory(NULL, "creating nodeset\n");
3582 	xmlFree(ret);
3583 	return(NULL);
3584     }
3585     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3586     ret->nodeMax = size;
3587     return(ret);
3588 }
3589 
3590 /**
3591  * xmlXPathNodeSetContains:
3592  * @cur:  the node-set
3593  * @val:  the node
3594  *
3595  * checks whether @cur contains @val
3596  *
3597  * Returns true (1) if @cur contains @val, false (0) otherwise
3598  */
3599 int
xmlXPathNodeSetContains(xmlNodeSetPtr cur,xmlNodePtr val)3600 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3601     int i;
3602 
3603     if ((cur == NULL) || (val == NULL)) return(0);
3604     if (val->type == XML_NAMESPACE_DECL) {
3605 	for (i = 0; i < cur->nodeNr; i++) {
3606 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3607 		xmlNsPtr ns1, ns2;
3608 
3609 		ns1 = (xmlNsPtr) val;
3610 		ns2 = (xmlNsPtr) cur->nodeTab[i];
3611 		if (ns1 == ns2)
3612 		    return(1);
3613 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3614 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
3615 		    return(1);
3616 	    }
3617 	}
3618     } else {
3619 	for (i = 0; i < cur->nodeNr; i++) {
3620 	    if (cur->nodeTab[i] == val)
3621 		return(1);
3622 	}
3623     }
3624     return(0);
3625 }
3626 
3627 /**
3628  * xmlXPathNodeSetAddNs:
3629  * @cur:  the initial node set
3630  * @node:  the hosting node
3631  * @ns:  a the namespace node
3632  *
3633  * add a new namespace node to an existing NodeSet
3634  *
3635  * Returns 0 in case of success and -1 in case of error
3636  */
3637 int
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur,xmlNodePtr node,xmlNsPtr ns)3638 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3639     int i;
3640 
3641 
3642     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3643         (ns->type != XML_NAMESPACE_DECL) ||
3644 	(node->type != XML_ELEMENT_NODE))
3645 	return(-1);
3646 
3647     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3648     /*
3649      * prevent duplicates
3650      */
3651     for (i = 0;i < cur->nodeNr;i++) {
3652         if ((cur->nodeTab[i] != NULL) &&
3653 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3654 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3655 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3656 	    return(0);
3657     }
3658 
3659     /*
3660      * grow the nodeTab if needed
3661      */
3662     if (cur->nodeMax == 0) {
3663         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3664 					     sizeof(xmlNodePtr));
3665 	if (cur->nodeTab == NULL) {
3666 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3667 	    return(-1);
3668 	}
3669 	memset(cur->nodeTab, 0 ,
3670 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3671         cur->nodeMax = XML_NODESET_DEFAULT;
3672     } else if (cur->nodeNr == cur->nodeMax) {
3673         xmlNodePtr *temp;
3674 
3675         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3676             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3677             return(-1);
3678         }
3679 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3680 				      sizeof(xmlNodePtr));
3681 	if (temp == NULL) {
3682 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3683 	    return(-1);
3684 	}
3685         cur->nodeMax *= 2;
3686 	cur->nodeTab = temp;
3687     }
3688     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3689     return(0);
3690 }
3691 
3692 /**
3693  * xmlXPathNodeSetAdd:
3694  * @cur:  the initial node set
3695  * @val:  a new xmlNodePtr
3696  *
3697  * add a new xmlNodePtr to an existing NodeSet
3698  *
3699  * Returns 0 in case of success, and -1 in case of error
3700  */
3701 int
xmlXPathNodeSetAdd(xmlNodeSetPtr cur,xmlNodePtr val)3702 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3703     int i;
3704 
3705     if ((cur == NULL) || (val == NULL)) return(-1);
3706 
3707     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3708     /*
3709      * prevent duplcates
3710      */
3711     for (i = 0;i < cur->nodeNr;i++)
3712         if (cur->nodeTab[i] == val) return(0);
3713 
3714     /*
3715      * grow the nodeTab if needed
3716      */
3717     if (cur->nodeMax == 0) {
3718         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3719 					     sizeof(xmlNodePtr));
3720 	if (cur->nodeTab == NULL) {
3721 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3722 	    return(-1);
3723 	}
3724 	memset(cur->nodeTab, 0 ,
3725 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3726         cur->nodeMax = XML_NODESET_DEFAULT;
3727     } else if (cur->nodeNr == cur->nodeMax) {
3728         xmlNodePtr *temp;
3729 
3730         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3731             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3732             return(-1);
3733         }
3734 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3735 				      sizeof(xmlNodePtr));
3736 	if (temp == NULL) {
3737 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3738 	    return(-1);
3739 	}
3740         cur->nodeMax *= 2;
3741 	cur->nodeTab = temp;
3742     }
3743     if (val->type == XML_NAMESPACE_DECL) {
3744 	xmlNsPtr ns = (xmlNsPtr) val;
3745 
3746 	cur->nodeTab[cur->nodeNr++] =
3747 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3748     } else
3749 	cur->nodeTab[cur->nodeNr++] = val;
3750     return(0);
3751 }
3752 
3753 /**
3754  * xmlXPathNodeSetAddUnique:
3755  * @cur:  the initial node set
3756  * @val:  a new xmlNodePtr
3757  *
3758  * add a new xmlNodePtr to an existing NodeSet, optimized version
3759  * when we are sure the node is not already in the set.
3760  *
3761  * Returns 0 in case of success and -1 in case of failure
3762  */
3763 int
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur,xmlNodePtr val)3764 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3765     if ((cur == NULL) || (val == NULL)) return(-1);
3766 
3767     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3768     /*
3769      * grow the nodeTab if needed
3770      */
3771     if (cur->nodeMax == 0) {
3772         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3773 					     sizeof(xmlNodePtr));
3774 	if (cur->nodeTab == NULL) {
3775 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3776 	    return(-1);
3777 	}
3778 	memset(cur->nodeTab, 0 ,
3779 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3780         cur->nodeMax = XML_NODESET_DEFAULT;
3781     } else if (cur->nodeNr == cur->nodeMax) {
3782         xmlNodePtr *temp;
3783 
3784         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3785             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3786             return(-1);
3787         }
3788 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3789 				      sizeof(xmlNodePtr));
3790 	if (temp == NULL) {
3791 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3792 	    return(-1);
3793 	}
3794 	cur->nodeTab = temp;
3795         cur->nodeMax *= 2;
3796     }
3797     if (val->type == XML_NAMESPACE_DECL) {
3798 	xmlNsPtr ns = (xmlNsPtr) val;
3799 
3800 	cur->nodeTab[cur->nodeNr++] =
3801 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3802     } else
3803 	cur->nodeTab[cur->nodeNr++] = val;
3804     return(0);
3805 }
3806 
3807 /**
3808  * xmlXPathNodeSetMerge:
3809  * @val1:  the first NodeSet or NULL
3810  * @val2:  the second NodeSet
3811  *
3812  * Merges two nodesets, all nodes from @val2 are added to @val1
3813  * if @val1 is NULL, a new set is created and copied from @val2
3814  *
3815  * Returns @val1 once extended or NULL in case of error.
3816  */
3817 xmlNodeSetPtr
xmlXPathNodeSetMerge(xmlNodeSetPtr val1,xmlNodeSetPtr val2)3818 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3819     int i, j, initNr, skip;
3820     xmlNodePtr n1, n2;
3821 
3822     if (val2 == NULL) return(val1);
3823     if (val1 == NULL) {
3824 	val1 = xmlXPathNodeSetCreate(NULL);
3825     if (val1 == NULL)
3826         return (NULL);
3827 #if 0
3828 	/*
3829 	* TODO: The optimization won't work in every case, since
3830 	*  those nasty namespace nodes need to be added with
3831 	*  xmlXPathNodeSetDupNs() to the set; thus a pure
3832 	*  memcpy is not possible.
3833 	*  If there was a flag on the nodesetval, indicating that
3834 	*  some temporary nodes are in, that would be helpfull.
3835 	*/
3836 	/*
3837 	* Optimization: Create an equally sized node-set
3838 	* and memcpy the content.
3839 	*/
3840 	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3841 	if (val1 == NULL)
3842 	    return(NULL);
3843 	if (val2->nodeNr != 0) {
3844 	    if (val2->nodeNr == 1)
3845 		*(val1->nodeTab) = *(val2->nodeTab);
3846 	    else {
3847 		memcpy(val1->nodeTab, val2->nodeTab,
3848 		    val2->nodeNr * sizeof(xmlNodePtr));
3849 	    }
3850 	    val1->nodeNr = val2->nodeNr;
3851 	}
3852 	return(val1);
3853 #endif
3854     }
3855 
3856     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3857     initNr = val1->nodeNr;
3858 
3859     for (i = 0;i < val2->nodeNr;i++) {
3860 	n2 = val2->nodeTab[i];
3861 	/*
3862 	 * check against duplicates
3863 	 */
3864 	skip = 0;
3865 	for (j = 0; j < initNr; j++) {
3866 	    n1 = val1->nodeTab[j];
3867 	    if (n1 == n2) {
3868 		skip = 1;
3869 		break;
3870 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3871 		       (n2->type == XML_NAMESPACE_DECL)) {
3872 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3873 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3874 			((xmlNsPtr) n2)->prefix)))
3875 		{
3876 		    skip = 1;
3877 		    break;
3878 		}
3879 	    }
3880 	}
3881 	if (skip)
3882 	    continue;
3883 
3884 	/*
3885 	 * grow the nodeTab if needed
3886 	 */
3887 	if (val1->nodeMax == 0) {
3888 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3889 						    sizeof(xmlNodePtr));
3890 	    if (val1->nodeTab == NULL) {
3891 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3892 		return(NULL);
3893 	    }
3894 	    memset(val1->nodeTab, 0 ,
3895 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3896 	    val1->nodeMax = XML_NODESET_DEFAULT;
3897 	} else if (val1->nodeNr == val1->nodeMax) {
3898 	    xmlNodePtr *temp;
3899 
3900             if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3901                 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3902                 return(NULL);
3903             }
3904 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3905 					     sizeof(xmlNodePtr));
3906 	    if (temp == NULL) {
3907 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3908 		return(NULL);
3909 	    }
3910 	    val1->nodeTab = temp;
3911 	    val1->nodeMax *= 2;
3912 	}
3913 	if (n2->type == XML_NAMESPACE_DECL) {
3914 	    xmlNsPtr ns = (xmlNsPtr) n2;
3915 
3916 	    val1->nodeTab[val1->nodeNr++] =
3917 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3918 	} else
3919 	    val1->nodeTab[val1->nodeNr++] = n2;
3920     }
3921 
3922     return(val1);
3923 }
3924 
3925 
3926 /**
3927  * xmlXPathNodeSetMergeAndClear:
3928  * @set1:  the first NodeSet or NULL
3929  * @set2:  the second NodeSet
3930  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3931  *
3932  * Merges two nodesets, all nodes from @set2 are added to @set1
3933  * if @set1 is NULL, a new set is created and copied from @set2.
3934  * Checks for duplicate nodes. Clears set2.
3935  *
3936  * Returns @set1 once extended or NULL in case of error.
3937  */
3938 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1,xmlNodeSetPtr set2,int hasNullEntries)3939 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3940 			     int hasNullEntries)
3941 {
3942     if ((set1 == NULL) && (hasNullEntries == 0)) {
3943 	/*
3944 	* Note that doing a memcpy of the list, namespace nodes are
3945 	* just assigned to set1, since set2 is cleared anyway.
3946 	*/
3947 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3948 	if (set1 == NULL)
3949 	    return(NULL);
3950 	if (set2->nodeNr != 0) {
3951 	    memcpy(set1->nodeTab, set2->nodeTab,
3952 		set2->nodeNr * sizeof(xmlNodePtr));
3953 	    set1->nodeNr = set2->nodeNr;
3954 	}
3955     } else {
3956 	int i, j, initNbSet1;
3957 	xmlNodePtr n1, n2;
3958 
3959 	if (set1 == NULL)
3960             set1 = xmlXPathNodeSetCreate(NULL);
3961         if (set1 == NULL)
3962             return (NULL);
3963 
3964 	initNbSet1 = set1->nodeNr;
3965 	for (i = 0;i < set2->nodeNr;i++) {
3966 	    n2 = set2->nodeTab[i];
3967 	    /*
3968 	    * Skip NULLed entries.
3969 	    */
3970 	    if (n2 == NULL)
3971 		continue;
3972 	    /*
3973 	    * Skip duplicates.
3974 	    */
3975 	    for (j = 0; j < initNbSet1; j++) {
3976 		n1 = set1->nodeTab[j];
3977 		if (n1 == n2) {
3978 		    goto skip_node;
3979 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
3980 		    (n2->type == XML_NAMESPACE_DECL))
3981 		{
3982 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3983 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
3984 			((xmlNsPtr) n2)->prefix)))
3985 		    {
3986 			/*
3987 			* Free the namespace node.
3988 			*/
3989 			set2->nodeTab[i] = NULL;
3990 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3991 			goto skip_node;
3992 		    }
3993 		}
3994 	    }
3995 	    /*
3996 	    * grow the nodeTab if needed
3997 	    */
3998 	    if (set1->nodeMax == 0) {
3999 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4000 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4001 		if (set1->nodeTab == NULL) {
4002 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4003 		    return(NULL);
4004 		}
4005 		memset(set1->nodeTab, 0,
4006 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4007 		set1->nodeMax = XML_NODESET_DEFAULT;
4008 	    } else if (set1->nodeNr >= set1->nodeMax) {
4009 		xmlNodePtr *temp;
4010 
4011                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4012                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4013                     return(NULL);
4014                 }
4015 		temp = (xmlNodePtr *) xmlRealloc(
4016 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4017 		if (temp == NULL) {
4018 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4019 		    return(NULL);
4020 		}
4021 		set1->nodeTab = temp;
4022 		set1->nodeMax *= 2;
4023 	    }
4024 	    if (n2->type == XML_NAMESPACE_DECL) {
4025 		xmlNsPtr ns = (xmlNsPtr) n2;
4026 
4027 		set1->nodeTab[set1->nodeNr++] =
4028 		    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
4029 	    } else
4030 		set1->nodeTab[set1->nodeNr++] = n2;
4031 skip_node:
4032 	    {}
4033 	}
4034     }
4035     set2->nodeNr = 0;
4036     return(set1);
4037 }
4038 
4039 /**
4040  * xmlXPathNodeSetMergeAndClearNoDupls:
4041  * @set1:  the first NodeSet or NULL
4042  * @set2:  the second NodeSet
4043  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4044  *
4045  * Merges two nodesets, all nodes from @set2 are added to @set1
4046  * if @set1 is NULL, a new set is created and copied from @set2.
4047  * Doesn't chack for duplicate nodes. Clears set2.
4048  *
4049  * Returns @set1 once extended or NULL in case of error.
4050  */
4051 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1,xmlNodeSetPtr set2,int hasNullEntries)4052 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4053 				    int hasNullEntries)
4054 {
4055     if (set2 == NULL)
4056 	return(set1);
4057     if ((set1 == NULL) && (hasNullEntries == 0)) {
4058 	/*
4059 	* Note that doing a memcpy of the list, namespace nodes are
4060 	* just assigned to set1, since set2 is cleared anyway.
4061 	*/
4062 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4063 	if (set1 == NULL)
4064 	    return(NULL);
4065 	if (set2->nodeNr != 0) {
4066 	    memcpy(set1->nodeTab, set2->nodeTab,
4067 		set2->nodeNr * sizeof(xmlNodePtr));
4068 	    set1->nodeNr = set2->nodeNr;
4069 	}
4070     } else {
4071 	int i;
4072 	xmlNodePtr n2;
4073 
4074 	if (set1 == NULL)
4075 	    set1 = xmlXPathNodeSetCreate(NULL);
4076         if (set1 == NULL)
4077             return (NULL);
4078 
4079 	for (i = 0;i < set2->nodeNr;i++) {
4080 	    n2 = set2->nodeTab[i];
4081 	    /*
4082 	    * Skip NULLed entries.
4083 	    */
4084 	    if (n2 == NULL)
4085 		continue;
4086 	    if (set1->nodeMax == 0) {
4087 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4088 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4089 		if (set1->nodeTab == NULL) {
4090 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4091 		    return(NULL);
4092 		}
4093 		memset(set1->nodeTab, 0,
4094 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4095 		set1->nodeMax = XML_NODESET_DEFAULT;
4096 	    } else if (set1->nodeNr >= set1->nodeMax) {
4097 		xmlNodePtr *temp;
4098 
4099                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4100                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4101                     return(NULL);
4102                 }
4103 		temp = (xmlNodePtr *) xmlRealloc(
4104 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4105 		if (temp == NULL) {
4106 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4107 		    return(NULL);
4108 		}
4109 		set1->nodeTab = temp;
4110 		set1->nodeMax *= 2;
4111 	    }
4112 	    set1->nodeTab[set1->nodeNr++] = n2;
4113 	}
4114     }
4115     set2->nodeNr = 0;
4116     return(set1);
4117 }
4118 
4119 /**
4120  * xmlXPathNodeSetDel:
4121  * @cur:  the initial node set
4122  * @val:  an xmlNodePtr
4123  *
4124  * Removes an xmlNodePtr from an existing NodeSet
4125  */
4126 void
xmlXPathNodeSetDel(xmlNodeSetPtr cur,xmlNodePtr val)4127 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4128     int i;
4129 
4130     if (cur == NULL) return;
4131     if (val == NULL) return;
4132 
4133     /*
4134      * find node in nodeTab
4135      */
4136     for (i = 0;i < cur->nodeNr;i++)
4137         if (cur->nodeTab[i] == val) break;
4138 
4139     if (i >= cur->nodeNr) {	/* not found */
4140 #ifdef DEBUG
4141         xmlGenericError(xmlGenericErrorContext,
4142 	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4143 		val->name);
4144 #endif
4145         return;
4146     }
4147     if ((cur->nodeTab[i] != NULL) &&
4148 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4149 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4150     cur->nodeNr--;
4151     for (;i < cur->nodeNr;i++)
4152         cur->nodeTab[i] = cur->nodeTab[i + 1];
4153     cur->nodeTab[cur->nodeNr] = NULL;
4154 }
4155 
4156 /**
4157  * xmlXPathNodeSetRemove:
4158  * @cur:  the initial node set
4159  * @val:  the index to remove
4160  *
4161  * Removes an entry from an existing NodeSet list.
4162  */
4163 void
xmlXPathNodeSetRemove(xmlNodeSetPtr cur,int val)4164 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4165     if (cur == NULL) return;
4166     if (val >= cur->nodeNr) return;
4167     if ((cur->nodeTab[val] != NULL) &&
4168 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4169 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4170     cur->nodeNr--;
4171     for (;val < cur->nodeNr;val++)
4172         cur->nodeTab[val] = cur->nodeTab[val + 1];
4173     cur->nodeTab[cur->nodeNr] = NULL;
4174 }
4175 
4176 /**
4177  * xmlXPathFreeNodeSet:
4178  * @obj:  the xmlNodeSetPtr to free
4179  *
4180  * Free the NodeSet compound (not the actual nodes !).
4181  */
4182 void
xmlXPathFreeNodeSet(xmlNodeSetPtr obj)4183 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4184     if (obj == NULL) return;
4185     if (obj->nodeTab != NULL) {
4186 	int i;
4187 
4188 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
4189 	for (i = 0;i < obj->nodeNr;i++)
4190 	    if ((obj->nodeTab[i] != NULL) &&
4191 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4192 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4193 	xmlFree(obj->nodeTab);
4194     }
4195     xmlFree(obj);
4196 }
4197 
4198 /**
4199  * xmlXPathNodeSetClear:
4200  * @set:  the node set to clear
4201  *
4202  * Clears the list from all temporary XPath objects (e.g. namespace nodes
4203  * are feed), but does *not* free the list itself. Sets the length of the
4204  * list to 0.
4205  */
4206 static void
xmlXPathNodeSetClear(xmlNodeSetPtr set,int hasNsNodes)4207 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4208 {
4209     if ((set == NULL) || (set->nodeNr <= 0))
4210 	return;
4211     else if (hasNsNodes) {
4212 	int i;
4213 	xmlNodePtr node;
4214 
4215 	for (i = 0; i < set->nodeNr; i++) {
4216 	    node = set->nodeTab[i];
4217 	    if ((node != NULL) &&
4218 		(node->type == XML_NAMESPACE_DECL))
4219 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4220 	}
4221     }
4222     set->nodeNr = 0;
4223 }
4224 
4225 /**
4226  * xmlXPathNodeSetClearFromPos:
4227  * @set: the node set to be cleared
4228  * @pos: the start position to clear from
4229  *
4230  * Clears the list from temporary XPath objects (e.g. namespace nodes
4231  * are feed) starting with the entry at @pos, but does *not* free the list
4232  * itself. Sets the length of the list to @pos.
4233  */
4234 static void
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set,int pos,int hasNsNodes)4235 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4236 {
4237     if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4238 	return;
4239     else if ((hasNsNodes)) {
4240 	int i;
4241 	xmlNodePtr node;
4242 
4243 	for (i = pos; i < set->nodeNr; i++) {
4244 	    node = set->nodeTab[i];
4245 	    if ((node != NULL) &&
4246 		(node->type == XML_NAMESPACE_DECL))
4247 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4248 	}
4249     }
4250     set->nodeNr = pos;
4251 }
4252 
4253 /**
4254  * xmlXPathFreeValueTree:
4255  * @obj:  the xmlNodeSetPtr to free
4256  *
4257  * Free the NodeSet compound and the actual tree, this is different
4258  * from xmlXPathFreeNodeSet()
4259  */
4260 static void
xmlXPathFreeValueTree(xmlNodeSetPtr obj)4261 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4262     int i;
4263 
4264     if (obj == NULL) return;
4265 
4266     if (obj->nodeTab != NULL) {
4267 	for (i = 0;i < obj->nodeNr;i++) {
4268 	    if (obj->nodeTab[i] != NULL) {
4269 		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4270 		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4271 		} else {
4272 		    xmlFreeNodeList(obj->nodeTab[i]);
4273 		}
4274 	    }
4275 	}
4276 	xmlFree(obj->nodeTab);
4277     }
4278     xmlFree(obj);
4279 }
4280 
4281 #if defined(DEBUG) || defined(DEBUG_STEP)
4282 /**
4283  * xmlGenericErrorContextNodeSet:
4284  * @output:  a FILE * for the output
4285  * @obj:  the xmlNodeSetPtr to display
4286  *
4287  * Quick display of a NodeSet
4288  */
4289 void
xmlGenericErrorContextNodeSet(FILE * output,xmlNodeSetPtr obj)4290 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4291     int i;
4292 
4293     if (output == NULL) output = xmlGenericErrorContext;
4294     if (obj == NULL)  {
4295         fprintf(output, "NodeSet == NULL !\n");
4296 	return;
4297     }
4298     if (obj->nodeNr == 0) {
4299         fprintf(output, "NodeSet is empty\n");
4300 	return;
4301     }
4302     if (obj->nodeTab == NULL) {
4303 	fprintf(output, " nodeTab == NULL !\n");
4304 	return;
4305     }
4306     for (i = 0; i < obj->nodeNr; i++) {
4307         if (obj->nodeTab[i] == NULL) {
4308 	    fprintf(output, " NULL !\n");
4309 	    return;
4310         }
4311 	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4312 	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4313 	    fprintf(output, " /");
4314 	else if (obj->nodeTab[i]->name == NULL)
4315 	    fprintf(output, " noname!");
4316 	else fprintf(output, " %s", obj->nodeTab[i]->name);
4317     }
4318     fprintf(output, "\n");
4319 }
4320 #endif
4321 
4322 /**
4323  * xmlXPathNewNodeSet:
4324  * @val:  the NodePtr value
4325  *
4326  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4327  * it with the single Node @val
4328  *
4329  * Returns the newly created object.
4330  */
4331 xmlXPathObjectPtr
xmlXPathNewNodeSet(xmlNodePtr val)4332 xmlXPathNewNodeSet(xmlNodePtr val) {
4333     xmlXPathObjectPtr ret;
4334 
4335     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4336     if (ret == NULL) {
4337         xmlXPathErrMemory(NULL, "creating nodeset\n");
4338 	return(NULL);
4339     }
4340     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4341     ret->type = XPATH_NODESET;
4342     ret->boolval = 0;
4343     ret->nodesetval = xmlXPathNodeSetCreate(val);
4344     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4345 #ifdef XP_DEBUG_OBJ_USAGE
4346     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4347 #endif
4348     return(ret);
4349 }
4350 
4351 /**
4352  * xmlXPathNewValueTree:
4353  * @val:  the NodePtr value
4354  *
4355  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4356  * it with the tree root @val
4357  *
4358  * Returns the newly created object.
4359  */
4360 xmlXPathObjectPtr
xmlXPathNewValueTree(xmlNodePtr val)4361 xmlXPathNewValueTree(xmlNodePtr val) {
4362     xmlXPathObjectPtr ret;
4363 
4364     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4365     if (ret == NULL) {
4366         xmlXPathErrMemory(NULL, "creating result value tree\n");
4367 	return(NULL);
4368     }
4369     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4370     ret->type = XPATH_XSLT_TREE;
4371     ret->boolval = 1;
4372     ret->user = (void *) val;
4373     ret->nodesetval = xmlXPathNodeSetCreate(val);
4374 #ifdef XP_DEBUG_OBJ_USAGE
4375     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4376 #endif
4377     return(ret);
4378 }
4379 
4380 /**
4381  * xmlXPathNewNodeSetList:
4382  * @val:  an existing NodeSet
4383  *
4384  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4385  * it with the Nodeset @val
4386  *
4387  * Returns the newly created object.
4388  */
4389 xmlXPathObjectPtr
xmlXPathNewNodeSetList(xmlNodeSetPtr val)4390 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4391 {
4392     xmlXPathObjectPtr ret;
4393     int i;
4394 
4395     if (val == NULL)
4396         ret = NULL;
4397     else if (val->nodeTab == NULL)
4398         ret = xmlXPathNewNodeSet(NULL);
4399     else {
4400         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4401         if (ret) {
4402             for (i = 1; i < val->nodeNr; ++i) {
4403                 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4404 		    < 0) break;
4405 	    }
4406 	}
4407     }
4408 
4409     return (ret);
4410 }
4411 
4412 /**
4413  * xmlXPathWrapNodeSet:
4414  * @val:  the NodePtr value
4415  *
4416  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4417  *
4418  * Returns the newly created object.
4419  */
4420 xmlXPathObjectPtr
xmlXPathWrapNodeSet(xmlNodeSetPtr val)4421 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4422     xmlXPathObjectPtr ret;
4423 
4424     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4425     if (ret == NULL) {
4426         xmlXPathErrMemory(NULL, "creating node set object\n");
4427 	return(NULL);
4428     }
4429     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4430     ret->type = XPATH_NODESET;
4431     ret->nodesetval = val;
4432 #ifdef XP_DEBUG_OBJ_USAGE
4433     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4434 #endif
4435     return(ret);
4436 }
4437 
4438 /**
4439  * xmlXPathFreeNodeSetList:
4440  * @obj:  an existing NodeSetList object
4441  *
4442  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4443  * the list contrary to xmlXPathFreeObject().
4444  */
4445 void
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj)4446 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4447     if (obj == NULL) return;
4448 #ifdef XP_DEBUG_OBJ_USAGE
4449     xmlXPathDebugObjUsageReleased(NULL, obj->type);
4450 #endif
4451     xmlFree(obj);
4452 }
4453 
4454 /**
4455  * xmlXPathDifference:
4456  * @nodes1:  a node-set
4457  * @nodes2:  a node-set
4458  *
4459  * Implements the EXSLT - Sets difference() function:
4460  *    node-set set:difference (node-set, node-set)
4461  *
4462  * Returns the difference between the two node sets, or nodes1 if
4463  *         nodes2 is empty
4464  */
4465 xmlNodeSetPtr
xmlXPathDifference(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4466 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4467     xmlNodeSetPtr ret;
4468     int i, l1;
4469     xmlNodePtr cur;
4470 
4471     if (xmlXPathNodeSetIsEmpty(nodes2))
4472 	return(nodes1);
4473 
4474     ret = xmlXPathNodeSetCreate(NULL);
4475     if (xmlXPathNodeSetIsEmpty(nodes1))
4476 	return(ret);
4477 
4478     l1 = xmlXPathNodeSetGetLength(nodes1);
4479 
4480     for (i = 0; i < l1; i++) {
4481 	cur = xmlXPathNodeSetItem(nodes1, i);
4482 	if (!xmlXPathNodeSetContains(nodes2, cur)) {
4483 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4484 	        break;
4485 	}
4486     }
4487     return(ret);
4488 }
4489 
4490 /**
4491  * xmlXPathIntersection:
4492  * @nodes1:  a node-set
4493  * @nodes2:  a node-set
4494  *
4495  * Implements the EXSLT - Sets intersection() function:
4496  *    node-set set:intersection (node-set, node-set)
4497  *
4498  * Returns a node set comprising the nodes that are within both the
4499  *         node sets passed as arguments
4500  */
4501 xmlNodeSetPtr
xmlXPathIntersection(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4502 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4503     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4504     int i, l1;
4505     xmlNodePtr cur;
4506 
4507     if (ret == NULL)
4508         return(ret);
4509     if (xmlXPathNodeSetIsEmpty(nodes1))
4510 	return(ret);
4511     if (xmlXPathNodeSetIsEmpty(nodes2))
4512 	return(ret);
4513 
4514     l1 = xmlXPathNodeSetGetLength(nodes1);
4515 
4516     for (i = 0; i < l1; i++) {
4517 	cur = xmlXPathNodeSetItem(nodes1, i);
4518 	if (xmlXPathNodeSetContains(nodes2, cur)) {
4519 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4520 	        break;
4521 	}
4522     }
4523     return(ret);
4524 }
4525 
4526 /**
4527  * xmlXPathDistinctSorted:
4528  * @nodes:  a node-set, sorted by document order
4529  *
4530  * Implements the EXSLT - Sets distinct() function:
4531  *    node-set set:distinct (node-set)
4532  *
4533  * Returns a subset of the nodes contained in @nodes, or @nodes if
4534  *         it is empty
4535  */
4536 xmlNodeSetPtr
xmlXPathDistinctSorted(xmlNodeSetPtr nodes)4537 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4538     xmlNodeSetPtr ret;
4539     xmlHashTablePtr hash;
4540     int i, l;
4541     xmlChar * strval;
4542     xmlNodePtr cur;
4543 
4544     if (xmlXPathNodeSetIsEmpty(nodes))
4545 	return(nodes);
4546 
4547     ret = xmlXPathNodeSetCreate(NULL);
4548     if (ret == NULL)
4549         return(ret);
4550     l = xmlXPathNodeSetGetLength(nodes);
4551     hash = xmlHashCreate (l);
4552     for (i = 0; i < l; i++) {
4553 	cur = xmlXPathNodeSetItem(nodes, i);
4554 	strval = xmlXPathCastNodeToString(cur);
4555 	if (xmlHashLookup(hash, strval) == NULL) {
4556 	    xmlHashAddEntry(hash, strval, strval);
4557 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4558 	        break;
4559 	} else {
4560 	    xmlFree(strval);
4561 	}
4562     }
4563     xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4564     return(ret);
4565 }
4566 
4567 /**
4568  * xmlXPathDistinct:
4569  * @nodes:  a node-set
4570  *
4571  * Implements the EXSLT - Sets distinct() function:
4572  *    node-set set:distinct (node-set)
4573  * @nodes is sorted by document order, then #exslSetsDistinctSorted
4574  * is called with the sorted node-set
4575  *
4576  * Returns a subset of the nodes contained in @nodes, or @nodes if
4577  *         it is empty
4578  */
4579 xmlNodeSetPtr
xmlXPathDistinct(xmlNodeSetPtr nodes)4580 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4581     if (xmlXPathNodeSetIsEmpty(nodes))
4582 	return(nodes);
4583 
4584     xmlXPathNodeSetSort(nodes);
4585     return(xmlXPathDistinctSorted(nodes));
4586 }
4587 
4588 /**
4589  * xmlXPathHasSameNodes:
4590  * @nodes1:  a node-set
4591  * @nodes2:  a node-set
4592  *
4593  * Implements the EXSLT - Sets has-same-nodes function:
4594  *    boolean set:has-same-node(node-set, node-set)
4595  *
4596  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4597  *         otherwise
4598  */
4599 int
xmlXPathHasSameNodes(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4600 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4601     int i, l;
4602     xmlNodePtr cur;
4603 
4604     if (xmlXPathNodeSetIsEmpty(nodes1) ||
4605 	xmlXPathNodeSetIsEmpty(nodes2))
4606 	return(0);
4607 
4608     l = xmlXPathNodeSetGetLength(nodes1);
4609     for (i = 0; i < l; i++) {
4610 	cur = xmlXPathNodeSetItem(nodes1, i);
4611 	if (xmlXPathNodeSetContains(nodes2, cur))
4612 	    return(1);
4613     }
4614     return(0);
4615 }
4616 
4617 /**
4618  * xmlXPathNodeLeadingSorted:
4619  * @nodes: a node-set, sorted by document order
4620  * @node: a node
4621  *
4622  * Implements the EXSLT - Sets leading() function:
4623  *    node-set set:leading (node-set, node-set)
4624  *
4625  * Returns the nodes in @nodes that precede @node in document order,
4626  *         @nodes if @node is NULL or an empty node-set if @nodes
4627  *         doesn't contain @node
4628  */
4629 xmlNodeSetPtr
xmlXPathNodeLeadingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4630 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4631     int i, l;
4632     xmlNodePtr cur;
4633     xmlNodeSetPtr ret;
4634 
4635     if (node == NULL)
4636 	return(nodes);
4637 
4638     ret = xmlXPathNodeSetCreate(NULL);
4639     if (ret == NULL)
4640         return(ret);
4641     if (xmlXPathNodeSetIsEmpty(nodes) ||
4642 	(!xmlXPathNodeSetContains(nodes, node)))
4643 	return(ret);
4644 
4645     l = xmlXPathNodeSetGetLength(nodes);
4646     for (i = 0; i < l; i++) {
4647 	cur = xmlXPathNodeSetItem(nodes, i);
4648 	if (cur == node)
4649 	    break;
4650 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4651 	    break;
4652     }
4653     return(ret);
4654 }
4655 
4656 /**
4657  * xmlXPathNodeLeading:
4658  * @nodes:  a node-set
4659  * @node:  a node
4660  *
4661  * Implements the EXSLT - Sets leading() function:
4662  *    node-set set:leading (node-set, node-set)
4663  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4664  * is called.
4665  *
4666  * Returns the nodes in @nodes that precede @node in document order,
4667  *         @nodes if @node is NULL or an empty node-set if @nodes
4668  *         doesn't contain @node
4669  */
4670 xmlNodeSetPtr
xmlXPathNodeLeading(xmlNodeSetPtr nodes,xmlNodePtr node)4671 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4672     xmlXPathNodeSetSort(nodes);
4673     return(xmlXPathNodeLeadingSorted(nodes, node));
4674 }
4675 
4676 /**
4677  * xmlXPathLeadingSorted:
4678  * @nodes1:  a node-set, sorted by document order
4679  * @nodes2:  a node-set, sorted by document order
4680  *
4681  * Implements the EXSLT - Sets leading() function:
4682  *    node-set set:leading (node-set, node-set)
4683  *
4684  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4685  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4686  *         an empty node-set if @nodes1 doesn't contain @nodes2
4687  */
4688 xmlNodeSetPtr
xmlXPathLeadingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4689 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4690     if (xmlXPathNodeSetIsEmpty(nodes2))
4691 	return(nodes1);
4692     return(xmlXPathNodeLeadingSorted(nodes1,
4693 				     xmlXPathNodeSetItem(nodes2, 1)));
4694 }
4695 
4696 /**
4697  * xmlXPathLeading:
4698  * @nodes1:  a node-set
4699  * @nodes2:  a node-set
4700  *
4701  * Implements the EXSLT - Sets leading() function:
4702  *    node-set set:leading (node-set, node-set)
4703  * @nodes1 and @nodes2 are sorted by document order, then
4704  * #exslSetsLeadingSorted is called.
4705  *
4706  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4707  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4708  *         an empty node-set if @nodes1 doesn't contain @nodes2
4709  */
4710 xmlNodeSetPtr
xmlXPathLeading(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4711 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4712     if (xmlXPathNodeSetIsEmpty(nodes2))
4713 	return(nodes1);
4714     if (xmlXPathNodeSetIsEmpty(nodes1))
4715 	return(xmlXPathNodeSetCreate(NULL));
4716     xmlXPathNodeSetSort(nodes1);
4717     xmlXPathNodeSetSort(nodes2);
4718     return(xmlXPathNodeLeadingSorted(nodes1,
4719 				     xmlXPathNodeSetItem(nodes2, 1)));
4720 }
4721 
4722 /**
4723  * xmlXPathNodeTrailingSorted:
4724  * @nodes: a node-set, sorted by document order
4725  * @node: a node
4726  *
4727  * Implements the EXSLT - Sets trailing() function:
4728  *    node-set set:trailing (node-set, node-set)
4729  *
4730  * Returns the nodes in @nodes that follow @node in document order,
4731  *         @nodes if @node is NULL or an empty node-set if @nodes
4732  *         doesn't contain @node
4733  */
4734 xmlNodeSetPtr
xmlXPathNodeTrailingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4735 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4736     int i, l;
4737     xmlNodePtr cur;
4738     xmlNodeSetPtr ret;
4739 
4740     if (node == NULL)
4741 	return(nodes);
4742 
4743     ret = xmlXPathNodeSetCreate(NULL);
4744     if (ret == NULL)
4745         return(ret);
4746     if (xmlXPathNodeSetIsEmpty(nodes) ||
4747 	(!xmlXPathNodeSetContains(nodes, node)))
4748 	return(ret);
4749 
4750     l = xmlXPathNodeSetGetLength(nodes);
4751     for (i = l - 1; i >= 0; i--) {
4752 	cur = xmlXPathNodeSetItem(nodes, i);
4753 	if (cur == node)
4754 	    break;
4755 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4756 	    break;
4757     }
4758     xmlXPathNodeSetSort(ret);	/* bug 413451 */
4759     return(ret);
4760 }
4761 
4762 /**
4763  * xmlXPathNodeTrailing:
4764  * @nodes:  a node-set
4765  * @node:  a node
4766  *
4767  * Implements the EXSLT - Sets trailing() function:
4768  *    node-set set:trailing (node-set, node-set)
4769  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4770  * is called.
4771  *
4772  * Returns the nodes in @nodes that follow @node in document order,
4773  *         @nodes if @node is NULL or an empty node-set if @nodes
4774  *         doesn't contain @node
4775  */
4776 xmlNodeSetPtr
xmlXPathNodeTrailing(xmlNodeSetPtr nodes,xmlNodePtr node)4777 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4778     xmlXPathNodeSetSort(nodes);
4779     return(xmlXPathNodeTrailingSorted(nodes, node));
4780 }
4781 
4782 /**
4783  * xmlXPathTrailingSorted:
4784  * @nodes1:  a node-set, sorted by document order
4785  * @nodes2:  a node-set, sorted by document order
4786  *
4787  * Implements the EXSLT - Sets trailing() function:
4788  *    node-set set:trailing (node-set, node-set)
4789  *
4790  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4791  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4792  *         an empty node-set if @nodes1 doesn't contain @nodes2
4793  */
4794 xmlNodeSetPtr
xmlXPathTrailingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4795 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4796     if (xmlXPathNodeSetIsEmpty(nodes2))
4797 	return(nodes1);
4798     return(xmlXPathNodeTrailingSorted(nodes1,
4799 				      xmlXPathNodeSetItem(nodes2, 0)));
4800 }
4801 
4802 /**
4803  * xmlXPathTrailing:
4804  * @nodes1:  a node-set
4805  * @nodes2:  a node-set
4806  *
4807  * Implements the EXSLT - Sets trailing() function:
4808  *    node-set set:trailing (node-set, node-set)
4809  * @nodes1 and @nodes2 are sorted by document order, then
4810  * #xmlXPathTrailingSorted is called.
4811  *
4812  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4813  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4814  *         an empty node-set if @nodes1 doesn't contain @nodes2
4815  */
4816 xmlNodeSetPtr
xmlXPathTrailing(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4817 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4818     if (xmlXPathNodeSetIsEmpty(nodes2))
4819 	return(nodes1);
4820     if (xmlXPathNodeSetIsEmpty(nodes1))
4821 	return(xmlXPathNodeSetCreate(NULL));
4822     xmlXPathNodeSetSort(nodes1);
4823     xmlXPathNodeSetSort(nodes2);
4824     return(xmlXPathNodeTrailingSorted(nodes1,
4825 				      xmlXPathNodeSetItem(nodes2, 0)));
4826 }
4827 
4828 /************************************************************************
4829  *									*
4830  *		Routines to handle extra functions			*
4831  *									*
4832  ************************************************************************/
4833 
4834 /**
4835  * xmlXPathRegisterFunc:
4836  * @ctxt:  the XPath context
4837  * @name:  the function name
4838  * @f:  the function implementation or NULL
4839  *
4840  * Register a new function. If @f is NULL it unregisters the function
4841  *
4842  * Returns 0 in case of success, -1 in case of error
4843  */
4844 int
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathFunction f)4845 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4846 		     xmlXPathFunction f) {
4847     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4848 }
4849 
4850 /**
4851  * xmlXPathRegisterFuncNS:
4852  * @ctxt:  the XPath context
4853  * @name:  the function name
4854  * @ns_uri:  the function namespace URI
4855  * @f:  the function implementation or NULL
4856  *
4857  * Register a new function. If @f is NULL it unregisters the function
4858  *
4859  * Returns 0 in case of success, -1 in case of error
4860  */
4861 int
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathFunction f)4862 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4863 		       const xmlChar *ns_uri, xmlXPathFunction f) {
4864     if (ctxt == NULL)
4865 	return(-1);
4866     if (name == NULL)
4867 	return(-1);
4868 
4869     if (ctxt->funcHash == NULL)
4870 	ctxt->funcHash = xmlHashCreate(0);
4871     if (ctxt->funcHash == NULL)
4872 	return(-1);
4873     if (f == NULL)
4874         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4875     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4876 }
4877 
4878 /**
4879  * xmlXPathRegisterFuncLookup:
4880  * @ctxt:  the XPath context
4881  * @f:  the lookup function
4882  * @funcCtxt:  the lookup data
4883  *
4884  * Registers an external mechanism to do function lookup.
4885  */
4886 void
xmlXPathRegisterFuncLookup(xmlXPathContextPtr ctxt,xmlXPathFuncLookupFunc f,void * funcCtxt)4887 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4888 			    xmlXPathFuncLookupFunc f,
4889 			    void *funcCtxt) {
4890     if (ctxt == NULL)
4891 	return;
4892     ctxt->funcLookupFunc = f;
4893     ctxt->funcLookupData = funcCtxt;
4894 }
4895 
4896 /**
4897  * xmlXPathFunctionLookup:
4898  * @ctxt:  the XPath context
4899  * @name:  the function name
4900  *
4901  * Search in the Function array of the context for the given
4902  * function.
4903  *
4904  * Returns the xmlXPathFunction or NULL if not found
4905  */
4906 xmlXPathFunction
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt,const xmlChar * name)4907 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4908     if (ctxt == NULL)
4909 	return (NULL);
4910 
4911     if (ctxt->funcLookupFunc != NULL) {
4912 	xmlXPathFunction ret;
4913 	xmlXPathFuncLookupFunc f;
4914 
4915 	f = ctxt->funcLookupFunc;
4916 	ret = f(ctxt->funcLookupData, name, NULL);
4917 	if (ret != NULL)
4918 	    return(ret);
4919     }
4920     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4921 }
4922 
4923 /**
4924  * xmlXPathFunctionLookupNS:
4925  * @ctxt:  the XPath context
4926  * @name:  the function name
4927  * @ns_uri:  the function namespace URI
4928  *
4929  * Search in the Function array of the context for the given
4930  * function.
4931  *
4932  * Returns the xmlXPathFunction or NULL if not found
4933  */
4934 xmlXPathFunction
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4935 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4936 			 const xmlChar *ns_uri) {
4937     xmlXPathFunction ret;
4938 
4939     if (ctxt == NULL)
4940 	return(NULL);
4941     if (name == NULL)
4942 	return(NULL);
4943 
4944     if (ctxt->funcLookupFunc != NULL) {
4945 	xmlXPathFuncLookupFunc f;
4946 
4947 	f = ctxt->funcLookupFunc;
4948 	ret = f(ctxt->funcLookupData, name, ns_uri);
4949 	if (ret != NULL)
4950 	    return(ret);
4951     }
4952 
4953     if (ctxt->funcHash == NULL)
4954 	return(NULL);
4955 
4956     XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4957     return(ret);
4958 }
4959 
4960 /**
4961  * xmlXPathRegisteredFuncsCleanup:
4962  * @ctxt:  the XPath context
4963  *
4964  * Cleanup the XPath context data associated to registered functions
4965  */
4966 void
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt)4967 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4968     if (ctxt == NULL)
4969 	return;
4970 
4971     xmlHashFree(ctxt->funcHash, NULL);
4972     ctxt->funcHash = NULL;
4973 }
4974 
4975 /************************************************************************
4976  *									*
4977  *			Routines to handle Variables			*
4978  *									*
4979  ************************************************************************/
4980 
4981 /**
4982  * xmlXPathRegisterVariable:
4983  * @ctxt:  the XPath context
4984  * @name:  the variable name
4985  * @value:  the variable value or NULL
4986  *
4987  * Register a new variable value. If @value is NULL it unregisters
4988  * the variable
4989  *
4990  * Returns 0 in case of success, -1 in case of error
4991  */
4992 int
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathObjectPtr value)4993 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4994 			 xmlXPathObjectPtr value) {
4995     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4996 }
4997 
4998 /**
4999  * xmlXPathRegisterVariableNS:
5000  * @ctxt:  the XPath context
5001  * @name:  the variable name
5002  * @ns_uri:  the variable namespace URI
5003  * @value:  the variable value or NULL
5004  *
5005  * Register a new variable value. If @value is NULL it unregisters
5006  * the variable
5007  *
5008  * Returns 0 in case of success, -1 in case of error
5009  */
5010 int
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathObjectPtr value)5011 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5012 			   const xmlChar *ns_uri,
5013 			   xmlXPathObjectPtr value) {
5014     if (ctxt == NULL)
5015 	return(-1);
5016     if (name == NULL)
5017 	return(-1);
5018 
5019     if (ctxt->varHash == NULL)
5020 	ctxt->varHash = xmlHashCreate(0);
5021     if (ctxt->varHash == NULL)
5022 	return(-1);
5023     if (value == NULL)
5024         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5025 	                           (xmlHashDeallocator)xmlXPathFreeObject));
5026     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5027 			       (void *) value,
5028 			       (xmlHashDeallocator)xmlXPathFreeObject));
5029 }
5030 
5031 /**
5032  * xmlXPathRegisterVariableLookup:
5033  * @ctxt:  the XPath context
5034  * @f:  the lookup function
5035  * @data:  the lookup data
5036  *
5037  * register an external mechanism to do variable lookup
5038  */
5039 void
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,xmlXPathVariableLookupFunc f,void * data)5040 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5041 	 xmlXPathVariableLookupFunc f, void *data) {
5042     if (ctxt == NULL)
5043 	return;
5044     ctxt->varLookupFunc = f;
5045     ctxt->varLookupData = data;
5046 }
5047 
5048 /**
5049  * xmlXPathVariableLookup:
5050  * @ctxt:  the XPath context
5051  * @name:  the variable name
5052  *
5053  * Search in the Variable array of the context for the given
5054  * variable value.
5055  *
5056  * Returns a copy of the value or NULL if not found
5057  */
5058 xmlXPathObjectPtr
xmlXPathVariableLookup(xmlXPathContextPtr ctxt,const xmlChar * name)5059 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5060     if (ctxt == NULL)
5061 	return(NULL);
5062 
5063     if (ctxt->varLookupFunc != NULL) {
5064 	xmlXPathObjectPtr ret;
5065 
5066 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5067 	        (ctxt->varLookupData, name, NULL);
5068 	return(ret);
5069     }
5070     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5071 }
5072 
5073 /**
5074  * xmlXPathVariableLookupNS:
5075  * @ctxt:  the XPath context
5076  * @name:  the variable name
5077  * @ns_uri:  the variable namespace URI
5078  *
5079  * Search in the Variable array of the context for the given
5080  * variable value.
5081  *
5082  * Returns the a copy of the value or NULL if not found
5083  */
5084 xmlXPathObjectPtr
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)5085 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5086 			 const xmlChar *ns_uri) {
5087     if (ctxt == NULL)
5088 	return(NULL);
5089 
5090     if (ctxt->varLookupFunc != NULL) {
5091 	xmlXPathObjectPtr ret;
5092 
5093 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5094 	        (ctxt->varLookupData, name, ns_uri);
5095 	if (ret != NULL) return(ret);
5096     }
5097 
5098     if (ctxt->varHash == NULL)
5099 	return(NULL);
5100     if (name == NULL)
5101 	return(NULL);
5102 
5103     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5104 		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5105 }
5106 
5107 /**
5108  * xmlXPathRegisteredVariablesCleanup:
5109  * @ctxt:  the XPath context
5110  *
5111  * Cleanup the XPath context data associated to registered variables
5112  */
5113 void
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt)5114 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5115     if (ctxt == NULL)
5116 	return;
5117 
5118     xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5119     ctxt->varHash = NULL;
5120 }
5121 
5122 /**
5123  * xmlXPathRegisterNs:
5124  * @ctxt:  the XPath context
5125  * @prefix:  the namespace prefix cannot be NULL or empty string
5126  * @ns_uri:  the namespace name
5127  *
5128  * Register a new namespace. If @ns_uri is NULL it unregisters
5129  * the namespace
5130  *
5131  * Returns 0 in case of success, -1 in case of error
5132  */
5133 int
xmlXPathRegisterNs(xmlXPathContextPtr ctxt,const xmlChar * prefix,const xmlChar * ns_uri)5134 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5135 			   const xmlChar *ns_uri) {
5136     if (ctxt == NULL)
5137 	return(-1);
5138     if (prefix == NULL)
5139 	return(-1);
5140     if (prefix[0] == 0)
5141 	return(-1);
5142 
5143     if (ctxt->nsHash == NULL)
5144 	ctxt->nsHash = xmlHashCreate(10);
5145     if (ctxt->nsHash == NULL)
5146 	return(-1);
5147     if (ns_uri == NULL)
5148         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5149 	                          (xmlHashDeallocator)xmlFree));
5150     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5151 			      (xmlHashDeallocator)xmlFree));
5152 }
5153 
5154 /**
5155  * xmlXPathNsLookup:
5156  * @ctxt:  the XPath context
5157  * @prefix:  the namespace prefix value
5158  *
5159  * Search in the namespace declaration array of the context for the given
5160  * namespace name associated to the given prefix
5161  *
5162  * Returns the value or NULL if not found
5163  */
5164 const xmlChar *
xmlXPathNsLookup(xmlXPathContextPtr ctxt,const xmlChar * prefix)5165 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5166     if (ctxt == NULL)
5167 	return(NULL);
5168     if (prefix == NULL)
5169 	return(NULL);
5170 
5171 #ifdef XML_XML_NAMESPACE
5172     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5173 	return(XML_XML_NAMESPACE);
5174 #endif
5175 
5176     if (ctxt->namespaces != NULL) {
5177 	int i;
5178 
5179 	for (i = 0;i < ctxt->nsNr;i++) {
5180 	    if ((ctxt->namespaces[i] != NULL) &&
5181 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5182 		return(ctxt->namespaces[i]->href);
5183 	}
5184     }
5185 
5186     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5187 }
5188 
5189 /**
5190  * xmlXPathRegisteredNsCleanup:
5191  * @ctxt:  the XPath context
5192  *
5193  * Cleanup the XPath context data associated to registered variables
5194  */
5195 void
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt)5196 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5197     if (ctxt == NULL)
5198 	return;
5199 
5200     xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5201     ctxt->nsHash = NULL;
5202 }
5203 
5204 /************************************************************************
5205  *									*
5206  *			Routines to handle Values			*
5207  *									*
5208  ************************************************************************/
5209 
5210 /* Allocations are terrible, one needs to optimize all this !!! */
5211 
5212 /**
5213  * xmlXPathNewFloat:
5214  * @val:  the double value
5215  *
5216  * Create a new xmlXPathObjectPtr of type double and of value @val
5217  *
5218  * Returns the newly created object.
5219  */
5220 xmlXPathObjectPtr
xmlXPathNewFloat(double val)5221 xmlXPathNewFloat(double val) {
5222     xmlXPathObjectPtr ret;
5223 
5224     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5225     if (ret == NULL) {
5226         xmlXPathErrMemory(NULL, "creating float object\n");
5227 	return(NULL);
5228     }
5229     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5230     ret->type = XPATH_NUMBER;
5231     ret->floatval = val;
5232 #ifdef XP_DEBUG_OBJ_USAGE
5233     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5234 #endif
5235     return(ret);
5236 }
5237 
5238 /**
5239  * xmlXPathNewBoolean:
5240  * @val:  the boolean value
5241  *
5242  * Create a new xmlXPathObjectPtr of type boolean and of value @val
5243  *
5244  * Returns the newly created object.
5245  */
5246 xmlXPathObjectPtr
xmlXPathNewBoolean(int val)5247 xmlXPathNewBoolean(int val) {
5248     xmlXPathObjectPtr ret;
5249 
5250     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5251     if (ret == NULL) {
5252         xmlXPathErrMemory(NULL, "creating boolean object\n");
5253 	return(NULL);
5254     }
5255     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5256     ret->type = XPATH_BOOLEAN;
5257     ret->boolval = (val != 0);
5258 #ifdef XP_DEBUG_OBJ_USAGE
5259     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5260 #endif
5261     return(ret);
5262 }
5263 
5264 /**
5265  * xmlXPathNewString:
5266  * @val:  the xmlChar * value
5267  *
5268  * Create a new xmlXPathObjectPtr of type string and of value @val
5269  *
5270  * Returns the newly created object.
5271  */
5272 xmlXPathObjectPtr
xmlXPathNewString(const xmlChar * val)5273 xmlXPathNewString(const xmlChar *val) {
5274     xmlXPathObjectPtr ret;
5275 
5276     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5277     if (ret == NULL) {
5278         xmlXPathErrMemory(NULL, "creating string object\n");
5279 	return(NULL);
5280     }
5281     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5282     ret->type = XPATH_STRING;
5283     if (val != NULL)
5284 	ret->stringval = xmlStrdup(val);
5285     else
5286 	ret->stringval = xmlStrdup((const xmlChar *)"");
5287 #ifdef XP_DEBUG_OBJ_USAGE
5288     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5289 #endif
5290     return(ret);
5291 }
5292 
5293 /**
5294  * xmlXPathWrapString:
5295  * @val:  the xmlChar * value
5296  *
5297  * Wraps the @val string into an XPath object.
5298  *
5299  * Returns the newly created object.
5300  */
5301 xmlXPathObjectPtr
xmlXPathWrapString(xmlChar * val)5302 xmlXPathWrapString (xmlChar *val) {
5303     xmlXPathObjectPtr ret;
5304 
5305     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5306     if (ret == NULL) {
5307         xmlXPathErrMemory(NULL, "creating string object\n");
5308 	return(NULL);
5309     }
5310     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5311     ret->type = XPATH_STRING;
5312     ret->stringval = val;
5313 #ifdef XP_DEBUG_OBJ_USAGE
5314     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5315 #endif
5316     return(ret);
5317 }
5318 
5319 /**
5320  * xmlXPathNewCString:
5321  * @val:  the char * value
5322  *
5323  * Create a new xmlXPathObjectPtr of type string and of value @val
5324  *
5325  * Returns the newly created object.
5326  */
5327 xmlXPathObjectPtr
xmlXPathNewCString(const char * val)5328 xmlXPathNewCString(const char *val) {
5329     xmlXPathObjectPtr ret;
5330 
5331     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5332     if (ret == NULL) {
5333         xmlXPathErrMemory(NULL, "creating string object\n");
5334 	return(NULL);
5335     }
5336     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5337     ret->type = XPATH_STRING;
5338     ret->stringval = xmlStrdup(BAD_CAST val);
5339 #ifdef XP_DEBUG_OBJ_USAGE
5340     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5341 #endif
5342     return(ret);
5343 }
5344 
5345 /**
5346  * xmlXPathWrapCString:
5347  * @val:  the char * value
5348  *
5349  * Wraps a string into an XPath object.
5350  *
5351  * Returns the newly created object.
5352  */
5353 xmlXPathObjectPtr
xmlXPathWrapCString(char * val)5354 xmlXPathWrapCString (char * val) {
5355     return(xmlXPathWrapString((xmlChar *)(val)));
5356 }
5357 
5358 /**
5359  * xmlXPathWrapExternal:
5360  * @val:  the user data
5361  *
5362  * Wraps the @val data into an XPath object.
5363  *
5364  * Returns the newly created object.
5365  */
5366 xmlXPathObjectPtr
xmlXPathWrapExternal(void * val)5367 xmlXPathWrapExternal (void *val) {
5368     xmlXPathObjectPtr ret;
5369 
5370     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5371     if (ret == NULL) {
5372         xmlXPathErrMemory(NULL, "creating user object\n");
5373 	return(NULL);
5374     }
5375     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5376     ret->type = XPATH_USERS;
5377     ret->user = val;
5378 #ifdef XP_DEBUG_OBJ_USAGE
5379     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5380 #endif
5381     return(ret);
5382 }
5383 
5384 /**
5385  * xmlXPathObjectCopy:
5386  * @val:  the original object
5387  *
5388  * allocate a new copy of a given object
5389  *
5390  * Returns the newly created object.
5391  */
5392 xmlXPathObjectPtr
xmlXPathObjectCopy(xmlXPathObjectPtr val)5393 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5394     xmlXPathObjectPtr ret;
5395 
5396     if (val == NULL)
5397 	return(NULL);
5398 
5399     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5400     if (ret == NULL) {
5401         xmlXPathErrMemory(NULL, "copying object\n");
5402 	return(NULL);
5403     }
5404     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5405 #ifdef XP_DEBUG_OBJ_USAGE
5406     xmlXPathDebugObjUsageRequested(NULL, val->type);
5407 #endif
5408     switch (val->type) {
5409 	case XPATH_BOOLEAN:
5410 	case XPATH_NUMBER:
5411 	case XPATH_POINT:
5412 	case XPATH_RANGE:
5413 	    break;
5414 	case XPATH_STRING:
5415 	    ret->stringval = xmlStrdup(val->stringval);
5416 	    break;
5417 	case XPATH_XSLT_TREE:
5418 #if 0
5419 /*
5420   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5421   this previous handling is no longer correct, and can cause some serious
5422   problems (ref. bug 145547)
5423 */
5424 	    if ((val->nodesetval != NULL) &&
5425 		(val->nodesetval->nodeTab != NULL)) {
5426 		xmlNodePtr cur, tmp;
5427 		xmlDocPtr top;
5428 
5429 		ret->boolval = 1;
5430 		top =  xmlNewDoc(NULL);
5431 		top->name = (char *)
5432 		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
5433 		ret->user = top;
5434 		if (top != NULL) {
5435 		    top->doc = top;
5436 		    cur = val->nodesetval->nodeTab[0]->children;
5437 		    while (cur != NULL) {
5438 			tmp = xmlDocCopyNode(cur, top, 1);
5439 			xmlAddChild((xmlNodePtr) top, tmp);
5440 			cur = cur->next;
5441 		    }
5442 		}
5443 
5444 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5445 	    } else
5446 		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5447 	    /* Deallocate the copied tree value */
5448 	    break;
5449 #endif
5450 	case XPATH_NODESET:
5451 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5452 	    /* Do not deallocate the copied tree value */
5453 	    ret->boolval = 0;
5454 	    break;
5455 	case XPATH_LOCATIONSET:
5456 #ifdef LIBXML_XPTR_ENABLED
5457 	{
5458 	    xmlLocationSetPtr loc = val->user;
5459 	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5460 	    break;
5461 	}
5462 #endif
5463         case XPATH_USERS:
5464 	    ret->user = val->user;
5465 	    break;
5466         case XPATH_UNDEFINED:
5467 	    xmlGenericError(xmlGenericErrorContext,
5468 		    "xmlXPathObjectCopy: unsupported type %d\n",
5469 		    val->type);
5470 	    break;
5471     }
5472     return(ret);
5473 }
5474 
5475 /**
5476  * xmlXPathFreeObject:
5477  * @obj:  the object to free
5478  *
5479  * Free up an xmlXPathObjectPtr object.
5480  */
5481 void
xmlXPathFreeObject(xmlXPathObjectPtr obj)5482 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5483     if (obj == NULL) return;
5484     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5485 	if (obj->boolval) {
5486 #if 0
5487 	    if (obj->user != NULL) {
5488                 xmlXPathFreeNodeSet(obj->nodesetval);
5489 		xmlFreeNodeList((xmlNodePtr) obj->user);
5490 	    } else
5491 #endif
5492 	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5493 	    if (obj->nodesetval != NULL)
5494 		xmlXPathFreeValueTree(obj->nodesetval);
5495 	} else {
5496 	    if (obj->nodesetval != NULL)
5497 		xmlXPathFreeNodeSet(obj->nodesetval);
5498 	}
5499 #ifdef LIBXML_XPTR_ENABLED
5500     } else if (obj->type == XPATH_LOCATIONSET) {
5501 	if (obj->user != NULL)
5502 	    xmlXPtrFreeLocationSet(obj->user);
5503 #endif
5504     } else if (obj->type == XPATH_STRING) {
5505 	if (obj->stringval != NULL)
5506 	    xmlFree(obj->stringval);
5507     }
5508 #ifdef XP_DEBUG_OBJ_USAGE
5509     xmlXPathDebugObjUsageReleased(NULL, obj->type);
5510 #endif
5511     xmlFree(obj);
5512 }
5513 
5514 /**
5515  * xmlXPathReleaseObject:
5516  * @obj:  the xmlXPathObjectPtr to free or to cache
5517  *
5518  * Depending on the state of the cache this frees the given
5519  * XPath object or stores it in the cache.
5520  */
5521 static void
xmlXPathReleaseObject(xmlXPathContextPtr ctxt,xmlXPathObjectPtr obj)5522 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5523 {
5524 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5525 	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5526     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5527 
5528 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5529 
5530     if (obj == NULL)
5531 	return;
5532     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5533 	 xmlXPathFreeObject(obj);
5534     } else {
5535 	xmlXPathContextCachePtr cache =
5536 	    (xmlXPathContextCachePtr) ctxt->cache;
5537 
5538 	switch (obj->type) {
5539 	    case XPATH_NODESET:
5540 	    case XPATH_XSLT_TREE:
5541 		if (obj->nodesetval != NULL) {
5542 		    if (obj->boolval) {
5543 			/*
5544 			* It looks like the @boolval is used for
5545 			* evaluation if this an XSLT Result Tree Fragment.
5546 			* TODO: Check if this assumption is correct.
5547 			*/
5548 			obj->type = XPATH_XSLT_TREE; /* just for debugging */
5549 			xmlXPathFreeValueTree(obj->nodesetval);
5550 			obj->nodesetval = NULL;
5551 		    } else if ((obj->nodesetval->nodeMax <= 40) &&
5552 			(XP_CACHE_WANTS(cache->nodesetObjs,
5553 					cache->maxNodeset)))
5554 		    {
5555 			XP_CACHE_ADD(cache->nodesetObjs, obj);
5556 			goto obj_cached;
5557 		    } else {
5558 			xmlXPathFreeNodeSet(obj->nodesetval);
5559 			obj->nodesetval = NULL;
5560 		    }
5561 		}
5562 		break;
5563 	    case XPATH_STRING:
5564 		if (obj->stringval != NULL)
5565 		    xmlFree(obj->stringval);
5566 
5567 		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5568 		    XP_CACHE_ADD(cache->stringObjs, obj);
5569 		    goto obj_cached;
5570 		}
5571 		break;
5572 	    case XPATH_BOOLEAN:
5573 		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5574 		    XP_CACHE_ADD(cache->booleanObjs, obj);
5575 		    goto obj_cached;
5576 		}
5577 		break;
5578 	    case XPATH_NUMBER:
5579 		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5580 		    XP_CACHE_ADD(cache->numberObjs, obj);
5581 		    goto obj_cached;
5582 		}
5583 		break;
5584 #ifdef LIBXML_XPTR_ENABLED
5585 	    case XPATH_LOCATIONSET:
5586 		if (obj->user != NULL) {
5587 		    xmlXPtrFreeLocationSet(obj->user);
5588 		}
5589 		goto free_obj;
5590 #endif
5591 	    default:
5592 		goto free_obj;
5593 	}
5594 
5595 	/*
5596 	* Fallback to adding to the misc-objects slot.
5597 	*/
5598 	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5599 	    XP_CACHE_ADD(cache->miscObjs, obj);
5600 	} else
5601 	    goto free_obj;
5602 
5603 obj_cached:
5604 
5605 #ifdef XP_DEBUG_OBJ_USAGE
5606 	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5607 #endif
5608 
5609 	if (obj->nodesetval != NULL) {
5610 	    xmlNodeSetPtr tmpset = obj->nodesetval;
5611 
5612 	    /*
5613 	    * TODO: Due to those nasty ns-nodes, we need to traverse
5614 	    *  the list and free the ns-nodes.
5615 	    * URGENT TODO: Check if it's actually slowing things down.
5616 	    *  Maybe we shouldn't try to preserve the list.
5617 	    */
5618 	    if (tmpset->nodeNr > 1) {
5619 		int i;
5620 		xmlNodePtr node;
5621 
5622 		for (i = 0; i < tmpset->nodeNr; i++) {
5623 		    node = tmpset->nodeTab[i];
5624 		    if ((node != NULL) &&
5625 			(node->type == XML_NAMESPACE_DECL))
5626 		    {
5627 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5628 		    }
5629 		}
5630 	    } else if (tmpset->nodeNr == 1) {
5631 		if ((tmpset->nodeTab[0] != NULL) &&
5632 		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5633 		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5634 	    }
5635 	    tmpset->nodeNr = 0;
5636 	    memset(obj, 0, sizeof(xmlXPathObject));
5637 	    obj->nodesetval = tmpset;
5638 	} else
5639 	    memset(obj, 0, sizeof(xmlXPathObject));
5640 
5641 	return;
5642 
5643 free_obj:
5644 	/*
5645 	* Cache is full; free the object.
5646 	*/
5647 	if (obj->nodesetval != NULL)
5648 	    xmlXPathFreeNodeSet(obj->nodesetval);
5649 #ifdef XP_DEBUG_OBJ_USAGE
5650 	xmlXPathDebugObjUsageReleased(NULL, obj->type);
5651 #endif
5652 	xmlFree(obj);
5653     }
5654     return;
5655 }
5656 
5657 
5658 /************************************************************************
5659  *									*
5660  *			Type Casting Routines				*
5661  *									*
5662  ************************************************************************/
5663 
5664 /**
5665  * xmlXPathCastBooleanToString:
5666  * @val:  a boolean
5667  *
5668  * Converts a boolean to its string value.
5669  *
5670  * Returns a newly allocated string.
5671  */
5672 xmlChar *
xmlXPathCastBooleanToString(int val)5673 xmlXPathCastBooleanToString (int val) {
5674     xmlChar *ret;
5675     if (val)
5676 	ret = xmlStrdup((const xmlChar *) "true");
5677     else
5678 	ret = xmlStrdup((const xmlChar *) "false");
5679     return(ret);
5680 }
5681 
5682 /**
5683  * xmlXPathCastNumberToString:
5684  * @val:  a number
5685  *
5686  * Converts a number to its string value.
5687  *
5688  * Returns a newly allocated string.
5689  */
5690 xmlChar *
xmlXPathCastNumberToString(double val)5691 xmlXPathCastNumberToString (double val) {
5692     xmlChar *ret;
5693     switch (xmlXPathIsInf(val)) {
5694     case 1:
5695 	ret = xmlStrdup((const xmlChar *) "Infinity");
5696 	break;
5697     case -1:
5698 	ret = xmlStrdup((const xmlChar *) "-Infinity");
5699 	break;
5700     default:
5701 	if (xmlXPathIsNaN(val)) {
5702 	    ret = xmlStrdup((const xmlChar *) "NaN");
5703 	} else if (val == 0 && xmlXPathGetSign(val) != 0) {
5704 	    ret = xmlStrdup((const xmlChar *) "0");
5705 	} else {
5706 	    /* could be improved */
5707 	    char buf[100];
5708 	    xmlXPathFormatNumber(val, buf, 99);
5709 	    buf[99] = 0;
5710 	    ret = xmlStrdup((const xmlChar *) buf);
5711 	}
5712     }
5713     return(ret);
5714 }
5715 
5716 /**
5717  * xmlXPathCastNodeToString:
5718  * @node:  a node
5719  *
5720  * Converts a node to its string value.
5721  *
5722  * Returns a newly allocated string.
5723  */
5724 xmlChar *
xmlXPathCastNodeToString(xmlNodePtr node)5725 xmlXPathCastNodeToString (xmlNodePtr node) {
5726 xmlChar *ret;
5727     if ((ret = xmlNodeGetContent(node)) == NULL)
5728 	ret = xmlStrdup((const xmlChar *) "");
5729     return(ret);
5730 }
5731 
5732 /**
5733  * xmlXPathCastNodeSetToString:
5734  * @ns:  a node-set
5735  *
5736  * Converts a node-set to its string value.
5737  *
5738  * Returns a newly allocated string.
5739  */
5740 xmlChar *
xmlXPathCastNodeSetToString(xmlNodeSetPtr ns)5741 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5742     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5743 	return(xmlStrdup((const xmlChar *) ""));
5744 
5745     if (ns->nodeNr > 1)
5746 	xmlXPathNodeSetSort(ns);
5747     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5748 }
5749 
5750 /**
5751  * xmlXPathCastToString:
5752  * @val:  an XPath object
5753  *
5754  * Converts an existing object to its string() equivalent
5755  *
5756  * Returns the allocated string value of the object, NULL in case of error.
5757  *         It's up to the caller to free the string memory with xmlFree().
5758  */
5759 xmlChar *
xmlXPathCastToString(xmlXPathObjectPtr val)5760 xmlXPathCastToString(xmlXPathObjectPtr val) {
5761     xmlChar *ret = NULL;
5762 
5763     if (val == NULL)
5764 	return(xmlStrdup((const xmlChar *) ""));
5765     switch (val->type) {
5766 	case XPATH_UNDEFINED:
5767 #ifdef DEBUG_EXPR
5768 	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5769 #endif
5770 	    ret = xmlStrdup((const xmlChar *) "");
5771 	    break;
5772         case XPATH_NODESET:
5773         case XPATH_XSLT_TREE:
5774 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
5775 	    break;
5776 	case XPATH_STRING:
5777 	    return(xmlStrdup(val->stringval));
5778         case XPATH_BOOLEAN:
5779 	    ret = xmlXPathCastBooleanToString(val->boolval);
5780 	    break;
5781 	case XPATH_NUMBER: {
5782 	    ret = xmlXPathCastNumberToString(val->floatval);
5783 	    break;
5784 	}
5785 	case XPATH_USERS:
5786 	case XPATH_POINT:
5787 	case XPATH_RANGE:
5788 	case XPATH_LOCATIONSET:
5789 	    TODO
5790 	    ret = xmlStrdup((const xmlChar *) "");
5791 	    break;
5792     }
5793     return(ret);
5794 }
5795 
5796 /**
5797  * xmlXPathConvertString:
5798  * @val:  an XPath object
5799  *
5800  * Converts an existing object to its string() equivalent
5801  *
5802  * Returns the new object, the old one is freed (or the operation
5803  *         is done directly on @val)
5804  */
5805 xmlXPathObjectPtr
xmlXPathConvertString(xmlXPathObjectPtr val)5806 xmlXPathConvertString(xmlXPathObjectPtr val) {
5807     xmlChar *res = NULL;
5808 
5809     if (val == NULL)
5810 	return(xmlXPathNewCString(""));
5811 
5812     switch (val->type) {
5813     case XPATH_UNDEFINED:
5814 #ifdef DEBUG_EXPR
5815 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5816 #endif
5817 	break;
5818     case XPATH_NODESET:
5819     case XPATH_XSLT_TREE:
5820 	res = xmlXPathCastNodeSetToString(val->nodesetval);
5821 	break;
5822     case XPATH_STRING:
5823 	return(val);
5824     case XPATH_BOOLEAN:
5825 	res = xmlXPathCastBooleanToString(val->boolval);
5826 	break;
5827     case XPATH_NUMBER:
5828 	res = xmlXPathCastNumberToString(val->floatval);
5829 	break;
5830     case XPATH_USERS:
5831     case XPATH_POINT:
5832     case XPATH_RANGE:
5833     case XPATH_LOCATIONSET:
5834 	TODO;
5835 	break;
5836     }
5837     xmlXPathFreeObject(val);
5838     if (res == NULL)
5839 	return(xmlXPathNewCString(""));
5840     return(xmlXPathWrapString(res));
5841 }
5842 
5843 /**
5844  * xmlXPathCastBooleanToNumber:
5845  * @val:  a boolean
5846  *
5847  * Converts a boolean to its number value
5848  *
5849  * Returns the number value
5850  */
5851 double
xmlXPathCastBooleanToNumber(int val)5852 xmlXPathCastBooleanToNumber(int val) {
5853     if (val)
5854 	return(1.0);
5855     return(0.0);
5856 }
5857 
5858 /**
5859  * xmlXPathCastStringToNumber:
5860  * @val:  a string
5861  *
5862  * Converts a string to its number value
5863  *
5864  * Returns the number value
5865  */
5866 double
xmlXPathCastStringToNumber(const xmlChar * val)5867 xmlXPathCastStringToNumber(const xmlChar * val) {
5868     return(xmlXPathStringEvalNumber(val));
5869 }
5870 
5871 /**
5872  * xmlXPathCastNodeToNumber:
5873  * @node:  a node
5874  *
5875  * Converts a node to its number value
5876  *
5877  * Returns the number value
5878  */
5879 double
xmlXPathCastNodeToNumber(xmlNodePtr node)5880 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5881     xmlChar *strval;
5882     double ret;
5883 
5884     if (node == NULL)
5885 	return(xmlXPathNAN);
5886     strval = xmlXPathCastNodeToString(node);
5887     if (strval == NULL)
5888 	return(xmlXPathNAN);
5889     ret = xmlXPathCastStringToNumber(strval);
5890     xmlFree(strval);
5891 
5892     return(ret);
5893 }
5894 
5895 /**
5896  * xmlXPathCastNodeSetToNumber:
5897  * @ns:  a node-set
5898  *
5899  * Converts a node-set to its number value
5900  *
5901  * Returns the number value
5902  */
5903 double
xmlXPathCastNodeSetToNumber(xmlNodeSetPtr ns)5904 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5905     xmlChar *str;
5906     double ret;
5907 
5908     if (ns == NULL)
5909 	return(xmlXPathNAN);
5910     str = xmlXPathCastNodeSetToString(ns);
5911     ret = xmlXPathCastStringToNumber(str);
5912     xmlFree(str);
5913     return(ret);
5914 }
5915 
5916 /**
5917  * xmlXPathCastToNumber:
5918  * @val:  an XPath object
5919  *
5920  * Converts an XPath object to its number value
5921  *
5922  * Returns the number value
5923  */
5924 double
xmlXPathCastToNumber(xmlXPathObjectPtr val)5925 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5926     double ret = 0.0;
5927 
5928     if (val == NULL)
5929 	return(xmlXPathNAN);
5930     switch (val->type) {
5931     case XPATH_UNDEFINED:
5932 #ifdef DEGUB_EXPR
5933 	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5934 #endif
5935 	ret = xmlXPathNAN;
5936 	break;
5937     case XPATH_NODESET:
5938     case XPATH_XSLT_TREE:
5939 	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5940 	break;
5941     case XPATH_STRING:
5942 	ret = xmlXPathCastStringToNumber(val->stringval);
5943 	break;
5944     case XPATH_NUMBER:
5945 	ret = val->floatval;
5946 	break;
5947     case XPATH_BOOLEAN:
5948 	ret = xmlXPathCastBooleanToNumber(val->boolval);
5949 	break;
5950     case XPATH_USERS:
5951     case XPATH_POINT:
5952     case XPATH_RANGE:
5953     case XPATH_LOCATIONSET:
5954 	TODO;
5955 	ret = xmlXPathNAN;
5956 	break;
5957     }
5958     return(ret);
5959 }
5960 
5961 /**
5962  * xmlXPathConvertNumber:
5963  * @val:  an XPath object
5964  *
5965  * Converts an existing object to its number() equivalent
5966  *
5967  * Returns the new object, the old one is freed (or the operation
5968  *         is done directly on @val)
5969  */
5970 xmlXPathObjectPtr
xmlXPathConvertNumber(xmlXPathObjectPtr val)5971 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5972     xmlXPathObjectPtr ret;
5973 
5974     if (val == NULL)
5975 	return(xmlXPathNewFloat(0.0));
5976     if (val->type == XPATH_NUMBER)
5977 	return(val);
5978     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5979     xmlXPathFreeObject(val);
5980     return(ret);
5981 }
5982 
5983 /**
5984  * xmlXPathCastNumberToBoolean:
5985  * @val:  a number
5986  *
5987  * Converts a number to its boolean value
5988  *
5989  * Returns the boolean value
5990  */
5991 int
xmlXPathCastNumberToBoolean(double val)5992 xmlXPathCastNumberToBoolean (double val) {
5993      if (xmlXPathIsNaN(val) || (val == 0.0))
5994 	 return(0);
5995      return(1);
5996 }
5997 
5998 /**
5999  * xmlXPathCastStringToBoolean:
6000  * @val:  a string
6001  *
6002  * Converts a string to its boolean value
6003  *
6004  * Returns the boolean value
6005  */
6006 int
xmlXPathCastStringToBoolean(const xmlChar * val)6007 xmlXPathCastStringToBoolean (const xmlChar *val) {
6008     if ((val == NULL) || (xmlStrlen(val) == 0))
6009 	return(0);
6010     return(1);
6011 }
6012 
6013 /**
6014  * xmlXPathCastNodeSetToBoolean:
6015  * @ns:  a node-set
6016  *
6017  * Converts a node-set to its boolean value
6018  *
6019  * Returns the boolean value
6020  */
6021 int
xmlXPathCastNodeSetToBoolean(xmlNodeSetPtr ns)6022 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6023     if ((ns == NULL) || (ns->nodeNr == 0))
6024 	return(0);
6025     return(1);
6026 }
6027 
6028 /**
6029  * xmlXPathCastToBoolean:
6030  * @val:  an XPath object
6031  *
6032  * Converts an XPath object to its boolean value
6033  *
6034  * Returns the boolean value
6035  */
6036 int
xmlXPathCastToBoolean(xmlXPathObjectPtr val)6037 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6038     int ret = 0;
6039 
6040     if (val == NULL)
6041 	return(0);
6042     switch (val->type) {
6043     case XPATH_UNDEFINED:
6044 #ifdef DEBUG_EXPR
6045 	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6046 #endif
6047 	ret = 0;
6048 	break;
6049     case XPATH_NODESET:
6050     case XPATH_XSLT_TREE:
6051 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6052 	break;
6053     case XPATH_STRING:
6054 	ret = xmlXPathCastStringToBoolean(val->stringval);
6055 	break;
6056     case XPATH_NUMBER:
6057 	ret = xmlXPathCastNumberToBoolean(val->floatval);
6058 	break;
6059     case XPATH_BOOLEAN:
6060 	ret = val->boolval;
6061 	break;
6062     case XPATH_USERS:
6063     case XPATH_POINT:
6064     case XPATH_RANGE:
6065     case XPATH_LOCATIONSET:
6066 	TODO;
6067 	ret = 0;
6068 	break;
6069     }
6070     return(ret);
6071 }
6072 
6073 
6074 /**
6075  * xmlXPathConvertBoolean:
6076  * @val:  an XPath object
6077  *
6078  * Converts an existing object to its boolean() equivalent
6079  *
6080  * Returns the new object, the old one is freed (or the operation
6081  *         is done directly on @val)
6082  */
6083 xmlXPathObjectPtr
xmlXPathConvertBoolean(xmlXPathObjectPtr val)6084 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6085     xmlXPathObjectPtr ret;
6086 
6087     if (val == NULL)
6088 	return(xmlXPathNewBoolean(0));
6089     if (val->type == XPATH_BOOLEAN)
6090 	return(val);
6091     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6092     xmlXPathFreeObject(val);
6093     return(ret);
6094 }
6095 
6096 /************************************************************************
6097  *									*
6098  *		Routines to handle XPath contexts			*
6099  *									*
6100  ************************************************************************/
6101 
6102 /**
6103  * xmlXPathNewContext:
6104  * @doc:  the XML document
6105  *
6106  * Create a new xmlXPathContext
6107  *
6108  * Returns the xmlXPathContext just allocated. The caller will need to free it.
6109  */
6110 xmlXPathContextPtr
xmlXPathNewContext(xmlDocPtr doc)6111 xmlXPathNewContext(xmlDocPtr doc) {
6112     xmlXPathContextPtr ret;
6113 
6114     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6115     if (ret == NULL) {
6116         xmlXPathErrMemory(NULL, "creating context\n");
6117 	return(NULL);
6118     }
6119     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6120     ret->doc = doc;
6121     ret->node = NULL;
6122 
6123     ret->varHash = NULL;
6124 
6125     ret->nb_types = 0;
6126     ret->max_types = 0;
6127     ret->types = NULL;
6128 
6129     ret->funcHash = xmlHashCreate(0);
6130 
6131     ret->nb_axis = 0;
6132     ret->max_axis = 0;
6133     ret->axis = NULL;
6134 
6135     ret->nsHash = NULL;
6136     ret->user = NULL;
6137 
6138     ret->contextSize = -1;
6139     ret->proximityPosition = -1;
6140 
6141 #ifdef XP_DEFAULT_CACHE_ON
6142     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6143 	xmlXPathFreeContext(ret);
6144 	return(NULL);
6145     }
6146 #endif
6147 
6148     xmlXPathRegisterAllFunctions(ret);
6149 
6150     return(ret);
6151 }
6152 
6153 /**
6154  * xmlXPathFreeContext:
6155  * @ctxt:  the context to free
6156  *
6157  * Free up an xmlXPathContext
6158  */
6159 void
xmlXPathFreeContext(xmlXPathContextPtr ctxt)6160 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6161     if (ctxt == NULL) return;
6162 
6163     if (ctxt->cache != NULL)
6164 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6165     xmlXPathRegisteredNsCleanup(ctxt);
6166     xmlXPathRegisteredFuncsCleanup(ctxt);
6167     xmlXPathRegisteredVariablesCleanup(ctxt);
6168     xmlResetError(&ctxt->lastError);
6169     xmlFree(ctxt);
6170 }
6171 
6172 /************************************************************************
6173  *									*
6174  *		Routines to handle XPath parser contexts		*
6175  *									*
6176  ************************************************************************/
6177 
6178 #define CHECK_CTXT(ctxt)						\
6179     if (ctxt == NULL) {						\
6180 	__xmlRaiseError(NULL, NULL, NULL,				\
6181 		NULL, NULL, XML_FROM_XPATH,				\
6182 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6183 		__FILE__, __LINE__,					\
6184 		NULL, NULL, NULL, 0, 0,					\
6185 		"NULL context pointer\n");				\
6186 	return(NULL);							\
6187     }									\
6188 
6189 #define CHECK_CTXT_NEG(ctxt)						\
6190     if (ctxt == NULL) {						\
6191 	__xmlRaiseError(NULL, NULL, NULL,				\
6192 		NULL, NULL, XML_FROM_XPATH,				\
6193 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6194 		__FILE__, __LINE__,					\
6195 		NULL, NULL, NULL, 0, 0,					\
6196 		"NULL context pointer\n");				\
6197 	return(-1);							\
6198     }									\
6199 
6200 
6201 #define CHECK_CONTEXT(ctxt)						\
6202     if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
6203         (ctxt->doc->children == NULL)) {				\
6204 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
6205 	return(NULL);							\
6206     }
6207 
6208 
6209 /**
6210  * xmlXPathNewParserContext:
6211  * @str:  the XPath expression
6212  * @ctxt:  the XPath context
6213  *
6214  * Create a new xmlXPathParserContext
6215  *
6216  * Returns the xmlXPathParserContext just allocated.
6217  */
6218 xmlXPathParserContextPtr
xmlXPathNewParserContext(const xmlChar * str,xmlXPathContextPtr ctxt)6219 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6220     xmlXPathParserContextPtr ret;
6221 
6222     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6223     if (ret == NULL) {
6224         xmlXPathErrMemory(ctxt, "creating parser context\n");
6225 	return(NULL);
6226     }
6227     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6228     ret->cur = ret->base = str;
6229     ret->context = ctxt;
6230 
6231     ret->comp = xmlXPathNewCompExpr();
6232     if (ret->comp == NULL) {
6233 	xmlFree(ret->valueTab);
6234 	xmlFree(ret);
6235 	return(NULL);
6236     }
6237     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6238         ret->comp->dict = ctxt->dict;
6239 	xmlDictReference(ret->comp->dict);
6240     }
6241 
6242     return(ret);
6243 }
6244 
6245 /**
6246  * xmlXPathCompParserContext:
6247  * @comp:  the XPath compiled expression
6248  * @ctxt:  the XPath context
6249  *
6250  * Create a new xmlXPathParserContext when processing a compiled expression
6251  *
6252  * Returns the xmlXPathParserContext just allocated.
6253  */
6254 static xmlXPathParserContextPtr
xmlXPathCompParserContext(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)6255 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6256     xmlXPathParserContextPtr ret;
6257 
6258     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6259     if (ret == NULL) {
6260         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6261 	return(NULL);
6262     }
6263     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6264 
6265     /* Allocate the value stack */
6266     ret->valueTab = (xmlXPathObjectPtr *)
6267                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6268     if (ret->valueTab == NULL) {
6269 	xmlFree(ret);
6270 	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6271 	return(NULL);
6272     }
6273     ret->valueNr = 0;
6274     ret->valueMax = 10;
6275     ret->value = NULL;
6276     ret->valueFrame = 0;
6277 
6278     ret->context = ctxt;
6279     ret->comp = comp;
6280 
6281     return(ret);
6282 }
6283 
6284 /**
6285  * xmlXPathFreeParserContext:
6286  * @ctxt:  the context to free
6287  *
6288  * Free up an xmlXPathParserContext
6289  */
6290 void
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt)6291 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6292     if (ctxt->valueTab != NULL) {
6293         xmlFree(ctxt->valueTab);
6294     }
6295     if (ctxt->comp != NULL) {
6296 #ifdef XPATH_STREAMING
6297 	if (ctxt->comp->stream != NULL) {
6298 	    xmlFreePatternList(ctxt->comp->stream);
6299 	    ctxt->comp->stream = NULL;
6300 	}
6301 #endif
6302 	xmlXPathFreeCompExpr(ctxt->comp);
6303     }
6304     xmlFree(ctxt);
6305 }
6306 
6307 /************************************************************************
6308  *									*
6309  *		The implicit core function library			*
6310  *									*
6311  ************************************************************************/
6312 
6313 /**
6314  * xmlXPathNodeValHash:
6315  * @node:  a node pointer
6316  *
6317  * Function computing the beginning of the string value of the node,
6318  * used to speed up comparisons
6319  *
6320  * Returns an int usable as a hash
6321  */
6322 static unsigned int
xmlXPathNodeValHash(xmlNodePtr node)6323 xmlXPathNodeValHash(xmlNodePtr node) {
6324     int len = 2;
6325     const xmlChar * string = NULL;
6326     xmlNodePtr tmp = NULL;
6327     unsigned int ret = 0;
6328 
6329     if (node == NULL)
6330 	return(0);
6331 
6332     if (node->type == XML_DOCUMENT_NODE) {
6333 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
6334 	if (tmp == NULL)
6335 	    node = node->children;
6336 	else
6337 	    node = tmp;
6338 
6339 	if (node == NULL)
6340 	    return(0);
6341     }
6342 
6343     switch (node->type) {
6344 	case XML_COMMENT_NODE:
6345 	case XML_PI_NODE:
6346 	case XML_CDATA_SECTION_NODE:
6347 	case XML_TEXT_NODE:
6348 	    string = node->content;
6349 	    if (string == NULL)
6350 		return(0);
6351 	    if (string[0] == 0)
6352 		return(0);
6353 	    return(((unsigned int) string[0]) +
6354 		   (((unsigned int) string[1]) << 8));
6355 	case XML_NAMESPACE_DECL:
6356 	    string = ((xmlNsPtr)node)->href;
6357 	    if (string == NULL)
6358 		return(0);
6359 	    if (string[0] == 0)
6360 		return(0);
6361 	    return(((unsigned int) string[0]) +
6362 		   (((unsigned int) string[1]) << 8));
6363 	case XML_ATTRIBUTE_NODE:
6364 	    tmp = ((xmlAttrPtr) node)->children;
6365 	    break;
6366 	case XML_ELEMENT_NODE:
6367 	    tmp = node->children;
6368 	    break;
6369 	default:
6370 	    return(0);
6371     }
6372     while (tmp != NULL) {
6373 	switch (tmp->type) {
6374 	    case XML_COMMENT_NODE:
6375 	    case XML_PI_NODE:
6376 	    case XML_CDATA_SECTION_NODE:
6377 	    case XML_TEXT_NODE:
6378 		string = tmp->content;
6379 		break;
6380 	    case XML_NAMESPACE_DECL:
6381 		string = ((xmlNsPtr)tmp)->href;
6382 		break;
6383 	    default:
6384 		break;
6385 	}
6386 	if ((string != NULL) && (string[0] != 0)) {
6387 	    if (len == 1) {
6388 		return(ret + (((unsigned int) string[0]) << 8));
6389 	    }
6390 	    if (string[1] == 0) {
6391 		len = 1;
6392 		ret = (unsigned int) string[0];
6393 	    } else {
6394 		return(((unsigned int) string[0]) +
6395 		       (((unsigned int) string[1]) << 8));
6396 	    }
6397 	}
6398 	/*
6399 	 * Skip to next node
6400 	 */
6401 	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6402 	    if (tmp->children->type != XML_ENTITY_DECL) {
6403 		tmp = tmp->children;
6404 		continue;
6405 	    }
6406 	}
6407 	if (tmp == node)
6408 	    break;
6409 
6410 	if (tmp->next != NULL) {
6411 	    tmp = tmp->next;
6412 	    continue;
6413 	}
6414 
6415 	do {
6416 	    tmp = tmp->parent;
6417 	    if (tmp == NULL)
6418 		break;
6419 	    if (tmp == node) {
6420 		tmp = NULL;
6421 		break;
6422 	    }
6423 	    if (tmp->next != NULL) {
6424 		tmp = tmp->next;
6425 		break;
6426 	    }
6427 	} while (tmp != NULL);
6428     }
6429     return(ret);
6430 }
6431 
6432 /**
6433  * xmlXPathStringHash:
6434  * @string:  a string
6435  *
6436  * Function computing the beginning of the string value of the node,
6437  * used to speed up comparisons
6438  *
6439  * Returns an int usable as a hash
6440  */
6441 static unsigned int
xmlXPathStringHash(const xmlChar * string)6442 xmlXPathStringHash(const xmlChar * string) {
6443     if (string == NULL)
6444 	return((unsigned int) 0);
6445     if (string[0] == 0)
6446 	return(0);
6447     return(((unsigned int) string[0]) +
6448 	   (((unsigned int) string[1]) << 8));
6449 }
6450 
6451 /**
6452  * xmlXPathCompareNodeSetFloat:
6453  * @ctxt:  the XPath Parser context
6454  * @inf:  less than (1) or greater than (0)
6455  * @strict:  is the comparison strict
6456  * @arg:  the node set
6457  * @f:  the value
6458  *
6459  * Implement the compare operation between a nodeset and a number
6460  *     @ns < @val    (1, 1, ...
6461  *     @ns <= @val   (1, 0, ...
6462  *     @ns > @val    (0, 1, ...
6463  *     @ns >= @val   (0, 0, ...
6464  *
6465  * If one object to be compared is a node-set and the other is a number,
6466  * then the comparison will be true if and only if there is a node in the
6467  * node-set such that the result of performing the comparison on the number
6468  * to be compared and on the result of converting the string-value of that
6469  * node to a number using the number function is true.
6470  *
6471  * Returns 0 or 1 depending on the results of the test.
6472  */
6473 static int
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr f)6474 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6475 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6476     int i, ret = 0;
6477     xmlNodeSetPtr ns;
6478     xmlChar *str2;
6479 
6480     if ((f == NULL) || (arg == NULL) ||
6481 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6482 	xmlXPathReleaseObject(ctxt->context, arg);
6483 	xmlXPathReleaseObject(ctxt->context, f);
6484         return(0);
6485     }
6486     ns = arg->nodesetval;
6487     if (ns != NULL) {
6488 	for (i = 0;i < ns->nodeNr;i++) {
6489 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6490 	     if (str2 != NULL) {
6491 		 valuePush(ctxt,
6492 			   xmlXPathCacheNewString(ctxt->context, str2));
6493 		 xmlFree(str2);
6494 		 xmlXPathNumberFunction(ctxt, 1);
6495 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6496 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6497 		 if (ret)
6498 		     break;
6499 	     }
6500 	}
6501     }
6502     xmlXPathReleaseObject(ctxt->context, arg);
6503     xmlXPathReleaseObject(ctxt->context, f);
6504     return(ret);
6505 }
6506 
6507 /**
6508  * xmlXPathCompareNodeSetString:
6509  * @ctxt:  the XPath Parser context
6510  * @inf:  less than (1) or greater than (0)
6511  * @strict:  is the comparison strict
6512  * @arg:  the node set
6513  * @s:  the value
6514  *
6515  * Implement the compare operation between a nodeset and a string
6516  *     @ns < @val    (1, 1, ...
6517  *     @ns <= @val   (1, 0, ...
6518  *     @ns > @val    (0, 1, ...
6519  *     @ns >= @val   (0, 0, ...
6520  *
6521  * If one object to be compared is a node-set and the other is a string,
6522  * then the comparison will be true if and only if there is a node in
6523  * the node-set such that the result of performing the comparison on the
6524  * string-value of the node and the other string is true.
6525  *
6526  * Returns 0 or 1 depending on the results of the test.
6527  */
6528 static int
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr s)6529 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6530 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6531     int i, ret = 0;
6532     xmlNodeSetPtr ns;
6533     xmlChar *str2;
6534 
6535     if ((s == NULL) || (arg == NULL) ||
6536 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6537 	xmlXPathReleaseObject(ctxt->context, arg);
6538 	xmlXPathReleaseObject(ctxt->context, s);
6539         return(0);
6540     }
6541     ns = arg->nodesetval;
6542     if (ns != NULL) {
6543 	for (i = 0;i < ns->nodeNr;i++) {
6544 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6545 	     if (str2 != NULL) {
6546 		 valuePush(ctxt,
6547 			   xmlXPathCacheNewString(ctxt->context, str2));
6548 		 xmlFree(str2);
6549 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6550 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6551 		 if (ret)
6552 		     break;
6553 	     }
6554 	}
6555     }
6556     xmlXPathReleaseObject(ctxt->context, arg);
6557     xmlXPathReleaseObject(ctxt->context, s);
6558     return(ret);
6559 }
6560 
6561 /**
6562  * xmlXPathCompareNodeSets:
6563  * @inf:  less than (1) or greater than (0)
6564  * @strict:  is the comparison strict
6565  * @arg1:  the first node set object
6566  * @arg2:  the second node set object
6567  *
6568  * Implement the compare operation on nodesets:
6569  *
6570  * If both objects to be compared are node-sets, then the comparison
6571  * will be true if and only if there is a node in the first node-set
6572  * and a node in the second node-set such that the result of performing
6573  * the comparison on the string-values of the two nodes is true.
6574  * ....
6575  * When neither object to be compared is a node-set and the operator
6576  * is <=, <, >= or >, then the objects are compared by converting both
6577  * objects to numbers and comparing the numbers according to IEEE 754.
6578  * ....
6579  * The number function converts its argument to a number as follows:
6580  *  - a string that consists of optional whitespace followed by an
6581  *    optional minus sign followed by a Number followed by whitespace
6582  *    is converted to the IEEE 754 number that is nearest (according
6583  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6584  *    represented by the string; any other string is converted to NaN
6585  *
6586  * Conclusion all nodes need to be converted first to their string value
6587  * and then the comparison must be done when possible
6588  */
6589 static int
xmlXPathCompareNodeSets(int inf,int strict,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6590 xmlXPathCompareNodeSets(int inf, int strict,
6591 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6592     int i, j, init = 0;
6593     double val1;
6594     double *values2;
6595     int ret = 0;
6596     xmlNodeSetPtr ns1;
6597     xmlNodeSetPtr ns2;
6598 
6599     if ((arg1 == NULL) ||
6600 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6601 	xmlXPathFreeObject(arg2);
6602         return(0);
6603     }
6604     if ((arg2 == NULL) ||
6605 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6606 	xmlXPathFreeObject(arg1);
6607 	xmlXPathFreeObject(arg2);
6608         return(0);
6609     }
6610 
6611     ns1 = arg1->nodesetval;
6612     ns2 = arg2->nodesetval;
6613 
6614     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6615 	xmlXPathFreeObject(arg1);
6616 	xmlXPathFreeObject(arg2);
6617 	return(0);
6618     }
6619     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6620 	xmlXPathFreeObject(arg1);
6621 	xmlXPathFreeObject(arg2);
6622 	return(0);
6623     }
6624 
6625     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6626     if (values2 == NULL) {
6627         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6628 	xmlXPathFreeObject(arg1);
6629 	xmlXPathFreeObject(arg2);
6630 	return(0);
6631     }
6632     for (i = 0;i < ns1->nodeNr;i++) {
6633 	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6634 	if (xmlXPathIsNaN(val1))
6635 	    continue;
6636 	for (j = 0;j < ns2->nodeNr;j++) {
6637 	    if (init == 0) {
6638 		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6639 	    }
6640 	    if (xmlXPathIsNaN(values2[j]))
6641 		continue;
6642 	    if (inf && strict)
6643 		ret = (val1 < values2[j]);
6644 	    else if (inf && !strict)
6645 		ret = (val1 <= values2[j]);
6646 	    else if (!inf && strict)
6647 		ret = (val1 > values2[j]);
6648 	    else if (!inf && !strict)
6649 		ret = (val1 >= values2[j]);
6650 	    if (ret)
6651 		break;
6652 	}
6653 	if (ret)
6654 	    break;
6655 	init = 1;
6656     }
6657     xmlFree(values2);
6658     xmlXPathFreeObject(arg1);
6659     xmlXPathFreeObject(arg2);
6660     return(ret);
6661 }
6662 
6663 /**
6664  * xmlXPathCompareNodeSetValue:
6665  * @ctxt:  the XPath Parser context
6666  * @inf:  less than (1) or greater than (0)
6667  * @strict:  is the comparison strict
6668  * @arg:  the node set
6669  * @val:  the value
6670  *
6671  * Implement the compare operation between a nodeset and a value
6672  *     @ns < @val    (1, 1, ...
6673  *     @ns <= @val   (1, 0, ...
6674  *     @ns > @val    (0, 1, ...
6675  *     @ns >= @val   (0, 0, ...
6676  *
6677  * If one object to be compared is a node-set and the other is a boolean,
6678  * then the comparison will be true if and only if the result of performing
6679  * the comparison on the boolean and on the result of converting
6680  * the node-set to a boolean using the boolean function is true.
6681  *
6682  * Returns 0 or 1 depending on the results of the test.
6683  */
6684 static int
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr val)6685 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6686 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6687     if ((val == NULL) || (arg == NULL) ||
6688 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6689         return(0);
6690 
6691     switch(val->type) {
6692         case XPATH_NUMBER:
6693 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6694         case XPATH_NODESET:
6695         case XPATH_XSLT_TREE:
6696 	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6697         case XPATH_STRING:
6698 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6699         case XPATH_BOOLEAN:
6700 	    valuePush(ctxt, arg);
6701 	    xmlXPathBooleanFunction(ctxt, 1);
6702 	    valuePush(ctxt, val);
6703 	    return(xmlXPathCompareValues(ctxt, inf, strict));
6704 	default:
6705 	    TODO
6706     }
6707     return(0);
6708 }
6709 
6710 /**
6711  * xmlXPathEqualNodeSetString:
6712  * @arg:  the nodeset object argument
6713  * @str:  the string to compare to.
6714  * @neq:  flag to show whether for '=' (0) or '!=' (1)
6715  *
6716  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6717  * If one object to be compared is a node-set and the other is a string,
6718  * then the comparison will be true if and only if there is a node in
6719  * the node-set such that the result of performing the comparison on the
6720  * string-value of the node and the other string is true.
6721  *
6722  * Returns 0 or 1 depending on the results of the test.
6723  */
6724 static int
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg,const xmlChar * str,int neq)6725 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6726 {
6727     int i;
6728     xmlNodeSetPtr ns;
6729     xmlChar *str2;
6730     unsigned int hash;
6731 
6732     if ((str == NULL) || (arg == NULL) ||
6733         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6734         return (0);
6735     ns = arg->nodesetval;
6736     /*
6737      * A NULL nodeset compared with a string is always false
6738      * (since there is no node equal, and no node not equal)
6739      */
6740     if ((ns == NULL) || (ns->nodeNr <= 0) )
6741         return (0);
6742     hash = xmlXPathStringHash(str);
6743     for (i = 0; i < ns->nodeNr; i++) {
6744         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6745             str2 = xmlNodeGetContent(ns->nodeTab[i]);
6746             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6747                 xmlFree(str2);
6748 		if (neq)
6749 		    continue;
6750                 return (1);
6751 	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6752 		if (neq)
6753 		    continue;
6754                 return (1);
6755             } else if (neq) {
6756 		if (str2 != NULL)
6757 		    xmlFree(str2);
6758 		return (1);
6759 	    }
6760             if (str2 != NULL)
6761                 xmlFree(str2);
6762         } else if (neq)
6763 	    return (1);
6764     }
6765     return (0);
6766 }
6767 
6768 /**
6769  * xmlXPathEqualNodeSetFloat:
6770  * @arg:  the nodeset object argument
6771  * @f:  the float to compare to
6772  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6773  *
6774  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6775  * If one object to be compared is a node-set and the other is a number,
6776  * then the comparison will be true if and only if there is a node in
6777  * the node-set such that the result of performing the comparison on the
6778  * number to be compared and on the result of converting the string-value
6779  * of that node to a number using the number function is true.
6780  *
6781  * Returns 0 or 1 depending on the results of the test.
6782  */
6783 static int
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,double f,int neq)6784 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6785     xmlXPathObjectPtr arg, double f, int neq) {
6786   int i, ret=0;
6787   xmlNodeSetPtr ns;
6788   xmlChar *str2;
6789   xmlXPathObjectPtr val;
6790   double v;
6791 
6792     if ((arg == NULL) ||
6793 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6794         return(0);
6795 
6796     ns = arg->nodesetval;
6797     if (ns != NULL) {
6798 	for (i=0;i<ns->nodeNr;i++) {
6799 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6800 	    if (str2 != NULL) {
6801 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6802 		xmlFree(str2);
6803 		xmlXPathNumberFunction(ctxt, 1);
6804 		val = valuePop(ctxt);
6805 		v = val->floatval;
6806 		xmlXPathReleaseObject(ctxt->context, val);
6807 		if (!xmlXPathIsNaN(v)) {
6808 		    if ((!neq) && (v==f)) {
6809 			ret = 1;
6810 			break;
6811 		    } else if ((neq) && (v!=f)) {
6812 			ret = 1;
6813 			break;
6814 		    }
6815 		} else {	/* NaN is unequal to any value */
6816 		    if (neq)
6817 			ret = 1;
6818 		}
6819 	    }
6820 	}
6821     }
6822 
6823     return(ret);
6824 }
6825 
6826 
6827 /**
6828  * xmlXPathEqualNodeSets:
6829  * @arg1:  first nodeset object argument
6830  * @arg2:  second nodeset object argument
6831  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6832  *
6833  * Implement the equal / not equal operation on XPath nodesets:
6834  * @arg1 == @arg2  or  @arg1 != @arg2
6835  * If both objects to be compared are node-sets, then the comparison
6836  * will be true if and only if there is a node in the first node-set and
6837  * a node in the second node-set such that the result of performing the
6838  * comparison on the string-values of the two nodes is true.
6839  *
6840  * (needless to say, this is a costly operation)
6841  *
6842  * Returns 0 or 1 depending on the results of the test.
6843  */
6844 static int
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2,int neq)6845 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6846     int i, j;
6847     unsigned int *hashs1;
6848     unsigned int *hashs2;
6849     xmlChar **values1;
6850     xmlChar **values2;
6851     int ret = 0;
6852     xmlNodeSetPtr ns1;
6853     xmlNodeSetPtr ns2;
6854 
6855     if ((arg1 == NULL) ||
6856 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6857         return(0);
6858     if ((arg2 == NULL) ||
6859 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6860         return(0);
6861 
6862     ns1 = arg1->nodesetval;
6863     ns2 = arg2->nodesetval;
6864 
6865     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6866 	return(0);
6867     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6868 	return(0);
6869 
6870     /*
6871      * for equal, check if there is a node pertaining to both sets
6872      */
6873     if (neq == 0)
6874 	for (i = 0;i < ns1->nodeNr;i++)
6875 	    for (j = 0;j < ns2->nodeNr;j++)
6876 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
6877 		    return(1);
6878 
6879     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6880     if (values1 == NULL) {
6881         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6882 	return(0);
6883     }
6884     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6885     if (hashs1 == NULL) {
6886         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6887 	xmlFree(values1);
6888 	return(0);
6889     }
6890     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6891     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6892     if (values2 == NULL) {
6893         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6894 	xmlFree(hashs1);
6895 	xmlFree(values1);
6896 	return(0);
6897     }
6898     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6899     if (hashs2 == NULL) {
6900         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6901 	xmlFree(hashs1);
6902 	xmlFree(values1);
6903 	xmlFree(values2);
6904 	return(0);
6905     }
6906     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6907     for (i = 0;i < ns1->nodeNr;i++) {
6908 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6909 	for (j = 0;j < ns2->nodeNr;j++) {
6910 	    if (i == 0)
6911 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6912 	    if (hashs1[i] != hashs2[j]) {
6913 		if (neq) {
6914 		    ret = 1;
6915 		    break;
6916 		}
6917 	    }
6918 	    else {
6919 		if (values1[i] == NULL)
6920 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6921 		if (values2[j] == NULL)
6922 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6923 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6924 		if (ret)
6925 		    break;
6926 	    }
6927 	}
6928 	if (ret)
6929 	    break;
6930     }
6931     for (i = 0;i < ns1->nodeNr;i++)
6932 	if (values1[i] != NULL)
6933 	    xmlFree(values1[i]);
6934     for (j = 0;j < ns2->nodeNr;j++)
6935 	if (values2[j] != NULL)
6936 	    xmlFree(values2[j]);
6937     xmlFree(values1);
6938     xmlFree(values2);
6939     xmlFree(hashs1);
6940     xmlFree(hashs2);
6941     return(ret);
6942 }
6943 
6944 static int
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6945 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6946   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6947     int ret = 0;
6948     /*
6949      *At this point we are assured neither arg1 nor arg2
6950      *is a nodeset, so we can just pick the appropriate routine.
6951      */
6952     switch (arg1->type) {
6953         case XPATH_UNDEFINED:
6954 #ifdef DEBUG_EXPR
6955 	    xmlGenericError(xmlGenericErrorContext,
6956 		    "Equal: undefined\n");
6957 #endif
6958 	    break;
6959         case XPATH_BOOLEAN:
6960 	    switch (arg2->type) {
6961 	        case XPATH_UNDEFINED:
6962 #ifdef DEBUG_EXPR
6963 		    xmlGenericError(xmlGenericErrorContext,
6964 			    "Equal: undefined\n");
6965 #endif
6966 		    break;
6967 		case XPATH_BOOLEAN:
6968 #ifdef DEBUG_EXPR
6969 		    xmlGenericError(xmlGenericErrorContext,
6970 			    "Equal: %d boolean %d \n",
6971 			    arg1->boolval, arg2->boolval);
6972 #endif
6973 		    ret = (arg1->boolval == arg2->boolval);
6974 		    break;
6975 		case XPATH_NUMBER:
6976 		    ret = (arg1->boolval ==
6977 			   xmlXPathCastNumberToBoolean(arg2->floatval));
6978 		    break;
6979 		case XPATH_STRING:
6980 		    if ((arg2->stringval == NULL) ||
6981 			(arg2->stringval[0] == 0)) ret = 0;
6982 		    else
6983 			ret = 1;
6984 		    ret = (arg1->boolval == ret);
6985 		    break;
6986 		case XPATH_USERS:
6987 		case XPATH_POINT:
6988 		case XPATH_RANGE:
6989 		case XPATH_LOCATIONSET:
6990 		    TODO
6991 		    break;
6992 		case XPATH_NODESET:
6993 		case XPATH_XSLT_TREE:
6994 		    break;
6995 	    }
6996 	    break;
6997         case XPATH_NUMBER:
6998 	    switch (arg2->type) {
6999 	        case XPATH_UNDEFINED:
7000 #ifdef DEBUG_EXPR
7001 		    xmlGenericError(xmlGenericErrorContext,
7002 			    "Equal: undefined\n");
7003 #endif
7004 		    break;
7005 		case XPATH_BOOLEAN:
7006 		    ret = (arg2->boolval==
7007 			   xmlXPathCastNumberToBoolean(arg1->floatval));
7008 		    break;
7009 		case XPATH_STRING:
7010 		    valuePush(ctxt, arg2);
7011 		    xmlXPathNumberFunction(ctxt, 1);
7012 		    arg2 = valuePop(ctxt);
7013 		    /* no break on purpose */
7014 		case XPATH_NUMBER:
7015 		    /* Hand check NaN and Infinity equalities */
7016 		    if (xmlXPathIsNaN(arg1->floatval) ||
7017 			    xmlXPathIsNaN(arg2->floatval)) {
7018 		        ret = 0;
7019 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7020 		        if (xmlXPathIsInf(arg2->floatval) == 1)
7021 			    ret = 1;
7022 			else
7023 			    ret = 0;
7024 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7025 			if (xmlXPathIsInf(arg2->floatval) == -1)
7026 			    ret = 1;
7027 			else
7028 			    ret = 0;
7029 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7030 			if (xmlXPathIsInf(arg1->floatval) == 1)
7031 			    ret = 1;
7032 			else
7033 			    ret = 0;
7034 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7035 			if (xmlXPathIsInf(arg1->floatval) == -1)
7036 			    ret = 1;
7037 			else
7038 			    ret = 0;
7039 		    } else {
7040 		        ret = (arg1->floatval == arg2->floatval);
7041 		    }
7042 		    break;
7043 		case XPATH_USERS:
7044 		case XPATH_POINT:
7045 		case XPATH_RANGE:
7046 		case XPATH_LOCATIONSET:
7047 		    TODO
7048 		    break;
7049 		case XPATH_NODESET:
7050 		case XPATH_XSLT_TREE:
7051 		    break;
7052 	    }
7053 	    break;
7054         case XPATH_STRING:
7055 	    switch (arg2->type) {
7056 	        case XPATH_UNDEFINED:
7057 #ifdef DEBUG_EXPR
7058 		    xmlGenericError(xmlGenericErrorContext,
7059 			    "Equal: undefined\n");
7060 #endif
7061 		    break;
7062 		case XPATH_BOOLEAN:
7063 		    if ((arg1->stringval == NULL) ||
7064 			(arg1->stringval[0] == 0)) ret = 0;
7065 		    else
7066 			ret = 1;
7067 		    ret = (arg2->boolval == ret);
7068 		    break;
7069 		case XPATH_STRING:
7070 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7071 		    break;
7072 		case XPATH_NUMBER:
7073 		    valuePush(ctxt, arg1);
7074 		    xmlXPathNumberFunction(ctxt, 1);
7075 		    arg1 = valuePop(ctxt);
7076 		    /* Hand check NaN and Infinity equalities */
7077 		    if (xmlXPathIsNaN(arg1->floatval) ||
7078 			    xmlXPathIsNaN(arg2->floatval)) {
7079 		        ret = 0;
7080 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7081 			if (xmlXPathIsInf(arg2->floatval) == 1)
7082 			    ret = 1;
7083 			else
7084 			    ret = 0;
7085 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7086 			if (xmlXPathIsInf(arg2->floatval) == -1)
7087 			    ret = 1;
7088 			else
7089 			    ret = 0;
7090 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7091 			if (xmlXPathIsInf(arg1->floatval) == 1)
7092 			    ret = 1;
7093 			else
7094 			    ret = 0;
7095 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7096 			if (xmlXPathIsInf(arg1->floatval) == -1)
7097 			    ret = 1;
7098 			else
7099 			    ret = 0;
7100 		    } else {
7101 		        ret = (arg1->floatval == arg2->floatval);
7102 		    }
7103 		    break;
7104 		case XPATH_USERS:
7105 		case XPATH_POINT:
7106 		case XPATH_RANGE:
7107 		case XPATH_LOCATIONSET:
7108 		    TODO
7109 		    break;
7110 		case XPATH_NODESET:
7111 		case XPATH_XSLT_TREE:
7112 		    break;
7113 	    }
7114 	    break;
7115         case XPATH_USERS:
7116 	case XPATH_POINT:
7117 	case XPATH_RANGE:
7118 	case XPATH_LOCATIONSET:
7119 	    TODO
7120 	    break;
7121 	case XPATH_NODESET:
7122 	case XPATH_XSLT_TREE:
7123 	    break;
7124     }
7125     xmlXPathReleaseObject(ctxt->context, arg1);
7126     xmlXPathReleaseObject(ctxt->context, arg2);
7127     return(ret);
7128 }
7129 
7130 /**
7131  * xmlXPathEqualValues:
7132  * @ctxt:  the XPath Parser context
7133  *
7134  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7135  *
7136  * Returns 0 or 1 depending on the results of the test.
7137  */
7138 int
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt)7139 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7140     xmlXPathObjectPtr arg1, arg2, argtmp;
7141     int ret = 0;
7142 
7143     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7144     arg2 = valuePop(ctxt);
7145     arg1 = valuePop(ctxt);
7146     if ((arg1 == NULL) || (arg2 == NULL)) {
7147 	if (arg1 != NULL)
7148 	    xmlXPathReleaseObject(ctxt->context, arg1);
7149 	else
7150 	    xmlXPathReleaseObject(ctxt->context, arg2);
7151 	XP_ERROR0(XPATH_INVALID_OPERAND);
7152     }
7153 
7154     if (arg1 == arg2) {
7155 #ifdef DEBUG_EXPR
7156         xmlGenericError(xmlGenericErrorContext,
7157 		"Equal: by pointer\n");
7158 #endif
7159 	xmlXPathFreeObject(arg1);
7160         return(1);
7161     }
7162 
7163     /*
7164      *If either argument is a nodeset, it's a 'special case'
7165      */
7166     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7167       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7168 	/*
7169 	 *Hack it to assure arg1 is the nodeset
7170 	 */
7171 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7172 		argtmp = arg2;
7173 		arg2 = arg1;
7174 		arg1 = argtmp;
7175 	}
7176 	switch (arg2->type) {
7177 	    case XPATH_UNDEFINED:
7178 #ifdef DEBUG_EXPR
7179 		xmlGenericError(xmlGenericErrorContext,
7180 			"Equal: undefined\n");
7181 #endif
7182 		break;
7183 	    case XPATH_NODESET:
7184 	    case XPATH_XSLT_TREE:
7185 		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7186 		break;
7187 	    case XPATH_BOOLEAN:
7188 		if ((arg1->nodesetval == NULL) ||
7189 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7190 		else
7191 		    ret = 1;
7192 		ret = (ret == arg2->boolval);
7193 		break;
7194 	    case XPATH_NUMBER:
7195 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7196 		break;
7197 	    case XPATH_STRING:
7198 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7199 		break;
7200 	    case XPATH_USERS:
7201 	    case XPATH_POINT:
7202 	    case XPATH_RANGE:
7203 	    case XPATH_LOCATIONSET:
7204 		TODO
7205 		break;
7206 	}
7207 	xmlXPathReleaseObject(ctxt->context, arg1);
7208 	xmlXPathReleaseObject(ctxt->context, arg2);
7209 	return(ret);
7210     }
7211 
7212     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7213 }
7214 
7215 /**
7216  * xmlXPathNotEqualValues:
7217  * @ctxt:  the XPath Parser context
7218  *
7219  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7220  *
7221  * Returns 0 or 1 depending on the results of the test.
7222  */
7223 int
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt)7224 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7225     xmlXPathObjectPtr arg1, arg2, argtmp;
7226     int ret = 0;
7227 
7228     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7229     arg2 = valuePop(ctxt);
7230     arg1 = valuePop(ctxt);
7231     if ((arg1 == NULL) || (arg2 == NULL)) {
7232 	if (arg1 != NULL)
7233 	    xmlXPathReleaseObject(ctxt->context, arg1);
7234 	else
7235 	    xmlXPathReleaseObject(ctxt->context, arg2);
7236 	XP_ERROR0(XPATH_INVALID_OPERAND);
7237     }
7238 
7239     if (arg1 == arg2) {
7240 #ifdef DEBUG_EXPR
7241         xmlGenericError(xmlGenericErrorContext,
7242 		"NotEqual: by pointer\n");
7243 #endif
7244 	xmlXPathReleaseObject(ctxt->context, arg1);
7245         return(0);
7246     }
7247 
7248     /*
7249      *If either argument is a nodeset, it's a 'special case'
7250      */
7251     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7252       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7253 	/*
7254 	 *Hack it to assure arg1 is the nodeset
7255 	 */
7256 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7257 		argtmp = arg2;
7258 		arg2 = arg1;
7259 		arg1 = argtmp;
7260 	}
7261 	switch (arg2->type) {
7262 	    case XPATH_UNDEFINED:
7263 #ifdef DEBUG_EXPR
7264 		xmlGenericError(xmlGenericErrorContext,
7265 			"NotEqual: undefined\n");
7266 #endif
7267 		break;
7268 	    case XPATH_NODESET:
7269 	    case XPATH_XSLT_TREE:
7270 		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7271 		break;
7272 	    case XPATH_BOOLEAN:
7273 		if ((arg1->nodesetval == NULL) ||
7274 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7275 		else
7276 		    ret = 1;
7277 		ret = (ret != arg2->boolval);
7278 		break;
7279 	    case XPATH_NUMBER:
7280 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7281 		break;
7282 	    case XPATH_STRING:
7283 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7284 		break;
7285 	    case XPATH_USERS:
7286 	    case XPATH_POINT:
7287 	    case XPATH_RANGE:
7288 	    case XPATH_LOCATIONSET:
7289 		TODO
7290 		break;
7291 	}
7292 	xmlXPathReleaseObject(ctxt->context, arg1);
7293 	xmlXPathReleaseObject(ctxt->context, arg2);
7294 	return(ret);
7295     }
7296 
7297     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7298 }
7299 
7300 /**
7301  * xmlXPathCompareValues:
7302  * @ctxt:  the XPath Parser context
7303  * @inf:  less than (1) or greater than (0)
7304  * @strict:  is the comparison strict
7305  *
7306  * Implement the compare operation on XPath objects:
7307  *     @arg1 < @arg2    (1, 1, ...
7308  *     @arg1 <= @arg2   (1, 0, ...
7309  *     @arg1 > @arg2    (0, 1, ...
7310  *     @arg1 >= @arg2   (0, 0, ...
7311  *
7312  * When neither object to be compared is a node-set and the operator is
7313  * <=, <, >=, >, then the objects are compared by converted both objects
7314  * to numbers and comparing the numbers according to IEEE 754. The <
7315  * comparison will be true if and only if the first number is less than the
7316  * second number. The <= comparison will be true if and only if the first
7317  * number is less than or equal to the second number. The > comparison
7318  * will be true if and only if the first number is greater than the second
7319  * number. The >= comparison will be true if and only if the first number
7320  * is greater than or equal to the second number.
7321  *
7322  * Returns 1 if the comparison succeeded, 0 if it failed
7323  */
7324 int
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt,int inf,int strict)7325 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7326     int ret = 0, arg1i = 0, arg2i = 0;
7327     xmlXPathObjectPtr arg1, arg2;
7328 
7329     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7330     arg2 = valuePop(ctxt);
7331     arg1 = valuePop(ctxt);
7332     if ((arg1 == NULL) || (arg2 == NULL)) {
7333 	if (arg1 != NULL)
7334 	    xmlXPathReleaseObject(ctxt->context, arg1);
7335 	else
7336 	    xmlXPathReleaseObject(ctxt->context, arg2);
7337 	XP_ERROR0(XPATH_INVALID_OPERAND);
7338     }
7339 
7340     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7341       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7342 	/*
7343 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7344 	 * are not freed from within this routine; they will be freed from the
7345 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7346 	 */
7347 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7348 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7349 	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7350 	} else {
7351 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7352 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7353 			                          arg1, arg2);
7354 	    } else {
7355 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7356 			                          arg2, arg1);
7357 	    }
7358 	}
7359 	return(ret);
7360     }
7361 
7362     if (arg1->type != XPATH_NUMBER) {
7363 	valuePush(ctxt, arg1);
7364 	xmlXPathNumberFunction(ctxt, 1);
7365 	arg1 = valuePop(ctxt);
7366     }
7367     if (arg1->type != XPATH_NUMBER) {
7368 	xmlXPathFreeObject(arg1);
7369 	xmlXPathFreeObject(arg2);
7370 	XP_ERROR0(XPATH_INVALID_OPERAND);
7371     }
7372     if (arg2->type != XPATH_NUMBER) {
7373 	valuePush(ctxt, arg2);
7374 	xmlXPathNumberFunction(ctxt, 1);
7375 	arg2 = valuePop(ctxt);
7376     }
7377     if (arg2->type != XPATH_NUMBER) {
7378 	xmlXPathReleaseObject(ctxt->context, arg1);
7379 	xmlXPathReleaseObject(ctxt->context, arg2);
7380 	XP_ERROR0(XPATH_INVALID_OPERAND);
7381     }
7382     /*
7383      * Add tests for infinity and nan
7384      * => feedback on 3.4 for Inf and NaN
7385      */
7386     /* Hand check NaN and Infinity comparisons */
7387     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7388 	ret=0;
7389     } else {
7390 	arg1i=xmlXPathIsInf(arg1->floatval);
7391 	arg2i=xmlXPathIsInf(arg2->floatval);
7392 	if (inf && strict) {
7393 	    if ((arg1i == -1 && arg2i != -1) ||
7394 		(arg2i == 1 && arg1i != 1)) {
7395 		ret = 1;
7396 	    } else if (arg1i == 0 && arg2i == 0) {
7397 		ret = (arg1->floatval < arg2->floatval);
7398 	    } else {
7399 		ret = 0;
7400 	    }
7401 	}
7402 	else if (inf && !strict) {
7403 	    if (arg1i == -1 || arg2i == 1) {
7404 		ret = 1;
7405 	    } else if (arg1i == 0 && arg2i == 0) {
7406 		ret = (arg1->floatval <= arg2->floatval);
7407 	    } else {
7408 		ret = 0;
7409 	    }
7410 	}
7411 	else if (!inf && strict) {
7412 	    if ((arg1i == 1 && arg2i != 1) ||
7413 		(arg2i == -1 && arg1i != -1)) {
7414 		ret = 1;
7415 	    } else if (arg1i == 0 && arg2i == 0) {
7416 		ret = (arg1->floatval > arg2->floatval);
7417 	    } else {
7418 		ret = 0;
7419 	    }
7420 	}
7421 	else if (!inf && !strict) {
7422 	    if (arg1i == 1 || arg2i == -1) {
7423 		ret = 1;
7424 	    } else if (arg1i == 0 && arg2i == 0) {
7425 		ret = (arg1->floatval >= arg2->floatval);
7426 	    } else {
7427 		ret = 0;
7428 	    }
7429 	}
7430     }
7431     xmlXPathReleaseObject(ctxt->context, arg1);
7432     xmlXPathReleaseObject(ctxt->context, arg2);
7433     return(ret);
7434 }
7435 
7436 /**
7437  * xmlXPathValueFlipSign:
7438  * @ctxt:  the XPath Parser context
7439  *
7440  * Implement the unary - operation on an XPath object
7441  * The numeric operators convert their operands to numbers as if
7442  * by calling the number function.
7443  */
7444 void
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt)7445 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7446     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7447     CAST_TO_NUMBER;
7448     CHECK_TYPE(XPATH_NUMBER);
7449     if (xmlXPathIsNaN(ctxt->value->floatval))
7450         ctxt->value->floatval=xmlXPathNAN;
7451     else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7452         ctxt->value->floatval=xmlXPathNINF;
7453     else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7454         ctxt->value->floatval=xmlXPathPINF;
7455     else if (ctxt->value->floatval == 0) {
7456         if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7457 	    ctxt->value->floatval = xmlXPathNZERO;
7458 	else
7459 	    ctxt->value->floatval = 0;
7460     }
7461     else
7462         ctxt->value->floatval = - ctxt->value->floatval;
7463 }
7464 
7465 /**
7466  * xmlXPathAddValues:
7467  * @ctxt:  the XPath Parser context
7468  *
7469  * Implement the add operation on XPath objects:
7470  * The numeric operators convert their operands to numbers as if
7471  * by calling the number function.
7472  */
7473 void
xmlXPathAddValues(xmlXPathParserContextPtr ctxt)7474 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7475     xmlXPathObjectPtr arg;
7476     double val;
7477 
7478     arg = valuePop(ctxt);
7479     if (arg == NULL)
7480 	XP_ERROR(XPATH_INVALID_OPERAND);
7481     val = xmlXPathCastToNumber(arg);
7482     xmlXPathReleaseObject(ctxt->context, arg);
7483     CAST_TO_NUMBER;
7484     CHECK_TYPE(XPATH_NUMBER);
7485     ctxt->value->floatval += val;
7486 }
7487 
7488 /**
7489  * xmlXPathSubValues:
7490  * @ctxt:  the XPath Parser context
7491  *
7492  * Implement the subtraction operation on XPath objects:
7493  * The numeric operators convert their operands to numbers as if
7494  * by calling the number function.
7495  */
7496 void
xmlXPathSubValues(xmlXPathParserContextPtr ctxt)7497 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7498     xmlXPathObjectPtr arg;
7499     double val;
7500 
7501     arg = valuePop(ctxt);
7502     if (arg == NULL)
7503 	XP_ERROR(XPATH_INVALID_OPERAND);
7504     val = xmlXPathCastToNumber(arg);
7505     xmlXPathReleaseObject(ctxt->context, arg);
7506     CAST_TO_NUMBER;
7507     CHECK_TYPE(XPATH_NUMBER);
7508     ctxt->value->floatval -= val;
7509 }
7510 
7511 /**
7512  * xmlXPathMultValues:
7513  * @ctxt:  the XPath Parser context
7514  *
7515  * Implement the multiply operation on XPath objects:
7516  * The numeric operators convert their operands to numbers as if
7517  * by calling the number function.
7518  */
7519 void
xmlXPathMultValues(xmlXPathParserContextPtr ctxt)7520 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7521     xmlXPathObjectPtr arg;
7522     double val;
7523 
7524     arg = valuePop(ctxt);
7525     if (arg == NULL)
7526 	XP_ERROR(XPATH_INVALID_OPERAND);
7527     val = xmlXPathCastToNumber(arg);
7528     xmlXPathReleaseObject(ctxt->context, arg);
7529     CAST_TO_NUMBER;
7530     CHECK_TYPE(XPATH_NUMBER);
7531     ctxt->value->floatval *= val;
7532 }
7533 
7534 /**
7535  * xmlXPathDivValues:
7536  * @ctxt:  the XPath Parser context
7537  *
7538  * Implement the div operation on XPath objects @arg1 / @arg2:
7539  * The numeric operators convert their operands to numbers as if
7540  * by calling the number function.
7541  */
7542 void
xmlXPathDivValues(xmlXPathParserContextPtr ctxt)7543 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7544     xmlXPathObjectPtr arg;
7545     double val;
7546 
7547     arg = valuePop(ctxt);
7548     if (arg == NULL)
7549 	XP_ERROR(XPATH_INVALID_OPERAND);
7550     val = xmlXPathCastToNumber(arg);
7551     xmlXPathReleaseObject(ctxt->context, arg);
7552     CAST_TO_NUMBER;
7553     CHECK_TYPE(XPATH_NUMBER);
7554     if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7555 	ctxt->value->floatval = xmlXPathNAN;
7556     else if (val == 0 && xmlXPathGetSign(val) != 0) {
7557 	if (ctxt->value->floatval == 0)
7558 	    ctxt->value->floatval = xmlXPathNAN;
7559 	else if (ctxt->value->floatval > 0)
7560 	    ctxt->value->floatval = xmlXPathNINF;
7561 	else if (ctxt->value->floatval < 0)
7562 	    ctxt->value->floatval = xmlXPathPINF;
7563     }
7564     else if (val == 0) {
7565 	if (ctxt->value->floatval == 0)
7566 	    ctxt->value->floatval = xmlXPathNAN;
7567 	else if (ctxt->value->floatval > 0)
7568 	    ctxt->value->floatval = xmlXPathPINF;
7569 	else if (ctxt->value->floatval < 0)
7570 	    ctxt->value->floatval = xmlXPathNINF;
7571     } else
7572 	ctxt->value->floatval /= val;
7573 }
7574 
7575 /**
7576  * xmlXPathModValues:
7577  * @ctxt:  the XPath Parser context
7578  *
7579  * Implement the mod operation on XPath objects: @arg1 / @arg2
7580  * The numeric operators convert their operands to numbers as if
7581  * by calling the number function.
7582  */
7583 void
xmlXPathModValues(xmlXPathParserContextPtr ctxt)7584 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7585     xmlXPathObjectPtr arg;
7586     double arg1, arg2;
7587 
7588     arg = valuePop(ctxt);
7589     if (arg == NULL)
7590 	XP_ERROR(XPATH_INVALID_OPERAND);
7591     arg2 = xmlXPathCastToNumber(arg);
7592     xmlXPathReleaseObject(ctxt->context, arg);
7593     CAST_TO_NUMBER;
7594     CHECK_TYPE(XPATH_NUMBER);
7595     arg1 = ctxt->value->floatval;
7596     if (arg2 == 0)
7597 	ctxt->value->floatval = xmlXPathNAN;
7598     else {
7599 	ctxt->value->floatval = fmod(arg1, arg2);
7600     }
7601 }
7602 
7603 /************************************************************************
7604  *									*
7605  *		The traversal functions					*
7606  *									*
7607  ************************************************************************/
7608 
7609 /*
7610  * A traversal function enumerates nodes along an axis.
7611  * Initially it must be called with NULL, and it indicates
7612  * termination on the axis by returning NULL.
7613  */
7614 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7615                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7616 
7617 /*
7618  * xmlXPathTraversalFunctionExt:
7619  * A traversal function enumerates nodes along an axis.
7620  * Initially it must be called with NULL, and it indicates
7621  * termination on the axis by returning NULL.
7622  * The context node of the traversal is specified via @contextNode.
7623  */
7624 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7625                     (xmlNodePtr cur, xmlNodePtr contextNode);
7626 
7627 /*
7628  * xmlXPathNodeSetMergeFunction:
7629  * Used for merging node sets in xmlXPathCollectAndTest().
7630  */
7631 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7632 		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
7633 
7634 
7635 /**
7636  * xmlXPathNextSelf:
7637  * @ctxt:  the XPath Parser context
7638  * @cur:  the current node in the traversal
7639  *
7640  * Traversal function for the "self" direction
7641  * The self axis contains just the context node itself
7642  *
7643  * Returns the next element following that axis
7644  */
7645 xmlNodePtr
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7646 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7647     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7648     if (cur == NULL)
7649         return(ctxt->context->node);
7650     return(NULL);
7651 }
7652 
7653 /**
7654  * xmlXPathNextChild:
7655  * @ctxt:  the XPath Parser context
7656  * @cur:  the current node in the traversal
7657  *
7658  * Traversal function for the "child" direction
7659  * The child axis contains the children of the context node in document order.
7660  *
7661  * Returns the next element following that axis
7662  */
7663 xmlNodePtr
xmlXPathNextChild(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7664 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7665     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7666     if (cur == NULL) {
7667 	if (ctxt->context->node == NULL) return(NULL);
7668 	switch (ctxt->context->node->type) {
7669             case XML_ELEMENT_NODE:
7670             case XML_TEXT_NODE:
7671             case XML_CDATA_SECTION_NODE:
7672             case XML_ENTITY_REF_NODE:
7673             case XML_ENTITY_NODE:
7674             case XML_PI_NODE:
7675             case XML_COMMENT_NODE:
7676             case XML_NOTATION_NODE:
7677             case XML_DTD_NODE:
7678 		return(ctxt->context->node->children);
7679             case XML_DOCUMENT_NODE:
7680             case XML_DOCUMENT_TYPE_NODE:
7681             case XML_DOCUMENT_FRAG_NODE:
7682             case XML_HTML_DOCUMENT_NODE:
7683 #ifdef LIBXML_DOCB_ENABLED
7684 	    case XML_DOCB_DOCUMENT_NODE:
7685 #endif
7686 		return(((xmlDocPtr) ctxt->context->node)->children);
7687 	    case XML_ELEMENT_DECL:
7688 	    case XML_ATTRIBUTE_DECL:
7689 	    case XML_ENTITY_DECL:
7690             case XML_ATTRIBUTE_NODE:
7691 	    case XML_NAMESPACE_DECL:
7692 	    case XML_XINCLUDE_START:
7693 	    case XML_XINCLUDE_END:
7694 		return(NULL);
7695 	}
7696 	return(NULL);
7697     }
7698     if ((cur->type == XML_DOCUMENT_NODE) ||
7699         (cur->type == XML_HTML_DOCUMENT_NODE))
7700 	return(NULL);
7701     return(cur->next);
7702 }
7703 
7704 /**
7705  * xmlXPathNextChildElement:
7706  * @ctxt:  the XPath Parser context
7707  * @cur:  the current node in the traversal
7708  *
7709  * Traversal function for the "child" direction and nodes of type element.
7710  * The child axis contains the children of the context node in document order.
7711  *
7712  * Returns the next element following that axis
7713  */
7714 static xmlNodePtr
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7715 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7716     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7717     if (cur == NULL) {
7718 	cur = ctxt->context->node;
7719 	if (cur == NULL) return(NULL);
7720 	/*
7721 	* Get the first element child.
7722 	*/
7723 	switch (cur->type) {
7724             case XML_ELEMENT_NODE:
7725 	    case XML_DOCUMENT_FRAG_NODE:
7726 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7727             case XML_ENTITY_NODE:
7728 		cur = cur->children;
7729 		if (cur != NULL) {
7730 		    if (cur->type == XML_ELEMENT_NODE)
7731 			return(cur);
7732 		    do {
7733 			cur = cur->next;
7734 		    } while ((cur != NULL) &&
7735 			(cur->type != XML_ELEMENT_NODE));
7736 		    return(cur);
7737 		}
7738 		return(NULL);
7739             case XML_DOCUMENT_NODE:
7740             case XML_HTML_DOCUMENT_NODE:
7741 #ifdef LIBXML_DOCB_ENABLED
7742 	    case XML_DOCB_DOCUMENT_NODE:
7743 #endif
7744 		return(xmlDocGetRootElement((xmlDocPtr) cur));
7745 	    default:
7746 		return(NULL);
7747 	}
7748 	return(NULL);
7749     }
7750     /*
7751     * Get the next sibling element node.
7752     */
7753     switch (cur->type) {
7754 	case XML_ELEMENT_NODE:
7755 	case XML_TEXT_NODE:
7756 	case XML_ENTITY_REF_NODE:
7757 	case XML_ENTITY_NODE:
7758 	case XML_CDATA_SECTION_NODE:
7759 	case XML_PI_NODE:
7760 	case XML_COMMENT_NODE:
7761 	case XML_XINCLUDE_END:
7762 	    break;
7763 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7764 	default:
7765 	    return(NULL);
7766     }
7767     if (cur->next != NULL) {
7768 	if (cur->next->type == XML_ELEMENT_NODE)
7769 	    return(cur->next);
7770 	cur = cur->next;
7771 	do {
7772 	    cur = cur->next;
7773 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7774 	return(cur);
7775     }
7776     return(NULL);
7777 }
7778 
7779 #if 0
7780 /**
7781  * xmlXPathNextDescendantOrSelfElemParent:
7782  * @ctxt:  the XPath Parser context
7783  * @cur:  the current node in the traversal
7784  *
7785  * Traversal function for the "descendant-or-self" axis.
7786  * Additionally it returns only nodes which can be parents of
7787  * element nodes.
7788  *
7789  *
7790  * Returns the next element following that axis
7791  */
7792 static xmlNodePtr
7793 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7794 				       xmlNodePtr contextNode)
7795 {
7796     if (cur == NULL) {
7797 	if (contextNode == NULL)
7798 	    return(NULL);
7799 	switch (contextNode->type) {
7800 	    case XML_ELEMENT_NODE:
7801 	    case XML_XINCLUDE_START:
7802 	    case XML_DOCUMENT_FRAG_NODE:
7803 	    case XML_DOCUMENT_NODE:
7804 #ifdef LIBXML_DOCB_ENABLED
7805 	    case XML_DOCB_DOCUMENT_NODE:
7806 #endif
7807 	    case XML_HTML_DOCUMENT_NODE:
7808 		return(contextNode);
7809 	    default:
7810 		return(NULL);
7811 	}
7812 	return(NULL);
7813     } else {
7814 	xmlNodePtr start = cur;
7815 
7816 	while (cur != NULL) {
7817 	    switch (cur->type) {
7818 		case XML_ELEMENT_NODE:
7819 		/* TODO: OK to have XInclude here? */
7820 		case XML_XINCLUDE_START:
7821 		case XML_DOCUMENT_FRAG_NODE:
7822 		    if (cur != start)
7823 			return(cur);
7824 		    if (cur->children != NULL) {
7825 			cur = cur->children;
7826 			continue;
7827 		    }
7828 		    break;
7829 		/* Not sure if we need those here. */
7830 		case XML_DOCUMENT_NODE:
7831 #ifdef LIBXML_DOCB_ENABLED
7832 		case XML_DOCB_DOCUMENT_NODE:
7833 #endif
7834 		case XML_HTML_DOCUMENT_NODE:
7835 		    if (cur != start)
7836 			return(cur);
7837 		    return(xmlDocGetRootElement((xmlDocPtr) cur));
7838 		default:
7839 		    break;
7840 	    }
7841 
7842 next_sibling:
7843 	    if ((cur == NULL) || (cur == contextNode))
7844 		return(NULL);
7845 	    if (cur->next != NULL) {
7846 		cur = cur->next;
7847 	    } else {
7848 		cur = cur->parent;
7849 		goto next_sibling;
7850 	    }
7851 	}
7852     }
7853     return(NULL);
7854 }
7855 #endif
7856 
7857 /**
7858  * xmlXPathNextDescendant:
7859  * @ctxt:  the XPath Parser context
7860  * @cur:  the current node in the traversal
7861  *
7862  * Traversal function for the "descendant" direction
7863  * the descendant axis contains the descendants of the context node in document
7864  * order; a descendant is a child or a child of a child and so on.
7865  *
7866  * Returns the next element following that axis
7867  */
7868 xmlNodePtr
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7869 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7870     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7871     if (cur == NULL) {
7872 	if (ctxt->context->node == NULL)
7873 	    return(NULL);
7874 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7875 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7876 	    return(NULL);
7877 
7878         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7879 	    return(ctxt->context->doc->children);
7880         return(ctxt->context->node->children);
7881     }
7882 
7883     if (cur->type == XML_NAMESPACE_DECL)
7884         return(NULL);
7885     if (cur->children != NULL) {
7886 	/*
7887 	 * Do not descend on entities declarations
7888 	 */
7889 	if (cur->children->type != XML_ENTITY_DECL) {
7890 	    cur = cur->children;
7891 	    /*
7892 	     * Skip DTDs
7893 	     */
7894 	    if (cur->type != XML_DTD_NODE)
7895 		return(cur);
7896 	}
7897     }
7898 
7899     if (cur == ctxt->context->node) return(NULL);
7900 
7901     while (cur->next != NULL) {
7902 	cur = cur->next;
7903 	if ((cur->type != XML_ENTITY_DECL) &&
7904 	    (cur->type != XML_DTD_NODE))
7905 	    return(cur);
7906     }
7907 
7908     do {
7909         cur = cur->parent;
7910 	if (cur == NULL) break;
7911 	if (cur == ctxt->context->node) return(NULL);
7912 	if (cur->next != NULL) {
7913 	    cur = cur->next;
7914 	    return(cur);
7915 	}
7916     } while (cur != NULL);
7917     return(cur);
7918 }
7919 
7920 /**
7921  * xmlXPathNextDescendantOrSelf:
7922  * @ctxt:  the XPath Parser context
7923  * @cur:  the current node in the traversal
7924  *
7925  * Traversal function for the "descendant-or-self" direction
7926  * the descendant-or-self axis contains the context node and the descendants
7927  * of the context node in document order; thus the context node is the first
7928  * node on the axis, and the first child of the context node is the second node
7929  * on the axis
7930  *
7931  * Returns the next element following that axis
7932  */
7933 xmlNodePtr
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7934 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7935     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7936     if (cur == NULL) {
7937 	if (ctxt->context->node == NULL)
7938 	    return(NULL);
7939 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7940 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7941 	    return(NULL);
7942         return(ctxt->context->node);
7943     }
7944 
7945     return(xmlXPathNextDescendant(ctxt, cur));
7946 }
7947 
7948 /**
7949  * xmlXPathNextParent:
7950  * @ctxt:  the XPath Parser context
7951  * @cur:  the current node in the traversal
7952  *
7953  * Traversal function for the "parent" direction
7954  * The parent axis contains the parent of the context node, if there is one.
7955  *
7956  * Returns the next element following that axis
7957  */
7958 xmlNodePtr
xmlXPathNextParent(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7959 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7960     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7961     /*
7962      * the parent of an attribute or namespace node is the element
7963      * to which the attribute or namespace node is attached
7964      * Namespace handling !!!
7965      */
7966     if (cur == NULL) {
7967 	if (ctxt->context->node == NULL) return(NULL);
7968 	switch (ctxt->context->node->type) {
7969             case XML_ELEMENT_NODE:
7970             case XML_TEXT_NODE:
7971             case XML_CDATA_SECTION_NODE:
7972             case XML_ENTITY_REF_NODE:
7973             case XML_ENTITY_NODE:
7974             case XML_PI_NODE:
7975             case XML_COMMENT_NODE:
7976             case XML_NOTATION_NODE:
7977             case XML_DTD_NODE:
7978 	    case XML_ELEMENT_DECL:
7979 	    case XML_ATTRIBUTE_DECL:
7980 	    case XML_XINCLUDE_START:
7981 	    case XML_XINCLUDE_END:
7982 	    case XML_ENTITY_DECL:
7983 		if (ctxt->context->node->parent == NULL)
7984 		    return((xmlNodePtr) ctxt->context->doc);
7985 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7986 		    ((ctxt->context->node->parent->name[0] == ' ') ||
7987 		     (xmlStrEqual(ctxt->context->node->parent->name,
7988 				 BAD_CAST "fake node libxslt"))))
7989 		    return(NULL);
7990 		return(ctxt->context->node->parent);
7991             case XML_ATTRIBUTE_NODE: {
7992 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7993 
7994 		return(att->parent);
7995 	    }
7996             case XML_DOCUMENT_NODE:
7997             case XML_DOCUMENT_TYPE_NODE:
7998             case XML_DOCUMENT_FRAG_NODE:
7999             case XML_HTML_DOCUMENT_NODE:
8000 #ifdef LIBXML_DOCB_ENABLED
8001 	    case XML_DOCB_DOCUMENT_NODE:
8002 #endif
8003                 return(NULL);
8004 	    case XML_NAMESPACE_DECL: {
8005 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8006 
8007 		if ((ns->next != NULL) &&
8008 		    (ns->next->type != XML_NAMESPACE_DECL))
8009 		    return((xmlNodePtr) ns->next);
8010                 return(NULL);
8011 	    }
8012 	}
8013     }
8014     return(NULL);
8015 }
8016 
8017 /**
8018  * xmlXPathNextAncestor:
8019  * @ctxt:  the XPath Parser context
8020  * @cur:  the current node in the traversal
8021  *
8022  * Traversal function for the "ancestor" direction
8023  * the ancestor axis contains the ancestors of the context node; the ancestors
8024  * of the context node consist of the parent of context node and the parent's
8025  * parent and so on; the nodes are ordered in reverse document order; thus the
8026  * parent is the first node on the axis, and the parent's parent is the second
8027  * node on the axis
8028  *
8029  * Returns the next element following that axis
8030  */
8031 xmlNodePtr
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8032 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8033     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8034     /*
8035      * the parent of an attribute or namespace node is the element
8036      * to which the attribute or namespace node is attached
8037      * !!!!!!!!!!!!!
8038      */
8039     if (cur == NULL) {
8040 	if (ctxt->context->node == NULL) return(NULL);
8041 	switch (ctxt->context->node->type) {
8042             case XML_ELEMENT_NODE:
8043             case XML_TEXT_NODE:
8044             case XML_CDATA_SECTION_NODE:
8045             case XML_ENTITY_REF_NODE:
8046             case XML_ENTITY_NODE:
8047             case XML_PI_NODE:
8048             case XML_COMMENT_NODE:
8049 	    case XML_DTD_NODE:
8050 	    case XML_ELEMENT_DECL:
8051 	    case XML_ATTRIBUTE_DECL:
8052 	    case XML_ENTITY_DECL:
8053             case XML_NOTATION_NODE:
8054 	    case XML_XINCLUDE_START:
8055 	    case XML_XINCLUDE_END:
8056 		if (ctxt->context->node->parent == NULL)
8057 		    return((xmlNodePtr) ctxt->context->doc);
8058 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8059 		    ((ctxt->context->node->parent->name[0] == ' ') ||
8060 		     (xmlStrEqual(ctxt->context->node->parent->name,
8061 				 BAD_CAST "fake node libxslt"))))
8062 		    return(NULL);
8063 		return(ctxt->context->node->parent);
8064             case XML_ATTRIBUTE_NODE: {
8065 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8066 
8067 		return(tmp->parent);
8068 	    }
8069             case XML_DOCUMENT_NODE:
8070             case XML_DOCUMENT_TYPE_NODE:
8071             case XML_DOCUMENT_FRAG_NODE:
8072             case XML_HTML_DOCUMENT_NODE:
8073 #ifdef LIBXML_DOCB_ENABLED
8074 	    case XML_DOCB_DOCUMENT_NODE:
8075 #endif
8076                 return(NULL);
8077 	    case XML_NAMESPACE_DECL: {
8078 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
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 	}
8087 	return(NULL);
8088     }
8089     if (cur == ctxt->context->doc->children)
8090 	return((xmlNodePtr) ctxt->context->doc);
8091     if (cur == (xmlNodePtr) ctxt->context->doc)
8092 	return(NULL);
8093     switch (cur->type) {
8094 	case XML_ELEMENT_NODE:
8095 	case XML_TEXT_NODE:
8096 	case XML_CDATA_SECTION_NODE:
8097 	case XML_ENTITY_REF_NODE:
8098 	case XML_ENTITY_NODE:
8099 	case XML_PI_NODE:
8100 	case XML_COMMENT_NODE:
8101 	case XML_NOTATION_NODE:
8102 	case XML_DTD_NODE:
8103         case XML_ELEMENT_DECL:
8104         case XML_ATTRIBUTE_DECL:
8105         case XML_ENTITY_DECL:
8106 	case XML_XINCLUDE_START:
8107 	case XML_XINCLUDE_END:
8108 	    if (cur->parent == NULL)
8109 		return(NULL);
8110 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
8111 		((cur->parent->name[0] == ' ') ||
8112 		 (xmlStrEqual(cur->parent->name,
8113 			      BAD_CAST "fake node libxslt"))))
8114 		return(NULL);
8115 	    return(cur->parent);
8116 	case XML_ATTRIBUTE_NODE: {
8117 	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8118 
8119 	    return(att->parent);
8120 	}
8121 	case XML_NAMESPACE_DECL: {
8122 	    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8123 
8124 	    if ((ns->next != NULL) &&
8125 	        (ns->next->type != XML_NAMESPACE_DECL))
8126 	        return((xmlNodePtr) ns->next);
8127 	    /* Bad, how did that namespace end up here ? */
8128             return(NULL);
8129 	}
8130 	case XML_DOCUMENT_NODE:
8131 	case XML_DOCUMENT_TYPE_NODE:
8132 	case XML_DOCUMENT_FRAG_NODE:
8133 	case XML_HTML_DOCUMENT_NODE:
8134 #ifdef LIBXML_DOCB_ENABLED
8135 	case XML_DOCB_DOCUMENT_NODE:
8136 #endif
8137 	    return(NULL);
8138     }
8139     return(NULL);
8140 }
8141 
8142 /**
8143  * xmlXPathNextAncestorOrSelf:
8144  * @ctxt:  the XPath Parser context
8145  * @cur:  the current node in the traversal
8146  *
8147  * Traversal function for the "ancestor-or-self" direction
8148  * he ancestor-or-self axis contains the context node and ancestors of
8149  * the context node in reverse document order; thus the context node is
8150  * the first node on the axis, and the context node's parent the second;
8151  * parent here is defined the same as with the parent axis.
8152  *
8153  * Returns the next element following that axis
8154  */
8155 xmlNodePtr
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8156 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8157     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8158     if (cur == NULL)
8159         return(ctxt->context->node);
8160     return(xmlXPathNextAncestor(ctxt, cur));
8161 }
8162 
8163 /**
8164  * xmlXPathNextFollowingSibling:
8165  * @ctxt:  the XPath Parser context
8166  * @cur:  the current node in the traversal
8167  *
8168  * Traversal function for the "following-sibling" direction
8169  * The following-sibling axis contains the following siblings of the context
8170  * node in document order.
8171  *
8172  * Returns the next element following that axis
8173  */
8174 xmlNodePtr
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8175 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8176     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8177     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8178 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8179 	return(NULL);
8180     if (cur == (xmlNodePtr) ctxt->context->doc)
8181         return(NULL);
8182     if (cur == NULL)
8183         return(ctxt->context->node->next);
8184     return(cur->next);
8185 }
8186 
8187 /**
8188  * xmlXPathNextPrecedingSibling:
8189  * @ctxt:  the XPath Parser context
8190  * @cur:  the current node in the traversal
8191  *
8192  * Traversal function for the "preceding-sibling" direction
8193  * The preceding-sibling axis contains the preceding siblings of the context
8194  * node in reverse document order; the first preceding sibling is first on the
8195  * axis; the sibling preceding that node is the second on the axis and so on.
8196  *
8197  * Returns the next element following that axis
8198  */
8199 xmlNodePtr
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8200 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8201     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8202     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8203 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8204 	return(NULL);
8205     if (cur == (xmlNodePtr) ctxt->context->doc)
8206         return(NULL);
8207     if (cur == NULL)
8208         return(ctxt->context->node->prev);
8209     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8210 	cur = cur->prev;
8211 	if (cur == NULL)
8212 	    return(ctxt->context->node->prev);
8213     }
8214     return(cur->prev);
8215 }
8216 
8217 /**
8218  * xmlXPathNextFollowing:
8219  * @ctxt:  the XPath Parser context
8220  * @cur:  the current node in the traversal
8221  *
8222  * Traversal function for the "following" direction
8223  * The following axis contains all nodes in the same document as the context
8224  * node that are after the context node in document order, excluding any
8225  * descendants and excluding attribute nodes and namespace nodes; the nodes
8226  * are ordered in document order
8227  *
8228  * Returns the next element following that axis
8229  */
8230 xmlNodePtr
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8231 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8232     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8233     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8234         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8235         return(cur->children);
8236 
8237     if (cur == NULL) {
8238         cur = ctxt->context->node;
8239         if (cur->type == XML_NAMESPACE_DECL)
8240             return(NULL);
8241         if (cur->type == XML_ATTRIBUTE_NODE)
8242             cur = cur->parent;
8243     }
8244     if (cur == NULL) return(NULL) ; /* ERROR */
8245     if (cur->next != NULL) return(cur->next) ;
8246     do {
8247         cur = cur->parent;
8248         if (cur == NULL) break;
8249         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8250         if (cur->next != NULL) return(cur->next);
8251     } while (cur != NULL);
8252     return(cur);
8253 }
8254 
8255 /*
8256  * xmlXPathIsAncestor:
8257  * @ancestor:  the ancestor node
8258  * @node:  the current node
8259  *
8260  * Check that @ancestor is a @node's ancestor
8261  *
8262  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8263  */
8264 static int
xmlXPathIsAncestor(xmlNodePtr ancestor,xmlNodePtr node)8265 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8266     if ((ancestor == NULL) || (node == NULL)) return(0);
8267     if (node->type == XML_NAMESPACE_DECL)
8268         return(0);
8269     if (ancestor->type == XML_NAMESPACE_DECL)
8270         return(0);
8271     /* nodes need to be in the same document */
8272     if (ancestor->doc != node->doc) return(0);
8273     /* avoid searching if ancestor or node is the root node */
8274     if (ancestor == (xmlNodePtr) node->doc) return(1);
8275     if (node == (xmlNodePtr) ancestor->doc) return(0);
8276     while (node->parent != NULL) {
8277         if (node->parent == ancestor)
8278             return(1);
8279 	node = node->parent;
8280     }
8281     return(0);
8282 }
8283 
8284 /**
8285  * xmlXPathNextPreceding:
8286  * @ctxt:  the XPath Parser context
8287  * @cur:  the current node in the traversal
8288  *
8289  * Traversal function for the "preceding" direction
8290  * the preceding axis contains all nodes in the same document as the context
8291  * node that are before the context node in document order, excluding any
8292  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8293  * ordered in reverse document order
8294  *
8295  * Returns the next element following that axis
8296  */
8297 xmlNodePtr
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8298 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8299 {
8300     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8301     if (cur == NULL) {
8302         cur = ctxt->context->node;
8303         if (cur->type == XML_NAMESPACE_DECL)
8304             return(NULL);
8305         if (cur->type == XML_ATTRIBUTE_NODE)
8306             return(cur->parent);
8307     }
8308     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8309 	return (NULL);
8310     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8311 	cur = cur->prev;
8312     do {
8313         if (cur->prev != NULL) {
8314             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8315             return (cur);
8316         }
8317 
8318         cur = cur->parent;
8319         if (cur == NULL)
8320             return (NULL);
8321         if (cur == ctxt->context->doc->children)
8322             return (NULL);
8323     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8324     return (cur);
8325 }
8326 
8327 /**
8328  * xmlXPathNextPrecedingInternal:
8329  * @ctxt:  the XPath Parser context
8330  * @cur:  the current node in the traversal
8331  *
8332  * Traversal function for the "preceding" direction
8333  * the preceding axis contains all nodes in the same document as the context
8334  * node that are before the context node in document order, excluding any
8335  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8336  * ordered in reverse document order
8337  * This is a faster implementation but internal only since it requires a
8338  * state kept in the parser context: ctxt->ancestor.
8339  *
8340  * Returns the next element following that axis
8341  */
8342 static xmlNodePtr
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8343 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8344                               xmlNodePtr cur)
8345 {
8346     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8347     if (cur == NULL) {
8348         cur = ctxt->context->node;
8349         if (cur == NULL)
8350             return (NULL);
8351         if (cur->type == XML_NAMESPACE_DECL)
8352             return (NULL);
8353         ctxt->ancestor = cur->parent;
8354     }
8355     if (cur->type == XML_NAMESPACE_DECL)
8356         return(NULL);
8357     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8358 	cur = cur->prev;
8359     while (cur->prev == NULL) {
8360         cur = cur->parent;
8361         if (cur == NULL)
8362             return (NULL);
8363         if (cur == ctxt->context->doc->children)
8364             return (NULL);
8365         if (cur != ctxt->ancestor)
8366             return (cur);
8367         ctxt->ancestor = cur->parent;
8368     }
8369     cur = cur->prev;
8370     while (cur->last != NULL)
8371         cur = cur->last;
8372     return (cur);
8373 }
8374 
8375 /**
8376  * xmlXPathNextNamespace:
8377  * @ctxt:  the XPath Parser context
8378  * @cur:  the current attribute in the traversal
8379  *
8380  * Traversal function for the "namespace" direction
8381  * the namespace axis contains the namespace nodes of the context node;
8382  * the order of nodes on this axis is implementation-defined; the axis will
8383  * be empty unless the context node is an element
8384  *
8385  * We keep the XML namespace node at the end of the list.
8386  *
8387  * Returns the next element following that axis
8388  */
8389 xmlNodePtr
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8390 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8391     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8392     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8393     if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
8394         if (ctxt->context->tmpNsList != NULL)
8395 	    xmlFree(ctxt->context->tmpNsList);
8396 	ctxt->context->tmpNsList =
8397 	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8398 	ctxt->context->tmpNsNr = 0;
8399 	if (ctxt->context->tmpNsList != NULL) {
8400 	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8401 		ctxt->context->tmpNsNr++;
8402 	    }
8403 	}
8404 	return((xmlNodePtr) xmlXPathXMLNamespace);
8405     }
8406     if (ctxt->context->tmpNsNr > 0) {
8407 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8408     } else {
8409 	if (ctxt->context->tmpNsList != NULL)
8410 	    xmlFree(ctxt->context->tmpNsList);
8411 	ctxt->context->tmpNsList = NULL;
8412 	return(NULL);
8413     }
8414 }
8415 
8416 /**
8417  * xmlXPathNextAttribute:
8418  * @ctxt:  the XPath Parser context
8419  * @cur:  the current attribute in the traversal
8420  *
8421  * Traversal function for the "attribute" direction
8422  * TODO: support DTD inherited default attributes
8423  *
8424  * Returns the next element following that axis
8425  */
8426 xmlNodePtr
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8427 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8428     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8429     if (ctxt->context->node == NULL)
8430 	return(NULL);
8431     if (ctxt->context->node->type != XML_ELEMENT_NODE)
8432 	return(NULL);
8433     if (cur == NULL) {
8434         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8435 	    return(NULL);
8436         return((xmlNodePtr)ctxt->context->node->properties);
8437     }
8438     return((xmlNodePtr)cur->next);
8439 }
8440 
8441 /************************************************************************
8442  *									*
8443  *		NodeTest Functions					*
8444  *									*
8445  ************************************************************************/
8446 
8447 #define IS_FUNCTION			200
8448 
8449 
8450 /************************************************************************
8451  *									*
8452  *		Implicit tree core function library			*
8453  *									*
8454  ************************************************************************/
8455 
8456 /**
8457  * xmlXPathRoot:
8458  * @ctxt:  the XPath Parser context
8459  *
8460  * Initialize the context to the root of the document
8461  */
8462 void
xmlXPathRoot(xmlXPathParserContextPtr ctxt)8463 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8464     if ((ctxt == NULL) || (ctxt->context == NULL))
8465 	return;
8466     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8467     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8468 	ctxt->context->node));
8469 }
8470 
8471 /************************************************************************
8472  *									*
8473  *		The explicit core function library			*
8474  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
8475  *									*
8476  ************************************************************************/
8477 
8478 
8479 /**
8480  * xmlXPathLastFunction:
8481  * @ctxt:  the XPath Parser context
8482  * @nargs:  the number of arguments
8483  *
8484  * Implement the last() XPath function
8485  *    number last()
8486  * The last function returns the number of nodes in the context node list.
8487  */
8488 void
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt,int nargs)8489 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8490     CHECK_ARITY(0);
8491     if (ctxt->context->contextSize >= 0) {
8492 	valuePush(ctxt,
8493 	    xmlXPathCacheNewFloat(ctxt->context,
8494 		(double) ctxt->context->contextSize));
8495 #ifdef DEBUG_EXPR
8496 	xmlGenericError(xmlGenericErrorContext,
8497 		"last() : %d\n", ctxt->context->contextSize);
8498 #endif
8499     } else {
8500 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8501     }
8502 }
8503 
8504 /**
8505  * xmlXPathPositionFunction:
8506  * @ctxt:  the XPath Parser context
8507  * @nargs:  the number of arguments
8508  *
8509  * Implement the position() XPath function
8510  *    number position()
8511  * The position function returns the position of the context node in the
8512  * context node list. The first position is 1, and so the last position
8513  * will be equal to last().
8514  */
8515 void
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt,int nargs)8516 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8517     CHECK_ARITY(0);
8518     if (ctxt->context->proximityPosition >= 0) {
8519 	valuePush(ctxt,
8520 	      xmlXPathCacheNewFloat(ctxt->context,
8521 		(double) ctxt->context->proximityPosition));
8522 #ifdef DEBUG_EXPR
8523 	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8524 		ctxt->context->proximityPosition);
8525 #endif
8526     } else {
8527 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8528     }
8529 }
8530 
8531 /**
8532  * xmlXPathCountFunction:
8533  * @ctxt:  the XPath Parser context
8534  * @nargs:  the number of arguments
8535  *
8536  * Implement the count() XPath function
8537  *    number count(node-set)
8538  */
8539 void
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt,int nargs)8540 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8541     xmlXPathObjectPtr cur;
8542 
8543     CHECK_ARITY(1);
8544     if ((ctxt->value == NULL) ||
8545 	((ctxt->value->type != XPATH_NODESET) &&
8546 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8547 	XP_ERROR(XPATH_INVALID_TYPE);
8548     cur = valuePop(ctxt);
8549 
8550     if ((cur == NULL) || (cur->nodesetval == NULL))
8551 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8552     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8553 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8554 	    (double) cur->nodesetval->nodeNr));
8555     } else {
8556 	if ((cur->nodesetval->nodeNr != 1) ||
8557 	    (cur->nodesetval->nodeTab == NULL)) {
8558 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8559 	} else {
8560 	    xmlNodePtr tmp;
8561 	    int i = 0;
8562 
8563 	    tmp = cur->nodesetval->nodeTab[0];
8564 	    if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
8565 		tmp = tmp->children;
8566 		while (tmp != NULL) {
8567 		    tmp = tmp->next;
8568 		    i++;
8569 		}
8570 	    }
8571 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8572 	}
8573     }
8574     xmlXPathReleaseObject(ctxt->context, cur);
8575 }
8576 
8577 /**
8578  * xmlXPathGetElementsByIds:
8579  * @doc:  the document
8580  * @ids:  a whitespace separated list of IDs
8581  *
8582  * Selects elements by their unique ID.
8583  *
8584  * Returns a node-set of selected elements.
8585  */
8586 static xmlNodeSetPtr
xmlXPathGetElementsByIds(xmlDocPtr doc,const xmlChar * ids)8587 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8588     xmlNodeSetPtr ret;
8589     const xmlChar *cur = ids;
8590     xmlChar *ID;
8591     xmlAttrPtr attr;
8592     xmlNodePtr elem = NULL;
8593 
8594     if (ids == NULL) return(NULL);
8595 
8596     ret = xmlXPathNodeSetCreate(NULL);
8597     if (ret == NULL)
8598         return(ret);
8599 
8600     while (IS_BLANK_CH(*cur)) cur++;
8601     while (*cur != 0) {
8602 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8603 	    cur++;
8604 
8605         ID = xmlStrndup(ids, cur - ids);
8606 	if (ID != NULL) {
8607 	    /*
8608 	     * We used to check the fact that the value passed
8609 	     * was an NCName, but this generated much troubles for
8610 	     * me and Aleksey Sanin, people blatantly violated that
8611 	     * constaint, like Visa3D spec.
8612 	     * if (xmlValidateNCName(ID, 1) == 0)
8613 	     */
8614 	    attr = xmlGetID(doc, ID);
8615 	    if (attr != NULL) {
8616 		if (attr->type == XML_ATTRIBUTE_NODE)
8617 		    elem = attr->parent;
8618 		else if (attr->type == XML_ELEMENT_NODE)
8619 		    elem = (xmlNodePtr) attr;
8620 		else
8621 		    elem = NULL;
8622 		if (elem != NULL)
8623 		    xmlXPathNodeSetAdd(ret, elem);
8624 	    }
8625 	    xmlFree(ID);
8626 	}
8627 
8628 	while (IS_BLANK_CH(*cur)) cur++;
8629 	ids = cur;
8630     }
8631     return(ret);
8632 }
8633 
8634 /**
8635  * xmlXPathIdFunction:
8636  * @ctxt:  the XPath Parser context
8637  * @nargs:  the number of arguments
8638  *
8639  * Implement the id() XPath function
8640  *    node-set id(object)
8641  * The id function selects elements by their unique ID
8642  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8643  * then the result is the union of the result of applying id to the
8644  * string value of each of the nodes in the argument node-set. When the
8645  * argument to id is of any other type, the argument is converted to a
8646  * string as if by a call to the string function; the string is split
8647  * into a whitespace-separated list of tokens (whitespace is any sequence
8648  * of characters matching the production S); the result is a node-set
8649  * containing the elements in the same document as the context node that
8650  * have a unique ID equal to any of the tokens in the list.
8651  */
8652 void
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt,int nargs)8653 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8654     xmlChar *tokens;
8655     xmlNodeSetPtr ret;
8656     xmlXPathObjectPtr obj;
8657 
8658     CHECK_ARITY(1);
8659     obj = valuePop(ctxt);
8660     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8661     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8662 	xmlNodeSetPtr ns;
8663 	int i;
8664 
8665 	ret = xmlXPathNodeSetCreate(NULL);
8666         /*
8667          * FIXME -- in an out-of-memory condition this will behave badly.
8668          * The solution is not clear -- we already popped an item from
8669          * ctxt, so the object is in a corrupt state.
8670          */
8671 
8672 	if (obj->nodesetval != NULL) {
8673 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8674 		tokens =
8675 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8676 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8677 		ret = xmlXPathNodeSetMerge(ret, ns);
8678 		xmlXPathFreeNodeSet(ns);
8679 		if (tokens != NULL)
8680 		    xmlFree(tokens);
8681 	    }
8682 	}
8683 	xmlXPathReleaseObject(ctxt->context, obj);
8684 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8685 	return;
8686     }
8687     obj = xmlXPathCacheConvertString(ctxt->context, obj);
8688     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8689     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8690     xmlXPathReleaseObject(ctxt->context, obj);
8691     return;
8692 }
8693 
8694 /**
8695  * xmlXPathLocalNameFunction:
8696  * @ctxt:  the XPath Parser context
8697  * @nargs:  the number of arguments
8698  *
8699  * Implement the local-name() XPath function
8700  *    string local-name(node-set?)
8701  * The local-name function returns a string containing the local part
8702  * of the name of the node in the argument node-set that is first in
8703  * document order. If the node-set is empty or the first node has no
8704  * name, an empty string is returned. If the argument is omitted it
8705  * defaults to the context node.
8706  */
8707 void
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8708 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8709     xmlXPathObjectPtr cur;
8710 
8711     if (ctxt == NULL) return;
8712 
8713     if (nargs == 0) {
8714 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8715 	    ctxt->context->node));
8716 	nargs = 1;
8717     }
8718 
8719     CHECK_ARITY(1);
8720     if ((ctxt->value == NULL) ||
8721 	((ctxt->value->type != XPATH_NODESET) &&
8722 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8723 	XP_ERROR(XPATH_INVALID_TYPE);
8724     cur = valuePop(ctxt);
8725 
8726     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8727 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8728     } else {
8729 	int i = 0; /* Should be first in document order !!!!! */
8730 	switch (cur->nodesetval->nodeTab[i]->type) {
8731 	case XML_ELEMENT_NODE:
8732 	case XML_ATTRIBUTE_NODE:
8733 	case XML_PI_NODE:
8734 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8735 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8736 	    else
8737 		valuePush(ctxt,
8738 		      xmlXPathCacheNewString(ctxt->context,
8739 			cur->nodesetval->nodeTab[i]->name));
8740 	    break;
8741 	case XML_NAMESPACE_DECL:
8742 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8743 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8744 	    break;
8745 	default:
8746 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8747 	}
8748     }
8749     xmlXPathReleaseObject(ctxt->context, cur);
8750 }
8751 
8752 /**
8753  * xmlXPathNamespaceURIFunction:
8754  * @ctxt:  the XPath Parser context
8755  * @nargs:  the number of arguments
8756  *
8757  * Implement the namespace-uri() XPath function
8758  *    string namespace-uri(node-set?)
8759  * The namespace-uri function returns a string containing the
8760  * namespace URI of the expanded name of the node in the argument
8761  * node-set that is first in document order. If the node-set is empty,
8762  * the first node has no name, or the expanded name has no namespace
8763  * URI, an empty string is returned. If the argument is omitted it
8764  * defaults to the context node.
8765  */
8766 void
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt,int nargs)8767 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8768     xmlXPathObjectPtr cur;
8769 
8770     if (ctxt == NULL) return;
8771 
8772     if (nargs == 0) {
8773 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8774 	    ctxt->context->node));
8775 	nargs = 1;
8776     }
8777     CHECK_ARITY(1);
8778     if ((ctxt->value == NULL) ||
8779 	((ctxt->value->type != XPATH_NODESET) &&
8780 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8781 	XP_ERROR(XPATH_INVALID_TYPE);
8782     cur = valuePop(ctxt);
8783 
8784     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8785 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8786     } else {
8787 	int i = 0; /* Should be first in document order !!!!! */
8788 	switch (cur->nodesetval->nodeTab[i]->type) {
8789 	case XML_ELEMENT_NODE:
8790 	case XML_ATTRIBUTE_NODE:
8791 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
8792 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8793 	    else
8794 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8795 			  cur->nodesetval->nodeTab[i]->ns->href));
8796 	    break;
8797 	default:
8798 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8799 	}
8800     }
8801     xmlXPathReleaseObject(ctxt->context, cur);
8802 }
8803 
8804 /**
8805  * xmlXPathNameFunction:
8806  * @ctxt:  the XPath Parser context
8807  * @nargs:  the number of arguments
8808  *
8809  * Implement the name() XPath function
8810  *    string name(node-set?)
8811  * The name function returns a string containing a QName representing
8812  * the name of the node in the argument node-set that is first in document
8813  * order. The QName must represent the name with respect to the namespace
8814  * declarations in effect on the node whose name is being represented.
8815  * Typically, this will be the form in which the name occurred in the XML
8816  * source. This need not be the case if there are namespace declarations
8817  * in effect on the node that associate multiple prefixes with the same
8818  * namespace. However, an implementation may include information about
8819  * the original prefix in its representation of nodes; in this case, an
8820  * implementation can ensure that the returned string is always the same
8821  * as the QName used in the XML source. If the argument it omitted it
8822  * defaults to the context node.
8823  * Libxml keep the original prefix so the "real qualified name" used is
8824  * returned.
8825  */
8826 static void
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8827 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8828 {
8829     xmlXPathObjectPtr cur;
8830 
8831     if (nargs == 0) {
8832 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8833 	    ctxt->context->node));
8834         nargs = 1;
8835     }
8836 
8837     CHECK_ARITY(1);
8838     if ((ctxt->value == NULL) ||
8839         ((ctxt->value->type != XPATH_NODESET) &&
8840          (ctxt->value->type != XPATH_XSLT_TREE)))
8841         XP_ERROR(XPATH_INVALID_TYPE);
8842     cur = valuePop(ctxt);
8843 
8844     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8845         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8846     } else {
8847         int i = 0;              /* Should be first in document order !!!!! */
8848 
8849         switch (cur->nodesetval->nodeTab[i]->type) {
8850             case XML_ELEMENT_NODE:
8851             case XML_ATTRIBUTE_NODE:
8852 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8853 		    valuePush(ctxt,
8854 			xmlXPathCacheNewCString(ctxt->context, ""));
8855 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8856                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8857 		    valuePush(ctxt,
8858 		        xmlXPathCacheNewString(ctxt->context,
8859 			    cur->nodesetval->nodeTab[i]->name));
8860 		} else {
8861 		    xmlChar *fullname;
8862 
8863 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8864 				     cur->nodesetval->nodeTab[i]->ns->prefix,
8865 				     NULL, 0);
8866 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
8867 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8868 		    if (fullname == NULL) {
8869 			XP_ERROR(XPATH_MEMORY_ERROR);
8870 		    }
8871 		    valuePush(ctxt, xmlXPathCacheWrapString(
8872 			ctxt->context, fullname));
8873                 }
8874                 break;
8875             default:
8876 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8877 		    cur->nodesetval->nodeTab[i]));
8878                 xmlXPathLocalNameFunction(ctxt, 1);
8879         }
8880     }
8881     xmlXPathReleaseObject(ctxt->context, cur);
8882 }
8883 
8884 
8885 /**
8886  * xmlXPathStringFunction:
8887  * @ctxt:  the XPath Parser context
8888  * @nargs:  the number of arguments
8889  *
8890  * Implement the string() XPath function
8891  *    string string(object?)
8892  * The string function converts an object to a string as follows:
8893  *    - A node-set is converted to a string by returning the value of
8894  *      the node in the node-set that is first in document order.
8895  *      If the node-set is empty, an empty string is returned.
8896  *    - A number is converted to a string as follows
8897  *      + NaN is converted to the string NaN
8898  *      + positive zero is converted to the string 0
8899  *      + negative zero is converted to the string 0
8900  *      + positive infinity is converted to the string Infinity
8901  *      + negative infinity is converted to the string -Infinity
8902  *      + if the number is an integer, the number is represented in
8903  *        decimal form as a Number with no decimal point and no leading
8904  *        zeros, preceded by a minus sign (-) if the number is negative
8905  *      + otherwise, the number is represented in decimal form as a
8906  *        Number including a decimal point with at least one digit
8907  *        before the decimal point and at least one digit after the
8908  *        decimal point, preceded by a minus sign (-) if the number
8909  *        is negative; there must be no leading zeros before the decimal
8910  *        point apart possibly from the one required digit immediately
8911  *        before the decimal point; beyond the one required digit
8912  *        after the decimal point there must be as many, but only as
8913  *        many, more digits as are needed to uniquely distinguish the
8914  *        number from all other IEEE 754 numeric values.
8915  *    - The boolean false value is converted to the string false.
8916  *      The boolean true value is converted to the string true.
8917  *
8918  * If the argument is omitted, it defaults to a node-set with the
8919  * context node as its only member.
8920  */
8921 void
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt,int nargs)8922 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8923     xmlXPathObjectPtr cur;
8924 
8925     if (ctxt == NULL) return;
8926     if (nargs == 0) {
8927     valuePush(ctxt,
8928 	xmlXPathCacheWrapString(ctxt->context,
8929 	    xmlXPathCastNodeToString(ctxt->context->node)));
8930 	return;
8931     }
8932 
8933     CHECK_ARITY(1);
8934     cur = valuePop(ctxt);
8935     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8936     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8937 }
8938 
8939 /**
8940  * xmlXPathStringLengthFunction:
8941  * @ctxt:  the XPath Parser context
8942  * @nargs:  the number of arguments
8943  *
8944  * Implement the string-length() XPath function
8945  *    number string-length(string?)
8946  * The string-length returns the number of characters in the string
8947  * (see [3.6 Strings]). If the argument is omitted, it defaults to
8948  * the context node converted to a string, in other words the value
8949  * of the context node.
8950  */
8951 void
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt,int nargs)8952 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8953     xmlXPathObjectPtr cur;
8954 
8955     if (nargs == 0) {
8956         if ((ctxt == NULL) || (ctxt->context == NULL))
8957 	    return;
8958 	if (ctxt->context->node == NULL) {
8959 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8960 	} else {
8961 	    xmlChar *content;
8962 
8963 	    content = xmlXPathCastNodeToString(ctxt->context->node);
8964 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8965 		xmlUTF8Strlen(content)));
8966 	    xmlFree(content);
8967 	}
8968 	return;
8969     }
8970     CHECK_ARITY(1);
8971     CAST_TO_STRING;
8972     CHECK_TYPE(XPATH_STRING);
8973     cur = valuePop(ctxt);
8974     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8975 	xmlUTF8Strlen(cur->stringval)));
8976     xmlXPathReleaseObject(ctxt->context, cur);
8977 }
8978 
8979 /**
8980  * xmlXPathConcatFunction:
8981  * @ctxt:  the XPath Parser context
8982  * @nargs:  the number of arguments
8983  *
8984  * Implement the concat() XPath function
8985  *    string concat(string, string, string*)
8986  * The concat function returns the concatenation of its arguments.
8987  */
8988 void
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt,int nargs)8989 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8990     xmlXPathObjectPtr cur, newobj;
8991     xmlChar *tmp;
8992 
8993     if (ctxt == NULL) return;
8994     if (nargs < 2) {
8995 	CHECK_ARITY(2);
8996     }
8997 
8998     CAST_TO_STRING;
8999     cur = valuePop(ctxt);
9000     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
9001 	xmlXPathReleaseObject(ctxt->context, cur);
9002 	return;
9003     }
9004     nargs--;
9005 
9006     while (nargs > 0) {
9007 	CAST_TO_STRING;
9008 	newobj = valuePop(ctxt);
9009 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
9010 	    xmlXPathReleaseObject(ctxt->context, newobj);
9011 	    xmlXPathReleaseObject(ctxt->context, cur);
9012 	    XP_ERROR(XPATH_INVALID_TYPE);
9013 	}
9014 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
9015 	newobj->stringval = cur->stringval;
9016 	cur->stringval = tmp;
9017 	xmlXPathReleaseObject(ctxt->context, newobj);
9018 	nargs--;
9019     }
9020     valuePush(ctxt, cur);
9021 }
9022 
9023 /**
9024  * xmlXPathContainsFunction:
9025  * @ctxt:  the XPath Parser context
9026  * @nargs:  the number of arguments
9027  *
9028  * Implement the contains() XPath function
9029  *    boolean contains(string, string)
9030  * The contains function returns true if the first argument string
9031  * contains the second argument string, and otherwise returns false.
9032  */
9033 void
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt,int nargs)9034 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9035     xmlXPathObjectPtr hay, needle;
9036 
9037     CHECK_ARITY(2);
9038     CAST_TO_STRING;
9039     CHECK_TYPE(XPATH_STRING);
9040     needle = valuePop(ctxt);
9041     CAST_TO_STRING;
9042     hay = valuePop(ctxt);
9043 
9044     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9045 	xmlXPathReleaseObject(ctxt->context, hay);
9046 	xmlXPathReleaseObject(ctxt->context, needle);
9047 	XP_ERROR(XPATH_INVALID_TYPE);
9048     }
9049     if (xmlStrstr(hay->stringval, needle->stringval))
9050 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9051     else
9052 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9053     xmlXPathReleaseObject(ctxt->context, hay);
9054     xmlXPathReleaseObject(ctxt->context, needle);
9055 }
9056 
9057 /**
9058  * xmlXPathStartsWithFunction:
9059  * @ctxt:  the XPath Parser context
9060  * @nargs:  the number of arguments
9061  *
9062  * Implement the starts-with() XPath function
9063  *    boolean starts-with(string, string)
9064  * The starts-with function returns true if the first argument string
9065  * starts with the second argument string, and otherwise returns false.
9066  */
9067 void
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt,int nargs)9068 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9069     xmlXPathObjectPtr hay, needle;
9070     int n;
9071 
9072     CHECK_ARITY(2);
9073     CAST_TO_STRING;
9074     CHECK_TYPE(XPATH_STRING);
9075     needle = valuePop(ctxt);
9076     CAST_TO_STRING;
9077     hay = valuePop(ctxt);
9078 
9079     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9080 	xmlXPathReleaseObject(ctxt->context, hay);
9081 	xmlXPathReleaseObject(ctxt->context, needle);
9082 	XP_ERROR(XPATH_INVALID_TYPE);
9083     }
9084     n = xmlStrlen(needle->stringval);
9085     if (xmlStrncmp(hay->stringval, needle->stringval, n))
9086         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9087     else
9088         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9089     xmlXPathReleaseObject(ctxt->context, hay);
9090     xmlXPathReleaseObject(ctxt->context, needle);
9091 }
9092 
9093 /**
9094  * xmlXPathSubstringFunction:
9095  * @ctxt:  the XPath Parser context
9096  * @nargs:  the number of arguments
9097  *
9098  * Implement the substring() XPath function
9099  *    string substring(string, number, number?)
9100  * The substring function returns the substring of the first argument
9101  * starting at the position specified in the second argument with
9102  * length specified in the third argument. For example,
9103  * substring("12345",2,3) returns "234". If the third argument is not
9104  * specified, it returns the substring starting at the position specified
9105  * in the second argument and continuing to the end of the string. For
9106  * example, substring("12345",2) returns "2345".  More precisely, each
9107  * character in the string (see [3.6 Strings]) is considered to have a
9108  * numeric position: the position of the first character is 1, the position
9109  * of the second character is 2 and so on. The returned substring contains
9110  * those characters for which the position of the character is greater than
9111  * or equal to the second argument and, if the third argument is specified,
9112  * less than the sum of the second and third arguments; the comparisons
9113  * and addition used for the above follow the standard IEEE 754 rules. Thus:
9114  *  - substring("12345", 1.5, 2.6) returns "234"
9115  *  - substring("12345", 0, 3) returns "12"
9116  *  - substring("12345", 0 div 0, 3) returns ""
9117  *  - substring("12345", 1, 0 div 0) returns ""
9118  *  - substring("12345", -42, 1 div 0) returns "12345"
9119  *  - substring("12345", -1 div 0, 1 div 0) returns ""
9120  */
9121 void
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt,int nargs)9122 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9123     xmlXPathObjectPtr str, start, len;
9124     double le=0, in;
9125     int i, l, m;
9126     xmlChar *ret;
9127 
9128     if (nargs < 2) {
9129 	CHECK_ARITY(2);
9130     }
9131     if (nargs > 3) {
9132 	CHECK_ARITY(3);
9133     }
9134     /*
9135      * take care of possible last (position) argument
9136     */
9137     if (nargs == 3) {
9138 	CAST_TO_NUMBER;
9139 	CHECK_TYPE(XPATH_NUMBER);
9140 	len = valuePop(ctxt);
9141 	le = len->floatval;
9142 	xmlXPathReleaseObject(ctxt->context, len);
9143     }
9144 
9145     CAST_TO_NUMBER;
9146     CHECK_TYPE(XPATH_NUMBER);
9147     start = valuePop(ctxt);
9148     in = start->floatval;
9149     xmlXPathReleaseObject(ctxt->context, start);
9150     CAST_TO_STRING;
9151     CHECK_TYPE(XPATH_STRING);
9152     str = valuePop(ctxt);
9153     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9154 
9155     /*
9156      * If last pos not present, calculate last position
9157     */
9158     if (nargs != 3) {
9159 	le = (double)m;
9160 	if (in < 1.0)
9161 	    in = 1.0;
9162     }
9163 
9164     /* Need to check for the special cases where either
9165      * the index is NaN, the length is NaN, or both
9166      * arguments are infinity (relying on Inf + -Inf = NaN)
9167      */
9168     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9169         /*
9170          * To meet the requirements of the spec, the arguments
9171 	 * must be converted to integer format before
9172 	 * initial index calculations are done
9173          *
9174          * First we go to integer form, rounding up
9175 	 * and checking for special cases
9176          */
9177         i = (int) in;
9178         if (((double)i)+0.5 <= in) i++;
9179 
9180 	if (xmlXPathIsInf(le) == 1) {
9181 	    l = m;
9182 	    if (i < 1)
9183 		i = 1;
9184 	}
9185 	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9186 	    l = 0;
9187 	else {
9188 	    l = (int) le;
9189 	    if (((double)l)+0.5 <= le) l++;
9190 	}
9191 
9192 	/* Now we normalize inidices */
9193         i -= 1;
9194         l += i;
9195         if (i < 0)
9196             i = 0;
9197         if (l > m)
9198             l = m;
9199 
9200         /* number of chars to copy */
9201         l -= i;
9202 
9203         ret = xmlUTF8Strsub(str->stringval, i, l);
9204     }
9205     else {
9206         ret = NULL;
9207     }
9208     if (ret == NULL)
9209 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9210     else {
9211 	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9212 	xmlFree(ret);
9213     }
9214     xmlXPathReleaseObject(ctxt->context, str);
9215 }
9216 
9217 /**
9218  * xmlXPathSubstringBeforeFunction:
9219  * @ctxt:  the XPath Parser context
9220  * @nargs:  the number of arguments
9221  *
9222  * Implement the substring-before() XPath function
9223  *    string substring-before(string, string)
9224  * The substring-before function returns the substring of the first
9225  * argument string that precedes the first occurrence of the second
9226  * argument string in the first argument string, or the empty string
9227  * if the first argument string does not contain the second argument
9228  * string. For example, substring-before("1999/04/01","/") returns 1999.
9229  */
9230 void
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt,int nargs)9231 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9232   xmlXPathObjectPtr str;
9233   xmlXPathObjectPtr find;
9234   xmlBufPtr target;
9235   const xmlChar *point;
9236   int offset;
9237 
9238   CHECK_ARITY(2);
9239   CAST_TO_STRING;
9240   find = valuePop(ctxt);
9241   CAST_TO_STRING;
9242   str = valuePop(ctxt);
9243 
9244   target = xmlBufCreate();
9245   if (target) {
9246     point = xmlStrstr(str->stringval, find->stringval);
9247     if (point) {
9248       offset = (int)(point - str->stringval);
9249       xmlBufAdd(target, str->stringval, offset);
9250     }
9251     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9252 	xmlBufContent(target)));
9253     xmlBufFree(target);
9254   }
9255   xmlXPathReleaseObject(ctxt->context, str);
9256   xmlXPathReleaseObject(ctxt->context, find);
9257 }
9258 
9259 /**
9260  * xmlXPathSubstringAfterFunction:
9261  * @ctxt:  the XPath Parser context
9262  * @nargs:  the number of arguments
9263  *
9264  * Implement the substring-after() XPath function
9265  *    string substring-after(string, string)
9266  * The substring-after function returns the substring of the first
9267  * argument string that follows the first occurrence of the second
9268  * argument string in the first argument string, or the empty stringi
9269  * if the first argument string does not contain the second argument
9270  * string. For example, substring-after("1999/04/01","/") returns 04/01,
9271  * and substring-after("1999/04/01","19") returns 99/04/01.
9272  */
9273 void
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt,int nargs)9274 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9275   xmlXPathObjectPtr str;
9276   xmlXPathObjectPtr find;
9277   xmlBufPtr target;
9278   const xmlChar *point;
9279   int offset;
9280 
9281   CHECK_ARITY(2);
9282   CAST_TO_STRING;
9283   find = valuePop(ctxt);
9284   CAST_TO_STRING;
9285   str = valuePop(ctxt);
9286 
9287   target = xmlBufCreate();
9288   if (target) {
9289     point = xmlStrstr(str->stringval, find->stringval);
9290     if (point) {
9291       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9292       xmlBufAdd(target, &str->stringval[offset],
9293 		   xmlStrlen(str->stringval) - offset);
9294     }
9295     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9296 	xmlBufContent(target)));
9297     xmlBufFree(target);
9298   }
9299   xmlXPathReleaseObject(ctxt->context, str);
9300   xmlXPathReleaseObject(ctxt->context, find);
9301 }
9302 
9303 /**
9304  * xmlXPathNormalizeFunction:
9305  * @ctxt:  the XPath Parser context
9306  * @nargs:  the number of arguments
9307  *
9308  * Implement the normalize-space() XPath function
9309  *    string normalize-space(string?)
9310  * The normalize-space function returns the argument string with white
9311  * space normalized by stripping leading and trailing whitespace
9312  * and replacing sequences of whitespace characters by a single
9313  * space. Whitespace characters are the same allowed by the S production
9314  * in XML. If the argument is omitted, it defaults to the context
9315  * node converted to a string, in other words the value of the context node.
9316  */
9317 void
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt,int nargs)9318 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9319   xmlXPathObjectPtr obj = NULL;
9320   xmlChar *source = NULL;
9321   xmlBufPtr target;
9322   xmlChar blank;
9323 
9324   if (ctxt == NULL) return;
9325   if (nargs == 0) {
9326     /* Use current context node */
9327       valuePush(ctxt,
9328 	  xmlXPathCacheWrapString(ctxt->context,
9329 	    xmlXPathCastNodeToString(ctxt->context->node)));
9330     nargs = 1;
9331   }
9332 
9333   CHECK_ARITY(1);
9334   CAST_TO_STRING;
9335   CHECK_TYPE(XPATH_STRING);
9336   obj = valuePop(ctxt);
9337   source = obj->stringval;
9338 
9339   target = xmlBufCreate();
9340   if (target && source) {
9341 
9342     /* Skip leading whitespaces */
9343     while (IS_BLANK_CH(*source))
9344       source++;
9345 
9346     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9347     blank = 0;
9348     while (*source) {
9349       if (IS_BLANK_CH(*source)) {
9350 	blank = 0x20;
9351       } else {
9352 	if (blank) {
9353 	  xmlBufAdd(target, &blank, 1);
9354 	  blank = 0;
9355 	}
9356 	xmlBufAdd(target, source, 1);
9357       }
9358       source++;
9359     }
9360     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9361 	xmlBufContent(target)));
9362     xmlBufFree(target);
9363   }
9364   xmlXPathReleaseObject(ctxt->context, obj);
9365 }
9366 
9367 /**
9368  * xmlXPathTranslateFunction:
9369  * @ctxt:  the XPath Parser context
9370  * @nargs:  the number of arguments
9371  *
9372  * Implement the translate() XPath function
9373  *    string translate(string, string, string)
9374  * The translate function returns the first argument string with
9375  * occurrences of characters in the second argument string replaced
9376  * by the character at the corresponding position in the third argument
9377  * string. For example, translate("bar","abc","ABC") returns the string
9378  * BAr. If there is a character in the second argument string with no
9379  * character at a corresponding position in the third argument string
9380  * (because the second argument string is longer than the third argument
9381  * string), then occurrences of that character in the first argument
9382  * string are removed. For example, translate("--aaa--","abc-","ABC")
9383  * returns "AAA". If a character occurs more than once in second
9384  * argument string, then the first occurrence determines the replacement
9385  * character. If the third argument string is longer than the second
9386  * argument string, then excess characters are ignored.
9387  */
9388 void
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt,int nargs)9389 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9390     xmlXPathObjectPtr str;
9391     xmlXPathObjectPtr from;
9392     xmlXPathObjectPtr to;
9393     xmlBufPtr target;
9394     int offset, max;
9395     xmlChar ch;
9396     const xmlChar *point;
9397     xmlChar *cptr;
9398 
9399     CHECK_ARITY(3);
9400 
9401     CAST_TO_STRING;
9402     to = valuePop(ctxt);
9403     CAST_TO_STRING;
9404     from = valuePop(ctxt);
9405     CAST_TO_STRING;
9406     str = valuePop(ctxt);
9407 
9408     target = xmlBufCreate();
9409     if (target) {
9410 	max = xmlUTF8Strlen(to->stringval);
9411 	for (cptr = str->stringval; (ch=*cptr); ) {
9412 	    offset = xmlUTF8Strloc(from->stringval, cptr);
9413 	    if (offset >= 0) {
9414 		if (offset < max) {
9415 		    point = xmlUTF8Strpos(to->stringval, offset);
9416 		    if (point)
9417 			xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9418 		}
9419 	    } else
9420 		xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9421 
9422 	    /* Step to next character in input */
9423 	    cptr++;
9424 	    if ( ch & 0x80 ) {
9425 		/* if not simple ascii, verify proper format */
9426 		if ( (ch & 0xc0) != 0xc0 ) {
9427 		    xmlGenericError(xmlGenericErrorContext,
9428 			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
9429                     /* not asserting an XPath error is probably better */
9430 		    break;
9431 		}
9432 		/* then skip over remaining bytes for this char */
9433 		while ( (ch <<= 1) & 0x80 )
9434 		    if ( (*cptr++ & 0xc0) != 0x80 ) {
9435 			xmlGenericError(xmlGenericErrorContext,
9436 			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9437                         /* not asserting an XPath error is probably better */
9438 			break;
9439 		    }
9440 		if (ch & 0x80) /* must have had error encountered */
9441 		    break;
9442 	    }
9443 	}
9444     }
9445     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9446 	xmlBufContent(target)));
9447     xmlBufFree(target);
9448     xmlXPathReleaseObject(ctxt->context, str);
9449     xmlXPathReleaseObject(ctxt->context, from);
9450     xmlXPathReleaseObject(ctxt->context, to);
9451 }
9452 
9453 /**
9454  * xmlXPathBooleanFunction:
9455  * @ctxt:  the XPath Parser context
9456  * @nargs:  the number of arguments
9457  *
9458  * Implement the boolean() XPath function
9459  *    boolean boolean(object)
9460  * The boolean function converts its argument to a boolean as follows:
9461  *    - a number is true if and only if it is neither positive or
9462  *      negative zero nor NaN
9463  *    - a node-set is true if and only if it is non-empty
9464  *    - a string is true if and only if its length is non-zero
9465  */
9466 void
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt,int nargs)9467 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9468     xmlXPathObjectPtr cur;
9469 
9470     CHECK_ARITY(1);
9471     cur = valuePop(ctxt);
9472     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9473     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9474     valuePush(ctxt, cur);
9475 }
9476 
9477 /**
9478  * xmlXPathNotFunction:
9479  * @ctxt:  the XPath Parser context
9480  * @nargs:  the number of arguments
9481  *
9482  * Implement the not() XPath function
9483  *    boolean not(boolean)
9484  * The not function returns true if its argument is false,
9485  * and false otherwise.
9486  */
9487 void
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt,int nargs)9488 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9489     CHECK_ARITY(1);
9490     CAST_TO_BOOLEAN;
9491     CHECK_TYPE(XPATH_BOOLEAN);
9492     ctxt->value->boolval = ! ctxt->value->boolval;
9493 }
9494 
9495 /**
9496  * xmlXPathTrueFunction:
9497  * @ctxt:  the XPath Parser context
9498  * @nargs:  the number of arguments
9499  *
9500  * Implement the true() XPath function
9501  *    boolean true()
9502  */
9503 void
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt,int nargs)9504 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9505     CHECK_ARITY(0);
9506     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9507 }
9508 
9509 /**
9510  * xmlXPathFalseFunction:
9511  * @ctxt:  the XPath Parser context
9512  * @nargs:  the number of arguments
9513  *
9514  * Implement the false() XPath function
9515  *    boolean false()
9516  */
9517 void
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt,int nargs)9518 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9519     CHECK_ARITY(0);
9520     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9521 }
9522 
9523 /**
9524  * xmlXPathLangFunction:
9525  * @ctxt:  the XPath Parser context
9526  * @nargs:  the number of arguments
9527  *
9528  * Implement the lang() XPath function
9529  *    boolean lang(string)
9530  * The lang function returns true or false depending on whether the
9531  * language of the context node as specified by xml:lang attributes
9532  * is the same as or is a sublanguage of the language specified by
9533  * the argument string. The language of the context node is determined
9534  * by the value of the xml:lang attribute on the context node, or, if
9535  * the context node has no xml:lang attribute, by the value of the
9536  * xml:lang attribute on the nearest ancestor of the context node that
9537  * has an xml:lang attribute. If there is no such attribute, then lang
9538  * returns false. If there is such an attribute, then lang returns
9539  * true if the attribute value is equal to the argument ignoring case,
9540  * or if there is some suffix starting with - such that the attribute
9541  * value is equal to the argument ignoring that suffix of the attribute
9542  * value and ignoring case.
9543  */
9544 void
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt,int nargs)9545 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9546     xmlXPathObjectPtr val = NULL;
9547     const xmlChar *theLang = NULL;
9548     const xmlChar *lang;
9549     int ret = 0;
9550     int i;
9551 
9552     CHECK_ARITY(1);
9553     CAST_TO_STRING;
9554     CHECK_TYPE(XPATH_STRING);
9555     val = valuePop(ctxt);
9556     lang = val->stringval;
9557     theLang = xmlNodeGetLang(ctxt->context->node);
9558     if ((theLang != NULL) && (lang != NULL)) {
9559         for (i = 0;lang[i] != 0;i++)
9560 	    if (toupper(lang[i]) != toupper(theLang[i]))
9561 	        goto not_equal;
9562 	if ((theLang[i] == 0) || (theLang[i] == '-'))
9563 	    ret = 1;
9564     }
9565 not_equal:
9566     if (theLang != NULL)
9567 	xmlFree((void *)theLang);
9568 
9569     xmlXPathReleaseObject(ctxt->context, val);
9570     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9571 }
9572 
9573 /**
9574  * xmlXPathNumberFunction:
9575  * @ctxt:  the XPath Parser context
9576  * @nargs:  the number of arguments
9577  *
9578  * Implement the number() XPath function
9579  *    number number(object?)
9580  */
9581 void
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt,int nargs)9582 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9583     xmlXPathObjectPtr cur;
9584     double res;
9585 
9586     if (ctxt == NULL) return;
9587     if (nargs == 0) {
9588 	if (ctxt->context->node == NULL) {
9589 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9590 	} else {
9591 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9592 
9593 	    res = xmlXPathStringEvalNumber(content);
9594 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9595 	    xmlFree(content);
9596 	}
9597 	return;
9598     }
9599 
9600     CHECK_ARITY(1);
9601     cur = valuePop(ctxt);
9602     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9603 }
9604 
9605 /**
9606  * xmlXPathSumFunction:
9607  * @ctxt:  the XPath Parser context
9608  * @nargs:  the number of arguments
9609  *
9610  * Implement the sum() XPath function
9611  *    number sum(node-set)
9612  * The sum function returns the sum of the values of the nodes in
9613  * the argument node-set.
9614  */
9615 void
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt,int nargs)9616 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9617     xmlXPathObjectPtr cur;
9618     int i;
9619     double res = 0.0;
9620 
9621     CHECK_ARITY(1);
9622     if ((ctxt->value == NULL) ||
9623 	((ctxt->value->type != XPATH_NODESET) &&
9624 	 (ctxt->value->type != XPATH_XSLT_TREE)))
9625 	XP_ERROR(XPATH_INVALID_TYPE);
9626     cur = valuePop(ctxt);
9627 
9628     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9629 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9630 	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9631 	}
9632     }
9633     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9634     xmlXPathReleaseObject(ctxt->context, cur);
9635 }
9636 
9637 /*
9638  * To assure working code on multiple platforms, we want to only depend
9639  * upon the characteristic truncation of converting a floating point value
9640  * to an integer.  Unfortunately, because of the different storage sizes
9641  * of our internal floating point value (double) and integer (int), we
9642  * can't directly convert (see bug 301162).  This macro is a messy
9643  * 'workaround'
9644  */
9645 #define XTRUNC(f, v)            \
9646     f = fmod((v), INT_MAX);     \
9647     f = (v) - (f) + (double)((int)(f));
9648 
9649 /**
9650  * xmlXPathFloorFunction:
9651  * @ctxt:  the XPath Parser context
9652  * @nargs:  the number of arguments
9653  *
9654  * Implement the floor() XPath function
9655  *    number floor(number)
9656  * The floor function returns the largest (closest to positive infinity)
9657  * number that is not greater than the argument and that is an integer.
9658  */
9659 void
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt,int nargs)9660 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9661     double f;
9662 
9663     CHECK_ARITY(1);
9664     CAST_TO_NUMBER;
9665     CHECK_TYPE(XPATH_NUMBER);
9666 
9667     XTRUNC(f, ctxt->value->floatval);
9668     if (f != ctxt->value->floatval) {
9669 	if (ctxt->value->floatval > 0)
9670 	    ctxt->value->floatval = f;
9671 	else
9672 	    ctxt->value->floatval = f - 1;
9673     }
9674 }
9675 
9676 /**
9677  * xmlXPathCeilingFunction:
9678  * @ctxt:  the XPath Parser context
9679  * @nargs:  the number of arguments
9680  *
9681  * Implement the ceiling() XPath function
9682  *    number ceiling(number)
9683  * The ceiling function returns the smallest (closest to negative infinity)
9684  * number that is not less than the argument and that is an integer.
9685  */
9686 void
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt,int nargs)9687 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9688     double f;
9689 
9690     CHECK_ARITY(1);
9691     CAST_TO_NUMBER;
9692     CHECK_TYPE(XPATH_NUMBER);
9693 
9694 #if 0
9695     ctxt->value->floatval = ceil(ctxt->value->floatval);
9696 #else
9697     XTRUNC(f, ctxt->value->floatval);
9698     if (f != ctxt->value->floatval) {
9699 	if (ctxt->value->floatval > 0)
9700 	    ctxt->value->floatval = f + 1;
9701 	else {
9702 	    if (ctxt->value->floatval < 0 && f == 0)
9703 	        ctxt->value->floatval = xmlXPathNZERO;
9704 	    else
9705 	        ctxt->value->floatval = f;
9706 	}
9707 
9708     }
9709 #endif
9710 }
9711 
9712 /**
9713  * xmlXPathRoundFunction:
9714  * @ctxt:  the XPath Parser context
9715  * @nargs:  the number of arguments
9716  *
9717  * Implement the round() XPath function
9718  *    number round(number)
9719  * The round function returns the number that is closest to the
9720  * argument and that is an integer. If there are two such numbers,
9721  * then the one that is even is returned.
9722  */
9723 void
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt,int nargs)9724 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9725     double f;
9726 
9727     CHECK_ARITY(1);
9728     CAST_TO_NUMBER;
9729     CHECK_TYPE(XPATH_NUMBER);
9730 
9731     if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9732 	(xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9733 	(xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9734 	(ctxt->value->floatval == 0.0))
9735 	return;
9736 
9737     XTRUNC(f, ctxt->value->floatval);
9738     if (ctxt->value->floatval < 0) {
9739 	if (ctxt->value->floatval < f - 0.5)
9740 	    ctxt->value->floatval = f - 1;
9741 	else
9742 	    ctxt->value->floatval = f;
9743 	if (ctxt->value->floatval == 0)
9744 	    ctxt->value->floatval = xmlXPathNZERO;
9745     } else {
9746 	if (ctxt->value->floatval < f + 0.5)
9747 	    ctxt->value->floatval = f;
9748 	else
9749 	    ctxt->value->floatval = f + 1;
9750     }
9751 }
9752 
9753 /************************************************************************
9754  *									*
9755  *			The Parser					*
9756  *									*
9757  ************************************************************************/
9758 
9759 /*
9760  * a few forward declarations since we use a recursive call based
9761  * implementation.
9762  */
9763 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9764 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9765 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9766 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9767 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9768 	                                  int qualified);
9769 
9770 /**
9771  * xmlXPathCurrentChar:
9772  * @ctxt:  the XPath parser context
9773  * @cur:  pointer to the beginning of the char
9774  * @len:  pointer to the length of the char read
9775  *
9776  * The current char value, if using UTF-8 this may actually span multiple
9777  * bytes in the input buffer.
9778  *
9779  * Returns the current char value and its length
9780  */
9781 
9782 static int
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt,int * len)9783 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9784     unsigned char c;
9785     unsigned int val;
9786     const xmlChar *cur;
9787 
9788     if (ctxt == NULL)
9789 	return(0);
9790     cur = ctxt->cur;
9791 
9792     /*
9793      * We are supposed to handle UTF8, check it's valid
9794      * From rfc2044: encoding of the Unicode values on UTF-8:
9795      *
9796      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9797      * 0000 0000-0000 007F   0xxxxxxx
9798      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9799      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9800      *
9801      * Check for the 0x110000 limit too
9802      */
9803     c = *cur;
9804     if (c & 0x80) {
9805 	if ((cur[1] & 0xc0) != 0x80)
9806 	    goto encoding_error;
9807 	if ((c & 0xe0) == 0xe0) {
9808 
9809 	    if ((cur[2] & 0xc0) != 0x80)
9810 		goto encoding_error;
9811 	    if ((c & 0xf0) == 0xf0) {
9812 		if (((c & 0xf8) != 0xf0) ||
9813 		    ((cur[3] & 0xc0) != 0x80))
9814 		    goto encoding_error;
9815 		/* 4-byte code */
9816 		*len = 4;
9817 		val = (cur[0] & 0x7) << 18;
9818 		val |= (cur[1] & 0x3f) << 12;
9819 		val |= (cur[2] & 0x3f) << 6;
9820 		val |= cur[3] & 0x3f;
9821 	    } else {
9822 	      /* 3-byte code */
9823 		*len = 3;
9824 		val = (cur[0] & 0xf) << 12;
9825 		val |= (cur[1] & 0x3f) << 6;
9826 		val |= cur[2] & 0x3f;
9827 	    }
9828 	} else {
9829 	  /* 2-byte code */
9830 	    *len = 2;
9831 	    val = (cur[0] & 0x1f) << 6;
9832 	    val |= cur[1] & 0x3f;
9833 	}
9834 	if (!IS_CHAR(val)) {
9835 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9836 	}
9837 	return(val);
9838     } else {
9839 	/* 1-byte code */
9840 	*len = 1;
9841 	return((int) *cur);
9842     }
9843 encoding_error:
9844     /*
9845      * If we detect an UTF8 error that probably means that the
9846      * input encoding didn't get properly advertised in the
9847      * declaration header. Report the error and switch the encoding
9848      * to ISO-Latin-1 (if you don't like this policy, just declare the
9849      * encoding !)
9850      */
9851     *len = 0;
9852     XP_ERROR0(XPATH_ENCODING_ERROR);
9853 }
9854 
9855 /**
9856  * xmlXPathParseNCName:
9857  * @ctxt:  the XPath Parser context
9858  *
9859  * parse an XML namespace non qualified name.
9860  *
9861  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9862  *
9863  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9864  *                       CombiningChar | Extender
9865  *
9866  * Returns the namespace name or NULL
9867  */
9868 
9869 xmlChar *
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt)9870 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9871     const xmlChar *in;
9872     xmlChar *ret;
9873     int count = 0;
9874 
9875     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9876     /*
9877      * Accelerator for simple ASCII names
9878      */
9879     in = ctxt->cur;
9880     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9881 	((*in >= 0x41) && (*in <= 0x5A)) ||
9882 	(*in == '_')) {
9883 	in++;
9884 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9885 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9886 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9887 	       (*in == '_') || (*in == '.') ||
9888 	       (*in == '-'))
9889 	    in++;
9890 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9891             (*in == '[') || (*in == ']') || (*in == ':') ||
9892             (*in == '@') || (*in == '*')) {
9893 	    count = in - ctxt->cur;
9894 	    if (count == 0)
9895 		return(NULL);
9896 	    ret = xmlStrndup(ctxt->cur, count);
9897 	    ctxt->cur = in;
9898 	    return(ret);
9899 	}
9900     }
9901     return(xmlXPathParseNameComplex(ctxt, 0));
9902 }
9903 
9904 
9905 /**
9906  * xmlXPathParseQName:
9907  * @ctxt:  the XPath Parser context
9908  * @prefix:  a xmlChar **
9909  *
9910  * parse an XML qualified name
9911  *
9912  * [NS 5] QName ::= (Prefix ':')? LocalPart
9913  *
9914  * [NS 6] Prefix ::= NCName
9915  *
9916  * [NS 7] LocalPart ::= NCName
9917  *
9918  * Returns the function returns the local part, and prefix is updated
9919  *   to get the Prefix if any.
9920  */
9921 
9922 static xmlChar *
xmlXPathParseQName(xmlXPathParserContextPtr ctxt,xmlChar ** prefix)9923 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9924     xmlChar *ret = NULL;
9925 
9926     *prefix = NULL;
9927     ret = xmlXPathParseNCName(ctxt);
9928     if (ret && CUR == ':') {
9929         *prefix = ret;
9930 	NEXT;
9931 	ret = xmlXPathParseNCName(ctxt);
9932     }
9933     return(ret);
9934 }
9935 
9936 /**
9937  * xmlXPathParseName:
9938  * @ctxt:  the XPath Parser context
9939  *
9940  * parse an XML name
9941  *
9942  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9943  *                  CombiningChar | Extender
9944  *
9945  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9946  *
9947  * Returns the namespace name or NULL
9948  */
9949 
9950 xmlChar *
xmlXPathParseName(xmlXPathParserContextPtr ctxt)9951 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9952     const xmlChar *in;
9953     xmlChar *ret;
9954     size_t count = 0;
9955 
9956     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9957     /*
9958      * Accelerator for simple ASCII names
9959      */
9960     in = ctxt->cur;
9961     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9962 	((*in >= 0x41) && (*in <= 0x5A)) ||
9963 	(*in == '_') || (*in == ':')) {
9964 	in++;
9965 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9966 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9967 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9968 	       (*in == '_') || (*in == '-') ||
9969 	       (*in == ':') || (*in == '.'))
9970 	    in++;
9971 	if ((*in > 0) && (*in < 0x80)) {
9972 	    count = in - ctxt->cur;
9973             if (count > XML_MAX_NAME_LENGTH) {
9974                 ctxt->cur = in;
9975                 XP_ERRORNULL(XPATH_EXPR_ERROR);
9976             }
9977 	    ret = xmlStrndup(ctxt->cur, count);
9978 	    ctxt->cur = in;
9979 	    return(ret);
9980 	}
9981     }
9982     return(xmlXPathParseNameComplex(ctxt, 1));
9983 }
9984 
9985 static xmlChar *
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,int qualified)9986 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9987     xmlChar buf[XML_MAX_NAMELEN + 5];
9988     int len = 0, l;
9989     int c;
9990 
9991     /*
9992      * Handler for more complex cases
9993      */
9994     c = CUR_CHAR(l);
9995     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9996         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9997         (c == '*') || /* accelerators */
9998 	(!IS_LETTER(c) && (c != '_') &&
9999          ((qualified) && (c != ':')))) {
10000 	return(NULL);
10001     }
10002 
10003     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10004 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10005             (c == '.') || (c == '-') ||
10006 	    (c == '_') || ((qualified) && (c == ':')) ||
10007 	    (IS_COMBINING(c)) ||
10008 	    (IS_EXTENDER(c)))) {
10009 	COPY_BUF(l,buf,len,c);
10010 	NEXTL(l);
10011 	c = CUR_CHAR(l);
10012 	if (len >= XML_MAX_NAMELEN) {
10013 	    /*
10014 	     * Okay someone managed to make a huge name, so he's ready to pay
10015 	     * for the processing speed.
10016 	     */
10017 	    xmlChar *buffer;
10018 	    int max = len * 2;
10019 
10020             if (len > XML_MAX_NAME_LENGTH) {
10021                 XP_ERRORNULL(XPATH_EXPR_ERROR);
10022             }
10023 	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
10024 	    if (buffer == NULL) {
10025 		XP_ERRORNULL(XPATH_MEMORY_ERROR);
10026 	    }
10027 	    memcpy(buffer, buf, len);
10028 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10029 		   (c == '.') || (c == '-') ||
10030 		   (c == '_') || ((qualified) && (c == ':')) ||
10031 		   (IS_COMBINING(c)) ||
10032 		   (IS_EXTENDER(c))) {
10033 		if (len + 10 > max) {
10034                     if (max > XML_MAX_NAME_LENGTH) {
10035                         XP_ERRORNULL(XPATH_EXPR_ERROR);
10036                     }
10037 		    max *= 2;
10038 		    buffer = (xmlChar *) xmlRealloc(buffer,
10039 			                            max * sizeof(xmlChar));
10040 		    if (buffer == NULL) {
10041 			XP_ERRORNULL(XPATH_MEMORY_ERROR);
10042 		    }
10043 		}
10044 		COPY_BUF(l,buffer,len,c);
10045 		NEXTL(l);
10046 		c = CUR_CHAR(l);
10047 	    }
10048 	    buffer[len] = 0;
10049 	    return(buffer);
10050 	}
10051     }
10052     if (len == 0)
10053 	return(NULL);
10054     return(xmlStrndup(buf, len));
10055 }
10056 
10057 #define MAX_FRAC 20
10058 
10059 /*
10060  * These are used as divisors for the fractional part of a number.
10061  * Since the table includes 1.0 (representing '0' fractional digits),
10062  * it must be dimensioned at MAX_FRAC+1 (bug 133921)
10063  */
10064 static double my_pow10[MAX_FRAC+1] = {
10065     1.0, 10.0, 100.0, 1000.0, 10000.0,
10066     100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
10067     10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
10068     100000000000000.0,
10069     1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
10070     1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
10071 };
10072 
10073 /**
10074  * xmlXPathStringEvalNumber:
10075  * @str:  A string to scan
10076  *
10077  *  [30a]  Float  ::= Number ('e' Digits?)?
10078  *
10079  *  [30]   Number ::=   Digits ('.' Digits?)?
10080  *                    | '.' Digits
10081  *  [31]   Digits ::=   [0-9]+
10082  *
10083  * Compile a Number in the string
10084  * In complement of the Number expression, this function also handles
10085  * negative values : '-' Number.
10086  *
10087  * Returns the double value.
10088  */
10089 double
xmlXPathStringEvalNumber(const xmlChar * str)10090 xmlXPathStringEvalNumber(const xmlChar *str) {
10091     const xmlChar *cur = str;
10092     double ret;
10093     int ok = 0;
10094     int isneg = 0;
10095     int exponent = 0;
10096     int is_exponent_negative = 0;
10097 #ifdef __GNUC__
10098     unsigned long tmp = 0;
10099     double temp;
10100 #endif
10101     if (cur == NULL) return(0);
10102     while (IS_BLANK_CH(*cur)) cur++;
10103     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10104         return(xmlXPathNAN);
10105     }
10106     if (*cur == '-') {
10107 	isneg = 1;
10108 	cur++;
10109     }
10110 
10111 #ifdef __GNUC__
10112     /*
10113      * tmp/temp is a workaround against a gcc compiler bug
10114      * http://veillard.com/gcc.bug
10115      */
10116     ret = 0;
10117     while ((*cur >= '0') && (*cur <= '9')) {
10118 	ret = ret * 10;
10119 	tmp = (*cur - '0');
10120 	ok = 1;
10121 	cur++;
10122 	temp = (double) tmp;
10123 	ret = ret + temp;
10124     }
10125 #else
10126     ret = 0;
10127     while ((*cur >= '0') && (*cur <= '9')) {
10128 	ret = ret * 10 + (*cur - '0');
10129 	ok = 1;
10130 	cur++;
10131     }
10132 #endif
10133 
10134     if (*cur == '.') {
10135 	int v, frac = 0;
10136 	double fraction = 0;
10137 
10138         cur++;
10139 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10140 	    return(xmlXPathNAN);
10141 	}
10142 	while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10143 	    v = (*cur - '0');
10144 	    fraction = fraction * 10 + v;
10145 	    frac = frac + 1;
10146 	    cur++;
10147 	}
10148 	fraction /= my_pow10[frac];
10149 	ret = ret + fraction;
10150 	while ((*cur >= '0') && (*cur <= '9'))
10151 	    cur++;
10152     }
10153     if ((*cur == 'e') || (*cur == 'E')) {
10154       cur++;
10155       if (*cur == '-') {
10156 	is_exponent_negative = 1;
10157 	cur++;
10158       } else if (*cur == '+') {
10159         cur++;
10160       }
10161       while ((*cur >= '0') && (*cur <= '9')) {
10162 	exponent = exponent * 10 + (*cur - '0');
10163 	cur++;
10164       }
10165     }
10166     while (IS_BLANK_CH(*cur)) cur++;
10167     if (*cur != 0) return(xmlXPathNAN);
10168     if (isneg) ret = -ret;
10169     if (is_exponent_negative) exponent = -exponent;
10170     ret *= pow(10.0, (double)exponent);
10171     return(ret);
10172 }
10173 
10174 /**
10175  * xmlXPathCompNumber:
10176  * @ctxt:  the XPath Parser context
10177  *
10178  *  [30]   Number ::=   Digits ('.' Digits?)?
10179  *                    | '.' Digits
10180  *  [31]   Digits ::=   [0-9]+
10181  *
10182  * Compile a Number, then push it on the stack
10183  *
10184  */
10185 static void
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)10186 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10187 {
10188     double ret = 0.0;
10189     int ok = 0;
10190     int exponent = 0;
10191     int is_exponent_negative = 0;
10192 #ifdef __GNUC__
10193     unsigned long tmp = 0;
10194     double temp;
10195 #endif
10196 
10197     CHECK_ERROR;
10198     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10199         XP_ERROR(XPATH_NUMBER_ERROR);
10200     }
10201 #ifdef __GNUC__
10202     /*
10203      * tmp/temp is a workaround against a gcc compiler bug
10204      * http://veillard.com/gcc.bug
10205      */
10206     ret = 0;
10207     while ((CUR >= '0') && (CUR <= '9')) {
10208 	ret = ret * 10;
10209 	tmp = (CUR - '0');
10210         ok = 1;
10211         NEXT;
10212 	temp = (double) tmp;
10213 	ret = ret + temp;
10214     }
10215 #else
10216     ret = 0;
10217     while ((CUR >= '0') && (CUR <= '9')) {
10218 	ret = ret * 10 + (CUR - '0');
10219 	ok = 1;
10220 	NEXT;
10221     }
10222 #endif
10223     if (CUR == '.') {
10224 	int v, frac = 0;
10225 	double fraction = 0;
10226 
10227         NEXT;
10228         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10229             XP_ERROR(XPATH_NUMBER_ERROR);
10230         }
10231         while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10232 	    v = (CUR - '0');
10233 	    fraction = fraction * 10 + v;
10234 	    frac = frac + 1;
10235             NEXT;
10236         }
10237         fraction /= my_pow10[frac];
10238         ret = ret + fraction;
10239         while ((CUR >= '0') && (CUR <= '9'))
10240             NEXT;
10241     }
10242     if ((CUR == 'e') || (CUR == 'E')) {
10243         NEXT;
10244         if (CUR == '-') {
10245             is_exponent_negative = 1;
10246             NEXT;
10247         } else if (CUR == '+') {
10248 	    NEXT;
10249 	}
10250         while ((CUR >= '0') && (CUR <= '9')) {
10251             exponent = exponent * 10 + (CUR - '0');
10252             NEXT;
10253         }
10254         if (is_exponent_negative)
10255             exponent = -exponent;
10256         ret *= pow(10.0, (double) exponent);
10257     }
10258     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10259                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10260 }
10261 
10262 /**
10263  * xmlXPathParseLiteral:
10264  * @ctxt:  the XPath Parser context
10265  *
10266  * Parse a Literal
10267  *
10268  *  [29]   Literal ::=   '"' [^"]* '"'
10269  *                    | "'" [^']* "'"
10270  *
10271  * Returns the value found or NULL in case of error
10272  */
10273 static xmlChar *
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt)10274 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10275     const xmlChar *q;
10276     xmlChar *ret = NULL;
10277 
10278     if (CUR == '"') {
10279         NEXT;
10280 	q = CUR_PTR;
10281 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10282 	    NEXT;
10283 	if (!IS_CHAR_CH(CUR)) {
10284 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10285 	} else {
10286 	    ret = xmlStrndup(q, CUR_PTR - q);
10287 	    NEXT;
10288         }
10289     } else if (CUR == '\'') {
10290         NEXT;
10291 	q = CUR_PTR;
10292 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10293 	    NEXT;
10294 	if (!IS_CHAR_CH(CUR)) {
10295 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10296 	} else {
10297 	    ret = xmlStrndup(q, CUR_PTR - q);
10298 	    NEXT;
10299         }
10300     } else {
10301 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10302     }
10303     return(ret);
10304 }
10305 
10306 /**
10307  * xmlXPathCompLiteral:
10308  * @ctxt:  the XPath Parser context
10309  *
10310  * Parse a Literal and push it on the stack.
10311  *
10312  *  [29]   Literal ::=   '"' [^"]* '"'
10313  *                    | "'" [^']* "'"
10314  *
10315  * TODO: xmlXPathCompLiteral memory allocation could be improved.
10316  */
10317 static void
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt)10318 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10319     const xmlChar *q;
10320     xmlChar *ret = NULL;
10321 
10322     if (CUR == '"') {
10323         NEXT;
10324 	q = CUR_PTR;
10325 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10326 	    NEXT;
10327 	if (!IS_CHAR_CH(CUR)) {
10328 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10329 	} else {
10330 	    ret = xmlStrndup(q, CUR_PTR - q);
10331 	    NEXT;
10332         }
10333     } else if (CUR == '\'') {
10334         NEXT;
10335 	q = CUR_PTR;
10336 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10337 	    NEXT;
10338 	if (!IS_CHAR_CH(CUR)) {
10339 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10340 	} else {
10341 	    ret = xmlStrndup(q, CUR_PTR - q);
10342 	    NEXT;
10343         }
10344     } else {
10345 	XP_ERROR(XPATH_START_LITERAL_ERROR);
10346     }
10347     if (ret == NULL) return;
10348     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10349 	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
10350     xmlFree(ret);
10351 }
10352 
10353 /**
10354  * xmlXPathCompVariableReference:
10355  * @ctxt:  the XPath Parser context
10356  *
10357  * Parse a VariableReference, evaluate it and push it on the stack.
10358  *
10359  * The variable bindings consist of a mapping from variable names
10360  * to variable values. The value of a variable is an object, which can be
10361  * of any of the types that are possible for the value of an expression,
10362  * and may also be of additional types not specified here.
10363  *
10364  * Early evaluation is possible since:
10365  * The variable bindings [...] used to evaluate a subexpression are
10366  * always the same as those used to evaluate the containing expression.
10367  *
10368  *  [36]   VariableReference ::=   '$' QName
10369  */
10370 static void
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt)10371 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10372     xmlChar *name;
10373     xmlChar *prefix;
10374 
10375     SKIP_BLANKS;
10376     if (CUR != '$') {
10377 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10378     }
10379     NEXT;
10380     name = xmlXPathParseQName(ctxt, &prefix);
10381     if (name == NULL) {
10382 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10383     }
10384     ctxt->comp->last = -1;
10385     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10386 	           name, prefix);
10387     SKIP_BLANKS;
10388     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10389 	XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10390     }
10391 }
10392 
10393 /**
10394  * xmlXPathIsNodeType:
10395  * @name:  a name string
10396  *
10397  * Is the name given a NodeType one.
10398  *
10399  *  [38]   NodeType ::=   'comment'
10400  *                    | 'text'
10401  *                    | 'processing-instruction'
10402  *                    | 'node'
10403  *
10404  * Returns 1 if true 0 otherwise
10405  */
10406 int
xmlXPathIsNodeType(const xmlChar * name)10407 xmlXPathIsNodeType(const xmlChar *name) {
10408     if (name == NULL)
10409 	return(0);
10410 
10411     if (xmlStrEqual(name, BAD_CAST "node"))
10412 	return(1);
10413     if (xmlStrEqual(name, BAD_CAST "text"))
10414 	return(1);
10415     if (xmlStrEqual(name, BAD_CAST "comment"))
10416 	return(1);
10417     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10418 	return(1);
10419     return(0);
10420 }
10421 
10422 /**
10423  * xmlXPathCompFunctionCall:
10424  * @ctxt:  the XPath Parser context
10425  *
10426  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10427  *  [17]   Argument ::=   Expr
10428  *
10429  * Compile a function call, the evaluation of all arguments are
10430  * pushed on the stack
10431  */
10432 static void
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt)10433 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10434     xmlChar *name;
10435     xmlChar *prefix;
10436     int nbargs = 0;
10437     int sort = 1;
10438 
10439     name = xmlXPathParseQName(ctxt, &prefix);
10440     if (name == NULL) {
10441 	xmlFree(prefix);
10442 	XP_ERROR(XPATH_EXPR_ERROR);
10443     }
10444     SKIP_BLANKS;
10445 #ifdef DEBUG_EXPR
10446     if (prefix == NULL)
10447 	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10448 			name);
10449     else
10450 	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10451 			prefix, name);
10452 #endif
10453 
10454     if (CUR != '(') {
10455 	XP_ERROR(XPATH_EXPR_ERROR);
10456     }
10457     NEXT;
10458     SKIP_BLANKS;
10459 
10460     /*
10461     * Optimization for count(): we don't need the node-set to be sorted.
10462     */
10463     if ((prefix == NULL) && (name[0] == 'c') &&
10464 	xmlStrEqual(name, BAD_CAST "count"))
10465     {
10466 	sort = 0;
10467     }
10468     ctxt->comp->last = -1;
10469     if (CUR != ')') {
10470 	while (CUR != 0) {
10471 	    int op1 = ctxt->comp->last;
10472 	    ctxt->comp->last = -1;
10473 	    xmlXPathCompileExpr(ctxt, sort);
10474 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
10475 		xmlFree(name);
10476 		xmlFree(prefix);
10477 		return;
10478 	    }
10479 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10480 	    nbargs++;
10481 	    if (CUR == ')') break;
10482 	    if (CUR != ',') {
10483 		XP_ERROR(XPATH_EXPR_ERROR);
10484 	    }
10485 	    NEXT;
10486 	    SKIP_BLANKS;
10487 	}
10488     }
10489     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10490 	           name, prefix);
10491     NEXT;
10492     SKIP_BLANKS;
10493 }
10494 
10495 /**
10496  * xmlXPathCompPrimaryExpr:
10497  * @ctxt:  the XPath Parser context
10498  *
10499  *  [15]   PrimaryExpr ::=   VariableReference
10500  *                | '(' Expr ')'
10501  *                | Literal
10502  *                | Number
10503  *                | FunctionCall
10504  *
10505  * Compile a primary expression.
10506  */
10507 static void
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt)10508 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10509     SKIP_BLANKS;
10510     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10511     else if (CUR == '(') {
10512 	NEXT;
10513 	SKIP_BLANKS;
10514 	xmlXPathCompileExpr(ctxt, 1);
10515 	CHECK_ERROR;
10516 	if (CUR != ')') {
10517 	    XP_ERROR(XPATH_EXPR_ERROR);
10518 	}
10519 	NEXT;
10520 	SKIP_BLANKS;
10521     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10522 	xmlXPathCompNumber(ctxt);
10523     } else if ((CUR == '\'') || (CUR == '"')) {
10524 	xmlXPathCompLiteral(ctxt);
10525     } else {
10526 	xmlXPathCompFunctionCall(ctxt);
10527     }
10528     SKIP_BLANKS;
10529 }
10530 
10531 /**
10532  * xmlXPathCompFilterExpr:
10533  * @ctxt:  the XPath Parser context
10534  *
10535  *  [20]   FilterExpr ::=   PrimaryExpr
10536  *               | FilterExpr Predicate
10537  *
10538  * Compile a filter expression.
10539  * Square brackets are used to filter expressions in the same way that
10540  * they are used in location paths. It is an error if the expression to
10541  * be filtered does not evaluate to a node-set. The context node list
10542  * used for evaluating the expression in square brackets is the node-set
10543  * to be filtered listed in document order.
10544  */
10545 
10546 static void
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt)10547 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10548     xmlXPathCompPrimaryExpr(ctxt);
10549     CHECK_ERROR;
10550     SKIP_BLANKS;
10551 
10552     while (CUR == '[') {
10553 	xmlXPathCompPredicate(ctxt, 1);
10554 	SKIP_BLANKS;
10555     }
10556 
10557 
10558 }
10559 
10560 /**
10561  * xmlXPathScanName:
10562  * @ctxt:  the XPath Parser context
10563  *
10564  * Trickery: parse an XML name but without consuming the input flow
10565  * Needed to avoid insanity in the parser state.
10566  *
10567  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10568  *                  CombiningChar | Extender
10569  *
10570  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10571  *
10572  * [6] Names ::= Name (S Name)*
10573  *
10574  * Returns the Name parsed or NULL
10575  */
10576 
10577 static xmlChar *
xmlXPathScanName(xmlXPathParserContextPtr ctxt)10578 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10579     int len = 0, l;
10580     int c;
10581     const xmlChar *cur;
10582     xmlChar *ret;
10583 
10584     cur = ctxt->cur;
10585 
10586     c = CUR_CHAR(l);
10587     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10588 	(!IS_LETTER(c) && (c != '_') &&
10589          (c != ':'))) {
10590 	return(NULL);
10591     }
10592 
10593     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10594 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10595             (c == '.') || (c == '-') ||
10596 	    (c == '_') || (c == ':') ||
10597 	    (IS_COMBINING(c)) ||
10598 	    (IS_EXTENDER(c)))) {
10599 	len += l;
10600 	NEXTL(l);
10601 	c = CUR_CHAR(l);
10602     }
10603     ret = xmlStrndup(cur, ctxt->cur - cur);
10604     ctxt->cur = cur;
10605     return(ret);
10606 }
10607 
10608 /**
10609  * xmlXPathCompPathExpr:
10610  * @ctxt:  the XPath Parser context
10611  *
10612  *  [19]   PathExpr ::=   LocationPath
10613  *               | FilterExpr
10614  *               | FilterExpr '/' RelativeLocationPath
10615  *               | FilterExpr '//' RelativeLocationPath
10616  *
10617  * Compile a path expression.
10618  * The / operator and // operators combine an arbitrary expression
10619  * and a relative location path. It is an error if the expression
10620  * does not evaluate to a node-set.
10621  * The / operator does composition in the same way as when / is
10622  * used in a location path. As in location paths, // is short for
10623  * /descendant-or-self::node()/.
10624  */
10625 
10626 static void
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt)10627 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10628     int lc = 1;           /* Should we branch to LocationPath ?         */
10629     xmlChar *name = NULL; /* we may have to preparse a name to find out */
10630 
10631     SKIP_BLANKS;
10632     if ((CUR == '$') || (CUR == '(') ||
10633 	(IS_ASCII_DIGIT(CUR)) ||
10634         (CUR == '\'') || (CUR == '"') ||
10635 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10636 	lc = 0;
10637     } else if (CUR == '*') {
10638 	/* relative or absolute location path */
10639 	lc = 1;
10640     } else if (CUR == '/') {
10641 	/* relative or absolute location path */
10642 	lc = 1;
10643     } else if (CUR == '@') {
10644 	/* relative abbreviated attribute location path */
10645 	lc = 1;
10646     } else if (CUR == '.') {
10647 	/* relative abbreviated attribute location path */
10648 	lc = 1;
10649     } else {
10650 	/*
10651 	 * Problem is finding if we have a name here whether it's:
10652 	 *   - a nodetype
10653 	 *   - a function call in which case it's followed by '('
10654 	 *   - an axis in which case it's followed by ':'
10655 	 *   - a element name
10656 	 * We do an a priori analysis here rather than having to
10657 	 * maintain parsed token content through the recursive function
10658 	 * calls. This looks uglier but makes the code easier to
10659 	 * read/write/debug.
10660 	 */
10661 	SKIP_BLANKS;
10662 	name = xmlXPathScanName(ctxt);
10663 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10664 #ifdef DEBUG_STEP
10665 	    xmlGenericError(xmlGenericErrorContext,
10666 		    "PathExpr: Axis\n");
10667 #endif
10668 	    lc = 1;
10669 	    xmlFree(name);
10670 	} else if (name != NULL) {
10671 	    int len =xmlStrlen(name);
10672 
10673 
10674 	    while (NXT(len) != 0) {
10675 		if (NXT(len) == '/') {
10676 		    /* element name */
10677 #ifdef DEBUG_STEP
10678 		    xmlGenericError(xmlGenericErrorContext,
10679 			    "PathExpr: AbbrRelLocation\n");
10680 #endif
10681 		    lc = 1;
10682 		    break;
10683 		} else if (IS_BLANK_CH(NXT(len))) {
10684 		    /* ignore blanks */
10685 		    ;
10686 		} else if (NXT(len) == ':') {
10687 #ifdef DEBUG_STEP
10688 		    xmlGenericError(xmlGenericErrorContext,
10689 			    "PathExpr: AbbrRelLocation\n");
10690 #endif
10691 		    lc = 1;
10692 		    break;
10693 		} else if ((NXT(len) == '(')) {
10694 		    /* Note Type or Function */
10695 		    if (xmlXPathIsNodeType(name)) {
10696 #ifdef DEBUG_STEP
10697 		        xmlGenericError(xmlGenericErrorContext,
10698 				"PathExpr: Type search\n");
10699 #endif
10700 			lc = 1;
10701 		    } else {
10702 #ifdef DEBUG_STEP
10703 		        xmlGenericError(xmlGenericErrorContext,
10704 				"PathExpr: function call\n");
10705 #endif
10706 			lc = 0;
10707 		    }
10708                     break;
10709 		} else if ((NXT(len) == '[')) {
10710 		    /* element name */
10711 #ifdef DEBUG_STEP
10712 		    xmlGenericError(xmlGenericErrorContext,
10713 			    "PathExpr: AbbrRelLocation\n");
10714 #endif
10715 		    lc = 1;
10716 		    break;
10717 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10718 			   (NXT(len) == '=')) {
10719 		    lc = 1;
10720 		    break;
10721 		} else {
10722 		    lc = 1;
10723 		    break;
10724 		}
10725 		len++;
10726 	    }
10727 	    if (NXT(len) == 0) {
10728 #ifdef DEBUG_STEP
10729 		xmlGenericError(xmlGenericErrorContext,
10730 			"PathExpr: AbbrRelLocation\n");
10731 #endif
10732 		/* element name */
10733 		lc = 1;
10734 	    }
10735 	    xmlFree(name);
10736 	} else {
10737 	    /* make sure all cases are covered explicitly */
10738 	    XP_ERROR(XPATH_EXPR_ERROR);
10739 	}
10740     }
10741 
10742     if (lc) {
10743 	if (CUR == '/') {
10744 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10745 	} else {
10746 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10747 	}
10748 	xmlXPathCompLocationPath(ctxt);
10749     } else {
10750 	xmlXPathCompFilterExpr(ctxt);
10751 	CHECK_ERROR;
10752 	if ((CUR == '/') && (NXT(1) == '/')) {
10753 	    SKIP(2);
10754 	    SKIP_BLANKS;
10755 
10756 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10757 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10758 	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10759 
10760 	    xmlXPathCompRelativeLocationPath(ctxt);
10761 	} else if (CUR == '/') {
10762 	    xmlXPathCompRelativeLocationPath(ctxt);
10763 	}
10764     }
10765     SKIP_BLANKS;
10766 }
10767 
10768 /**
10769  * xmlXPathCompUnionExpr:
10770  * @ctxt:  the XPath Parser context
10771  *
10772  *  [18]   UnionExpr ::=   PathExpr
10773  *               | UnionExpr '|' PathExpr
10774  *
10775  * Compile an union expression.
10776  */
10777 
10778 static void
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt)10779 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10780     xmlXPathCompPathExpr(ctxt);
10781     CHECK_ERROR;
10782     SKIP_BLANKS;
10783     while (CUR == '|') {
10784 	int op1 = ctxt->comp->last;
10785 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10786 
10787 	NEXT;
10788 	SKIP_BLANKS;
10789 	xmlXPathCompPathExpr(ctxt);
10790 
10791 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10792 
10793 	SKIP_BLANKS;
10794     }
10795 }
10796 
10797 /**
10798  * xmlXPathCompUnaryExpr:
10799  * @ctxt:  the XPath Parser context
10800  *
10801  *  [27]   UnaryExpr ::=   UnionExpr
10802  *                   | '-' UnaryExpr
10803  *
10804  * Compile an unary expression.
10805  */
10806 
10807 static void
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt)10808 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10809     int minus = 0;
10810     int found = 0;
10811 
10812     SKIP_BLANKS;
10813     while (CUR == '-') {
10814         minus = 1 - minus;
10815 	found = 1;
10816 	NEXT;
10817 	SKIP_BLANKS;
10818     }
10819 
10820     xmlXPathCompUnionExpr(ctxt);
10821     CHECK_ERROR;
10822     if (found) {
10823 	if (minus)
10824 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10825 	else
10826 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10827     }
10828 }
10829 
10830 /**
10831  * xmlXPathCompMultiplicativeExpr:
10832  * @ctxt:  the XPath Parser context
10833  *
10834  *  [26]   MultiplicativeExpr ::=   UnaryExpr
10835  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10836  *                   | MultiplicativeExpr 'div' UnaryExpr
10837  *                   | MultiplicativeExpr 'mod' UnaryExpr
10838  *  [34]   MultiplyOperator ::=   '*'
10839  *
10840  * Compile an Additive expression.
10841  */
10842 
10843 static void
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt)10844 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10845     xmlXPathCompUnaryExpr(ctxt);
10846     CHECK_ERROR;
10847     SKIP_BLANKS;
10848     while ((CUR == '*') ||
10849            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10850            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10851 	int op = -1;
10852 	int op1 = ctxt->comp->last;
10853 
10854         if (CUR == '*') {
10855 	    op = 0;
10856 	    NEXT;
10857 	} else if (CUR == 'd') {
10858 	    op = 1;
10859 	    SKIP(3);
10860 	} else if (CUR == 'm') {
10861 	    op = 2;
10862 	    SKIP(3);
10863 	}
10864 	SKIP_BLANKS;
10865         xmlXPathCompUnaryExpr(ctxt);
10866 	CHECK_ERROR;
10867 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10868 	SKIP_BLANKS;
10869     }
10870 }
10871 
10872 /**
10873  * xmlXPathCompAdditiveExpr:
10874  * @ctxt:  the XPath Parser context
10875  *
10876  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10877  *                   | AdditiveExpr '+' MultiplicativeExpr
10878  *                   | AdditiveExpr '-' MultiplicativeExpr
10879  *
10880  * Compile an Additive expression.
10881  */
10882 
10883 static void
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt)10884 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10885 
10886     xmlXPathCompMultiplicativeExpr(ctxt);
10887     CHECK_ERROR;
10888     SKIP_BLANKS;
10889     while ((CUR == '+') || (CUR == '-')) {
10890 	int plus;
10891 	int op1 = ctxt->comp->last;
10892 
10893         if (CUR == '+') plus = 1;
10894 	else plus = 0;
10895 	NEXT;
10896 	SKIP_BLANKS;
10897         xmlXPathCompMultiplicativeExpr(ctxt);
10898 	CHECK_ERROR;
10899 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10900 	SKIP_BLANKS;
10901     }
10902 }
10903 
10904 /**
10905  * xmlXPathCompRelationalExpr:
10906  * @ctxt:  the XPath Parser context
10907  *
10908  *  [24]   RelationalExpr ::=   AdditiveExpr
10909  *                 | RelationalExpr '<' AdditiveExpr
10910  *                 | RelationalExpr '>' AdditiveExpr
10911  *                 | RelationalExpr '<=' AdditiveExpr
10912  *                 | RelationalExpr '>=' AdditiveExpr
10913  *
10914  *  A <= B > C is allowed ? Answer from James, yes with
10915  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10916  *  which is basically what got implemented.
10917  *
10918  * Compile a Relational expression, then push the result
10919  * on the stack
10920  */
10921 
10922 static void
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt)10923 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10924     xmlXPathCompAdditiveExpr(ctxt);
10925     CHECK_ERROR;
10926     SKIP_BLANKS;
10927     while ((CUR == '<') ||
10928            (CUR == '>') ||
10929            ((CUR == '<') && (NXT(1) == '=')) ||
10930            ((CUR == '>') && (NXT(1) == '='))) {
10931 	int inf, strict;
10932 	int op1 = ctxt->comp->last;
10933 
10934         if (CUR == '<') inf = 1;
10935 	else inf = 0;
10936 	if (NXT(1) == '=') strict = 0;
10937 	else strict = 1;
10938 	NEXT;
10939 	if (!strict) NEXT;
10940 	SKIP_BLANKS;
10941         xmlXPathCompAdditiveExpr(ctxt);
10942 	CHECK_ERROR;
10943 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10944 	SKIP_BLANKS;
10945     }
10946 }
10947 
10948 /**
10949  * xmlXPathCompEqualityExpr:
10950  * @ctxt:  the XPath Parser context
10951  *
10952  *  [23]   EqualityExpr ::=   RelationalExpr
10953  *                 | EqualityExpr '=' RelationalExpr
10954  *                 | EqualityExpr '!=' RelationalExpr
10955  *
10956  *  A != B != C is allowed ? Answer from James, yes with
10957  *  (RelationalExpr = RelationalExpr) = RelationalExpr
10958  *  (RelationalExpr != RelationalExpr) != RelationalExpr
10959  *  which is basically what got implemented.
10960  *
10961  * Compile an Equality expression.
10962  *
10963  */
10964 static void
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt)10965 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10966     xmlXPathCompRelationalExpr(ctxt);
10967     CHECK_ERROR;
10968     SKIP_BLANKS;
10969     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10970 	int eq;
10971 	int op1 = ctxt->comp->last;
10972 
10973         if (CUR == '=') eq = 1;
10974 	else eq = 0;
10975 	NEXT;
10976 	if (!eq) NEXT;
10977 	SKIP_BLANKS;
10978         xmlXPathCompRelationalExpr(ctxt);
10979 	CHECK_ERROR;
10980 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10981 	SKIP_BLANKS;
10982     }
10983 }
10984 
10985 /**
10986  * xmlXPathCompAndExpr:
10987  * @ctxt:  the XPath Parser context
10988  *
10989  *  [22]   AndExpr ::=   EqualityExpr
10990  *                 | AndExpr 'and' EqualityExpr
10991  *
10992  * Compile an AND expression.
10993  *
10994  */
10995 static void
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt)10996 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10997     xmlXPathCompEqualityExpr(ctxt);
10998     CHECK_ERROR;
10999     SKIP_BLANKS;
11000     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
11001 	int op1 = ctxt->comp->last;
11002         SKIP(3);
11003 	SKIP_BLANKS;
11004         xmlXPathCompEqualityExpr(ctxt);
11005 	CHECK_ERROR;
11006 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
11007 	SKIP_BLANKS;
11008     }
11009 }
11010 
11011 /**
11012  * xmlXPathCompileExpr:
11013  * @ctxt:  the XPath Parser context
11014  *
11015  *  [14]   Expr ::=   OrExpr
11016  *  [21]   OrExpr ::=   AndExpr
11017  *                 | OrExpr 'or' AndExpr
11018  *
11019  * Parse and compile an expression
11020  */
11021 static void
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt,int sort)11022 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
11023     xmlXPathCompAndExpr(ctxt);
11024     CHECK_ERROR;
11025     SKIP_BLANKS;
11026     while ((CUR == 'o') && (NXT(1) == 'r')) {
11027 	int op1 = ctxt->comp->last;
11028         SKIP(2);
11029 	SKIP_BLANKS;
11030         xmlXPathCompAndExpr(ctxt);
11031 	CHECK_ERROR;
11032 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
11033 	SKIP_BLANKS;
11034     }
11035     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
11036 	/* more ops could be optimized too */
11037 	/*
11038 	* This is the main place to eliminate sorting for
11039 	* operations which don't require a sorted node-set.
11040 	* E.g. count().
11041 	*/
11042 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11043     }
11044 }
11045 
11046 /**
11047  * xmlXPathCompPredicate:
11048  * @ctxt:  the XPath Parser context
11049  * @filter:  act as a filter
11050  *
11051  *  [8]   Predicate ::=   '[' PredicateExpr ']'
11052  *  [9]   PredicateExpr ::=   Expr
11053  *
11054  * Compile a predicate expression
11055  */
11056 static void
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt,int filter)11057 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11058     int op1 = ctxt->comp->last;
11059 
11060     SKIP_BLANKS;
11061     if (CUR != '[') {
11062 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11063     }
11064     NEXT;
11065     SKIP_BLANKS;
11066 
11067     ctxt->comp->last = -1;
11068     /*
11069     * This call to xmlXPathCompileExpr() will deactivate sorting
11070     * of the predicate result.
11071     * TODO: Sorting is still activated for filters, since I'm not
11072     *  sure if needed. Normally sorting should not be needed, since
11073     *  a filter can only diminish the number of items in a sequence,
11074     *  but won't change its order; so if the initial sequence is sorted,
11075     *  subsequent sorting is not needed.
11076     */
11077     if (! filter)
11078 	xmlXPathCompileExpr(ctxt, 0);
11079     else
11080 	xmlXPathCompileExpr(ctxt, 1);
11081     CHECK_ERROR;
11082 
11083     if (CUR != ']') {
11084 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11085     }
11086 
11087     if (filter)
11088 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11089     else
11090 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11091 
11092     NEXT;
11093     SKIP_BLANKS;
11094 }
11095 
11096 /**
11097  * xmlXPathCompNodeTest:
11098  * @ctxt:  the XPath Parser context
11099  * @test:  pointer to a xmlXPathTestVal
11100  * @type:  pointer to a xmlXPathTypeVal
11101  * @prefix:  placeholder for a possible name prefix
11102  *
11103  * [7] NodeTest ::=   NameTest
11104  *		    | NodeType '(' ')'
11105  *		    | 'processing-instruction' '(' Literal ')'
11106  *
11107  * [37] NameTest ::=  '*'
11108  *		    | NCName ':' '*'
11109  *		    | QName
11110  * [38] NodeType ::= 'comment'
11111  *		   | 'text'
11112  *		   | 'processing-instruction'
11113  *		   | 'node'
11114  *
11115  * Returns the name found and updates @test, @type and @prefix appropriately
11116  */
11117 static xmlChar *
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt,xmlXPathTestVal * test,xmlXPathTypeVal * type,const xmlChar ** prefix,xmlChar * name)11118 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11119 	             xmlXPathTypeVal *type, const xmlChar **prefix,
11120 		     xmlChar *name) {
11121     int blanks;
11122 
11123     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11124 	STRANGE;
11125 	return(NULL);
11126     }
11127     *type = (xmlXPathTypeVal) 0;
11128     *test = (xmlXPathTestVal) 0;
11129     *prefix = NULL;
11130     SKIP_BLANKS;
11131 
11132     if ((name == NULL) && (CUR == '*')) {
11133 	/*
11134 	 * All elements
11135 	 */
11136 	NEXT;
11137 	*test = NODE_TEST_ALL;
11138 	return(NULL);
11139     }
11140 
11141     if (name == NULL)
11142 	name = xmlXPathParseNCName(ctxt);
11143     if (name == NULL) {
11144 	XP_ERRORNULL(XPATH_EXPR_ERROR);
11145     }
11146 
11147     blanks = IS_BLANK_CH(CUR);
11148     SKIP_BLANKS;
11149     if (CUR == '(') {
11150 	NEXT;
11151 	/*
11152 	 * NodeType or PI search
11153 	 */
11154 	if (xmlStrEqual(name, BAD_CAST "comment"))
11155 	    *type = NODE_TYPE_COMMENT;
11156 	else if (xmlStrEqual(name, BAD_CAST "node"))
11157 	    *type = NODE_TYPE_NODE;
11158 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11159 	    *type = NODE_TYPE_PI;
11160 	else if (xmlStrEqual(name, BAD_CAST "text"))
11161 	    *type = NODE_TYPE_TEXT;
11162 	else {
11163 	    if (name != NULL)
11164 		xmlFree(name);
11165 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11166 	}
11167 
11168 	*test = NODE_TEST_TYPE;
11169 
11170 	SKIP_BLANKS;
11171 	if (*type == NODE_TYPE_PI) {
11172 	    /*
11173 	     * Specific case: search a PI by name.
11174 	     */
11175 	    if (name != NULL)
11176 		xmlFree(name);
11177 	    name = NULL;
11178 	    if (CUR != ')') {
11179 		name = xmlXPathParseLiteral(ctxt);
11180 		CHECK_ERROR NULL;
11181 		*test = NODE_TEST_PI;
11182 		SKIP_BLANKS;
11183 	    }
11184 	}
11185 	if (CUR != ')') {
11186 	    if (name != NULL)
11187 		xmlFree(name);
11188 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11189 	}
11190 	NEXT;
11191 	return(name);
11192     }
11193     *test = NODE_TEST_NAME;
11194     if ((!blanks) && (CUR == ':')) {
11195 	NEXT;
11196 
11197 	/*
11198 	 * Since currently the parser context don't have a
11199 	 * namespace list associated:
11200 	 * The namespace name for this prefix can be computed
11201 	 * only at evaluation time. The compilation is done
11202 	 * outside of any context.
11203 	 */
11204 #if 0
11205 	*prefix = xmlXPathNsLookup(ctxt->context, name);
11206 	if (name != NULL)
11207 	    xmlFree(name);
11208 	if (*prefix == NULL) {
11209 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11210 	}
11211 #else
11212 	*prefix = name;
11213 #endif
11214 
11215 	if (CUR == '*') {
11216 	    /*
11217 	     * All elements
11218 	     */
11219 	    NEXT;
11220 	    *test = NODE_TEST_ALL;
11221 	    return(NULL);
11222 	}
11223 
11224 	name = xmlXPathParseNCName(ctxt);
11225 	if (name == NULL) {
11226 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11227 	}
11228     }
11229     return(name);
11230 }
11231 
11232 /**
11233  * xmlXPathIsAxisName:
11234  * @name:  a preparsed name token
11235  *
11236  * [6] AxisName ::=   'ancestor'
11237  *                  | 'ancestor-or-self'
11238  *                  | 'attribute'
11239  *                  | 'child'
11240  *                  | 'descendant'
11241  *                  | 'descendant-or-self'
11242  *                  | 'following'
11243  *                  | 'following-sibling'
11244  *                  | 'namespace'
11245  *                  | 'parent'
11246  *                  | 'preceding'
11247  *                  | 'preceding-sibling'
11248  *                  | 'self'
11249  *
11250  * Returns the axis or 0
11251  */
11252 static xmlXPathAxisVal
xmlXPathIsAxisName(const xmlChar * name)11253 xmlXPathIsAxisName(const xmlChar *name) {
11254     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11255     switch (name[0]) {
11256 	case 'a':
11257 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
11258 		ret = AXIS_ANCESTOR;
11259 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11260 		ret = AXIS_ANCESTOR_OR_SELF;
11261 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
11262 		ret = AXIS_ATTRIBUTE;
11263 	    break;
11264 	case 'c':
11265 	    if (xmlStrEqual(name, BAD_CAST "child"))
11266 		ret = AXIS_CHILD;
11267 	    break;
11268 	case 'd':
11269 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
11270 		ret = AXIS_DESCENDANT;
11271 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11272 		ret = AXIS_DESCENDANT_OR_SELF;
11273 	    break;
11274 	case 'f':
11275 	    if (xmlStrEqual(name, BAD_CAST "following"))
11276 		ret = AXIS_FOLLOWING;
11277 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11278 		ret = AXIS_FOLLOWING_SIBLING;
11279 	    break;
11280 	case 'n':
11281 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
11282 		ret = AXIS_NAMESPACE;
11283 	    break;
11284 	case 'p':
11285 	    if (xmlStrEqual(name, BAD_CAST "parent"))
11286 		ret = AXIS_PARENT;
11287 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
11288 		ret = AXIS_PRECEDING;
11289 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11290 		ret = AXIS_PRECEDING_SIBLING;
11291 	    break;
11292 	case 's':
11293 	    if (xmlStrEqual(name, BAD_CAST "self"))
11294 		ret = AXIS_SELF;
11295 	    break;
11296     }
11297     return(ret);
11298 }
11299 
11300 /**
11301  * xmlXPathCompStep:
11302  * @ctxt:  the XPath Parser context
11303  *
11304  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11305  *                  | AbbreviatedStep
11306  *
11307  * [12] AbbreviatedStep ::=   '.' | '..'
11308  *
11309  * [5] AxisSpecifier ::= AxisName '::'
11310  *                  | AbbreviatedAxisSpecifier
11311  *
11312  * [13] AbbreviatedAxisSpecifier ::= '@'?
11313  *
11314  * Modified for XPtr range support as:
11315  *
11316  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11317  *                     | AbbreviatedStep
11318  *                     | 'range-to' '(' Expr ')' Predicate*
11319  *
11320  * Compile one step in a Location Path
11321  * A location step of . is short for self::node(). This is
11322  * particularly useful in conjunction with //. For example, the
11323  * location path .//para is short for
11324  * self::node()/descendant-or-self::node()/child::para
11325  * and so will select all para descendant elements of the context
11326  * node.
11327  * Similarly, a location step of .. is short for parent::node().
11328  * For example, ../title is short for parent::node()/child::title
11329  * and so will select the title children of the parent of the context
11330  * node.
11331  */
11332 static void
xmlXPathCompStep(xmlXPathParserContextPtr ctxt)11333 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11334 #ifdef LIBXML_XPTR_ENABLED
11335     int rangeto = 0;
11336     int op2 = -1;
11337 #endif
11338 
11339     SKIP_BLANKS;
11340     if ((CUR == '.') && (NXT(1) == '.')) {
11341 	SKIP(2);
11342 	SKIP_BLANKS;
11343 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11344 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11345     } else if (CUR == '.') {
11346 	NEXT;
11347 	SKIP_BLANKS;
11348     } else {
11349 	xmlChar *name = NULL;
11350 	const xmlChar *prefix = NULL;
11351 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
11352 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11353 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11354 	int op1;
11355 
11356 	/*
11357 	 * The modification needed for XPointer change to the production
11358 	 */
11359 #ifdef LIBXML_XPTR_ENABLED
11360 	if (ctxt->xptr) {
11361 	    name = xmlXPathParseNCName(ctxt);
11362 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11363                 op2 = ctxt->comp->last;
11364 		xmlFree(name);
11365 		SKIP_BLANKS;
11366 		if (CUR != '(') {
11367 		    XP_ERROR(XPATH_EXPR_ERROR);
11368 		}
11369 		NEXT;
11370 		SKIP_BLANKS;
11371 
11372 		xmlXPathCompileExpr(ctxt, 1);
11373 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11374 		CHECK_ERROR;
11375 
11376 		SKIP_BLANKS;
11377 		if (CUR != ')') {
11378 		    XP_ERROR(XPATH_EXPR_ERROR);
11379 		}
11380 		NEXT;
11381 		rangeto = 1;
11382 		goto eval_predicates;
11383 	    }
11384 	}
11385 #endif
11386 	if (CUR == '*') {
11387 	    axis = AXIS_CHILD;
11388 	} else {
11389 	    if (name == NULL)
11390 		name = xmlXPathParseNCName(ctxt);
11391 	    if (name != NULL) {
11392 		axis = xmlXPathIsAxisName(name);
11393 		if (axis != 0) {
11394 		    SKIP_BLANKS;
11395 		    if ((CUR == ':') && (NXT(1) == ':')) {
11396 			SKIP(2);
11397 			xmlFree(name);
11398 			name = NULL;
11399 		    } else {
11400 			/* an element name can conflict with an axis one :-\ */
11401 			axis = AXIS_CHILD;
11402 		    }
11403 		} else {
11404 		    axis = AXIS_CHILD;
11405 		}
11406 	    } else if (CUR == '@') {
11407 		NEXT;
11408 		axis = AXIS_ATTRIBUTE;
11409 	    } else {
11410 		axis = AXIS_CHILD;
11411 	    }
11412 	}
11413 
11414         if (ctxt->error != XPATH_EXPRESSION_OK) {
11415             xmlFree(name);
11416             return;
11417         }
11418 
11419 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11420 	if (test == 0)
11421 	    return;
11422 
11423         if ((prefix != NULL) && (ctxt->context != NULL) &&
11424 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11425 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11426 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11427 	    }
11428 	}
11429 #ifdef DEBUG_STEP
11430 	xmlGenericError(xmlGenericErrorContext,
11431 		"Basis : computing new set\n");
11432 #endif
11433 
11434 #ifdef DEBUG_STEP
11435 	xmlGenericError(xmlGenericErrorContext, "Basis : ");
11436 	if (ctxt->value == NULL)
11437 	    xmlGenericError(xmlGenericErrorContext, "no value\n");
11438 	else if (ctxt->value->nodesetval == NULL)
11439 	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
11440 	else
11441 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11442 #endif
11443 
11444 #ifdef LIBXML_XPTR_ENABLED
11445 eval_predicates:
11446 #endif
11447 	op1 = ctxt->comp->last;
11448 	ctxt->comp->last = -1;
11449 
11450 	SKIP_BLANKS;
11451 	while (CUR == '[') {
11452 	    xmlXPathCompPredicate(ctxt, 0);
11453 	}
11454 
11455 #ifdef LIBXML_XPTR_ENABLED
11456 	if (rangeto) {
11457 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11458 	} else
11459 #endif
11460 	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11461 			   test, type, (void *)prefix, (void *)name);
11462 
11463     }
11464 #ifdef DEBUG_STEP
11465     xmlGenericError(xmlGenericErrorContext, "Step : ");
11466     if (ctxt->value == NULL)
11467 	xmlGenericError(xmlGenericErrorContext, "no value\n");
11468     else if (ctxt->value->nodesetval == NULL)
11469 	xmlGenericError(xmlGenericErrorContext, "Empty\n");
11470     else
11471 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11472 		ctxt->value->nodesetval);
11473 #endif
11474 }
11475 
11476 /**
11477  * xmlXPathCompRelativeLocationPath:
11478  * @ctxt:  the XPath Parser context
11479  *
11480  *  [3]   RelativeLocationPath ::=   Step
11481  *                     | RelativeLocationPath '/' Step
11482  *                     | AbbreviatedRelativeLocationPath
11483  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11484  *
11485  * Compile a relative location path.
11486  */
11487 static void
xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt)11488 xmlXPathCompRelativeLocationPath
11489 (xmlXPathParserContextPtr ctxt) {
11490     SKIP_BLANKS;
11491     if ((CUR == '/') && (NXT(1) == '/')) {
11492 	SKIP(2);
11493 	SKIP_BLANKS;
11494 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11495 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11496     } else if (CUR == '/') {
11497 	    NEXT;
11498 	SKIP_BLANKS;
11499     }
11500     xmlXPathCompStep(ctxt);
11501     CHECK_ERROR;
11502     SKIP_BLANKS;
11503     while (CUR == '/') {
11504 	if ((CUR == '/') && (NXT(1) == '/')) {
11505 	    SKIP(2);
11506 	    SKIP_BLANKS;
11507 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11508 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11509 	    xmlXPathCompStep(ctxt);
11510 	} else if (CUR == '/') {
11511 	    NEXT;
11512 	    SKIP_BLANKS;
11513 	    xmlXPathCompStep(ctxt);
11514 	}
11515 	SKIP_BLANKS;
11516     }
11517 }
11518 
11519 /**
11520  * xmlXPathCompLocationPath:
11521  * @ctxt:  the XPath Parser context
11522  *
11523  *  [1]   LocationPath ::=   RelativeLocationPath
11524  *                     | AbsoluteLocationPath
11525  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11526  *                     | AbbreviatedAbsoluteLocationPath
11527  *  [10]   AbbreviatedAbsoluteLocationPath ::=
11528  *                           '//' RelativeLocationPath
11529  *
11530  * Compile a location path
11531  *
11532  * // is short for /descendant-or-self::node()/. For example,
11533  * //para is short for /descendant-or-self::node()/child::para and
11534  * so will select any para element in the document (even a para element
11535  * that is a document element will be selected by //para since the
11536  * document element node is a child of the root node); div//para is
11537  * short for div/descendant-or-self::node()/child::para and so will
11538  * select all para descendants of div children.
11539  */
11540 static void
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt)11541 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11542     SKIP_BLANKS;
11543     if (CUR != '/') {
11544         xmlXPathCompRelativeLocationPath(ctxt);
11545     } else {
11546 	while (CUR == '/') {
11547 	    if ((CUR == '/') && (NXT(1) == '/')) {
11548 		SKIP(2);
11549 		SKIP_BLANKS;
11550 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11551 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11552 		xmlXPathCompRelativeLocationPath(ctxt);
11553 	    } else if (CUR == '/') {
11554 		NEXT;
11555 		SKIP_BLANKS;
11556 		if ((CUR != 0 ) &&
11557 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11558 		     (CUR == '@') || (CUR == '*')))
11559 		    xmlXPathCompRelativeLocationPath(ctxt);
11560 	    }
11561 	    CHECK_ERROR;
11562 	}
11563     }
11564 }
11565 
11566 /************************************************************************
11567  *									*
11568  *		XPath precompiled expression evaluation			*
11569  *									*
11570  ************************************************************************/
11571 
11572 static int
11573 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11574 
11575 #ifdef DEBUG_STEP
11576 static void
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,int nbNodes)11577 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11578 			  int nbNodes)
11579 {
11580     xmlGenericError(xmlGenericErrorContext, "new step : ");
11581     switch (op->value) {
11582         case AXIS_ANCESTOR:
11583             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11584             break;
11585         case AXIS_ANCESTOR_OR_SELF:
11586             xmlGenericError(xmlGenericErrorContext,
11587                             "axis 'ancestors-or-self' ");
11588             break;
11589         case AXIS_ATTRIBUTE:
11590             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11591             break;
11592         case AXIS_CHILD:
11593             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11594             break;
11595         case AXIS_DESCENDANT:
11596             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11597             break;
11598         case AXIS_DESCENDANT_OR_SELF:
11599             xmlGenericError(xmlGenericErrorContext,
11600                             "axis 'descendant-or-self' ");
11601             break;
11602         case AXIS_FOLLOWING:
11603             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11604             break;
11605         case AXIS_FOLLOWING_SIBLING:
11606             xmlGenericError(xmlGenericErrorContext,
11607                             "axis 'following-siblings' ");
11608             break;
11609         case AXIS_NAMESPACE:
11610             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11611             break;
11612         case AXIS_PARENT:
11613             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11614             break;
11615         case AXIS_PRECEDING:
11616             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11617             break;
11618         case AXIS_PRECEDING_SIBLING:
11619             xmlGenericError(xmlGenericErrorContext,
11620                             "axis 'preceding-sibling' ");
11621             break;
11622         case AXIS_SELF:
11623             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11624             break;
11625     }
11626     xmlGenericError(xmlGenericErrorContext,
11627 	" context contains %d nodes\n", nbNodes);
11628     switch (op->value2) {
11629         case NODE_TEST_NONE:
11630             xmlGenericError(xmlGenericErrorContext,
11631                             "           searching for none !!!\n");
11632             break;
11633         case NODE_TEST_TYPE:
11634             xmlGenericError(xmlGenericErrorContext,
11635                             "           searching for type %d\n", op->value3);
11636             break;
11637         case NODE_TEST_PI:
11638             xmlGenericError(xmlGenericErrorContext,
11639                             "           searching for PI !!!\n");
11640             break;
11641         case NODE_TEST_ALL:
11642             xmlGenericError(xmlGenericErrorContext,
11643                             "           searching for *\n");
11644             break;
11645         case NODE_TEST_NS:
11646             xmlGenericError(xmlGenericErrorContext,
11647                             "           searching for namespace %s\n",
11648                             op->value5);
11649             break;
11650         case NODE_TEST_NAME:
11651             xmlGenericError(xmlGenericErrorContext,
11652                             "           searching for name %s\n", op->value5);
11653             if (op->value4)
11654                 xmlGenericError(xmlGenericErrorContext,
11655                                 "           with namespace %s\n", op->value4);
11656             break;
11657     }
11658     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11659 }
11660 #endif /* DEBUG_STEP */
11661 
11662 static int
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int contextSize,int hasNsNodes)11663 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11664 			    xmlXPathStepOpPtr op,
11665 			    xmlNodeSetPtr set,
11666 			    int contextSize,
11667 			    int hasNsNodes)
11668 {
11669     if (op->ch1 != -1) {
11670 	xmlXPathCompExprPtr comp = ctxt->comp;
11671 	/*
11672 	* Process inner predicates first.
11673 	*/
11674 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11675 	    /*
11676 	    * TODO: raise an internal error.
11677 	    */
11678 	}
11679 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11680 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11681 	CHECK_ERROR0;
11682 	if (contextSize <= 0)
11683 	    return(0);
11684     }
11685     if (op->ch2 != -1) {
11686 	xmlXPathContextPtr xpctxt = ctxt->context;
11687 	xmlNodePtr contextNode, oldContextNode;
11688 	xmlDocPtr oldContextDoc;
11689 	int i, res, contextPos = 0, newContextSize;
11690 	xmlXPathStepOpPtr exprOp;
11691 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11692 
11693 #ifdef LIBXML_XPTR_ENABLED
11694 	/*
11695 	* URGENT TODO: Check the following:
11696 	*  We don't expect location sets if evaluating prediates, right?
11697 	*  Only filters should expect location sets, right?
11698 	*/
11699 #endif
11700 	/*
11701 	* SPEC XPath 1.0:
11702 	*  "For each node in the node-set to be filtered, the
11703 	*  PredicateExpr is evaluated with that node as the
11704 	*  context node, with the number of nodes in the
11705 	*  node-set as the context size, and with the proximity
11706 	*  position of the node in the node-set with respect to
11707 	*  the axis as the context position;"
11708 	* @oldset is the node-set" to be filtered.
11709 	*
11710 	* SPEC XPath 1.0:
11711 	*  "only predicates change the context position and
11712 	*  context size (see [2.4 Predicates])."
11713 	* Example:
11714 	*   node-set  context pos
11715 	*    nA         1
11716 	*    nB         2
11717 	*    nC         3
11718 	*   After applying predicate [position() > 1] :
11719 	*   node-set  context pos
11720 	*    nB         1
11721 	*    nC         2
11722 	*/
11723 	oldContextNode = xpctxt->node;
11724 	oldContextDoc = xpctxt->doc;
11725 	/*
11726 	* Get the expression of this predicate.
11727 	*/
11728 	exprOp = &ctxt->comp->steps[op->ch2];
11729 	newContextSize = 0;
11730 	for (i = 0; i < set->nodeNr; i++) {
11731 	    if (set->nodeTab[i] == NULL)
11732 		continue;
11733 
11734 	    contextNode = set->nodeTab[i];
11735 	    xpctxt->node = contextNode;
11736 	    xpctxt->contextSize = contextSize;
11737 	    xpctxt->proximityPosition = ++contextPos;
11738 
11739 	    /*
11740 	    * Also set the xpath document in case things like
11741 	    * key() are evaluated in the predicate.
11742 	    */
11743 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11744 		(contextNode->doc != NULL))
11745 		xpctxt->doc = contextNode->doc;
11746 	    /*
11747 	    * Evaluate the predicate expression with 1 context node
11748 	    * at a time; this node is packaged into a node set; this
11749 	    * node set is handed over to the evaluation mechanism.
11750 	    */
11751 	    if (contextObj == NULL)
11752 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11753 	    else {
11754 		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11755 		    contextNode) < 0) {
11756 		    ctxt->error = XPATH_MEMORY_ERROR;
11757 		    goto evaluation_exit;
11758 		}
11759 	    }
11760 
11761 	    valuePush(ctxt, contextObj);
11762 
11763 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11764 
11765 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11766 		xmlXPathNodeSetClear(set, hasNsNodes);
11767 		newContextSize = 0;
11768 		goto evaluation_exit;
11769 	    }
11770 
11771 	    if (res != 0) {
11772 		newContextSize++;
11773 	    } else {
11774 		/*
11775 		* Remove the entry from the initial node set.
11776 		*/
11777 		set->nodeTab[i] = NULL;
11778 		if (contextNode->type == XML_NAMESPACE_DECL)
11779 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11780 	    }
11781 	    if (ctxt->value == contextObj) {
11782 		/*
11783 		* Don't free the temporary XPath object holding the
11784 		* context node, in order to avoid massive recreation
11785 		* inside this loop.
11786 		*/
11787 		valuePop(ctxt);
11788 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11789 	    } else {
11790 		/*
11791 		* TODO: The object was lost in the evaluation machinery.
11792 		*  Can this happen? Maybe in internal-error cases.
11793 		*/
11794 		contextObj = NULL;
11795 	    }
11796 	}
11797 
11798 	if (contextObj != NULL) {
11799 	    if (ctxt->value == contextObj)
11800 		valuePop(ctxt);
11801 	    xmlXPathReleaseObject(xpctxt, contextObj);
11802 	}
11803 evaluation_exit:
11804 	if (exprRes != NULL)
11805 	    xmlXPathReleaseObject(ctxt->context, exprRes);
11806 	/*
11807 	* Reset/invalidate the context.
11808 	*/
11809 	xpctxt->node = oldContextNode;
11810 	xpctxt->doc = oldContextDoc;
11811 	xpctxt->contextSize = -1;
11812 	xpctxt->proximityPosition = -1;
11813 	return(newContextSize);
11814     }
11815     return(contextSize);
11816 }
11817 
11818 static int
xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int contextSize,int minPos,int maxPos,int hasNsNodes)11819 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11820 				      xmlXPathStepOpPtr op,
11821 				      xmlNodeSetPtr set,
11822 				      int contextSize,
11823 				      int minPos,
11824 				      int maxPos,
11825 				      int hasNsNodes)
11826 {
11827     if (op->ch1 != -1) {
11828 	xmlXPathCompExprPtr comp = ctxt->comp;
11829 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11830 	    /*
11831 	    * TODO: raise an internal error.
11832 	    */
11833 	}
11834 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11835 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11836 	CHECK_ERROR0;
11837 	if (contextSize <= 0)
11838 	    return(0);
11839     }
11840     /*
11841     * Check if the node set contains a sufficient number of nodes for
11842     * the requested range.
11843     */
11844     if (contextSize < minPos) {
11845 	xmlXPathNodeSetClear(set, hasNsNodes);
11846 	return(0);
11847     }
11848     if (op->ch2 == -1) {
11849 	/*
11850 	* TODO: Can this ever happen?
11851 	*/
11852 	return (contextSize);
11853     } else {
11854 	xmlDocPtr oldContextDoc;
11855 	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11856 	xmlXPathStepOpPtr exprOp;
11857 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11858 	xmlNodePtr oldContextNode, contextNode = NULL;
11859 	xmlXPathContextPtr xpctxt = ctxt->context;
11860         int frame;
11861 
11862 #ifdef LIBXML_XPTR_ENABLED
11863 	    /*
11864 	    * URGENT TODO: Check the following:
11865 	    *  We don't expect location sets if evaluating prediates, right?
11866 	    *  Only filters should expect location sets, right?
11867 	*/
11868 #endif /* LIBXML_XPTR_ENABLED */
11869 
11870 	/*
11871 	* Save old context.
11872 	*/
11873 	oldContextNode = xpctxt->node;
11874 	oldContextDoc = xpctxt->doc;
11875 	/*
11876 	* Get the expression of this predicate.
11877 	*/
11878 	exprOp = &ctxt->comp->steps[op->ch2];
11879 	for (i = 0; i < set->nodeNr; i++) {
11880             xmlXPathObjectPtr tmp;
11881 
11882 	    if (set->nodeTab[i] == NULL)
11883 		continue;
11884 
11885 	    contextNode = set->nodeTab[i];
11886 	    xpctxt->node = contextNode;
11887 	    xpctxt->contextSize = contextSize;
11888 	    xpctxt->proximityPosition = ++contextPos;
11889 
11890 	    /*
11891 	    * Initialize the new set.
11892 	    * Also set the xpath document in case things like
11893 	    * key() evaluation are attempted on the predicate
11894 	    */
11895 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11896 		(contextNode->doc != NULL))
11897 		xpctxt->doc = contextNode->doc;
11898 	    /*
11899 	    * Evaluate the predicate expression with 1 context node
11900 	    * at a time; this node is packaged into a node set; this
11901 	    * node set is handed over to the evaluation mechanism.
11902 	    */
11903 	    if (contextObj == NULL)
11904 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11905 	    else {
11906 		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11907 		    contextNode) < 0) {
11908 		    ctxt->error = XPATH_MEMORY_ERROR;
11909 		    goto evaluation_exit;
11910 		}
11911 	    }
11912 
11913             frame = xmlXPathSetFrame(ctxt);
11914 	    valuePush(ctxt, contextObj);
11915 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11916             tmp = valuePop(ctxt);
11917             xmlXPathPopFrame(ctxt, frame);
11918 
11919 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11920                 while (tmp != contextObj) {
11921                     /*
11922                      * Free up the result
11923                      * then pop off contextObj, which will be freed later
11924                      */
11925                     xmlXPathReleaseObject(xpctxt, tmp);
11926                     tmp = valuePop(ctxt);
11927                 }
11928 		goto evaluation_error;
11929 	    }
11930             /* push the result back onto the stack */
11931             valuePush(ctxt, tmp);
11932 
11933 	    if (res)
11934 		pos++;
11935 
11936 	    if (res && (pos >= minPos) && (pos <= maxPos)) {
11937 		/*
11938 		* Fits in the requested range.
11939 		*/
11940 		newContextSize++;
11941 		if (minPos == maxPos) {
11942 		    /*
11943 		    * Only 1 node was requested.
11944 		    */
11945 		    if (contextNode->type == XML_NAMESPACE_DECL) {
11946 			/*
11947 			* As always: take care of those nasty
11948 			* namespace nodes.
11949 			*/
11950 			set->nodeTab[i] = NULL;
11951 		    }
11952 		    xmlXPathNodeSetClear(set, hasNsNodes);
11953 		    set->nodeNr = 1;
11954 		    set->nodeTab[0] = contextNode;
11955 		    goto evaluation_exit;
11956 		}
11957 		if (pos == maxPos) {
11958 		    /*
11959 		    * We are done.
11960 		    */
11961 		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11962 		    goto evaluation_exit;
11963 		}
11964 	    } else {
11965 		/*
11966 		* Remove the entry from the initial node set.
11967 		*/
11968 		set->nodeTab[i] = NULL;
11969 		if (contextNode->type == XML_NAMESPACE_DECL)
11970 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11971 	    }
11972 	    if (exprRes != NULL) {
11973 		xmlXPathReleaseObject(ctxt->context, exprRes);
11974 		exprRes = NULL;
11975 	    }
11976 	    if (ctxt->value == contextObj) {
11977 		/*
11978 		* Don't free the temporary XPath object holding the
11979 		* context node, in order to avoid massive recreation
11980 		* inside this loop.
11981 		*/
11982 		valuePop(ctxt);
11983 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11984 	    } else {
11985 		/*
11986 		* The object was lost in the evaluation machinery.
11987 		* Can this happen? Maybe in case of internal-errors.
11988 		*/
11989 		contextObj = NULL;
11990 	    }
11991 	}
11992 	goto evaluation_exit;
11993 
11994 evaluation_error:
11995 	xmlXPathNodeSetClear(set, hasNsNodes);
11996 	newContextSize = 0;
11997 
11998 evaluation_exit:
11999 	if (contextObj != NULL) {
12000 	    if (ctxt->value == contextObj)
12001 		valuePop(ctxt);
12002 	    xmlXPathReleaseObject(xpctxt, contextObj);
12003 	}
12004 	if (exprRes != NULL)
12005 	    xmlXPathReleaseObject(ctxt->context, exprRes);
12006 	/*
12007 	* Reset/invalidate the context.
12008 	*/
12009 	xpctxt->node = oldContextNode;
12010 	xpctxt->doc = oldContextDoc;
12011 	xpctxt->contextSize = -1;
12012 	xpctxt->proximityPosition = -1;
12013 	return(newContextSize);
12014     }
12015     return(contextSize);
12016 }
12017 
12018 static int
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int * maxPos)12019 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
12020 			    xmlXPathStepOpPtr op,
12021 			    int *maxPos)
12022 {
12023 
12024     xmlXPathStepOpPtr exprOp;
12025 
12026     /*
12027     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12028     */
12029 
12030     /*
12031     * If not -1, then ch1 will point to:
12032     * 1) For predicates (XPATH_OP_PREDICATE):
12033     *    - an inner predicate operator
12034     * 2) For filters (XPATH_OP_FILTER):
12035     *    - an inner filter operater OR
12036     *    - an expression selecting the node set.
12037     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
12038     */
12039     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12040 	return(0);
12041 
12042     if (op->ch2 != -1) {
12043 	exprOp = &ctxt->comp->steps[op->ch2];
12044     } else
12045 	return(0);
12046 
12047     if ((exprOp != NULL) &&
12048 	(exprOp->op == XPATH_OP_VALUE) &&
12049 	(exprOp->value4 != NULL) &&
12050 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12051     {
12052 	/*
12053 	* We have a "[n]" predicate here.
12054 	* TODO: Unfortunately this simplistic test here is not
12055 	* able to detect a position() predicate in compound
12056 	* expressions like "[@attr = 'a" and position() = 1],
12057 	* and even not the usage of position() in
12058 	* "[position() = 1]"; thus - obviously - a position-range,
12059 	* like it "[position() < 5]", is also not detected.
12060 	* Maybe we could rewrite the AST to ease the optimization.
12061 	*/
12062 	*maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12063 
12064 	if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
12065 	    (float) *maxPos)
12066 	{
12067 	    return(1);
12068 	}
12069     }
12070     return(0);
12071 }
12072 
12073 static int
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first,xmlNodePtr * last,int toBool)12074 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12075                            xmlXPathStepOpPtr op,
12076 			   xmlNodePtr * first, xmlNodePtr * last,
12077 			   int toBool)
12078 {
12079 
12080 #define XP_TEST_HIT \
12081     if (hasAxisRange != 0) { \
12082 	if (++pos == maxPos) { \
12083 	    if (addNode(seq, cur) < 0) \
12084 	        ctxt->error = XPATH_MEMORY_ERROR; \
12085 	    goto axis_range_end; } \
12086     } else { \
12087 	if (addNode(seq, cur) < 0) \
12088 	    ctxt->error = XPATH_MEMORY_ERROR; \
12089 	if (breakOnFirstHit) goto first_hit; }
12090 
12091 #define XP_TEST_HIT_NS \
12092     if (hasAxisRange != 0) { \
12093 	if (++pos == maxPos) { \
12094 	    hasNsNodes = 1; \
12095 	    if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12096 	        ctxt->error = XPATH_MEMORY_ERROR; \
12097 	goto axis_range_end; } \
12098     } else { \
12099 	hasNsNodes = 1; \
12100 	if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12101 	    ctxt->error = XPATH_MEMORY_ERROR; \
12102 	if (breakOnFirstHit) goto first_hit; }
12103 
12104     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12105     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12106     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12107     const xmlChar *prefix = op->value4;
12108     const xmlChar *name = op->value5;
12109     const xmlChar *URI = NULL;
12110 
12111 #ifdef DEBUG_STEP
12112     int nbMatches = 0, prevMatches = 0;
12113 #endif
12114     int total = 0, hasNsNodes = 0;
12115     /* The popped object holding the context nodes */
12116     xmlXPathObjectPtr obj;
12117     /* The set of context nodes for the node tests */
12118     xmlNodeSetPtr contextSeq;
12119     int contextIdx;
12120     xmlNodePtr contextNode;
12121     /* The final resulting node set wrt to all context nodes */
12122     xmlNodeSetPtr outSeq;
12123     /*
12124     * The temporary resulting node set wrt 1 context node.
12125     * Used to feed predicate evaluation.
12126     */
12127     xmlNodeSetPtr seq;
12128     xmlNodePtr cur;
12129     /* First predicate operator */
12130     xmlXPathStepOpPtr predOp;
12131     int maxPos; /* The requested position() (when a "[n]" predicate) */
12132     int hasPredicateRange, hasAxisRange, pos, size, newSize;
12133     int breakOnFirstHit;
12134 
12135     xmlXPathTraversalFunction next = NULL;
12136     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12137     xmlXPathNodeSetMergeFunction mergeAndClear;
12138     xmlNodePtr oldContextNode;
12139     xmlXPathContextPtr xpctxt = ctxt->context;
12140 
12141 
12142     CHECK_TYPE0(XPATH_NODESET);
12143     obj = valuePop(ctxt);
12144     /*
12145     * Setup namespaces.
12146     */
12147     if (prefix != NULL) {
12148         URI = xmlXPathNsLookup(xpctxt, prefix);
12149         if (URI == NULL) {
12150 	    xmlXPathReleaseObject(xpctxt, obj);
12151             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12152 	}
12153     }
12154     /*
12155     * Setup axis.
12156     *
12157     * MAYBE FUTURE TODO: merging optimizations:
12158     * - If the nodes to be traversed wrt to the initial nodes and
12159     *   the current axis cannot overlap, then we could avoid searching
12160     *   for duplicates during the merge.
12161     *   But the question is how/when to evaluate if they cannot overlap.
12162     *   Example: if we know that for two initial nodes, the one is
12163     *   not in the ancestor-or-self axis of the other, then we could safely
12164     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12165     *   the descendant-or-self axis.
12166     */
12167     mergeAndClear = xmlXPathNodeSetMergeAndClear;
12168     switch (axis) {
12169         case AXIS_ANCESTOR:
12170             first = NULL;
12171             next = xmlXPathNextAncestor;
12172             break;
12173         case AXIS_ANCESTOR_OR_SELF:
12174             first = NULL;
12175             next = xmlXPathNextAncestorOrSelf;
12176             break;
12177         case AXIS_ATTRIBUTE:
12178             first = NULL;
12179 	    last = NULL;
12180             next = xmlXPathNextAttribute;
12181 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12182             break;
12183         case AXIS_CHILD:
12184 	    last = NULL;
12185 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12186 		(type == NODE_TYPE_NODE))
12187 	    {
12188 		/*
12189 		* Optimization if an element node type is 'element'.
12190 		*/
12191 		next = xmlXPathNextChildElement;
12192 	    } else
12193 		next = xmlXPathNextChild;
12194 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12195             break;
12196         case AXIS_DESCENDANT:
12197 	    last = NULL;
12198             next = xmlXPathNextDescendant;
12199             break;
12200         case AXIS_DESCENDANT_OR_SELF:
12201 	    last = NULL;
12202             next = xmlXPathNextDescendantOrSelf;
12203             break;
12204         case AXIS_FOLLOWING:
12205 	    last = NULL;
12206             next = xmlXPathNextFollowing;
12207             break;
12208         case AXIS_FOLLOWING_SIBLING:
12209 	    last = NULL;
12210             next = xmlXPathNextFollowingSibling;
12211             break;
12212         case AXIS_NAMESPACE:
12213             first = NULL;
12214 	    last = NULL;
12215             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12216 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12217             break;
12218         case AXIS_PARENT:
12219             first = NULL;
12220             next = xmlXPathNextParent;
12221             break;
12222         case AXIS_PRECEDING:
12223             first = NULL;
12224             next = xmlXPathNextPrecedingInternal;
12225             break;
12226         case AXIS_PRECEDING_SIBLING:
12227             first = NULL;
12228             next = xmlXPathNextPrecedingSibling;
12229             break;
12230         case AXIS_SELF:
12231             first = NULL;
12232 	    last = NULL;
12233             next = xmlXPathNextSelf;
12234 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12235             break;
12236     }
12237 
12238 #ifdef DEBUG_STEP
12239     xmlXPathDebugDumpStepAxis(op,
12240 	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12241 #endif
12242 
12243     if (next == NULL) {
12244 	xmlXPathReleaseObject(xpctxt, obj);
12245         return(0);
12246     }
12247     contextSeq = obj->nodesetval;
12248     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12249 	xmlXPathReleaseObject(xpctxt, obj);
12250         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12251         return(0);
12252     }
12253     /*
12254     * Predicate optimization ---------------------------------------------
12255     * If this step has a last predicate, which contains a position(),
12256     * then we'll optimize (although not exactly "position()", but only
12257     * the  short-hand form, i.e., "[n]".
12258     *
12259     * Example - expression "/foo[parent::bar][1]":
12260     *
12261     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12262     *   ROOT                               -- op->ch1
12263     *   PREDICATE                          -- op->ch2 (predOp)
12264     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12265     *       SORT
12266     *         COLLECT  'parent' 'name' 'node' bar
12267     *           NODE
12268     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12269     *
12270     */
12271     maxPos = 0;
12272     predOp = NULL;
12273     hasPredicateRange = 0;
12274     hasAxisRange = 0;
12275     if (op->ch2 != -1) {
12276 	/*
12277 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
12278 	*/
12279 	predOp = &ctxt->comp->steps[op->ch2];
12280 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12281 	    if (predOp->ch1 != -1) {
12282 		/*
12283 		* Use the next inner predicate operator.
12284 		*/
12285 		predOp = &ctxt->comp->steps[predOp->ch1];
12286 		hasPredicateRange = 1;
12287 	    } else {
12288 		/*
12289 		* There's no other predicate than the [n] predicate.
12290 		*/
12291 		predOp = NULL;
12292 		hasAxisRange = 1;
12293 	    }
12294 	}
12295     }
12296     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12297     /*
12298     * Axis traversal -----------------------------------------------------
12299     */
12300     /*
12301      * 2.3 Node Tests
12302      *  - For the attribute axis, the principal node type is attribute.
12303      *  - For the namespace axis, the principal node type is namespace.
12304      *  - For other axes, the principal node type is element.
12305      *
12306      * A node test * is true for any node of the
12307      * principal node type. For example, child::* will
12308      * select all element children of the context node
12309      */
12310     oldContextNode = xpctxt->node;
12311     addNode = xmlXPathNodeSetAddUnique;
12312     outSeq = NULL;
12313     seq = NULL;
12314     contextNode = NULL;
12315     contextIdx = 0;
12316 
12317 
12318     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12319            (ctxt->error == XPATH_EXPRESSION_OK)) {
12320 	xpctxt->node = contextSeq->nodeTab[contextIdx++];
12321 
12322 	if (seq == NULL) {
12323 	    seq = xmlXPathNodeSetCreate(NULL);
12324 	    if (seq == NULL) {
12325 		total = 0;
12326 		goto error;
12327 	    }
12328 	}
12329 	/*
12330 	* Traverse the axis and test the nodes.
12331 	*/
12332 	pos = 0;
12333 	cur = NULL;
12334 	hasNsNodes = 0;
12335         do {
12336             cur = next(ctxt, cur);
12337             if (cur == NULL)
12338                 break;
12339 
12340 	    /*
12341 	    * QUESTION TODO: What does the "first" and "last" stuff do?
12342 	    */
12343             if ((first != NULL) && (*first != NULL)) {
12344 		if (*first == cur)
12345 		    break;
12346 		if (((total % 256) == 0) &&
12347 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12348 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12349 #else
12350 		    (xmlXPathCmpNodes(*first, cur) >= 0))
12351 #endif
12352 		{
12353 		    break;
12354 		}
12355 	    }
12356 	    if ((last != NULL) && (*last != NULL)) {
12357 		if (*last == cur)
12358 		    break;
12359 		if (((total % 256) == 0) &&
12360 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12361 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12362 #else
12363 		    (xmlXPathCmpNodes(cur, *last) >= 0))
12364 #endif
12365 		{
12366 		    break;
12367 		}
12368 	    }
12369 
12370             total++;
12371 
12372 #ifdef DEBUG_STEP
12373             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12374 #endif
12375 
12376 	    switch (test) {
12377                 case NODE_TEST_NONE:
12378 		    total = 0;
12379                     STRANGE
12380 		    goto error;
12381                 case NODE_TEST_TYPE:
12382 		    /*
12383 		    * TODO: Don't we need to use
12384 		    *  xmlXPathNodeSetAddNs() for namespace nodes here?
12385 		    *  Surprisingly, some c14n tests fail, if we do this.
12386 		    */
12387 		    if (type == NODE_TYPE_NODE) {
12388 			switch (cur->type) {
12389 			    case XML_DOCUMENT_NODE:
12390 			    case XML_HTML_DOCUMENT_NODE:
12391 #ifdef LIBXML_DOCB_ENABLED
12392 			    case XML_DOCB_DOCUMENT_NODE:
12393 #endif
12394 			    case XML_ELEMENT_NODE:
12395 			    case XML_ATTRIBUTE_NODE:
12396 			    case XML_PI_NODE:
12397 			    case XML_COMMENT_NODE:
12398 			    case XML_CDATA_SECTION_NODE:
12399 			    case XML_TEXT_NODE:
12400 			    case XML_NAMESPACE_DECL:
12401 				XP_TEST_HIT
12402 				break;
12403 			    default:
12404 				break;
12405 			}
12406 		    } else if (cur->type == type) {
12407 			if (cur->type == XML_NAMESPACE_DECL)
12408 			    XP_TEST_HIT_NS
12409 			else
12410 			    XP_TEST_HIT
12411 		    } else if ((type == NODE_TYPE_TEXT) &&
12412 			 (cur->type == XML_CDATA_SECTION_NODE))
12413 		    {
12414 			XP_TEST_HIT
12415 		    }
12416 		    break;
12417                 case NODE_TEST_PI:
12418                     if ((cur->type == XML_PI_NODE) &&
12419                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12420 		    {
12421 			XP_TEST_HIT
12422                     }
12423                     break;
12424                 case NODE_TEST_ALL:
12425                     if (axis == AXIS_ATTRIBUTE) {
12426                         if (cur->type == XML_ATTRIBUTE_NODE)
12427 			{
12428                             if (prefix == NULL)
12429 			    {
12430 				XP_TEST_HIT
12431                             } else if ((cur->ns != NULL) &&
12432 				(xmlStrEqual(URI, cur->ns->href)))
12433 			    {
12434 				XP_TEST_HIT
12435                             }
12436                         }
12437                     } else if (axis == AXIS_NAMESPACE) {
12438                         if (cur->type == XML_NAMESPACE_DECL)
12439 			{
12440 			    XP_TEST_HIT_NS
12441                         }
12442                     } else {
12443                         if (cur->type == XML_ELEMENT_NODE) {
12444                             if (prefix == NULL)
12445 			    {
12446 				XP_TEST_HIT
12447 
12448                             } else if ((cur->ns != NULL) &&
12449 				(xmlStrEqual(URI, cur->ns->href)))
12450 			    {
12451 				XP_TEST_HIT
12452                             }
12453                         }
12454                     }
12455                     break;
12456                 case NODE_TEST_NS:{
12457                         TODO;
12458                         break;
12459                     }
12460                 case NODE_TEST_NAME:
12461                     if (axis == AXIS_ATTRIBUTE) {
12462                         if (cur->type != XML_ATTRIBUTE_NODE)
12463 			    break;
12464 		    } else if (axis == AXIS_NAMESPACE) {
12465                         if (cur->type != XML_NAMESPACE_DECL)
12466 			    break;
12467 		    } else {
12468 		        if (cur->type != XML_ELEMENT_NODE)
12469 			    break;
12470 		    }
12471                     switch (cur->type) {
12472                         case XML_ELEMENT_NODE:
12473                             if (xmlStrEqual(name, cur->name)) {
12474                                 if (prefix == NULL) {
12475                                     if (cur->ns == NULL)
12476 				    {
12477 					XP_TEST_HIT
12478                                     }
12479                                 } else {
12480                                     if ((cur->ns != NULL) &&
12481                                         (xmlStrEqual(URI, cur->ns->href)))
12482 				    {
12483 					XP_TEST_HIT
12484                                     }
12485                                 }
12486                             }
12487                             break;
12488                         case XML_ATTRIBUTE_NODE:{
12489                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12490 
12491                                 if (xmlStrEqual(name, attr->name)) {
12492                                     if (prefix == NULL) {
12493                                         if ((attr->ns == NULL) ||
12494                                             (attr->ns->prefix == NULL))
12495 					{
12496 					    XP_TEST_HIT
12497                                         }
12498                                     } else {
12499                                         if ((attr->ns != NULL) &&
12500                                             (xmlStrEqual(URI,
12501 					      attr->ns->href)))
12502 					{
12503 					    XP_TEST_HIT
12504                                         }
12505                                     }
12506                                 }
12507                                 break;
12508                             }
12509                         case XML_NAMESPACE_DECL:
12510                             if (cur->type == XML_NAMESPACE_DECL) {
12511                                 xmlNsPtr ns = (xmlNsPtr) cur;
12512 
12513                                 if ((ns->prefix != NULL) && (name != NULL)
12514                                     && (xmlStrEqual(ns->prefix, name)))
12515 				{
12516 				    XP_TEST_HIT_NS
12517                                 }
12518                             }
12519                             break;
12520                         default:
12521                             break;
12522                     }
12523                     break;
12524 	    } /* switch(test) */
12525         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12526 
12527 	goto apply_predicates;
12528 
12529 axis_range_end: /* ----------------------------------------------------- */
12530 	/*
12531 	* We have a "/foo[n]", and position() = n was reached.
12532 	* Note that we can have as well "/foo/::parent::foo[1]", so
12533 	* a duplicate-aware merge is still needed.
12534 	* Merge with the result.
12535 	*/
12536 	if (outSeq == NULL) {
12537 	    outSeq = seq;
12538 	    seq = NULL;
12539 	} else
12540 	    outSeq = mergeAndClear(outSeq, seq, 0);
12541 	/*
12542 	* Break if only a true/false result was requested.
12543 	*/
12544 	if (toBool)
12545 	    break;
12546 	continue;
12547 
12548 first_hit: /* ---------------------------------------------------------- */
12549 	/*
12550 	* Break if only a true/false result was requested and
12551 	* no predicates existed and a node test succeeded.
12552 	*/
12553 	if (outSeq == NULL) {
12554 	    outSeq = seq;
12555 	    seq = NULL;
12556 	} else
12557 	    outSeq = mergeAndClear(outSeq, seq, 0);
12558 	break;
12559 
12560 #ifdef DEBUG_STEP
12561 	if (seq != NULL)
12562 	    nbMatches += seq->nodeNr;
12563 #endif
12564 
12565 apply_predicates: /* --------------------------------------------------- */
12566         if (ctxt->error != XPATH_EXPRESSION_OK)
12567 	    goto error;
12568 
12569         /*
12570 	* Apply predicates.
12571 	*/
12572         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12573 	    /*
12574 	    * E.g. when we have a "/foo[some expression][n]".
12575 	    */
12576 	    /*
12577 	    * QUESTION TODO: The old predicate evaluation took into
12578 	    *  account location-sets.
12579 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12580 	    *  Do we expect such a set here?
12581 	    *  All what I learned now from the evaluation semantics
12582 	    *  does not indicate that a location-set will be processed
12583 	    *  here, so this looks OK.
12584 	    */
12585 	    /*
12586 	    * Iterate over all predicates, starting with the outermost
12587 	    * predicate.
12588 	    * TODO: Problem: we cannot execute the inner predicates first
12589 	    *  since we cannot go back *up* the operator tree!
12590 	    *  Options we have:
12591 	    *  1) Use of recursive functions (like is it currently done
12592 	    *     via xmlXPathCompOpEval())
12593 	    *  2) Add a predicate evaluation information stack to the
12594 	    *     context struct
12595 	    *  3) Change the way the operators are linked; we need a
12596 	    *     "parent" field on xmlXPathStepOp
12597 	    *
12598 	    * For the moment, I'll try to solve this with a recursive
12599 	    * function: xmlXPathCompOpEvalPredicate().
12600 	    */
12601 	    size = seq->nodeNr;
12602 	    if (hasPredicateRange != 0)
12603 		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12604 		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
12605 	    else
12606 		newSize = xmlXPathCompOpEvalPredicate(ctxt,
12607 		    predOp, seq, size, hasNsNodes);
12608 
12609 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12610 		total = 0;
12611 		goto error;
12612 	    }
12613 	    /*
12614 	    * Add the filtered set of nodes to the result node set.
12615 	    */
12616 	    if (newSize == 0) {
12617 		/*
12618 		* The predicates filtered all nodes out.
12619 		*/
12620 		xmlXPathNodeSetClear(seq, hasNsNodes);
12621 	    } else if (seq->nodeNr > 0) {
12622 		/*
12623 		* Add to result set.
12624 		*/
12625 		if (outSeq == NULL) {
12626 		    if (size != newSize) {
12627 			/*
12628 			* We need to merge and clear here, since
12629 			* the sequence will contained NULLed entries.
12630 			*/
12631 			outSeq = mergeAndClear(NULL, seq, 1);
12632 		    } else {
12633 			outSeq = seq;
12634 			seq = NULL;
12635 		    }
12636 		} else
12637 		    outSeq = mergeAndClear(outSeq, seq,
12638 			(size != newSize) ? 1: 0);
12639 		/*
12640 		* Break if only a true/false result was requested.
12641 		*/
12642 		if (toBool)
12643 		    break;
12644 	    }
12645         } else if (seq->nodeNr > 0) {
12646 	    /*
12647 	    * Add to result set.
12648 	    */
12649 	    if (outSeq == NULL) {
12650 		outSeq = seq;
12651 		seq = NULL;
12652 	    } else {
12653 		outSeq = mergeAndClear(outSeq, seq, 0);
12654 	    }
12655 	}
12656     }
12657 
12658 error:
12659     if ((obj->boolval) && (obj->user != NULL)) {
12660 	/*
12661 	* QUESTION TODO: What does this do and why?
12662 	* TODO: Do we have to do this also for the "error"
12663 	* cleanup further down?
12664 	*/
12665 	ctxt->value->boolval = 1;
12666 	ctxt->value->user = obj->user;
12667 	obj->user = NULL;
12668 	obj->boolval = 0;
12669     }
12670     xmlXPathReleaseObject(xpctxt, obj);
12671 
12672     /*
12673     * Ensure we return at least an emtpy set.
12674     */
12675     if (outSeq == NULL) {
12676 	if ((seq != NULL) && (seq->nodeNr == 0))
12677 	    outSeq = seq;
12678 	else
12679 	    outSeq = xmlXPathNodeSetCreate(NULL);
12680         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12681     }
12682     if ((seq != NULL) && (seq != outSeq)) {
12683 	 xmlXPathFreeNodeSet(seq);
12684     }
12685     /*
12686     * Hand over the result. Better to push the set also in
12687     * case of errors.
12688     */
12689     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12690     /*
12691     * Reset the context node.
12692     */
12693     xpctxt->node = oldContextNode;
12694 
12695 #ifdef DEBUG_STEP
12696     xmlGenericError(xmlGenericErrorContext,
12697 	"\nExamined %d nodes, found %d nodes at that step\n",
12698 	total, nbMatches);
12699 #endif
12700 
12701     return(total);
12702 }
12703 
12704 static int
12705 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12706 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12707 
12708 /**
12709  * xmlXPathCompOpEvalFirst:
12710  * @ctxt:  the XPath parser context with the compiled expression
12711  * @op:  an XPath compiled operation
12712  * @first:  the first elem found so far
12713  *
12714  * Evaluate the Precompiled XPath operation searching only the first
12715  * element in document order
12716  *
12717  * Returns the number of examined objects.
12718  */
12719 static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12720 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12721                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12722 {
12723     int total = 0, cur;
12724     xmlXPathCompExprPtr comp;
12725     xmlXPathObjectPtr arg1, arg2;
12726 
12727     CHECK_ERROR0;
12728     comp = ctxt->comp;
12729     switch (op->op) {
12730         case XPATH_OP_END:
12731             return (0);
12732         case XPATH_OP_UNION:
12733             total =
12734                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12735                                         first);
12736 	    CHECK_ERROR0;
12737             if ((ctxt->value != NULL)
12738                 && (ctxt->value->type == XPATH_NODESET)
12739                 && (ctxt->value->nodesetval != NULL)
12740                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12741                 /*
12742                  * limit tree traversing to first node in the result
12743                  */
12744 		/*
12745 		* OPTIMIZE TODO: This implicitely sorts
12746 		*  the result, even if not needed. E.g. if the argument
12747 		*  of the count() function, no sorting is needed.
12748 		* OPTIMIZE TODO: How do we know if the node-list wasn't
12749 		*  aready sorted?
12750 		*/
12751 		if (ctxt->value->nodesetval->nodeNr > 1)
12752 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12753                 *first = ctxt->value->nodesetval->nodeTab[0];
12754             }
12755             cur =
12756                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12757                                         first);
12758 	    CHECK_ERROR0;
12759             CHECK_TYPE0(XPATH_NODESET);
12760             arg2 = valuePop(ctxt);
12761 
12762             CHECK_TYPE0(XPATH_NODESET);
12763             arg1 = valuePop(ctxt);
12764 
12765             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12766                                                     arg2->nodesetval);
12767             valuePush(ctxt, arg1);
12768 	    xmlXPathReleaseObject(ctxt->context, arg2);
12769             /* optimizer */
12770 	    if (total > cur)
12771 		xmlXPathCompSwap(op);
12772             return (total + cur);
12773         case XPATH_OP_ROOT:
12774             xmlXPathRoot(ctxt);
12775             return (0);
12776         case XPATH_OP_NODE:
12777             if (op->ch1 != -1)
12778                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12779 	    CHECK_ERROR0;
12780             if (op->ch2 != -1)
12781                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12782 	    CHECK_ERROR0;
12783 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12784 		ctxt->context->node));
12785             return (total);
12786         case XPATH_OP_RESET:
12787             if (op->ch1 != -1)
12788                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12789 	    CHECK_ERROR0;
12790             if (op->ch2 != -1)
12791                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12792 	    CHECK_ERROR0;
12793             ctxt->context->node = NULL;
12794             return (total);
12795         case XPATH_OP_COLLECT:{
12796                 if (op->ch1 == -1)
12797                     return (total);
12798 
12799                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12800 		CHECK_ERROR0;
12801 
12802                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12803                 return (total);
12804             }
12805         case XPATH_OP_VALUE:
12806             valuePush(ctxt,
12807                       xmlXPathCacheObjectCopy(ctxt->context,
12808 			(xmlXPathObjectPtr) op->value4));
12809             return (0);
12810         case XPATH_OP_SORT:
12811             if (op->ch1 != -1)
12812                 total +=
12813                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12814                                             first);
12815 	    CHECK_ERROR0;
12816             if ((ctxt->value != NULL)
12817                 && (ctxt->value->type == XPATH_NODESET)
12818                 && (ctxt->value->nodesetval != NULL)
12819 		&& (ctxt->value->nodesetval->nodeNr > 1))
12820                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12821             return (total);
12822 #ifdef XP_OPTIMIZED_FILTER_FIRST
12823 	case XPATH_OP_FILTER:
12824                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12825             return (total);
12826 #endif
12827         default:
12828             return (xmlXPathCompOpEval(ctxt, op));
12829     }
12830 }
12831 
12832 /**
12833  * xmlXPathCompOpEvalLast:
12834  * @ctxt:  the XPath parser context with the compiled expression
12835  * @op:  an XPath compiled operation
12836  * @last:  the last elem found so far
12837  *
12838  * Evaluate the Precompiled XPath operation searching only the last
12839  * element in document order
12840  *
12841  * Returns the number of nodes traversed
12842  */
12843 static int
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * last)12844 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12845                        xmlNodePtr * last)
12846 {
12847     int total = 0, cur;
12848     xmlXPathCompExprPtr comp;
12849     xmlXPathObjectPtr arg1, arg2;
12850     xmlNodePtr bak;
12851     xmlDocPtr bakd;
12852     int pp;
12853     int cs;
12854 
12855     CHECK_ERROR0;
12856     comp = ctxt->comp;
12857     switch (op->op) {
12858         case XPATH_OP_END:
12859             return (0);
12860         case XPATH_OP_UNION:
12861 	    bakd = ctxt->context->doc;
12862 	    bak = ctxt->context->node;
12863 	    pp = ctxt->context->proximityPosition;
12864 	    cs = ctxt->context->contextSize;
12865             total =
12866                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12867 	    CHECK_ERROR0;
12868             if ((ctxt->value != NULL)
12869                 && (ctxt->value->type == XPATH_NODESET)
12870                 && (ctxt->value->nodesetval != NULL)
12871                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12872                 /*
12873                  * limit tree traversing to first node in the result
12874                  */
12875 		if (ctxt->value->nodesetval->nodeNr > 1)
12876 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12877                 *last =
12878                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12879                                                      nodesetval->nodeNr -
12880                                                      1];
12881             }
12882 	    ctxt->context->doc = bakd;
12883 	    ctxt->context->node = bak;
12884 	    ctxt->context->proximityPosition = pp;
12885 	    ctxt->context->contextSize = cs;
12886             cur =
12887                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12888 	    CHECK_ERROR0;
12889             if ((ctxt->value != NULL)
12890                 && (ctxt->value->type == XPATH_NODESET)
12891                 && (ctxt->value->nodesetval != NULL)
12892                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12893             }
12894             CHECK_TYPE0(XPATH_NODESET);
12895             arg2 = valuePop(ctxt);
12896 
12897             CHECK_TYPE0(XPATH_NODESET);
12898             arg1 = valuePop(ctxt);
12899 
12900             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12901                                                     arg2->nodesetval);
12902             valuePush(ctxt, arg1);
12903 	    xmlXPathReleaseObject(ctxt->context, arg2);
12904             /* optimizer */
12905 	    if (total > cur)
12906 		xmlXPathCompSwap(op);
12907             return (total + cur);
12908         case XPATH_OP_ROOT:
12909             xmlXPathRoot(ctxt);
12910             return (0);
12911         case XPATH_OP_NODE:
12912             if (op->ch1 != -1)
12913                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12914 	    CHECK_ERROR0;
12915             if (op->ch2 != -1)
12916                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12917 	    CHECK_ERROR0;
12918 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12919 		ctxt->context->node));
12920             return (total);
12921         case XPATH_OP_RESET:
12922             if (op->ch1 != -1)
12923                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12924 	    CHECK_ERROR0;
12925             if (op->ch2 != -1)
12926                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12927 	    CHECK_ERROR0;
12928             ctxt->context->node = NULL;
12929             return (total);
12930         case XPATH_OP_COLLECT:{
12931                 if (op->ch1 == -1)
12932                     return (0);
12933 
12934                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12935 		CHECK_ERROR0;
12936 
12937                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12938                 return (total);
12939             }
12940         case XPATH_OP_VALUE:
12941             valuePush(ctxt,
12942                       xmlXPathCacheObjectCopy(ctxt->context,
12943 			(xmlXPathObjectPtr) op->value4));
12944             return (0);
12945         case XPATH_OP_SORT:
12946             if (op->ch1 != -1)
12947                 total +=
12948                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12949                                            last);
12950 	    CHECK_ERROR0;
12951             if ((ctxt->value != NULL)
12952                 && (ctxt->value->type == XPATH_NODESET)
12953                 && (ctxt->value->nodesetval != NULL)
12954 		&& (ctxt->value->nodesetval->nodeNr > 1))
12955                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12956             return (total);
12957         default:
12958             return (xmlXPathCompOpEval(ctxt, op));
12959     }
12960 }
12961 
12962 #ifdef XP_OPTIMIZED_FILTER_FIRST
12963 static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12964 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12965 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
12966 {
12967     int total = 0;
12968     xmlXPathCompExprPtr comp;
12969     xmlXPathObjectPtr res;
12970     xmlXPathObjectPtr obj;
12971     xmlNodeSetPtr oldset;
12972     xmlNodePtr oldnode;
12973     xmlDocPtr oldDoc;
12974     int i;
12975 
12976     CHECK_ERROR0;
12977     comp = ctxt->comp;
12978     /*
12979     * Optimization for ()[last()] selection i.e. the last elem
12980     */
12981     if ((op->ch1 != -1) && (op->ch2 != -1) &&
12982 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12983 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12984 	int f = comp->steps[op->ch2].ch1;
12985 
12986 	if ((f != -1) &&
12987 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12988 	    (comp->steps[f].value5 == NULL) &&
12989 	    (comp->steps[f].value == 0) &&
12990 	    (comp->steps[f].value4 != NULL) &&
12991 	    (xmlStrEqual
12992 	    (comp->steps[f].value4, BAD_CAST "last"))) {
12993 	    xmlNodePtr last = NULL;
12994 
12995 	    total +=
12996 		xmlXPathCompOpEvalLast(ctxt,
12997 		    &comp->steps[op->ch1],
12998 		    &last);
12999 	    CHECK_ERROR0;
13000 	    /*
13001 	    * The nodeset should be in document order,
13002 	    * Keep only the last value
13003 	    */
13004 	    if ((ctxt->value != NULL) &&
13005 		(ctxt->value->type == XPATH_NODESET) &&
13006 		(ctxt->value->nodesetval != NULL) &&
13007 		(ctxt->value->nodesetval->nodeTab != NULL) &&
13008 		(ctxt->value->nodesetval->nodeNr > 1)) {
13009 		ctxt->value->nodesetval->nodeTab[0] =
13010 		    ctxt->value->nodesetval->nodeTab[ctxt->
13011 		    value->
13012 		    nodesetval->
13013 		    nodeNr -
13014 		    1];
13015 		ctxt->value->nodesetval->nodeNr = 1;
13016 		*first = *(ctxt->value->nodesetval->nodeTab);
13017 	    }
13018 	    return (total);
13019 	}
13020     }
13021 
13022     if (op->ch1 != -1)
13023 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13024     CHECK_ERROR0;
13025     if (op->ch2 == -1)
13026 	return (total);
13027     if (ctxt->value == NULL)
13028 	return (total);
13029 
13030 #ifdef LIBXML_XPTR_ENABLED
13031     oldnode = ctxt->context->node;
13032     /*
13033     * Hum are we filtering the result of an XPointer expression
13034     */
13035     if (ctxt->value->type == XPATH_LOCATIONSET) {
13036 	xmlXPathObjectPtr tmp = NULL;
13037 	xmlLocationSetPtr newlocset = NULL;
13038 	xmlLocationSetPtr oldlocset;
13039 
13040 	/*
13041 	* Extract the old locset, and then evaluate the result of the
13042 	* expression for all the element in the locset. use it to grow
13043 	* up a new locset.
13044 	*/
13045 	CHECK_TYPE0(XPATH_LOCATIONSET);
13046 	obj = valuePop(ctxt);
13047 	oldlocset = obj->user;
13048 	ctxt->context->node = NULL;
13049 
13050 	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13051 	    ctxt->context->contextSize = 0;
13052 	    ctxt->context->proximityPosition = 0;
13053 	    if (op->ch2 != -1)
13054 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13055 	    res = valuePop(ctxt);
13056 	    if (res != NULL) {
13057 		xmlXPathReleaseObject(ctxt->context, res);
13058 	    }
13059 	    valuePush(ctxt, obj);
13060 	    CHECK_ERROR0;
13061 	    return (total);
13062 	}
13063 	newlocset = xmlXPtrLocationSetCreate(NULL);
13064 
13065 	for (i = 0; i < oldlocset->locNr; i++) {
13066 	    /*
13067 	    * Run the evaluation with a node list made of a
13068 	    * single item in the nodelocset.
13069 	    */
13070 	    ctxt->context->node = oldlocset->locTab[i]->user;
13071 	    ctxt->context->contextSize = oldlocset->locNr;
13072 	    ctxt->context->proximityPosition = i + 1;
13073 	    if (tmp == NULL) {
13074 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13075 		    ctxt->context->node);
13076 	    } else {
13077 		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13078 		                             ctxt->context->node) < 0) {
13079 		    ctxt->error = XPATH_MEMORY_ERROR;
13080 		}
13081 	    }
13082 	    valuePush(ctxt, tmp);
13083 	    if (op->ch2 != -1)
13084 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13085 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13086 		xmlXPathFreeObject(obj);
13087 		return(0);
13088 	    }
13089 	    /*
13090 	    * The result of the evaluation need to be tested to
13091 	    * decided whether the filter succeeded or not
13092 	    */
13093 	    res = valuePop(ctxt);
13094 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13095 		xmlXPtrLocationSetAdd(newlocset,
13096 		    xmlXPathCacheObjectCopy(ctxt->context,
13097 			oldlocset->locTab[i]));
13098 	    }
13099 	    /*
13100 	    * Cleanup
13101 	    */
13102 	    if (res != NULL) {
13103 		xmlXPathReleaseObject(ctxt->context, res);
13104 	    }
13105 	    if (ctxt->value == tmp) {
13106 		valuePop(ctxt);
13107 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13108 		/*
13109 		* REVISIT TODO: Don't create a temporary nodeset
13110 		* for everly iteration.
13111 		*/
13112 		/* OLD: xmlXPathFreeObject(res); */
13113 	    } else
13114 		tmp = NULL;
13115 	    ctxt->context->node = NULL;
13116 	    /*
13117 	    * Only put the first node in the result, then leave.
13118 	    */
13119 	    if (newlocset->locNr > 0) {
13120 		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
13121 		break;
13122 	    }
13123 	}
13124 	if (tmp != NULL) {
13125 	    xmlXPathReleaseObject(ctxt->context, tmp);
13126 	}
13127 	/*
13128 	* The result is used as the new evaluation locset.
13129 	*/
13130 	xmlXPathReleaseObject(ctxt->context, obj);
13131 	ctxt->context->node = NULL;
13132 	ctxt->context->contextSize = -1;
13133 	ctxt->context->proximityPosition = -1;
13134 	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13135 	ctxt->context->node = oldnode;
13136 	return (total);
13137     }
13138 #endif /* LIBXML_XPTR_ENABLED */
13139 
13140     /*
13141     * Extract the old set, and then evaluate the result of the
13142     * expression for all the element in the set. use it to grow
13143     * up a new set.
13144     */
13145     CHECK_TYPE0(XPATH_NODESET);
13146     obj = valuePop(ctxt);
13147     oldset = obj->nodesetval;
13148 
13149     oldnode = ctxt->context->node;
13150     oldDoc = ctxt->context->doc;
13151     ctxt->context->node = NULL;
13152 
13153     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13154 	ctxt->context->contextSize = 0;
13155 	ctxt->context->proximityPosition = 0;
13156 	/* QUESTION TODO: Why was this code commented out?
13157 	    if (op->ch2 != -1)
13158 		total +=
13159 		    xmlXPathCompOpEval(ctxt,
13160 			&comp->steps[op->ch2]);
13161 	    CHECK_ERROR0;
13162 	    res = valuePop(ctxt);
13163 	    if (res != NULL)
13164 		xmlXPathFreeObject(res);
13165 	*/
13166 	valuePush(ctxt, obj);
13167 	ctxt->context->node = oldnode;
13168 	CHECK_ERROR0;
13169     } else {
13170 	xmlNodeSetPtr newset;
13171 	xmlXPathObjectPtr tmp = NULL;
13172 	/*
13173 	* Initialize the new set.
13174 	* Also set the xpath document in case things like
13175 	* key() evaluation are attempted on the predicate
13176 	*/
13177 	newset = xmlXPathNodeSetCreate(NULL);
13178         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13179 
13180 	for (i = 0; i < oldset->nodeNr; i++) {
13181 	    /*
13182 	    * Run the evaluation with a node list made of
13183 	    * a single item in the nodeset.
13184 	    */
13185 	    ctxt->context->node = oldset->nodeTab[i];
13186 	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13187 		(oldset->nodeTab[i]->doc != NULL))
13188 		ctxt->context->doc = oldset->nodeTab[i]->doc;
13189 	    if (tmp == NULL) {
13190 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13191 		    ctxt->context->node);
13192 	    } else {
13193 		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13194 		                             ctxt->context->node) < 0) {
13195 		    ctxt->error = XPATH_MEMORY_ERROR;
13196 		}
13197 	    }
13198 	    valuePush(ctxt, tmp);
13199 	    ctxt->context->contextSize = oldset->nodeNr;
13200 	    ctxt->context->proximityPosition = i + 1;
13201 	    if (op->ch2 != -1)
13202 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13203 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13204 		xmlXPathFreeNodeSet(newset);
13205 		xmlXPathFreeObject(obj);
13206 		return(0);
13207 	    }
13208 	    /*
13209 	    * The result of the evaluation needs to be tested to
13210 	    * decide whether the filter succeeded or not
13211 	    */
13212 	    res = valuePop(ctxt);
13213 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13214 		if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13215 		    ctxt->error = XPATH_MEMORY_ERROR;
13216 	    }
13217 	    /*
13218 	    * Cleanup
13219 	    */
13220 	    if (res != NULL) {
13221 		xmlXPathReleaseObject(ctxt->context, res);
13222 	    }
13223 	    if (ctxt->value == tmp) {
13224 		valuePop(ctxt);
13225 		/*
13226 		* Don't free the temporary nodeset
13227 		* in order to avoid massive recreation inside this
13228 		* loop.
13229 		*/
13230 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13231 	    } else
13232 		tmp = NULL;
13233 	    ctxt->context->node = NULL;
13234 	    /*
13235 	    * Only put the first node in the result, then leave.
13236 	    */
13237 	    if (newset->nodeNr > 0) {
13238 		*first = *(newset->nodeTab);
13239 		break;
13240 	    }
13241 	}
13242 	if (tmp != NULL) {
13243 	    xmlXPathReleaseObject(ctxt->context, tmp);
13244 	}
13245 	/*
13246 	* The result is used as the new evaluation set.
13247 	*/
13248 	xmlXPathReleaseObject(ctxt->context, obj);
13249 	ctxt->context->node = NULL;
13250 	ctxt->context->contextSize = -1;
13251 	ctxt->context->proximityPosition = -1;
13252 	/* may want to move this past the '}' later */
13253 	ctxt->context->doc = oldDoc;
13254 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13255     }
13256     ctxt->context->node = oldnode;
13257     return(total);
13258 }
13259 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13260 
13261 /**
13262  * xmlXPathCompOpEval:
13263  * @ctxt:  the XPath parser context with the compiled expression
13264  * @op:  an XPath compiled operation
13265  *
13266  * Evaluate the Precompiled XPath operation
13267  * Returns the number of nodes traversed
13268  */
13269 static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op)13270 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13271 {
13272     int total = 0;
13273     int equal, ret;
13274     xmlXPathCompExprPtr comp;
13275     xmlXPathObjectPtr arg1, arg2;
13276     xmlNodePtr bak;
13277     xmlDocPtr bakd;
13278     int pp;
13279     int cs;
13280 
13281     CHECK_ERROR0;
13282     comp = ctxt->comp;
13283     switch (op->op) {
13284         case XPATH_OP_END:
13285             return (0);
13286         case XPATH_OP_AND:
13287 	    bakd = ctxt->context->doc;
13288 	    bak = ctxt->context->node;
13289 	    pp = ctxt->context->proximityPosition;
13290 	    cs = ctxt->context->contextSize;
13291             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13292 	    CHECK_ERROR0;
13293             xmlXPathBooleanFunction(ctxt, 1);
13294             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13295                 return (total);
13296             arg2 = valuePop(ctxt);
13297 	    ctxt->context->doc = bakd;
13298 	    ctxt->context->node = bak;
13299 	    ctxt->context->proximityPosition = pp;
13300 	    ctxt->context->contextSize = cs;
13301             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13302 	    if (ctxt->error) {
13303 		xmlXPathFreeObject(arg2);
13304 		return(0);
13305 	    }
13306             xmlXPathBooleanFunction(ctxt, 1);
13307             arg1 = valuePop(ctxt);
13308             arg1->boolval &= arg2->boolval;
13309             valuePush(ctxt, arg1);
13310 	    xmlXPathReleaseObject(ctxt->context, arg2);
13311             return (total);
13312         case XPATH_OP_OR:
13313 	    bakd = ctxt->context->doc;
13314 	    bak = ctxt->context->node;
13315 	    pp = ctxt->context->proximityPosition;
13316 	    cs = ctxt->context->contextSize;
13317             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13318 	    CHECK_ERROR0;
13319             xmlXPathBooleanFunction(ctxt, 1);
13320             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13321                 return (total);
13322             arg2 = valuePop(ctxt);
13323 	    ctxt->context->doc = bakd;
13324 	    ctxt->context->node = bak;
13325 	    ctxt->context->proximityPosition = pp;
13326 	    ctxt->context->contextSize = cs;
13327             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13328 	    if (ctxt->error) {
13329 		xmlXPathFreeObject(arg2);
13330 		return(0);
13331 	    }
13332             xmlXPathBooleanFunction(ctxt, 1);
13333             arg1 = valuePop(ctxt);
13334             arg1->boolval |= arg2->boolval;
13335             valuePush(ctxt, arg1);
13336 	    xmlXPathReleaseObject(ctxt->context, arg2);
13337             return (total);
13338         case XPATH_OP_EQUAL:
13339 	    bakd = ctxt->context->doc;
13340 	    bak = ctxt->context->node;
13341 	    pp = ctxt->context->proximityPosition;
13342 	    cs = ctxt->context->contextSize;
13343             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13344 	    CHECK_ERROR0;
13345 	    ctxt->context->doc = bakd;
13346 	    ctxt->context->node = bak;
13347 	    ctxt->context->proximityPosition = pp;
13348 	    ctxt->context->contextSize = cs;
13349             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13350 	    CHECK_ERROR0;
13351 	    if (op->value)
13352 		equal = xmlXPathEqualValues(ctxt);
13353 	    else
13354 		equal = xmlXPathNotEqualValues(ctxt);
13355 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13356             return (total);
13357         case XPATH_OP_CMP:
13358 	    bakd = ctxt->context->doc;
13359 	    bak = ctxt->context->node;
13360 	    pp = ctxt->context->proximityPosition;
13361 	    cs = ctxt->context->contextSize;
13362             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13363 	    CHECK_ERROR0;
13364 	    ctxt->context->doc = bakd;
13365 	    ctxt->context->node = bak;
13366 	    ctxt->context->proximityPosition = pp;
13367 	    ctxt->context->contextSize = cs;
13368             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13369 	    CHECK_ERROR0;
13370             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13371 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13372             return (total);
13373         case XPATH_OP_PLUS:
13374 	    bakd = ctxt->context->doc;
13375 	    bak = ctxt->context->node;
13376 	    pp = ctxt->context->proximityPosition;
13377 	    cs = ctxt->context->contextSize;
13378             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13379 	    CHECK_ERROR0;
13380             if (op->ch2 != -1) {
13381 		ctxt->context->doc = bakd;
13382 		ctxt->context->node = bak;
13383 		ctxt->context->proximityPosition = pp;
13384 		ctxt->context->contextSize = cs;
13385                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13386 	    }
13387 	    CHECK_ERROR0;
13388             if (op->value == 0)
13389                 xmlXPathSubValues(ctxt);
13390             else if (op->value == 1)
13391                 xmlXPathAddValues(ctxt);
13392             else if (op->value == 2)
13393                 xmlXPathValueFlipSign(ctxt);
13394             else if (op->value == 3) {
13395                 CAST_TO_NUMBER;
13396                 CHECK_TYPE0(XPATH_NUMBER);
13397             }
13398             return (total);
13399         case XPATH_OP_MULT:
13400 	    bakd = ctxt->context->doc;
13401 	    bak = ctxt->context->node;
13402 	    pp = ctxt->context->proximityPosition;
13403 	    cs = ctxt->context->contextSize;
13404             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13405 	    CHECK_ERROR0;
13406 	    ctxt->context->doc = bakd;
13407 	    ctxt->context->node = bak;
13408 	    ctxt->context->proximityPosition = pp;
13409 	    ctxt->context->contextSize = cs;
13410             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13411 	    CHECK_ERROR0;
13412             if (op->value == 0)
13413                 xmlXPathMultValues(ctxt);
13414             else if (op->value == 1)
13415                 xmlXPathDivValues(ctxt);
13416             else if (op->value == 2)
13417                 xmlXPathModValues(ctxt);
13418             return (total);
13419         case XPATH_OP_UNION:
13420 	    bakd = ctxt->context->doc;
13421 	    bak = ctxt->context->node;
13422 	    pp = ctxt->context->proximityPosition;
13423 	    cs = ctxt->context->contextSize;
13424             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13425 	    CHECK_ERROR0;
13426 	    ctxt->context->doc = bakd;
13427 	    ctxt->context->node = bak;
13428 	    ctxt->context->proximityPosition = pp;
13429 	    ctxt->context->contextSize = cs;
13430             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13431 	    CHECK_ERROR0;
13432             CHECK_TYPE0(XPATH_NODESET);
13433             arg2 = valuePop(ctxt);
13434 
13435             CHECK_TYPE0(XPATH_NODESET);
13436             arg1 = valuePop(ctxt);
13437 
13438 	    if ((arg1->nodesetval == NULL) ||
13439 		((arg2->nodesetval != NULL) &&
13440 		 (arg2->nodesetval->nodeNr != 0)))
13441 	    {
13442 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13443 							arg2->nodesetval);
13444 	    }
13445 
13446             valuePush(ctxt, arg1);
13447 	    xmlXPathReleaseObject(ctxt->context, arg2);
13448             return (total);
13449         case XPATH_OP_ROOT:
13450             xmlXPathRoot(ctxt);
13451             return (total);
13452         case XPATH_OP_NODE:
13453             if (op->ch1 != -1)
13454                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13455 	    CHECK_ERROR0;
13456             if (op->ch2 != -1)
13457                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13458 	    CHECK_ERROR0;
13459 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13460 		ctxt->context->node));
13461             return (total);
13462         case XPATH_OP_RESET:
13463             if (op->ch1 != -1)
13464                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13465 	    CHECK_ERROR0;
13466             if (op->ch2 != -1)
13467                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13468 	    CHECK_ERROR0;
13469             ctxt->context->node = NULL;
13470             return (total);
13471         case XPATH_OP_COLLECT:{
13472                 if (op->ch1 == -1)
13473                     return (total);
13474 
13475                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13476 		CHECK_ERROR0;
13477 
13478                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13479                 return (total);
13480             }
13481         case XPATH_OP_VALUE:
13482             valuePush(ctxt,
13483                       xmlXPathCacheObjectCopy(ctxt->context,
13484 			(xmlXPathObjectPtr) op->value4));
13485             return (total);
13486         case XPATH_OP_VARIABLE:{
13487 		xmlXPathObjectPtr val;
13488 
13489                 if (op->ch1 != -1)
13490                     total +=
13491                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13492                 if (op->value5 == NULL) {
13493 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13494 		    if (val == NULL) {
13495 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13496 			return(0);
13497 		    }
13498                     valuePush(ctxt, val);
13499 		} else {
13500                     const xmlChar *URI;
13501 
13502                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13503                     if (URI == NULL) {
13504                         xmlGenericError(xmlGenericErrorContext,
13505             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13506                                     (char *) op->value4, (char *)op->value5);
13507                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13508                         return (total);
13509                     }
13510 		    val = xmlXPathVariableLookupNS(ctxt->context,
13511                                                        op->value4, URI);
13512 		    if (val == NULL) {
13513 			ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13514 			return(0);
13515 		    }
13516                     valuePush(ctxt, val);
13517                 }
13518                 return (total);
13519             }
13520         case XPATH_OP_FUNCTION:{
13521                 xmlXPathFunction func;
13522                 const xmlChar *oldFunc, *oldFuncURI;
13523 		int i;
13524                 int frame;
13525 
13526                 frame = xmlXPathSetFrame(ctxt);
13527                 if (op->ch1 != -1) {
13528                     total +=
13529                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13530                     if (ctxt->error != XPATH_EXPRESSION_OK) {
13531                         xmlXPathPopFrame(ctxt, frame);
13532                         return (total);
13533                     }
13534                 }
13535 		if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13536 		    xmlGenericError(xmlGenericErrorContext,
13537 			    "xmlXPathCompOpEval: parameter error\n");
13538 		    ctxt->error = XPATH_INVALID_OPERAND;
13539                     xmlXPathPopFrame(ctxt, frame);
13540 		    return (total);
13541 		}
13542 		for (i = 0; i < op->value; i++) {
13543 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13544 			xmlGenericError(xmlGenericErrorContext,
13545 				"xmlXPathCompOpEval: parameter error\n");
13546 			ctxt->error = XPATH_INVALID_OPERAND;
13547                         xmlXPathPopFrame(ctxt, frame);
13548 			return (total);
13549 		    }
13550                 }
13551                 if (op->cache != NULL)
13552                     XML_CAST_FPTR(func) = op->cache;
13553                 else {
13554                     const xmlChar *URI = NULL;
13555 
13556                     if (op->value5 == NULL)
13557                         func =
13558                             xmlXPathFunctionLookup(ctxt->context,
13559                                                    op->value4);
13560                     else {
13561                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
13562                         if (URI == NULL) {
13563                             xmlGenericError(xmlGenericErrorContext,
13564             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13565                                     (char *)op->value4, (char *)op->value5);
13566                             xmlXPathPopFrame(ctxt, frame);
13567                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13568                             return (total);
13569                         }
13570                         func = xmlXPathFunctionLookupNS(ctxt->context,
13571                                                         op->value4, URI);
13572                     }
13573                     if (func == NULL) {
13574                         xmlGenericError(xmlGenericErrorContext,
13575                                 "xmlXPathCompOpEval: function %s not found\n",
13576                                         (char *)op->value4);
13577                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13578                     }
13579                     op->cache = XML_CAST_FPTR(func);
13580                     op->cacheURI = (void *) URI;
13581                 }
13582                 oldFunc = ctxt->context->function;
13583                 oldFuncURI = ctxt->context->functionURI;
13584                 ctxt->context->function = op->value4;
13585                 ctxt->context->functionURI = op->cacheURI;
13586                 func(ctxt, op->value);
13587                 ctxt->context->function = oldFunc;
13588                 ctxt->context->functionURI = oldFuncURI;
13589                 xmlXPathPopFrame(ctxt, frame);
13590                 return (total);
13591             }
13592         case XPATH_OP_ARG:
13593 	    bakd = ctxt->context->doc;
13594 	    bak = ctxt->context->node;
13595 	    pp = ctxt->context->proximityPosition;
13596 	    cs = ctxt->context->contextSize;
13597             if (op->ch1 != -1) {
13598                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13599                 ctxt->context->contextSize = cs;
13600                 ctxt->context->proximityPosition = pp;
13601                 ctxt->context->node = bak;
13602                 ctxt->context->doc = bakd;
13603 	        CHECK_ERROR0;
13604             }
13605             if (op->ch2 != -1) {
13606                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13607                 ctxt->context->contextSize = cs;
13608                 ctxt->context->proximityPosition = pp;
13609                 ctxt->context->node = bak;
13610                 ctxt->context->doc = bakd;
13611 	        CHECK_ERROR0;
13612 	    }
13613             return (total);
13614         case XPATH_OP_PREDICATE:
13615         case XPATH_OP_FILTER:{
13616                 xmlXPathObjectPtr res;
13617                 xmlXPathObjectPtr obj, tmp;
13618                 xmlNodeSetPtr newset = NULL;
13619                 xmlNodeSetPtr oldset;
13620                 xmlNodePtr oldnode;
13621 		xmlDocPtr oldDoc;
13622                 int i;
13623 
13624                 /*
13625                  * Optimization for ()[1] selection i.e. the first elem
13626                  */
13627                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13628 #ifdef XP_OPTIMIZED_FILTER_FIRST
13629 		    /*
13630 		    * FILTER TODO: Can we assume that the inner processing
13631 		    *  will result in an ordered list if we have an
13632 		    *  XPATH_OP_FILTER?
13633 		    *  What about an additional field or flag on
13634 		    *  xmlXPathObject like @sorted ? This way we wouln'd need
13635 		    *  to assume anything, so it would be more robust and
13636 		    *  easier to optimize.
13637 		    */
13638                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13639 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13640 #else
13641 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13642 #endif
13643                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13644                     xmlXPathObjectPtr val;
13645 
13646                     val = comp->steps[op->ch2].value4;
13647                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13648                         (val->floatval == 1.0)) {
13649                         xmlNodePtr first = NULL;
13650 
13651                         total +=
13652                             xmlXPathCompOpEvalFirst(ctxt,
13653                                                     &comp->steps[op->ch1],
13654                                                     &first);
13655 			CHECK_ERROR0;
13656                         /*
13657                          * The nodeset should be in document order,
13658                          * Keep only the first value
13659                          */
13660                         if ((ctxt->value != NULL) &&
13661                             (ctxt->value->type == XPATH_NODESET) &&
13662                             (ctxt->value->nodesetval != NULL) &&
13663                             (ctxt->value->nodesetval->nodeNr > 1))
13664                             ctxt->value->nodesetval->nodeNr = 1;
13665                         return (total);
13666                     }
13667                 }
13668                 /*
13669                  * Optimization for ()[last()] selection i.e. the last elem
13670                  */
13671                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13672                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13673                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13674                     int f = comp->steps[op->ch2].ch1;
13675 
13676                     if ((f != -1) &&
13677                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13678                         (comp->steps[f].value5 == NULL) &&
13679                         (comp->steps[f].value == 0) &&
13680                         (comp->steps[f].value4 != NULL) &&
13681                         (xmlStrEqual
13682                          (comp->steps[f].value4, BAD_CAST "last"))) {
13683                         xmlNodePtr last = NULL;
13684 
13685                         total +=
13686                             xmlXPathCompOpEvalLast(ctxt,
13687                                                    &comp->steps[op->ch1],
13688                                                    &last);
13689 			CHECK_ERROR0;
13690                         /*
13691                          * The nodeset should be in document order,
13692                          * Keep only the last value
13693                          */
13694                         if ((ctxt->value != NULL) &&
13695                             (ctxt->value->type == XPATH_NODESET) &&
13696                             (ctxt->value->nodesetval != NULL) &&
13697                             (ctxt->value->nodesetval->nodeTab != NULL) &&
13698                             (ctxt->value->nodesetval->nodeNr > 1)) {
13699                             ctxt->value->nodesetval->nodeTab[0] =
13700                                 ctxt->value->nodesetval->nodeTab[ctxt->
13701                                                                  value->
13702                                                                  nodesetval->
13703                                                                  nodeNr -
13704                                                                  1];
13705                             ctxt->value->nodesetval->nodeNr = 1;
13706                         }
13707                         return (total);
13708                     }
13709                 }
13710 		/*
13711 		* Process inner predicates first.
13712 		* Example "index[parent::book][1]":
13713 		* ...
13714 		*   PREDICATE   <-- we are here "[1]"
13715 		*     PREDICATE <-- process "[parent::book]" first
13716 		*       SORT
13717 		*         COLLECT  'parent' 'name' 'node' book
13718 		*           NODE
13719 		*     ELEM Object is a number : 1
13720 		*/
13721                 if (op->ch1 != -1)
13722                     total +=
13723                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13724 		CHECK_ERROR0;
13725                 if (op->ch2 == -1)
13726                     return (total);
13727                 if (ctxt->value == NULL)
13728                     return (total);
13729 
13730                 oldnode = ctxt->context->node;
13731 
13732 #ifdef LIBXML_XPTR_ENABLED
13733                 /*
13734                  * Hum are we filtering the result of an XPointer expression
13735                  */
13736                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13737                     xmlLocationSetPtr newlocset = NULL;
13738                     xmlLocationSetPtr oldlocset;
13739 
13740                     /*
13741                      * Extract the old locset, and then evaluate the result of the
13742                      * expression for all the element in the locset. use it to grow
13743                      * up a new locset.
13744                      */
13745                     CHECK_TYPE0(XPATH_LOCATIONSET);
13746                     obj = valuePop(ctxt);
13747                     oldlocset = obj->user;
13748                     ctxt->context->node = NULL;
13749 
13750                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13751                         ctxt->context->contextSize = 0;
13752                         ctxt->context->proximityPosition = 0;
13753                         if (op->ch2 != -1)
13754                             total +=
13755                                 xmlXPathCompOpEval(ctxt,
13756                                                    &comp->steps[op->ch2]);
13757                         res = valuePop(ctxt);
13758                         if (res != NULL) {
13759 			    xmlXPathReleaseObject(ctxt->context, res);
13760 			}
13761                         valuePush(ctxt, obj);
13762                         CHECK_ERROR0;
13763                         return (total);
13764                     }
13765                     newlocset = xmlXPtrLocationSetCreate(NULL);
13766 
13767                     for (i = 0; i < oldlocset->locNr; i++) {
13768                         /*
13769                          * Run the evaluation with a node list made of a
13770                          * single item in the nodelocset.
13771                          */
13772                         ctxt->context->node = oldlocset->locTab[i]->user;
13773                         ctxt->context->contextSize = oldlocset->locNr;
13774                         ctxt->context->proximityPosition = i + 1;
13775 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13776 			    ctxt->context->node);
13777                         valuePush(ctxt, tmp);
13778 
13779                         if (op->ch2 != -1)
13780                             total +=
13781                                 xmlXPathCompOpEval(ctxt,
13782                                                    &comp->steps[op->ch2]);
13783 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13784 			    xmlXPathFreeObject(obj);
13785 			    return(0);
13786 			}
13787 
13788                         /*
13789                          * The result of the evaluation need to be tested to
13790                          * decided whether the filter succeeded or not
13791                          */
13792                         res = valuePop(ctxt);
13793                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13794                             xmlXPtrLocationSetAdd(newlocset,
13795                                                   xmlXPathObjectCopy
13796                                                   (oldlocset->locTab[i]));
13797                         }
13798 
13799                         /*
13800                          * Cleanup
13801                          */
13802                         if (res != NULL) {
13803 			    xmlXPathReleaseObject(ctxt->context, res);
13804 			}
13805                         if (ctxt->value == tmp) {
13806                             res = valuePop(ctxt);
13807 			    xmlXPathReleaseObject(ctxt->context, res);
13808                         }
13809 
13810                         ctxt->context->node = NULL;
13811                     }
13812 
13813                     /*
13814                      * The result is used as the new evaluation locset.
13815                      */
13816 		    xmlXPathReleaseObject(ctxt->context, obj);
13817                     ctxt->context->node = NULL;
13818                     ctxt->context->contextSize = -1;
13819                     ctxt->context->proximityPosition = -1;
13820                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13821                     ctxt->context->node = oldnode;
13822                     return (total);
13823                 }
13824 #endif /* LIBXML_XPTR_ENABLED */
13825 
13826                 /*
13827                  * Extract the old set, and then evaluate the result of the
13828                  * expression for all the element in the set. use it to grow
13829                  * up a new set.
13830                  */
13831                 CHECK_TYPE0(XPATH_NODESET);
13832                 obj = valuePop(ctxt);
13833                 oldset = obj->nodesetval;
13834 
13835                 oldnode = ctxt->context->node;
13836 		oldDoc = ctxt->context->doc;
13837                 ctxt->context->node = NULL;
13838 
13839                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13840                     ctxt->context->contextSize = 0;
13841                     ctxt->context->proximityPosition = 0;
13842 /*
13843                     if (op->ch2 != -1)
13844                         total +=
13845                             xmlXPathCompOpEval(ctxt,
13846                                                &comp->steps[op->ch2]);
13847 		    CHECK_ERROR0;
13848                     res = valuePop(ctxt);
13849                     if (res != NULL)
13850                         xmlXPathFreeObject(res);
13851 */
13852                     valuePush(ctxt, obj);
13853                     ctxt->context->node = oldnode;
13854                     CHECK_ERROR0;
13855                 } else {
13856 		    tmp = NULL;
13857                     /*
13858                      * Initialize the new set.
13859 		     * Also set the xpath document in case things like
13860 		     * key() evaluation are attempted on the predicate
13861                      */
13862                     newset = xmlXPathNodeSetCreate(NULL);
13863 		    /*
13864 		    * SPEC XPath 1.0:
13865 		    *  "For each node in the node-set to be filtered, the
13866 		    *  PredicateExpr is evaluated with that node as the
13867 		    *  context node, with the number of nodes in the
13868 		    *  node-set as the context size, and with the proximity
13869 		    *  position of the node in the node-set with respect to
13870 		    *  the axis as the context position;"
13871 		    * @oldset is the node-set" to be filtered.
13872 		    *
13873 		    * SPEC XPath 1.0:
13874 		    *  "only predicates change the context position and
13875 		    *  context size (see [2.4 Predicates])."
13876 		    * Example:
13877 		    *   node-set  context pos
13878 		    *    nA         1
13879 		    *    nB         2
13880 		    *    nC         3
13881 		    *   After applying predicate [position() > 1] :
13882 		    *   node-set  context pos
13883 		    *    nB         1
13884 		    *    nC         2
13885 		    *
13886 		    * removed the first node in the node-set, then
13887 		    * the context position of the
13888 		    */
13889                     for (i = 0; i < oldset->nodeNr; i++) {
13890                         /*
13891                          * Run the evaluation with a node list made of
13892                          * a single item in the nodeset.
13893                          */
13894                         ctxt->context->node = oldset->nodeTab[i];
13895 			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13896 			    (oldset->nodeTab[i]->doc != NULL))
13897 		            ctxt->context->doc = oldset->nodeTab[i]->doc;
13898 			if (tmp == NULL) {
13899 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13900 				ctxt->context->node);
13901 			} else {
13902 			    if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13903 				               ctxt->context->node) < 0) {
13904 				ctxt->error = XPATH_MEMORY_ERROR;
13905 			    }
13906 			}
13907                         valuePush(ctxt, tmp);
13908                         ctxt->context->contextSize = oldset->nodeNr;
13909                         ctxt->context->proximityPosition = i + 1;
13910 			/*
13911 			* Evaluate the predicate against the context node.
13912 			* Can/should we optimize position() predicates
13913 			* here (e.g. "[1]")?
13914 			*/
13915                         if (op->ch2 != -1)
13916                             total +=
13917                                 xmlXPathCompOpEval(ctxt,
13918                                                    &comp->steps[op->ch2]);
13919 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13920 			    xmlXPathFreeNodeSet(newset);
13921 			    xmlXPathFreeObject(obj);
13922 			    return(0);
13923 			}
13924 
13925                         /*
13926                          * The result of the evaluation needs to be tested to
13927                          * decide whether the filter succeeded or not
13928                          */
13929 			/*
13930 			* OPTIMIZE TODO: Can we use
13931 			* xmlXPathNodeSetAdd*Unique()* instead?
13932 			*/
13933                         res = valuePop(ctxt);
13934                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13935                             if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13936 			        < 0)
13937 				ctxt->error = XPATH_MEMORY_ERROR;
13938                         }
13939 
13940                         /*
13941                          * Cleanup
13942                          */
13943                         if (res != NULL) {
13944 			    xmlXPathReleaseObject(ctxt->context, res);
13945 			}
13946                         if (ctxt->value == tmp) {
13947                             valuePop(ctxt);
13948 			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
13949 			    /*
13950 			    * Don't free the temporary nodeset
13951 			    * in order to avoid massive recreation inside this
13952 			    * loop.
13953 			    */
13954                         } else
13955 			    tmp = NULL;
13956                         ctxt->context->node = NULL;
13957                     }
13958 		    if (tmp != NULL)
13959 			xmlXPathReleaseObject(ctxt->context, tmp);
13960                     /*
13961                      * The result is used as the new evaluation set.
13962                      */
13963 		    xmlXPathReleaseObject(ctxt->context, obj);
13964                     ctxt->context->node = NULL;
13965                     ctxt->context->contextSize = -1;
13966                     ctxt->context->proximityPosition = -1;
13967 		    /* may want to move this past the '}' later */
13968 		    ctxt->context->doc = oldDoc;
13969 		    valuePush(ctxt,
13970 			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13971                 }
13972                 ctxt->context->node = oldnode;
13973                 return (total);
13974             }
13975         case XPATH_OP_SORT:
13976             if (op->ch1 != -1)
13977                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13978 	    CHECK_ERROR0;
13979             if ((ctxt->value != NULL) &&
13980                 (ctxt->value->type == XPATH_NODESET) &&
13981                 (ctxt->value->nodesetval != NULL) &&
13982 		(ctxt->value->nodesetval->nodeNr > 1))
13983 	    {
13984                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13985 	    }
13986             return (total);
13987 #ifdef LIBXML_XPTR_ENABLED
13988         case XPATH_OP_RANGETO:{
13989                 xmlXPathObjectPtr range;
13990                 xmlXPathObjectPtr res, obj;
13991                 xmlXPathObjectPtr tmp;
13992                 xmlLocationSetPtr newlocset = NULL;
13993 		    xmlLocationSetPtr oldlocset;
13994                 xmlNodeSetPtr oldset;
13995                 int i, j;
13996 
13997                 if (op->ch1 != -1)
13998                     total +=
13999                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
14000                 if (op->ch2 == -1)
14001                     return (total);
14002 
14003                 if (ctxt->value->type == XPATH_LOCATIONSET) {
14004                     /*
14005                      * Extract the old locset, and then evaluate the result of the
14006                      * expression for all the element in the locset. use it to grow
14007                      * up a new locset.
14008                      */
14009                     CHECK_TYPE0(XPATH_LOCATIONSET);
14010                     obj = valuePop(ctxt);
14011                     oldlocset = obj->user;
14012 
14013                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
14014 		        ctxt->context->node = NULL;
14015                         ctxt->context->contextSize = 0;
14016                         ctxt->context->proximityPosition = 0;
14017                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
14018                         res = valuePop(ctxt);
14019                         if (res != NULL) {
14020 			    xmlXPathReleaseObject(ctxt->context, res);
14021 			}
14022                         valuePush(ctxt, obj);
14023                         CHECK_ERROR0;
14024                         return (total);
14025                     }
14026                     newlocset = xmlXPtrLocationSetCreate(NULL);
14027 
14028                     for (i = 0; i < oldlocset->locNr; i++) {
14029                         /*
14030                          * Run the evaluation with a node list made of a
14031                          * single item in the nodelocset.
14032                          */
14033                         ctxt->context->node = oldlocset->locTab[i]->user;
14034                         ctxt->context->contextSize = oldlocset->locNr;
14035                         ctxt->context->proximityPosition = i + 1;
14036 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14037 			    ctxt->context->node);
14038                         valuePush(ctxt, tmp);
14039 
14040                         if (op->ch2 != -1)
14041                             total +=
14042                                 xmlXPathCompOpEval(ctxt,
14043                                                    &comp->steps[op->ch2]);
14044 			if (ctxt->error != XPATH_EXPRESSION_OK) {
14045 			    xmlXPathFreeObject(obj);
14046 			    return(0);
14047 			}
14048 
14049                         res = valuePop(ctxt);
14050 			if (res->type == XPATH_LOCATIONSET) {
14051 			    xmlLocationSetPtr rloc =
14052 			        (xmlLocationSetPtr)res->user;
14053 			    for (j=0; j<rloc->locNr; j++) {
14054 			        range = xmlXPtrNewRange(
14055 				  oldlocset->locTab[i]->user,
14056 				  oldlocset->locTab[i]->index,
14057 				  rloc->locTab[j]->user2,
14058 				  rloc->locTab[j]->index2);
14059 				if (range != NULL) {
14060 				    xmlXPtrLocationSetAdd(newlocset, range);
14061 				}
14062 			    }
14063 			} else {
14064 			    range = xmlXPtrNewRangeNodeObject(
14065 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
14066                             if (range != NULL) {
14067                                 xmlXPtrLocationSetAdd(newlocset,range);
14068 			    }
14069                         }
14070 
14071                         /*
14072                          * Cleanup
14073                          */
14074                         if (res != NULL) {
14075 			    xmlXPathReleaseObject(ctxt->context, res);
14076 			}
14077                         if (ctxt->value == tmp) {
14078                             res = valuePop(ctxt);
14079 			    xmlXPathReleaseObject(ctxt->context, res);
14080                         }
14081 
14082                         ctxt->context->node = NULL;
14083                     }
14084 		} else {	/* Not a location set */
14085                     CHECK_TYPE0(XPATH_NODESET);
14086                     obj = valuePop(ctxt);
14087                     oldset = obj->nodesetval;
14088                     ctxt->context->node = NULL;
14089 
14090                     newlocset = xmlXPtrLocationSetCreate(NULL);
14091 
14092                     if (oldset != NULL) {
14093                         for (i = 0; i < oldset->nodeNr; i++) {
14094                             /*
14095                              * Run the evaluation with a node list made of a single item
14096                              * in the nodeset.
14097                              */
14098                             ctxt->context->node = oldset->nodeTab[i];
14099 			    /*
14100 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
14101 			    */
14102 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14103 				ctxt->context->node);
14104                             valuePush(ctxt, tmp);
14105 
14106                             if (op->ch2 != -1)
14107                                 total +=
14108                                     xmlXPathCompOpEval(ctxt,
14109                                                    &comp->steps[op->ch2]);
14110 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
14111 				xmlXPathFreeObject(obj);
14112 				return(0);
14113 			    }
14114 
14115                             res = valuePop(ctxt);
14116                             range =
14117                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14118                                                       res);
14119                             if (range != NULL) {
14120                                 xmlXPtrLocationSetAdd(newlocset, range);
14121                             }
14122 
14123                             /*
14124                              * Cleanup
14125                              */
14126                             if (res != NULL) {
14127 				xmlXPathReleaseObject(ctxt->context, res);
14128 			    }
14129                             if (ctxt->value == tmp) {
14130                                 res = valuePop(ctxt);
14131 				xmlXPathReleaseObject(ctxt->context, res);
14132                             }
14133 
14134                             ctxt->context->node = NULL;
14135                         }
14136                     }
14137                 }
14138 
14139                 /*
14140                  * The result is used as the new evaluation set.
14141                  */
14142 		xmlXPathReleaseObject(ctxt->context, obj);
14143                 ctxt->context->node = NULL;
14144                 ctxt->context->contextSize = -1;
14145                 ctxt->context->proximityPosition = -1;
14146                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
14147                 return (total);
14148             }
14149 #endif /* LIBXML_XPTR_ENABLED */
14150     }
14151     xmlGenericError(xmlGenericErrorContext,
14152                     "XPath: unknown precompiled operation %d\n", op->op);
14153     ctxt->error = XPATH_INVALID_OPERAND;
14154     return (total);
14155 }
14156 
14157 /**
14158  * xmlXPathCompOpEvalToBoolean:
14159  * @ctxt:  the XPath parser context
14160  *
14161  * Evaluates if the expression evaluates to true.
14162  *
14163  * Returns 1 if true, 0 if false and -1 on API or internal errors.
14164  */
14165 static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int isPredicate)14166 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14167 			    xmlXPathStepOpPtr op,
14168 			    int isPredicate)
14169 {
14170     xmlXPathObjectPtr resObj = NULL;
14171 
14172 start:
14173     /* comp = ctxt->comp; */
14174     switch (op->op) {
14175         case XPATH_OP_END:
14176             return (0);
14177 	case XPATH_OP_VALUE:
14178 	    resObj = (xmlXPathObjectPtr) op->value4;
14179 	    if (isPredicate)
14180 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14181 	    return(xmlXPathCastToBoolean(resObj));
14182 	case XPATH_OP_SORT:
14183 	    /*
14184 	    * We don't need sorting for boolean results. Skip this one.
14185 	    */
14186             if (op->ch1 != -1) {
14187 		op = &ctxt->comp->steps[op->ch1];
14188 		goto start;
14189 	    }
14190 	    return(0);
14191 	case XPATH_OP_COLLECT:
14192 	    if (op->ch1 == -1)
14193 		return(0);
14194 
14195             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14196 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14197 		return(-1);
14198 
14199             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14200 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14201 		return(-1);
14202 
14203 	    resObj = valuePop(ctxt);
14204 	    if (resObj == NULL)
14205 		return(-1);
14206 	    break;
14207 	default:
14208 	    /*
14209 	    * Fallback to call xmlXPathCompOpEval().
14210 	    */
14211 	    xmlXPathCompOpEval(ctxt, op);
14212 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14213 		return(-1);
14214 
14215 	    resObj = valuePop(ctxt);
14216 	    if (resObj == NULL)
14217 		return(-1);
14218 	    break;
14219     }
14220 
14221     if (resObj) {
14222 	int res;
14223 
14224 	if (resObj->type == XPATH_BOOLEAN) {
14225 	    res = resObj->boolval;
14226 	} else if (isPredicate) {
14227 	    /*
14228 	    * For predicates a result of type "number" is handled
14229 	    * differently:
14230 	    * SPEC XPath 1.0:
14231 	    * "If the result is a number, the result will be converted
14232 	    *  to true if the number is equal to the context position
14233 	    *  and will be converted to false otherwise;"
14234 	    */
14235 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14236 	} else {
14237 	    res = xmlXPathCastToBoolean(resObj);
14238 	}
14239 	xmlXPathReleaseObject(ctxt->context, resObj);
14240 	return(res);
14241     }
14242 
14243     return(0);
14244 }
14245 
14246 #ifdef XPATH_STREAMING
14247 /**
14248  * xmlXPathRunStreamEval:
14249  * @ctxt:  the XPath parser context with the compiled expression
14250  *
14251  * Evaluate the Precompiled Streamable XPath expression in the given context.
14252  */
14253 static int
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt,xmlPatternPtr comp,xmlXPathObjectPtr * resultSeq,int toBool)14254 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14255 		      xmlXPathObjectPtr *resultSeq, int toBool)
14256 {
14257     int max_depth, min_depth;
14258     int from_root;
14259     int ret, depth;
14260     int eval_all_nodes;
14261     xmlNodePtr cur = NULL, limit = NULL;
14262     xmlStreamCtxtPtr patstream = NULL;
14263 
14264     int nb_nodes = 0;
14265 
14266     if ((ctxt == NULL) || (comp == NULL))
14267         return(-1);
14268     max_depth = xmlPatternMaxDepth(comp);
14269     if (max_depth == -1)
14270         return(-1);
14271     if (max_depth == -2)
14272         max_depth = 10000;
14273     min_depth = xmlPatternMinDepth(comp);
14274     if (min_depth == -1)
14275         return(-1);
14276     from_root = xmlPatternFromRoot(comp);
14277     if (from_root < 0)
14278         return(-1);
14279 #if 0
14280     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14281 #endif
14282 
14283     if (! toBool) {
14284 	if (resultSeq == NULL)
14285 	    return(-1);
14286 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14287 	if (*resultSeq == NULL)
14288 	    return(-1);
14289     }
14290 
14291     /*
14292      * handle the special cases of "/" amd "." being matched
14293      */
14294     if (min_depth == 0) {
14295 	if (from_root) {
14296 	    /* Select "/" */
14297 	    if (toBool)
14298 		return(1);
14299 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14300 		                     (xmlNodePtr) ctxt->doc);
14301 	} else {
14302 	    /* Select "self::node()" */
14303 	    if (toBool)
14304 		return(1);
14305 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14306 	}
14307     }
14308     if (max_depth == 0) {
14309 	return(0);
14310     }
14311 
14312     if (from_root) {
14313         cur = (xmlNodePtr)ctxt->doc;
14314     } else if (ctxt->node != NULL) {
14315         switch (ctxt->node->type) {
14316             case XML_ELEMENT_NODE:
14317             case XML_DOCUMENT_NODE:
14318             case XML_DOCUMENT_FRAG_NODE:
14319             case XML_HTML_DOCUMENT_NODE:
14320 #ifdef LIBXML_DOCB_ENABLED
14321             case XML_DOCB_DOCUMENT_NODE:
14322 #endif
14323 	        cur = ctxt->node;
14324 		break;
14325             case XML_ATTRIBUTE_NODE:
14326             case XML_TEXT_NODE:
14327             case XML_CDATA_SECTION_NODE:
14328             case XML_ENTITY_REF_NODE:
14329             case XML_ENTITY_NODE:
14330             case XML_PI_NODE:
14331             case XML_COMMENT_NODE:
14332             case XML_NOTATION_NODE:
14333             case XML_DTD_NODE:
14334             case XML_DOCUMENT_TYPE_NODE:
14335             case XML_ELEMENT_DECL:
14336             case XML_ATTRIBUTE_DECL:
14337             case XML_ENTITY_DECL:
14338             case XML_NAMESPACE_DECL:
14339             case XML_XINCLUDE_START:
14340             case XML_XINCLUDE_END:
14341 		break;
14342 	}
14343 	limit = cur;
14344     }
14345     if (cur == NULL) {
14346         return(0);
14347     }
14348 
14349     patstream = xmlPatternGetStreamCtxt(comp);
14350     if (patstream == NULL) {
14351 	/*
14352 	* QUESTION TODO: Is this an error?
14353 	*/
14354 	return(0);
14355     }
14356 
14357     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14358 
14359     if (from_root) {
14360 	ret = xmlStreamPush(patstream, NULL, NULL);
14361 	if (ret < 0) {
14362 	} else if (ret == 1) {
14363 	    if (toBool)
14364 		goto return_1;
14365 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14366 	}
14367     }
14368     depth = 0;
14369     goto scan_children;
14370 next_node:
14371     do {
14372         nb_nodes++;
14373 
14374 	switch (cur->type) {
14375 	    case XML_ELEMENT_NODE:
14376 	    case XML_TEXT_NODE:
14377 	    case XML_CDATA_SECTION_NODE:
14378 	    case XML_COMMENT_NODE:
14379 	    case XML_PI_NODE:
14380 		if (cur->type == XML_ELEMENT_NODE) {
14381 		    ret = xmlStreamPush(patstream, cur->name,
14382 				(cur->ns ? cur->ns->href : NULL));
14383 		} else if (eval_all_nodes)
14384 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14385 		else
14386 		    break;
14387 
14388 		if (ret < 0) {
14389 		    /* NOP. */
14390 		} else if (ret == 1) {
14391 		    if (toBool)
14392 			goto return_1;
14393 		    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14394 		        < 0) {
14395 			ctxt->lastError.domain = XML_FROM_XPATH;
14396 			ctxt->lastError.code = XML_ERR_NO_MEMORY;
14397 		    }
14398 		}
14399 		if ((cur->children == NULL) || (depth >= max_depth)) {
14400 		    ret = xmlStreamPop(patstream);
14401 		    while (cur->next != NULL) {
14402 			cur = cur->next;
14403 			if ((cur->type != XML_ENTITY_DECL) &&
14404 			    (cur->type != XML_DTD_NODE))
14405 			    goto next_node;
14406 		    }
14407 		}
14408 	    default:
14409 		break;
14410 	}
14411 
14412 scan_children:
14413 	if (cur->type == XML_NAMESPACE_DECL) break;
14414 	if ((cur->children != NULL) && (depth < max_depth)) {
14415 	    /*
14416 	     * Do not descend on entities declarations
14417 	     */
14418 	    if (cur->children->type != XML_ENTITY_DECL) {
14419 		cur = cur->children;
14420 		depth++;
14421 		/*
14422 		 * Skip DTDs
14423 		 */
14424 		if (cur->type != XML_DTD_NODE)
14425 		    continue;
14426 	    }
14427 	}
14428 
14429 	if (cur == limit)
14430 	    break;
14431 
14432 	while (cur->next != NULL) {
14433 	    cur = cur->next;
14434 	    if ((cur->type != XML_ENTITY_DECL) &&
14435 		(cur->type != XML_DTD_NODE))
14436 		goto next_node;
14437 	}
14438 
14439 	do {
14440 	    cur = cur->parent;
14441 	    depth--;
14442 	    if ((cur == NULL) || (cur == limit))
14443 	        goto done;
14444 	    if (cur->type == XML_ELEMENT_NODE) {
14445 		ret = xmlStreamPop(patstream);
14446 	    } else if ((eval_all_nodes) &&
14447 		((cur->type == XML_TEXT_NODE) ||
14448 		 (cur->type == XML_CDATA_SECTION_NODE) ||
14449 		 (cur->type == XML_COMMENT_NODE) ||
14450 		 (cur->type == XML_PI_NODE)))
14451 	    {
14452 		ret = xmlStreamPop(patstream);
14453 	    }
14454 	    if (cur->next != NULL) {
14455 		cur = cur->next;
14456 		break;
14457 	    }
14458 	} while (cur != NULL);
14459 
14460     } while ((cur != NULL) && (depth >= 0));
14461 
14462 done:
14463 
14464 #if 0
14465     printf("stream eval: checked %d nodes selected %d\n",
14466            nb_nodes, retObj->nodesetval->nodeNr);
14467 #endif
14468 
14469     if (patstream)
14470 	xmlFreeStreamCtxt(patstream);
14471     return(0);
14472 
14473 return_1:
14474     if (patstream)
14475 	xmlFreeStreamCtxt(patstream);
14476     return(1);
14477 }
14478 #endif /* XPATH_STREAMING */
14479 
14480 /**
14481  * xmlXPathRunEval:
14482  * @ctxt:  the XPath parser context with the compiled expression
14483  * @toBool:  evaluate to a boolean result
14484  *
14485  * Evaluate the Precompiled XPath expression in the given context.
14486  */
14487 static int
xmlXPathRunEval(xmlXPathParserContextPtr ctxt,int toBool)14488 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14489 {
14490     xmlXPathCompExprPtr comp;
14491 
14492     if ((ctxt == NULL) || (ctxt->comp == NULL))
14493 	return(-1);
14494 
14495     if (ctxt->valueTab == NULL) {
14496 	/* Allocate the value stack */
14497 	ctxt->valueTab = (xmlXPathObjectPtr *)
14498 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14499 	if (ctxt->valueTab == NULL) {
14500 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14501 	    xmlFree(ctxt);
14502 	}
14503 	ctxt->valueNr = 0;
14504 	ctxt->valueMax = 10;
14505 	ctxt->value = NULL;
14506         ctxt->valueFrame = 0;
14507     }
14508 #ifdef XPATH_STREAMING
14509     if (ctxt->comp->stream) {
14510 	int res;
14511 
14512 	if (toBool) {
14513 	    /*
14514 	    * Evaluation to boolean result.
14515 	    */
14516 	    res = xmlXPathRunStreamEval(ctxt->context,
14517 		ctxt->comp->stream, NULL, 1);
14518 	    if (res != -1)
14519 		return(res);
14520 	} else {
14521 	    xmlXPathObjectPtr resObj = NULL;
14522 
14523 	    /*
14524 	    * Evaluation to a sequence.
14525 	    */
14526 	    res = xmlXPathRunStreamEval(ctxt->context,
14527 		ctxt->comp->stream, &resObj, 0);
14528 
14529 	    if ((res != -1) && (resObj != NULL)) {
14530 		valuePush(ctxt, resObj);
14531 		return(0);
14532 	    }
14533 	    if (resObj != NULL)
14534 		xmlXPathReleaseObject(ctxt->context, resObj);
14535 	}
14536 	/*
14537 	* QUESTION TODO: This falls back to normal XPath evaluation
14538 	* if res == -1. Is this intended?
14539 	*/
14540     }
14541 #endif
14542     comp = ctxt->comp;
14543     if (comp->last < 0) {
14544 	xmlGenericError(xmlGenericErrorContext,
14545 	    "xmlXPathRunEval: last is less than zero\n");
14546 	return(-1);
14547     }
14548     if (toBool)
14549 	return(xmlXPathCompOpEvalToBoolean(ctxt,
14550 	    &comp->steps[comp->last], 0));
14551     else
14552 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14553 
14554     return(0);
14555 }
14556 
14557 /************************************************************************
14558  *									*
14559  *			Public interfaces				*
14560  *									*
14561  ************************************************************************/
14562 
14563 /**
14564  * xmlXPathEvalPredicate:
14565  * @ctxt:  the XPath context
14566  * @res:  the Predicate Expression evaluation result
14567  *
14568  * Evaluate a predicate result for the current node.
14569  * A PredicateExpr is evaluated by evaluating the Expr and converting
14570  * the result to a boolean. If the result is a number, the result will
14571  * be converted to true if the number is equal to the position of the
14572  * context node in the context node list (as returned by the position
14573  * function) and will be converted to false otherwise; if the result
14574  * is not a number, then the result will be converted as if by a call
14575  * to the boolean function.
14576  *
14577  * Returns 1 if predicate is true, 0 otherwise
14578  */
14579 int
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt,xmlXPathObjectPtr res)14580 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14581     if ((ctxt == NULL) || (res == NULL)) return(0);
14582     switch (res->type) {
14583         case XPATH_BOOLEAN:
14584 	    return(res->boolval);
14585         case XPATH_NUMBER:
14586 	    return(res->floatval == ctxt->proximityPosition);
14587         case XPATH_NODESET:
14588         case XPATH_XSLT_TREE:
14589 	    if (res->nodesetval == NULL)
14590 		return(0);
14591 	    return(res->nodesetval->nodeNr != 0);
14592         case XPATH_STRING:
14593 	    return((res->stringval != NULL) &&
14594 	           (xmlStrlen(res->stringval) != 0));
14595         default:
14596 	    STRANGE
14597     }
14598     return(0);
14599 }
14600 
14601 /**
14602  * xmlXPathEvaluatePredicateResult:
14603  * @ctxt:  the XPath Parser context
14604  * @res:  the Predicate Expression evaluation result
14605  *
14606  * Evaluate a predicate result for the current node.
14607  * A PredicateExpr is evaluated by evaluating the Expr and converting
14608  * the result to a boolean. If the result is a number, the result will
14609  * be converted to true if the number is equal to the position of the
14610  * context node in the context node list (as returned by the position
14611  * function) and will be converted to false otherwise; if the result
14612  * is not a number, then the result will be converted as if by a call
14613  * to the boolean function.
14614  *
14615  * Returns 1 if predicate is true, 0 otherwise
14616  */
14617 int
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr res)14618 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14619                                 xmlXPathObjectPtr res) {
14620     if ((ctxt == NULL) || (res == NULL)) return(0);
14621     switch (res->type) {
14622         case XPATH_BOOLEAN:
14623 	    return(res->boolval);
14624         case XPATH_NUMBER:
14625 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14626 	    return((res->floatval == ctxt->context->proximityPosition) &&
14627 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14628 #else
14629 	    return(res->floatval == ctxt->context->proximityPosition);
14630 #endif
14631         case XPATH_NODESET:
14632         case XPATH_XSLT_TREE:
14633 	    if (res->nodesetval == NULL)
14634 		return(0);
14635 	    return(res->nodesetval->nodeNr != 0);
14636         case XPATH_STRING:
14637 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
14638 #ifdef LIBXML_XPTR_ENABLED
14639 	case XPATH_LOCATIONSET:{
14640 	    xmlLocationSetPtr ptr = res->user;
14641 	    if (ptr == NULL)
14642 	        return(0);
14643 	    return (ptr->locNr != 0);
14644 	    }
14645 #endif
14646         default:
14647 	    STRANGE
14648     }
14649     return(0);
14650 }
14651 
14652 #ifdef XPATH_STREAMING
14653 /**
14654  * xmlXPathTryStreamCompile:
14655  * @ctxt: an XPath context
14656  * @str:  the XPath expression
14657  *
14658  * Try to compile the XPath expression as a streamable subset.
14659  *
14660  * Returns the compiled expression or NULL if failed to compile.
14661  */
14662 static xmlXPathCompExprPtr
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14663 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14664     /*
14665      * Optimization: use streaming patterns when the XPath expression can
14666      * be compiled to a stream lookup
14667      */
14668     xmlPatternPtr stream;
14669     xmlXPathCompExprPtr comp;
14670     xmlDictPtr dict = NULL;
14671     const xmlChar **namespaces = NULL;
14672     xmlNsPtr ns;
14673     int i, j;
14674 
14675     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14676         (!xmlStrchr(str, '@'))) {
14677 	const xmlChar *tmp;
14678 
14679 	/*
14680 	 * We don't try to handle expressions using the verbose axis
14681 	 * specifiers ("::"), just the simplied form at this point.
14682 	 * Additionally, if there is no list of namespaces available and
14683 	 *  there's a ":" in the expression, indicating a prefixed QName,
14684 	 *  then we won't try to compile either. xmlPatterncompile() needs
14685 	 *  to have a list of namespaces at compilation time in order to
14686 	 *  compile prefixed name tests.
14687 	 */
14688 	tmp = xmlStrchr(str, ':');
14689 	if ((tmp != NULL) &&
14690 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14691 	    return(NULL);
14692 
14693 	if (ctxt != NULL) {
14694 	    dict = ctxt->dict;
14695 	    if (ctxt->nsNr > 0) {
14696 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14697 		if (namespaces == NULL) {
14698 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14699 		    return(NULL);
14700 		}
14701 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14702 		    ns = ctxt->namespaces[j];
14703 		    namespaces[i++] = ns->href;
14704 		    namespaces[i++] = ns->prefix;
14705 		}
14706 		namespaces[i++] = NULL;
14707 		namespaces[i] = NULL;
14708 	    }
14709 	}
14710 
14711 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14712 			&namespaces[0]);
14713 	if (namespaces != NULL) {
14714 	    xmlFree((xmlChar **)namespaces);
14715 	}
14716 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14717 	    comp = xmlXPathNewCompExpr();
14718 	    if (comp == NULL) {
14719 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14720 		return(NULL);
14721 	    }
14722 	    comp->stream = stream;
14723 	    comp->dict = dict;
14724 	    if (comp->dict)
14725 		xmlDictReference(comp->dict);
14726 	    return(comp);
14727 	}
14728 	xmlFreePattern(stream);
14729     }
14730     return(NULL);
14731 }
14732 #endif /* XPATH_STREAMING */
14733 
14734 static void
xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op)14735 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14736 {
14737     /*
14738     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14739     * internal representation.
14740     */
14741 
14742     if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14743         (op->ch1 != -1) &&
14744         (op->ch2 == -1 /* no predicate */))
14745     {
14746         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14747 
14748         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14749             ((xmlXPathAxisVal) prevop->value ==
14750                 AXIS_DESCENDANT_OR_SELF) &&
14751             (prevop->ch2 == -1) &&
14752             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14753             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14754         {
14755             /*
14756             * This is a "descendant-or-self::node()" without predicates.
14757             * Try to eliminate it.
14758             */
14759 
14760             switch ((xmlXPathAxisVal) op->value) {
14761                 case AXIS_CHILD:
14762                 case AXIS_DESCENDANT:
14763                     /*
14764                     * Convert "descendant-or-self::node()/child::" or
14765                     * "descendant-or-self::node()/descendant::" to
14766                     * "descendant::"
14767                     */
14768                     op->ch1   = prevop->ch1;
14769                     op->value = AXIS_DESCENDANT;
14770                     break;
14771                 case AXIS_SELF:
14772                 case AXIS_DESCENDANT_OR_SELF:
14773                     /*
14774                     * Convert "descendant-or-self::node()/self::" or
14775                     * "descendant-or-self::node()/descendant-or-self::" to
14776                     * to "descendant-or-self::"
14777                     */
14778                     op->ch1   = prevop->ch1;
14779                     op->value = AXIS_DESCENDANT_OR_SELF;
14780                     break;
14781                 default:
14782                     break;
14783             }
14784 	}
14785     }
14786 
14787     /* Recurse */
14788     if (op->ch1 != -1)
14789         xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
14790     if (op->ch2 != -1)
14791 	xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
14792 }
14793 
14794 /**
14795  * xmlXPathCtxtCompile:
14796  * @ctxt: an XPath context
14797  * @str:  the XPath expression
14798  *
14799  * Compile an XPath expression
14800  *
14801  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14802  *         the caller has to free the object.
14803  */
14804 xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14805 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14806     xmlXPathParserContextPtr pctxt;
14807     xmlXPathCompExprPtr comp;
14808 
14809 #ifdef XPATH_STREAMING
14810     comp = xmlXPathTryStreamCompile(ctxt, str);
14811     if (comp != NULL)
14812         return(comp);
14813 #endif
14814 
14815     xmlXPathInit();
14816 
14817     pctxt = xmlXPathNewParserContext(str, ctxt);
14818     if (pctxt == NULL)
14819         return NULL;
14820     xmlXPathCompileExpr(pctxt, 1);
14821 
14822     if( pctxt->error != XPATH_EXPRESSION_OK )
14823     {
14824         xmlXPathFreeParserContext(pctxt);
14825         return(NULL);
14826     }
14827 
14828     if (*pctxt->cur != 0) {
14829 	/*
14830 	 * aleksey: in some cases this line prints *second* error message
14831 	 * (see bug #78858) and probably this should be fixed.
14832 	 * However, we are not sure that all error messages are printed
14833 	 * out in other places. It's not critical so we leave it as-is for now
14834 	 */
14835 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14836 	comp = NULL;
14837     } else {
14838 	comp = pctxt->comp;
14839 	pctxt->comp = NULL;
14840     }
14841     xmlXPathFreeParserContext(pctxt);
14842 
14843     if (comp != NULL) {
14844 	comp->expr = xmlStrdup(str);
14845 #ifdef DEBUG_EVAL_COUNTS
14846 	comp->string = xmlStrdup(str);
14847 	comp->nb = 0;
14848 #endif
14849 	if ((comp->nbStep > 1) && (comp->last >= 0)) {
14850 	    xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
14851 	}
14852     }
14853     return(comp);
14854 }
14855 
14856 /**
14857  * xmlXPathCompile:
14858  * @str:  the XPath expression
14859  *
14860  * Compile an XPath expression
14861  *
14862  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14863  *         the caller has to free the object.
14864  */
14865 xmlXPathCompExprPtr
xmlXPathCompile(const xmlChar * str)14866 xmlXPathCompile(const xmlChar *str) {
14867     return(xmlXPathCtxtCompile(NULL, str));
14868 }
14869 
14870 /**
14871  * xmlXPathCompiledEvalInternal:
14872  * @comp:  the compiled XPath expression
14873  * @ctxt:  the XPath context
14874  * @resObj: the resulting XPath object or NULL
14875  * @toBool: 1 if only a boolean result is requested
14876  *
14877  * Evaluate the Precompiled XPath expression in the given context.
14878  * The caller has to free @resObj.
14879  *
14880  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14881  *         the caller has to free the object.
14882  */
14883 static int
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt,xmlXPathObjectPtr * resObj,int toBool)14884 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14885 			     xmlXPathContextPtr ctxt,
14886 			     xmlXPathObjectPtr *resObj,
14887 			     int toBool)
14888 {
14889     xmlXPathParserContextPtr pctxt;
14890 #ifndef LIBXML_THREAD_ENABLED
14891     static int reentance = 0;
14892 #endif
14893     int res;
14894 
14895     CHECK_CTXT_NEG(ctxt)
14896 
14897     if (comp == NULL)
14898 	return(-1);
14899     xmlXPathInit();
14900 
14901 #ifndef LIBXML_THREAD_ENABLED
14902     reentance++;
14903     if (reentance > 1)
14904 	xmlXPathDisableOptimizer = 1;
14905 #endif
14906 
14907 #ifdef DEBUG_EVAL_COUNTS
14908     comp->nb++;
14909     if ((comp->string != NULL) && (comp->nb > 100)) {
14910 	fprintf(stderr, "100 x %s\n", comp->string);
14911 	comp->nb = 0;
14912     }
14913 #endif
14914     pctxt = xmlXPathCompParserContext(comp, ctxt);
14915     res = xmlXPathRunEval(pctxt, toBool);
14916 
14917     if (resObj) {
14918 	if (pctxt->value == NULL) {
14919 	    xmlGenericError(xmlGenericErrorContext,
14920 		"xmlXPathCompiledEval: evaluation failed\n");
14921 	    *resObj = NULL;
14922 	} else {
14923 	    *resObj = valuePop(pctxt);
14924 	}
14925     }
14926 
14927     /*
14928     * Pop all remaining objects from the stack.
14929     */
14930     if (pctxt->valueNr > 0) {
14931 	xmlXPathObjectPtr tmp;
14932 	int stack = 0;
14933 
14934 	do {
14935 	    tmp = valuePop(pctxt);
14936 	    if (tmp != NULL) {
14937 		stack++;
14938 		xmlXPathReleaseObject(ctxt, tmp);
14939 	    }
14940 	} while (tmp != NULL);
14941 	if ((stack != 0) &&
14942 	    ((toBool) || ((resObj) && (*resObj))))
14943 	{
14944 	    xmlGenericError(xmlGenericErrorContext,
14945 		"xmlXPathCompiledEval: %d objects left on the stack.\n",
14946 		stack);
14947 	}
14948     }
14949 
14950     if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14951 	xmlXPathFreeObject(*resObj);
14952 	*resObj = NULL;
14953     }
14954     pctxt->comp = NULL;
14955     xmlXPathFreeParserContext(pctxt);
14956 #ifndef LIBXML_THREAD_ENABLED
14957     reentance--;
14958 #endif
14959 
14960     return(res);
14961 }
14962 
14963 /**
14964  * xmlXPathCompiledEval:
14965  * @comp:  the compiled XPath expression
14966  * @ctx:  the XPath context
14967  *
14968  * Evaluate the Precompiled XPath expression in the given context.
14969  *
14970  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14971  *         the caller has to free the object.
14972  */
14973 xmlXPathObjectPtr
xmlXPathCompiledEval(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctx)14974 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14975 {
14976     xmlXPathObjectPtr res = NULL;
14977 
14978     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14979     return(res);
14980 }
14981 
14982 /**
14983  * xmlXPathCompiledEvalToBoolean:
14984  * @comp:  the compiled XPath expression
14985  * @ctxt:  the XPath context
14986  *
14987  * Applies the XPath boolean() function on the result of the given
14988  * compiled expression.
14989  *
14990  * Returns 1 if the expression evaluated to true, 0 if to false and
14991  *         -1 in API and internal errors.
14992  */
14993 int
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)14994 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14995 			      xmlXPathContextPtr ctxt)
14996 {
14997     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14998 }
14999 
15000 /**
15001  * xmlXPathEvalExpr:
15002  * @ctxt:  the XPath Parser context
15003  *
15004  * Parse and evaluate an XPath expression in the given context,
15005  * then push the result on the context stack
15006  */
15007 void
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt)15008 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
15009 #ifdef XPATH_STREAMING
15010     xmlXPathCompExprPtr comp;
15011 #endif
15012 
15013     if (ctxt == NULL) return;
15014 
15015 #ifdef XPATH_STREAMING
15016     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
15017     if (comp != NULL) {
15018         if (ctxt->comp != NULL)
15019 	    xmlXPathFreeCompExpr(ctxt->comp);
15020         ctxt->comp = comp;
15021 	if (ctxt->cur != NULL)
15022 	    while (*ctxt->cur != 0) ctxt->cur++;
15023     } else
15024 #endif
15025     {
15026 	xmlXPathCompileExpr(ctxt, 1);
15027 	if ((ctxt->error == XPATH_EXPRESSION_OK) &&
15028 	    (ctxt->comp != NULL) &&
15029 	    (ctxt->comp->nbStep > 1) &&
15030 	    (ctxt->comp->last >= 0))
15031 	{
15032 	    xmlXPathOptimizeExpression(ctxt->comp,
15033 		&ctxt->comp->steps[ctxt->comp->last]);
15034 	}
15035     }
15036     CHECK_ERROR;
15037     xmlXPathRunEval(ctxt, 0);
15038 }
15039 
15040 /**
15041  * xmlXPathEval:
15042  * @str:  the XPath expression
15043  * @ctx:  the XPath context
15044  *
15045  * Evaluate the XPath Location Path in the given context.
15046  *
15047  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15048  *         the caller has to free the object.
15049  */
15050 xmlXPathObjectPtr
xmlXPathEval(const xmlChar * str,xmlXPathContextPtr ctx)15051 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
15052     xmlXPathParserContextPtr ctxt;
15053     xmlXPathObjectPtr res, tmp, init = NULL;
15054     int stack = 0;
15055 
15056     CHECK_CTXT(ctx)
15057 
15058     xmlXPathInit();
15059 
15060     ctxt = xmlXPathNewParserContext(str, ctx);
15061     if (ctxt == NULL)
15062         return NULL;
15063     xmlXPathEvalExpr(ctxt);
15064 
15065     if (ctxt->value == NULL) {
15066 	xmlGenericError(xmlGenericErrorContext,
15067 		"xmlXPathEval: evaluation failed\n");
15068 	res = NULL;
15069     } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
15070 #ifdef XPATH_STREAMING
15071             && (ctxt->comp->stream == NULL)
15072 #endif
15073 	      ) {
15074 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15075 	res = NULL;
15076     } else {
15077 	res = valuePop(ctxt);
15078     }
15079 
15080     do {
15081         tmp = valuePop(ctxt);
15082 	if (tmp != NULL) {
15083 	    if (tmp != init)
15084 		stack++;
15085 	    xmlXPathReleaseObject(ctx, tmp);
15086         }
15087     } while (tmp != NULL);
15088     if ((stack != 0) && (res != NULL)) {
15089 	xmlGenericError(xmlGenericErrorContext,
15090 		"xmlXPathEval: %d object left on the stack\n",
15091 	        stack);
15092     }
15093     if (ctxt->error != XPATH_EXPRESSION_OK) {
15094 	xmlXPathFreeObject(res);
15095 	res = NULL;
15096     }
15097 
15098     xmlXPathFreeParserContext(ctxt);
15099     return(res);
15100 }
15101 
15102 /**
15103  * xmlXPathSetContextNode:
15104  * @node: the node to to use as the context node
15105  * @ctx:  the XPath context
15106  *
15107  * Sets 'node' as the context node. The node must be in the same
15108  * document as that associated with the context.
15109  *
15110  * Returns -1 in case of error or 0 if successful
15111  */
15112 int
xmlXPathSetContextNode(xmlNodePtr node,xmlXPathContextPtr ctx)15113 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
15114     if ((node == NULL) || (ctx == NULL))
15115         return(-1);
15116 
15117     if (node->doc == ctx->doc) {
15118         ctx->node = node;
15119 	return(0);
15120     }
15121     return(-1);
15122 }
15123 
15124 /**
15125  * xmlXPathNodeEval:
15126  * @node: the node to to use as the context node
15127  * @str:  the XPath expression
15128  * @ctx:  the XPath context
15129  *
15130  * Evaluate the XPath Location Path in the given context. The node 'node'
15131  * is set as the context node. The context node is not restored.
15132  *
15133  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15134  *         the caller has to free the object.
15135  */
15136 xmlXPathObjectPtr
xmlXPathNodeEval(xmlNodePtr node,const xmlChar * str,xmlXPathContextPtr ctx)15137 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
15138     if (str == NULL)
15139         return(NULL);
15140     if (xmlXPathSetContextNode(node, ctx) < 0)
15141         return(NULL);
15142     return(xmlXPathEval(str, ctx));
15143 }
15144 
15145 /**
15146  * xmlXPathEvalExpression:
15147  * @str:  the XPath expression
15148  * @ctxt:  the XPath context
15149  *
15150  * Evaluate the XPath expression in the given context.
15151  *
15152  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15153  *         the caller has to free the object.
15154  */
15155 xmlXPathObjectPtr
xmlXPathEvalExpression(const xmlChar * str,xmlXPathContextPtr ctxt)15156 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15157     xmlXPathParserContextPtr pctxt;
15158     xmlXPathObjectPtr res, tmp;
15159     int stack = 0;
15160 
15161     CHECK_CTXT(ctxt)
15162 
15163     xmlXPathInit();
15164 
15165     pctxt = xmlXPathNewParserContext(str, ctxt);
15166     if (pctxt == NULL)
15167         return NULL;
15168     xmlXPathEvalExpr(pctxt);
15169 
15170     if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
15171 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15172 	res = NULL;
15173     } else {
15174 	res = valuePop(pctxt);
15175     }
15176     do {
15177         tmp = valuePop(pctxt);
15178 	if (tmp != NULL) {
15179 	    xmlXPathReleaseObject(ctxt, tmp);
15180 	    stack++;
15181 	}
15182     } while (tmp != NULL);
15183     if ((stack != 0) && (res != NULL)) {
15184 	xmlGenericError(xmlGenericErrorContext,
15185 		"xmlXPathEvalExpression: %d object left on the stack\n",
15186 	        stack);
15187     }
15188     xmlXPathFreeParserContext(pctxt);
15189     return(res);
15190 }
15191 
15192 /************************************************************************
15193  *									*
15194  *	Extra functions not pertaining to the XPath spec		*
15195  *									*
15196  ************************************************************************/
15197 /**
15198  * xmlXPathEscapeUriFunction:
15199  * @ctxt:  the XPath Parser context
15200  * @nargs:  the number of arguments
15201  *
15202  * Implement the escape-uri() XPath function
15203  *    string escape-uri(string $str, bool $escape-reserved)
15204  *
15205  * This function applies the URI escaping rules defined in section 2 of [RFC
15206  * 2396] to the string supplied as $uri-part, which typically represents all
15207  * or part of a URI. The effect of the function is to replace any special
15208  * character in the string by an escape sequence of the form %xx%yy...,
15209  * where xxyy... is the hexadecimal representation of the octets used to
15210  * represent the character in UTF-8.
15211  *
15212  * The set of characters that are escaped depends on the setting of the
15213  * boolean argument $escape-reserved.
15214  *
15215  * If $escape-reserved is true, all characters are escaped other than lower
15216  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15217  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15218  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15219  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15220  * A-F).
15221  *
15222  * If $escape-reserved is false, the behavior differs in that characters
15223  * referred to in [RFC 2396] as reserved characters are not escaped. These
15224  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15225  *
15226  * [RFC 2396] does not define whether escaped URIs should use lower case or
15227  * upper case for hexadecimal digits. To ensure that escaped URIs can be
15228  * compared using string comparison functions, this function must always use
15229  * the upper-case letters A-F.
15230  *
15231  * Generally, $escape-reserved should be set to true when escaping a string
15232  * that is to form a single part of a URI, and to false when escaping an
15233  * entire URI or URI reference.
15234  *
15235  * In the case of non-ascii characters, the string is encoded according to
15236  * utf-8 and then converted according to RFC 2396.
15237  *
15238  * Examples
15239  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15240  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15241  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15242  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15243  *
15244  */
15245 static void
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt,int nargs)15246 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15247     xmlXPathObjectPtr str;
15248     int escape_reserved;
15249     xmlBufPtr target;
15250     xmlChar *cptr;
15251     xmlChar escape[4];
15252 
15253     CHECK_ARITY(2);
15254 
15255     escape_reserved = xmlXPathPopBoolean(ctxt);
15256 
15257     CAST_TO_STRING;
15258     str = valuePop(ctxt);
15259 
15260     target = xmlBufCreate();
15261 
15262     escape[0] = '%';
15263     escape[3] = 0;
15264 
15265     if (target) {
15266 	for (cptr = str->stringval; *cptr; cptr++) {
15267 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
15268 		(*cptr >= 'a' && *cptr <= 'z') ||
15269 		(*cptr >= '0' && *cptr <= '9') ||
15270 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
15271 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
15272 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15273 		(*cptr == '%' &&
15274 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15275 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15276 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
15277 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15278 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15279 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15280 		(!escape_reserved &&
15281 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15282 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15283 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15284 		  *cptr == ','))) {
15285 		xmlBufAdd(target, cptr, 1);
15286 	    } else {
15287 		if ((*cptr >> 4) < 10)
15288 		    escape[1] = '0' + (*cptr >> 4);
15289 		else
15290 		    escape[1] = 'A' - 10 + (*cptr >> 4);
15291 		if ((*cptr & 0xF) < 10)
15292 		    escape[2] = '0' + (*cptr & 0xF);
15293 		else
15294 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
15295 
15296 		xmlBufAdd(target, &escape[0], 3);
15297 	    }
15298 	}
15299     }
15300     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15301 	xmlBufContent(target)));
15302     xmlBufFree(target);
15303     xmlXPathReleaseObject(ctxt->context, str);
15304 }
15305 
15306 /**
15307  * xmlXPathRegisterAllFunctions:
15308  * @ctxt:  the XPath context
15309  *
15310  * Registers all default XPath functions in this context
15311  */
15312 void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)15313 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15314 {
15315     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15316                          xmlXPathBooleanFunction);
15317     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15318                          xmlXPathCeilingFunction);
15319     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15320                          xmlXPathCountFunction);
15321     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15322                          xmlXPathConcatFunction);
15323     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15324                          xmlXPathContainsFunction);
15325     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15326                          xmlXPathIdFunction);
15327     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15328                          xmlXPathFalseFunction);
15329     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15330                          xmlXPathFloorFunction);
15331     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15332                          xmlXPathLastFunction);
15333     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15334                          xmlXPathLangFunction);
15335     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15336                          xmlXPathLocalNameFunction);
15337     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15338                          xmlXPathNotFunction);
15339     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15340                          xmlXPathNameFunction);
15341     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15342                          xmlXPathNamespaceURIFunction);
15343     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15344                          xmlXPathNormalizeFunction);
15345     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15346                          xmlXPathNumberFunction);
15347     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15348                          xmlXPathPositionFunction);
15349     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15350                          xmlXPathRoundFunction);
15351     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15352                          xmlXPathStringFunction);
15353     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15354                          xmlXPathStringLengthFunction);
15355     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15356                          xmlXPathStartsWithFunction);
15357     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15358                          xmlXPathSubstringFunction);
15359     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15360                          xmlXPathSubstringBeforeFunction);
15361     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15362                          xmlXPathSubstringAfterFunction);
15363     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15364                          xmlXPathSumFunction);
15365     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15366                          xmlXPathTrueFunction);
15367     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15368                          xmlXPathTranslateFunction);
15369 
15370     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15371 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15372                          xmlXPathEscapeUriFunction);
15373 }
15374 
15375 #endif /* LIBXML_XPATH_ENABLED */
15376 #define bottom_xpath
15377 #include "elfgcchack.h"
15378