xref: /reactos/sdk/lib/3rdparty/libxml2/xpath.c (revision 1dbad942)
1 /*
2  * xpath.c: XML Path Language implementation
3  *          XPath is a language for addressing parts of an XML document,
4  *          designed to be used by both XSLT and XPointer
5  *
6  * Reference: W3C Recommendation 16 November 1999
7  *     http://www.w3.org/TR/1999/REC-xpath-19991116
8  * Public reference:
9  *     http://www.w3.org/TR/xpath
10  *
11  * See Copyright for the status of this software
12  *
13  * Author: daniel@veillard.com
14  *
15  */
16 
17 /* To avoid EBCDIC trouble when parsing on zOS */
18 #if defined(__MVS__)
19 #pragma convert("ISO8859-1")
20 #endif
21 
22 #define IN_LIBXML
23 #include "libxml.h"
24 
25 #include <limits.h>
26 #include <string.h>
27 #include <stddef.h>
28 #include <math.h>
29 #include <float.h>
30 #include <ctype.h>
31 
32 #include <libxml/xmlmemory.h>
33 #include <libxml/tree.h>
34 #include <libxml/valid.h>
35 #include <libxml/xpath.h>
36 #include <libxml/xpathInternals.h>
37 #include <libxml/parserInternals.h>
38 #include <libxml/hash.h>
39 #ifdef LIBXML_XPTR_LOCS_ENABLED
40 #include <libxml/xpointer.h>
41 #endif
42 #ifdef LIBXML_DEBUG_ENABLED
43 #include <libxml/debugXML.h>
44 #endif
45 #include <libxml/xmlerror.h>
46 #include <libxml/threads.h>
47 #include <libxml/globals.h>
48 #ifdef LIBXML_PATTERN_ENABLED
49 #include <libxml/pattern.h>
50 #endif
51 
52 #include "buf.h"
53 
54 #ifdef LIBXML_PATTERN_ENABLED
55 #define XPATH_STREAMING
56 #endif
57 
58 #define TODO								\
59     xmlGenericError(xmlGenericErrorContext,				\
60 	    "Unimplemented block at %s:%d\n",				\
61             __FILE__, __LINE__);
62 
63 /**
64  * WITH_TIM_SORT:
65  *
66  * Use the Timsort algorithm provided in timsort.h to sort
67  * nodeset as this is a great improvement over the old Shell sort
68  * used in xmlXPathNodeSetSort()
69  */
70 #define WITH_TIM_SORT
71 
72 /*
73 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
74 * If defined, this will use xmlXPathCmpNodesExt() instead of
75 * xmlXPathCmpNodes(). The new function is optimized comparison of
76 * non-element nodes; actually it will speed up comparison only if
77 * xmlXPathOrderDocElems() was called in order to index the elements of
78 * a tree in document order; Libxslt does such an indexing, thus it will
79 * benefit from this optimization.
80 */
81 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
82 
83 /*
84 * XP_OPTIMIZED_FILTER_FIRST:
85 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
86 * in a way, that it stop evaluation at the first node.
87 */
88 #define XP_OPTIMIZED_FILTER_FIRST
89 
90 /*
91 * XP_DEBUG_OBJ_USAGE:
92 * Internal flag to enable tracking of how much XPath objects have been
93 * created.
94 */
95 /* #define XP_DEBUG_OBJ_USAGE */
96 
97 /*
98  * XPATH_MAX_STEPS:
99  * when compiling an XPath expression we arbitrary limit the maximum
100  * number of step operation in the compiled expression. 1000000 is
101  * an insanely large value which should never be reached under normal
102  * circumstances
103  */
104 #define XPATH_MAX_STEPS 1000000
105 
106 /*
107  * XPATH_MAX_STACK_DEPTH:
108  * when evaluating an XPath expression we arbitrary limit the maximum
109  * number of object allowed to be pushed on the stack. 1000000 is
110  * an insanely large value which should never be reached under normal
111  * circumstances
112  */
113 #define XPATH_MAX_STACK_DEPTH 1000000
114 
115 /*
116  * XPATH_MAX_NODESET_LENGTH:
117  * when evaluating an XPath expression nodesets are created and we
118  * arbitrary limit the maximum length of those node set. 10000000 is
119  * an insanely large value which should never be reached under normal
120  * circumstances, one would first need to construct an in memory tree
121  * with more than 10 millions nodes.
122  */
123 #define XPATH_MAX_NODESET_LENGTH 10000000
124 
125 /*
126  * XPATH_MAX_RECRUSION_DEPTH:
127  * Maximum amount of nested functions calls when parsing or evaluating
128  * expressions
129  */
130 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
131 #define XPATH_MAX_RECURSION_DEPTH 500
132 #else
133 #define XPATH_MAX_RECURSION_DEPTH 5000
134 #endif
135 
136 /*
137  * TODO:
138  * There are a few spots where some tests are done which depend upon ascii
139  * data.  These should be enhanced for full UTF8 support (see particularly
140  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
141  */
142 
143 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
144 /**
145  * xmlXPathCmpNodesExt:
146  * @node1:  the first node
147  * @node2:  the second node
148  *
149  * Compare two nodes w.r.t document order.
150  * This one is optimized for handling of non-element nodes.
151  *
152  * Returns -2 in case of error 1 if first point < second point, 0 if
153  *         it's the same node, -1 otherwise
154  */
155 static int
xmlXPathCmpNodesExt(xmlNodePtr node1,xmlNodePtr node2)156 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
157     int depth1, depth2;
158     int misc = 0, precedence1 = 0, precedence2 = 0;
159     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
160     xmlNodePtr cur, root;
161     ptrdiff_t l1, l2;
162 
163     if ((node1 == NULL) || (node2 == NULL))
164 	return(-2);
165 
166     if (node1 == node2)
167 	return(0);
168 
169     /*
170      * a couple of optimizations which will avoid computations in most cases
171      */
172     switch (node1->type) {
173 	case XML_ELEMENT_NODE:
174 	    if (node2->type == XML_ELEMENT_NODE) {
175 		if ((0 > (ptrdiff_t) node1->content) &&
176 		    (0 > (ptrdiff_t) node2->content) &&
177 		    (node1->doc == node2->doc))
178 		{
179 		    l1 = -((ptrdiff_t) node1->content);
180 		    l2 = -((ptrdiff_t) node2->content);
181 		    if (l1 < l2)
182 			return(1);
183 		    if (l1 > l2)
184 			return(-1);
185 		} else
186 		    goto turtle_comparison;
187 	    }
188 	    break;
189 	case XML_ATTRIBUTE_NODE:
190 	    precedence1 = 1; /* element is owner */
191 	    miscNode1 = node1;
192 	    node1 = node1->parent;
193 	    misc = 1;
194 	    break;
195 	case XML_TEXT_NODE:
196 	case XML_CDATA_SECTION_NODE:
197 	case XML_COMMENT_NODE:
198 	case XML_PI_NODE: {
199 	    miscNode1 = node1;
200 	    /*
201 	    * Find nearest element node.
202 	    */
203 	    if (node1->prev != NULL) {
204 		do {
205 		    node1 = node1->prev;
206 		    if (node1->type == XML_ELEMENT_NODE) {
207 			precedence1 = 3; /* element in prev-sibl axis */
208 			break;
209 		    }
210 		    if (node1->prev == NULL) {
211 			precedence1 = 2; /* element is parent */
212 			/*
213 			* URGENT TODO: Are there any cases, where the
214 			* parent of such a node is not an element node?
215 			*/
216 			node1 = node1->parent;
217 			break;
218 		    }
219 		} while (1);
220 	    } else {
221 		precedence1 = 2; /* element is parent */
222 		node1 = node1->parent;
223 	    }
224 	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
225 		(0 <= (ptrdiff_t) node1->content)) {
226 		/*
227 		* Fallback for whatever case.
228 		*/
229 		node1 = miscNode1;
230 		precedence1 = 0;
231 	    } else
232 		misc = 1;
233 	}
234 	    break;
235 	case XML_NAMESPACE_DECL:
236 	    /*
237 	    * TODO: why do we return 1 for namespace nodes?
238 	    */
239 	    return(1);
240 	default:
241 	    break;
242     }
243     switch (node2->type) {
244 	case XML_ELEMENT_NODE:
245 	    break;
246 	case XML_ATTRIBUTE_NODE:
247 	    precedence2 = 1; /* element is owner */
248 	    miscNode2 = node2;
249 	    node2 = node2->parent;
250 	    misc = 1;
251 	    break;
252 	case XML_TEXT_NODE:
253 	case XML_CDATA_SECTION_NODE:
254 	case XML_COMMENT_NODE:
255 	case XML_PI_NODE: {
256 	    miscNode2 = node2;
257 	    if (node2->prev != NULL) {
258 		do {
259 		    node2 = node2->prev;
260 		    if (node2->type == XML_ELEMENT_NODE) {
261 			precedence2 = 3; /* element in prev-sibl axis */
262 			break;
263 		    }
264 		    if (node2->prev == NULL) {
265 			precedence2 = 2; /* element is parent */
266 			node2 = node2->parent;
267 			break;
268 		    }
269 		} while (1);
270 	    } else {
271 		precedence2 = 2; /* element is parent */
272 		node2 = node2->parent;
273 	    }
274 	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
275 		(0 <= (ptrdiff_t) node2->content))
276 	    {
277 		node2 = miscNode2;
278 		precedence2 = 0;
279 	    } else
280 		misc = 1;
281 	}
282 	    break;
283 	case XML_NAMESPACE_DECL:
284 	    return(1);
285 	default:
286 	    break;
287     }
288     if (misc) {
289 	if (node1 == node2) {
290 	    if (precedence1 == precedence2) {
291 		/*
292 		* The ugly case; but normally there aren't many
293 		* adjacent non-element nodes around.
294 		*/
295 		cur = miscNode2->prev;
296 		while (cur != NULL) {
297 		    if (cur == miscNode1)
298 			return(1);
299 		    if (cur->type == XML_ELEMENT_NODE)
300 			return(-1);
301 		    cur = cur->prev;
302 		}
303 		return (-1);
304 	    } else {
305 		/*
306 		* Evaluate based on higher precedence wrt to the element.
307 		* TODO: This assumes attributes are sorted before content.
308 		*   Is this 100% correct?
309 		*/
310 		if (precedence1 < precedence2)
311 		    return(1);
312 		else
313 		    return(-1);
314 	    }
315 	}
316 	/*
317 	* Special case: One of the helper-elements is contained by the other.
318 	* <foo>
319 	*   <node2>
320 	*     <node1>Text-1(precedence1 == 2)</node1>
321 	*   </node2>
322 	*   Text-6(precedence2 == 3)
323 	* </foo>
324 	*/
325 	if ((precedence2 == 3) && (precedence1 > 1)) {
326 	    cur = node1->parent;
327 	    while (cur) {
328 		if (cur == node2)
329 		    return(1);
330 		cur = cur->parent;
331 	    }
332 	}
333 	if ((precedence1 == 3) && (precedence2 > 1)) {
334 	    cur = node2->parent;
335 	    while (cur) {
336 		if (cur == node1)
337 		    return(-1);
338 		cur = cur->parent;
339 	    }
340 	}
341     }
342 
343     /*
344      * Speedup using document order if available.
345      */
346     if ((node1->type == XML_ELEMENT_NODE) &&
347 	(node2->type == XML_ELEMENT_NODE) &&
348 	(0 > (ptrdiff_t) node1->content) &&
349 	(0 > (ptrdiff_t) node2->content) &&
350 	(node1->doc == node2->doc)) {
351 
352 	l1 = -((ptrdiff_t) node1->content);
353 	l2 = -((ptrdiff_t) node2->content);
354 	if (l1 < l2)
355 	    return(1);
356 	if (l1 > l2)
357 	    return(-1);
358     }
359 
360 turtle_comparison:
361 
362     if (node1 == node2->prev)
363 	return(1);
364     if (node1 == node2->next)
365 	return(-1);
366     /*
367      * compute depth to root
368      */
369     for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
370 	if (cur->parent == node1)
371 	    return(1);
372 	depth2++;
373     }
374     root = cur;
375     for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
376 	if (cur->parent == node2)
377 	    return(-1);
378 	depth1++;
379     }
380     /*
381      * Distinct document (or distinct entities :-( ) case.
382      */
383     if (root != cur) {
384 	return(-2);
385     }
386     /*
387      * get the nearest common ancestor.
388      */
389     while (depth1 > depth2) {
390 	depth1--;
391 	node1 = node1->parent;
392     }
393     while (depth2 > depth1) {
394 	depth2--;
395 	node2 = node2->parent;
396     }
397     while (node1->parent != node2->parent) {
398 	node1 = node1->parent;
399 	node2 = node2->parent;
400 	/* should not happen but just in case ... */
401 	if ((node1 == NULL) || (node2 == NULL))
402 	    return(-2);
403     }
404     /*
405      * Find who's first.
406      */
407     if (node1 == node2->prev)
408 	return(1);
409     if (node1 == node2->next)
410 	return(-1);
411     /*
412      * Speedup using document order if available.
413      */
414     if ((node1->type == XML_ELEMENT_NODE) &&
415 	(node2->type == XML_ELEMENT_NODE) &&
416 	(0 > (ptrdiff_t) node1->content) &&
417 	(0 > (ptrdiff_t) node2->content) &&
418 	(node1->doc == node2->doc)) {
419 
420 	l1 = -((ptrdiff_t) node1->content);
421 	l2 = -((ptrdiff_t) node2->content);
422 	if (l1 < l2)
423 	    return(1);
424 	if (l1 > l2)
425 	    return(-1);
426     }
427 
428     for (cur = node1->next;cur != NULL;cur = cur->next)
429 	if (cur == node2)
430 	    return(1);
431     return(-1); /* assume there is no sibling list corruption */
432 }
433 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
434 
435 /*
436  * Wrapper for the Timsort algorithm from timsort.h
437  */
438 #ifdef WITH_TIM_SORT
439 #define SORT_NAME libxml_domnode
440 #define SORT_TYPE xmlNodePtr
441 /**
442  * wrap_cmp:
443  * @x: a node
444  * @y: another node
445  *
446  * Comparison function for the Timsort implementation
447  *
448  * Returns -2 in case of error -1 if first point < second point, 0 if
449  *         it's the same node, +1 otherwise
450  */
451 static
452 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
453 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
wrap_cmp(xmlNodePtr x,xmlNodePtr y)454     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
455     {
456         int res = xmlXPathCmpNodesExt(x, y);
457         return res == -2 ? res : -res;
458     }
459 #else
wrap_cmp(xmlNodePtr x,xmlNodePtr y)460     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
461     {
462         int res = xmlXPathCmpNodes(x, y);
463         return res == -2 ? res : -res;
464     }
465 #endif
466 #define SORT_CMP(x, y)  (wrap_cmp(x, y))
467 #include "timsort.h"
468 #endif /* WITH_TIM_SORT */
469 
470 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
471 
472 /************************************************************************
473  *									*
474  *			Floating point stuff				*
475  *									*
476  ************************************************************************/
477 
478 double xmlXPathNAN = 0.0;
479 double xmlXPathPINF = 0.0;
480 double xmlXPathNINF = 0.0;
481 
482 /**
483  * xmlXPathInit:
484  *
485  * DEPRECATED: This function will be made private. Call xmlInitParser to
486  * initialize the library.
487  *
488  * Initialize the XPath environment
489  */
490 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
491 void
xmlXPathInit(void)492 xmlXPathInit(void) {
493 #if defined(NAN) && defined(INFINITY)
494     xmlXPathNAN = NAN;
495     xmlXPathPINF = INFINITY;
496     xmlXPathNINF = -INFINITY;
497 #else
498     /* MSVC doesn't allow division by zero in constant expressions. */
499     double zero = 0.0;
500     xmlXPathNAN = 0.0 / zero;
501     xmlXPathPINF = 1.0 / zero;
502     xmlXPathNINF = -xmlXPathPINF;
503 #endif
504 }
505 
506 /**
507  * xmlXPathIsNaN:
508  * @val:  a double value
509  *
510  * Returns 1 if the value is a NaN, 0 otherwise
511  */
512 int
xmlXPathIsNaN(double val)513 xmlXPathIsNaN(double val) {
514 #ifdef isnan
515     return isnan(val);
516 #else
517     return !(val == val);
518 #endif
519 }
520 
521 /**
522  * xmlXPathIsInf:
523  * @val:  a double value
524  *
525  * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
526  */
527 int
xmlXPathIsInf(double val)528 xmlXPathIsInf(double val) {
529 #ifdef isinf
530     return isinf(val) ? (val > 0 ? 1 : -1) : 0;
531 #else
532     if (val >= xmlXPathPINF)
533         return 1;
534     if (val <= -xmlXPathPINF)
535         return -1;
536     return 0;
537 #endif
538 }
539 
540 #endif /* SCHEMAS or XPATH */
541 
542 #ifdef LIBXML_XPATH_ENABLED
543 
544 /*
545  * TODO: when compatibility allows remove all "fake node libxslt" strings
546  *       the test should just be name[0] = ' '
547  */
548 #ifdef DEBUG_XPATH_EXPRESSION
549 #define DEBUG_STEP
550 #define DEBUG_EXPR
551 #define DEBUG_EVAL_COUNTS
552 #endif
553 
554 static xmlNs xmlXPathXMLNamespaceStruct = {
555     NULL,
556     XML_NAMESPACE_DECL,
557     XML_XML_NAMESPACE,
558     BAD_CAST "xml",
559     NULL,
560     NULL
561 };
562 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
563 #ifndef LIBXML_THREAD_ENABLED
564 /*
565  * Optimizer is disabled only when threaded apps are detected while
566  * the library ain't compiled for thread safety.
567  */
568 static int xmlXPathDisableOptimizer = 0;
569 #endif
570 
571 /************************************************************************
572  *									*
573  *			Error handling routines				*
574  *									*
575  ************************************************************************/
576 
577 /**
578  * XP_ERRORNULL:
579  * @X:  the error code
580  *
581  * Macro to raise an XPath error and return NULL.
582  */
583 #define XP_ERRORNULL(X)							\
584     { xmlXPathErr(ctxt, X); return(NULL); }
585 
586 /*
587  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
588  */
589 static const char* const xmlXPathErrorMessages[] = {
590     "Ok\n",
591     "Number encoding\n",
592     "Unfinished literal\n",
593     "Start of literal\n",
594     "Expected $ for variable reference\n",
595     "Undefined variable\n",
596     "Invalid predicate\n",
597     "Invalid expression\n",
598     "Missing closing curly brace\n",
599     "Unregistered function\n",
600     "Invalid operand\n",
601     "Invalid type\n",
602     "Invalid number of arguments\n",
603     "Invalid context size\n",
604     "Invalid context position\n",
605     "Memory allocation error\n",
606     "Syntax error\n",
607     "Resource error\n",
608     "Sub resource error\n",
609     "Undefined namespace prefix\n",
610     "Encoding error\n",
611     "Char out of XML range\n",
612     "Invalid or incomplete context\n",
613     "Stack usage error\n",
614     "Forbidden variable\n",
615     "Operation limit exceeded\n",
616     "Recursion limit exceeded\n",
617     "?? Unknown error ??\n"	/* Must be last in the list! */
618 };
619 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
620 		   sizeof(xmlXPathErrorMessages[0])) - 1)
621 /**
622  * xmlXPathErrMemory:
623  * @ctxt:  an XPath context
624  * @extra:  extra information
625  *
626  * Handle a redefinition of attribute error
627  */
628 static void
xmlXPathErrMemory(xmlXPathContextPtr ctxt,const char * extra)629 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
630 {
631     if (ctxt != NULL) {
632         xmlResetError(&ctxt->lastError);
633         if (extra) {
634             xmlChar buf[200];
635 
636             xmlStrPrintf(buf, 200,
637                          "Memory allocation failed : %s\n",
638                          extra);
639             ctxt->lastError.message = (char *) xmlStrdup(buf);
640         } else {
641             ctxt->lastError.message = (char *)
642 	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
643         }
644         ctxt->lastError.domain = XML_FROM_XPATH;
645         ctxt->lastError.code = XML_ERR_NO_MEMORY;
646 	if (ctxt->error != NULL)
647 	    ctxt->error(ctxt->userData, &ctxt->lastError);
648     } else {
649         if (extra)
650             __xmlRaiseError(NULL, NULL, NULL,
651                             NULL, NULL, XML_FROM_XPATH,
652                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
653                             extra, NULL, NULL, 0, 0,
654                             "Memory allocation failed : %s\n", extra);
655         else
656             __xmlRaiseError(NULL, NULL, NULL,
657                             NULL, NULL, XML_FROM_XPATH,
658                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
659                             NULL, NULL, NULL, 0, 0,
660                             "Memory allocation failed\n");
661     }
662 }
663 
664 /**
665  * xmlXPathPErrMemory:
666  * @ctxt:  an XPath parser context
667  * @extra:  extra information
668  *
669  * Handle a redefinition of attribute error
670  */
671 static void
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt,const char * extra)672 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
673 {
674     if (ctxt == NULL)
675 	xmlXPathErrMemory(NULL, extra);
676     else {
677 	ctxt->error = XPATH_MEMORY_ERROR;
678 	xmlXPathErrMemory(ctxt->context, extra);
679     }
680 }
681 
682 /**
683  * xmlXPathErr:
684  * @ctxt:  a XPath parser context
685  * @error:  the error code
686  *
687  * Handle an XPath error
688  */
689 void
xmlXPathErr(xmlXPathParserContextPtr ctxt,int error)690 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
691 {
692     if ((error < 0) || (error > MAXERRNO))
693 	error = MAXERRNO;
694     if (ctxt == NULL) {
695 	__xmlRaiseError(NULL, NULL, NULL,
696 			NULL, NULL, XML_FROM_XPATH,
697 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
698 			XML_ERR_ERROR, NULL, 0,
699 			NULL, NULL, NULL, 0, 0,
700 			"%s", xmlXPathErrorMessages[error]);
701 	return;
702     }
703     ctxt->error = error;
704     if (ctxt->context == NULL) {
705 	__xmlRaiseError(NULL, NULL, NULL,
706 			NULL, NULL, XML_FROM_XPATH,
707 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
708 			XML_ERR_ERROR, NULL, 0,
709 			(const char *) ctxt->base, NULL, NULL,
710 			ctxt->cur - ctxt->base, 0,
711 			"%s", xmlXPathErrorMessages[error]);
712 	return;
713     }
714 
715     /* cleanup current last error */
716     xmlResetError(&ctxt->context->lastError);
717 
718     ctxt->context->lastError.domain = XML_FROM_XPATH;
719     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
720                            XPATH_EXPRESSION_OK;
721     ctxt->context->lastError.level = XML_ERR_ERROR;
722     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
723     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
724     ctxt->context->lastError.node = ctxt->context->debugNode;
725     if (ctxt->context->error != NULL) {
726 	ctxt->context->error(ctxt->context->userData,
727 	                     &ctxt->context->lastError);
728     } else {
729 	__xmlRaiseError(NULL, NULL, NULL,
730 			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
731 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
732 			XML_ERR_ERROR, NULL, 0,
733 			(const char *) ctxt->base, NULL, NULL,
734 			ctxt->cur - ctxt->base, 0,
735 			"%s", xmlXPathErrorMessages[error]);
736     }
737 
738 }
739 
740 /**
741  * xmlXPatherror:
742  * @ctxt:  the XPath Parser context
743  * @file:  the file name
744  * @line:  the line number
745  * @no:  the error number
746  *
747  * Formats an error message.
748  */
749 void
xmlXPatherror(xmlXPathParserContextPtr ctxt,const char * file ATTRIBUTE_UNUSED,int line ATTRIBUTE_UNUSED,int no)750 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
751               int line ATTRIBUTE_UNUSED, int no) {
752     xmlXPathErr(ctxt, no);
753 }
754 
755 /**
756  * xmlXPathCheckOpLimit:
757  * @ctxt:  the XPath Parser context
758  * @opCount:  the number of operations to be added
759  *
760  * Adds opCount to the running total of operations and returns -1 if the
761  * operation limit is exceeded. Returns 0 otherwise.
762  */
763 static int
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt,unsigned long opCount)764 xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
765     xmlXPathContextPtr xpctxt = ctxt->context;
766 
767     if ((opCount > xpctxt->opLimit) ||
768         (xpctxt->opCount > xpctxt->opLimit - opCount)) {
769         xpctxt->opCount = xpctxt->opLimit;
770         xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
771         return(-1);
772     }
773 
774     xpctxt->opCount += opCount;
775     return(0);
776 }
777 
778 #define OP_LIMIT_EXCEEDED(ctxt, n) \
779     ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
780 
781 /************************************************************************
782  *									*
783  *			Utilities					*
784  *									*
785  ************************************************************************/
786 
787 /**
788  * xsltPointerList:
789  *
790  * Pointer-list for various purposes.
791  */
792 typedef struct _xmlPointerList xmlPointerList;
793 typedef xmlPointerList *xmlPointerListPtr;
794 struct _xmlPointerList {
795     void **items;
796     int number;
797     int size;
798 };
799 /*
800 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
801 * and here, we should make the functions public.
802 */
803 static int
xmlPointerListAddSize(xmlPointerListPtr list,void * item,int initialSize)804 xmlPointerListAddSize(xmlPointerListPtr list,
805 		       void *item,
806 		       int initialSize)
807 {
808     if (list->items == NULL) {
809 	if (initialSize <= 0)
810 	    initialSize = 1;
811 	list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
812 	if (list->items == NULL) {
813 	    xmlXPathErrMemory(NULL,
814 		"xmlPointerListCreate: allocating item\n");
815 	    return(-1);
816 	}
817 	list->number = 0;
818 	list->size = initialSize;
819     } else if (list->size <= list->number) {
820         if (list->size > 50000000) {
821 	    xmlXPathErrMemory(NULL,
822 		"xmlPointerListAddSize: re-allocating item\n");
823             return(-1);
824         }
825 	list->size *= 2;
826 	list->items = (void **) xmlRealloc(list->items,
827 	    list->size * sizeof(void *));
828 	if (list->items == NULL) {
829 	    xmlXPathErrMemory(NULL,
830 		"xmlPointerListAddSize: re-allocating item\n");
831 	    list->size = 0;
832 	    return(-1);
833 	}
834     }
835     list->items[list->number++] = item;
836     return(0);
837 }
838 
839 /**
840  * xsltPointerListCreate:
841  *
842  * Creates an xsltPointerList structure.
843  *
844  * Returns a xsltPointerList structure or NULL in case of an error.
845  */
846 static xmlPointerListPtr
xmlPointerListCreate(int initialSize)847 xmlPointerListCreate(int initialSize)
848 {
849     xmlPointerListPtr ret;
850 
851     ret = xmlMalloc(sizeof(xmlPointerList));
852     if (ret == NULL) {
853 	xmlXPathErrMemory(NULL,
854 	    "xmlPointerListCreate: allocating item\n");
855 	return (NULL);
856     }
857     memset(ret, 0, sizeof(xmlPointerList));
858     if (initialSize > 0) {
859 	xmlPointerListAddSize(ret, NULL, initialSize);
860 	ret->number = 0;
861     }
862     return (ret);
863 }
864 
865 /**
866  * xsltPointerListFree:
867  *
868  * Frees the xsltPointerList structure. This does not free
869  * the content of the list.
870  */
871 static void
xmlPointerListFree(xmlPointerListPtr list)872 xmlPointerListFree(xmlPointerListPtr list)
873 {
874     if (list == NULL)
875 	return;
876     if (list->items != NULL)
877 	xmlFree(list->items);
878     xmlFree(list);
879 }
880 
881 /************************************************************************
882  *									*
883  *			Parser Types					*
884  *									*
885  ************************************************************************/
886 
887 /*
888  * Types are private:
889  */
890 
891 typedef enum {
892     XPATH_OP_END=0,
893     XPATH_OP_AND,
894     XPATH_OP_OR,
895     XPATH_OP_EQUAL,
896     XPATH_OP_CMP,
897     XPATH_OP_PLUS,
898     XPATH_OP_MULT,
899     XPATH_OP_UNION,
900     XPATH_OP_ROOT,
901     XPATH_OP_NODE,
902     XPATH_OP_COLLECT,
903     XPATH_OP_VALUE, /* 11 */
904     XPATH_OP_VARIABLE,
905     XPATH_OP_FUNCTION,
906     XPATH_OP_ARG,
907     XPATH_OP_PREDICATE,
908     XPATH_OP_FILTER, /* 16 */
909     XPATH_OP_SORT /* 17 */
910 #ifdef LIBXML_XPTR_LOCS_ENABLED
911     ,XPATH_OP_RANGETO
912 #endif
913 } xmlXPathOp;
914 
915 typedef enum {
916     AXIS_ANCESTOR = 1,
917     AXIS_ANCESTOR_OR_SELF,
918     AXIS_ATTRIBUTE,
919     AXIS_CHILD,
920     AXIS_DESCENDANT,
921     AXIS_DESCENDANT_OR_SELF,
922     AXIS_FOLLOWING,
923     AXIS_FOLLOWING_SIBLING,
924     AXIS_NAMESPACE,
925     AXIS_PARENT,
926     AXIS_PRECEDING,
927     AXIS_PRECEDING_SIBLING,
928     AXIS_SELF
929 } xmlXPathAxisVal;
930 
931 typedef enum {
932     NODE_TEST_NONE = 0,
933     NODE_TEST_TYPE = 1,
934     NODE_TEST_PI = 2,
935     NODE_TEST_ALL = 3,
936     NODE_TEST_NS = 4,
937     NODE_TEST_NAME = 5
938 } xmlXPathTestVal;
939 
940 typedef enum {
941     NODE_TYPE_NODE = 0,
942     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
943     NODE_TYPE_TEXT = XML_TEXT_NODE,
944     NODE_TYPE_PI = XML_PI_NODE
945 } xmlXPathTypeVal;
946 
947 typedef struct _xmlXPathStepOp xmlXPathStepOp;
948 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
949 struct _xmlXPathStepOp {
950     xmlXPathOp op;		/* The identifier of the operation */
951     int ch1;			/* First child */
952     int ch2;			/* Second child */
953     int value;
954     int value2;
955     int value3;
956     void *value4;
957     void *value5;
958     xmlXPathFunction cache;
959     void *cacheURI;
960 };
961 
962 struct _xmlXPathCompExpr {
963     int nbStep;			/* Number of steps in this expression */
964     int maxStep;		/* Maximum number of steps allocated */
965     xmlXPathStepOp *steps;	/* ops for computation of this expression */
966     int last;			/* index of last step in expression */
967     xmlChar *expr;		/* the expression being computed */
968     xmlDictPtr dict;		/* the dictionary to use if any */
969 #ifdef DEBUG_EVAL_COUNTS
970     int nb;
971     xmlChar *string;
972 #endif
973 #ifdef XPATH_STREAMING
974     xmlPatternPtr stream;
975 #endif
976 };
977 
978 /************************************************************************
979  *									*
980  *			Forward declarations				*
981  *									*
982  ************************************************************************/
983 static void
984 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
985 static void
986 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
987 static int
988 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
989                         xmlXPathStepOpPtr op, xmlNodePtr *first);
990 static int
991 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
992 			    xmlXPathStepOpPtr op,
993 			    int isPredicate);
994 static void
995 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
996 
997 /************************************************************************
998  *									*
999  *			Parser Type functions				*
1000  *									*
1001  ************************************************************************/
1002 
1003 /**
1004  * xmlXPathNewCompExpr:
1005  *
1006  * Create a new Xpath component
1007  *
1008  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1009  */
1010 static xmlXPathCompExprPtr
xmlXPathNewCompExpr(void)1011 xmlXPathNewCompExpr(void) {
1012     xmlXPathCompExprPtr cur;
1013 
1014     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1015     if (cur == NULL) {
1016         xmlXPathErrMemory(NULL, "allocating component\n");
1017 	return(NULL);
1018     }
1019     memset(cur, 0, sizeof(xmlXPathCompExpr));
1020     cur->maxStep = 10;
1021     cur->nbStep = 0;
1022     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1023 	                                   sizeof(xmlXPathStepOp));
1024     if (cur->steps == NULL) {
1025         xmlXPathErrMemory(NULL, "allocating steps\n");
1026 	xmlFree(cur);
1027 	return(NULL);
1028     }
1029     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1030     cur->last = -1;
1031 #ifdef DEBUG_EVAL_COUNTS
1032     cur->nb = 0;
1033 #endif
1034     return(cur);
1035 }
1036 
1037 /**
1038  * xmlXPathFreeCompExpr:
1039  * @comp:  an XPATH comp
1040  *
1041  * Free up the memory allocated by @comp
1042  */
1043 void
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)1044 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1045 {
1046     xmlXPathStepOpPtr op;
1047     int i;
1048 
1049     if (comp == NULL)
1050         return;
1051     if (comp->dict == NULL) {
1052 	for (i = 0; i < comp->nbStep; i++) {
1053 	    op = &comp->steps[i];
1054 	    if (op->value4 != NULL) {
1055 		if (op->op == XPATH_OP_VALUE)
1056 		    xmlXPathFreeObject(op->value4);
1057 		else
1058 		    xmlFree(op->value4);
1059 	    }
1060 	    if (op->value5 != NULL)
1061 		xmlFree(op->value5);
1062 	}
1063     } else {
1064 	for (i = 0; i < comp->nbStep; i++) {
1065 	    op = &comp->steps[i];
1066 	    if (op->value4 != NULL) {
1067 		if (op->op == XPATH_OP_VALUE)
1068 		    xmlXPathFreeObject(op->value4);
1069 	    }
1070 	}
1071         xmlDictFree(comp->dict);
1072     }
1073     if (comp->steps != NULL) {
1074         xmlFree(comp->steps);
1075     }
1076 #ifdef DEBUG_EVAL_COUNTS
1077     if (comp->string != NULL) {
1078         xmlFree(comp->string);
1079     }
1080 #endif
1081 #ifdef XPATH_STREAMING
1082     if (comp->stream != NULL) {
1083         xmlFreePatternList(comp->stream);
1084     }
1085 #endif
1086     if (comp->expr != NULL) {
1087         xmlFree(comp->expr);
1088     }
1089 
1090     xmlFree(comp);
1091 }
1092 
1093 /**
1094  * xmlXPathCompExprAdd:
1095  * @comp:  the compiled expression
1096  * @ch1: first child index
1097  * @ch2: second child index
1098  * @op:  an op
1099  * @value:  the first int value
1100  * @value2:  the second int value
1101  * @value3:  the third int value
1102  * @value4:  the first string value
1103  * @value5:  the second string value
1104  *
1105  * Add a step to an XPath Compiled Expression
1106  *
1107  * Returns -1 in case of failure, the index otherwise
1108  */
1109 static int
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt,int ch1,int ch2,xmlXPathOp op,int value,int value2,int value3,void * value4,void * value5)1110 xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1111    xmlXPathOp op, int value,
1112    int value2, int value3, void *value4, void *value5) {
1113     xmlXPathCompExprPtr comp = ctxt->comp;
1114     if (comp->nbStep >= comp->maxStep) {
1115 	xmlXPathStepOp *real;
1116 
1117         if (comp->maxStep >= XPATH_MAX_STEPS) {
1118 	    xmlXPathPErrMemory(ctxt, "adding step\n");
1119 	    return(-1);
1120         }
1121 	comp->maxStep *= 2;
1122 	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1123 		                      comp->maxStep * sizeof(xmlXPathStepOp));
1124 	if (real == NULL) {
1125 	    comp->maxStep /= 2;
1126 	    xmlXPathPErrMemory(ctxt, "adding step\n");
1127 	    return(-1);
1128 	}
1129 	comp->steps = real;
1130     }
1131     comp->last = comp->nbStep;
1132     comp->steps[comp->nbStep].ch1 = ch1;
1133     comp->steps[comp->nbStep].ch2 = ch2;
1134     comp->steps[comp->nbStep].op = op;
1135     comp->steps[comp->nbStep].value = value;
1136     comp->steps[comp->nbStep].value2 = value2;
1137     comp->steps[comp->nbStep].value3 = value3;
1138     if ((comp->dict != NULL) &&
1139         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1140 	 (op == XPATH_OP_COLLECT))) {
1141         if (value4 != NULL) {
1142 	    comp->steps[comp->nbStep].value4 = (xmlChar *)
1143 	        (void *)xmlDictLookup(comp->dict, value4, -1);
1144 	    xmlFree(value4);
1145 	} else
1146 	    comp->steps[comp->nbStep].value4 = NULL;
1147         if (value5 != NULL) {
1148 	    comp->steps[comp->nbStep].value5 = (xmlChar *)
1149 	        (void *)xmlDictLookup(comp->dict, value5, -1);
1150 	    xmlFree(value5);
1151 	} else
1152 	    comp->steps[comp->nbStep].value5 = NULL;
1153     } else {
1154 	comp->steps[comp->nbStep].value4 = value4;
1155 	comp->steps[comp->nbStep].value5 = value5;
1156     }
1157     comp->steps[comp->nbStep].cache = NULL;
1158     return(comp->nbStep++);
1159 }
1160 
1161 /**
1162  * xmlXPathCompSwap:
1163  * @comp:  the compiled expression
1164  * @op: operation index
1165  *
1166  * Swaps 2 operations in the compiled expression
1167  */
1168 static void
xmlXPathCompSwap(xmlXPathStepOpPtr op)1169 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1170     int tmp;
1171 
1172 #ifndef LIBXML_THREAD_ENABLED
1173     /*
1174      * Since this manipulates possibly shared variables, this is
1175      * disabled if one detects that the library is used in a multithreaded
1176      * application
1177      */
1178     if (xmlXPathDisableOptimizer)
1179 	return;
1180 #endif
1181 
1182     tmp = op->ch1;
1183     op->ch1 = op->ch2;
1184     op->ch2 = tmp;
1185 }
1186 
1187 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
1188     xmlXPathCompExprAdd(ctxt, (op1), (op2),			\
1189 	                (op), (val), (val2), (val3), (val4), (val5))
1190 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
1191     xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,		\
1192 	                (op), (val), (val2), (val3), (val4), (val5))
1193 
1194 #define PUSH_LEAVE_EXPR(op, val, val2)					\
1195 xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1196 
1197 #define PUSH_UNARY_EXPR(op, ch, val, val2)				\
1198 xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1199 
1200 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
1201 xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),			\
1202 			(val), (val2), 0 ,NULL ,NULL)
1203 
1204 /************************************************************************
1205  *									*
1206  *		XPath object cache structures				*
1207  *									*
1208  ************************************************************************/
1209 
1210 /* #define XP_DEFAULT_CACHE_ON */
1211 
1212 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1213 
1214 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1215 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1216 struct _xmlXPathContextCache {
1217     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1218     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1219     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1220     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1221     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1222     int maxNodeset;
1223     int maxString;
1224     int maxBoolean;
1225     int maxNumber;
1226     int maxMisc;
1227 #ifdef XP_DEBUG_OBJ_USAGE
1228     int dbgCachedAll;
1229     int dbgCachedNodeset;
1230     int dbgCachedString;
1231     int dbgCachedBool;
1232     int dbgCachedNumber;
1233     int dbgCachedPoint;
1234     int dbgCachedRange;
1235     int dbgCachedLocset;
1236     int dbgCachedUsers;
1237     int dbgCachedXSLTTree;
1238     int dbgCachedUndefined;
1239 
1240 
1241     int dbgReusedAll;
1242     int dbgReusedNodeset;
1243     int dbgReusedString;
1244     int dbgReusedBool;
1245     int dbgReusedNumber;
1246     int dbgReusedPoint;
1247     int dbgReusedRange;
1248     int dbgReusedLocset;
1249     int dbgReusedUsers;
1250     int dbgReusedXSLTTree;
1251     int dbgReusedUndefined;
1252 
1253 #endif
1254 };
1255 
1256 /************************************************************************
1257  *									*
1258  *		Debugging related functions				*
1259  *									*
1260  ************************************************************************/
1261 
1262 #define STRANGE							\
1263     xmlGenericError(xmlGenericErrorContext,				\
1264 	    "Internal error at %s:%d\n",				\
1265             __FILE__, __LINE__);
1266 
1267 #ifdef LIBXML_DEBUG_ENABLED
1268 static void
xmlXPathDebugDumpNode(FILE * output,xmlNodePtr cur,int depth)1269 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1270     int i;
1271     char shift[100];
1272 
1273     for (i = 0;((i < depth) && (i < 25));i++)
1274         shift[2 * i] = shift[2 * i + 1] = ' ';
1275     shift[2 * i] = shift[2 * i + 1] = 0;
1276     if (cur == NULL) {
1277 	fprintf(output, "%s", shift);
1278 	fprintf(output, "Node is NULL !\n");
1279 	return;
1280 
1281     }
1282 
1283     if ((cur->type == XML_DOCUMENT_NODE) ||
1284 	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
1285 	fprintf(output, "%s", shift);
1286 	fprintf(output, " /\n");
1287     } else if (cur->type == XML_ATTRIBUTE_NODE)
1288 	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1289     else
1290 	xmlDebugDumpOneNode(output, cur, depth);
1291 }
1292 static void
xmlXPathDebugDumpNodeList(FILE * output,xmlNodePtr cur,int depth)1293 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1294     xmlNodePtr tmp;
1295     int i;
1296     char shift[100];
1297 
1298     for (i = 0;((i < depth) && (i < 25));i++)
1299         shift[2 * i] = shift[2 * i + 1] = ' ';
1300     shift[2 * i] = shift[2 * i + 1] = 0;
1301     if (cur == NULL) {
1302 	fprintf(output, "%s", shift);
1303 	fprintf(output, "Node is NULL !\n");
1304 	return;
1305 
1306     }
1307 
1308     while (cur != NULL) {
1309 	tmp = cur;
1310 	cur = cur->next;
1311 	xmlDebugDumpOneNode(output, tmp, depth);
1312     }
1313 }
1314 
1315 static void
xmlXPathDebugDumpNodeSet(FILE * output,xmlNodeSetPtr cur,int depth)1316 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1317     int i;
1318     char shift[100];
1319 
1320     for (i = 0;((i < depth) && (i < 25));i++)
1321         shift[2 * i] = shift[2 * i + 1] = ' ';
1322     shift[2 * i] = shift[2 * i + 1] = 0;
1323 
1324     if (cur == NULL) {
1325 	fprintf(output, "%s", shift);
1326 	fprintf(output, "NodeSet is NULL !\n");
1327 	return;
1328 
1329     }
1330 
1331     if (cur != NULL) {
1332 	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1333 	for (i = 0;i < cur->nodeNr;i++) {
1334 	    fprintf(output, "%s", shift);
1335 	    fprintf(output, "%d", i + 1);
1336 	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1337 	}
1338     }
1339 }
1340 
1341 static void
xmlXPathDebugDumpValueTree(FILE * output,xmlNodeSetPtr cur,int depth)1342 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1343     int i;
1344     char shift[100];
1345 
1346     for (i = 0;((i < depth) && (i < 25));i++)
1347         shift[2 * i] = shift[2 * i + 1] = ' ';
1348     shift[2 * i] = shift[2 * i + 1] = 0;
1349 
1350     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1351 	fprintf(output, "%s", shift);
1352 	fprintf(output, "Value Tree is NULL !\n");
1353 	return;
1354 
1355     }
1356 
1357     fprintf(output, "%s", shift);
1358     fprintf(output, "%d", i + 1);
1359     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1360 }
1361 #if defined(LIBXML_XPTR_LOCS_ENABLED)
1362 static void
xmlXPathDebugDumpLocationSet(FILE * output,xmlLocationSetPtr cur,int depth)1363 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1364     int i;
1365     char shift[100];
1366 
1367     for (i = 0;((i < depth) && (i < 25));i++)
1368         shift[2 * i] = shift[2 * i + 1] = ' ';
1369     shift[2 * i] = shift[2 * i + 1] = 0;
1370 
1371     if (cur == NULL) {
1372 	fprintf(output, "%s", shift);
1373 	fprintf(output, "LocationSet is NULL !\n");
1374 	return;
1375 
1376     }
1377 
1378     for (i = 0;i < cur->locNr;i++) {
1379 	fprintf(output, "%s", shift);
1380         fprintf(output, "%d : ", i + 1);
1381 	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1382     }
1383 }
1384 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1385 
1386 /**
1387  * xmlXPathDebugDumpObject:
1388  * @output:  the FILE * to dump the output
1389  * @cur:  the object to inspect
1390  * @depth:  indentation level
1391  *
1392  * Dump the content of the object for debugging purposes
1393  */
1394 void
xmlXPathDebugDumpObject(FILE * output,xmlXPathObjectPtr cur,int depth)1395 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1396     int i;
1397     char shift[100];
1398 
1399     if (output == NULL) return;
1400 
1401     for (i = 0;((i < depth) && (i < 25));i++)
1402         shift[2 * i] = shift[2 * i + 1] = ' ';
1403     shift[2 * i] = shift[2 * i + 1] = 0;
1404 
1405 
1406     fprintf(output, "%s", shift);
1407 
1408     if (cur == NULL) {
1409         fprintf(output, "Object is empty (NULL)\n");
1410 	return;
1411     }
1412     switch(cur->type) {
1413         case XPATH_UNDEFINED:
1414 	    fprintf(output, "Object is uninitialized\n");
1415 	    break;
1416         case XPATH_NODESET:
1417 	    fprintf(output, "Object is a Node Set :\n");
1418 	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1419 	    break;
1420 	case XPATH_XSLT_TREE:
1421 	    fprintf(output, "Object is an XSLT value tree :\n");
1422 	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1423 	    break;
1424         case XPATH_BOOLEAN:
1425 	    fprintf(output, "Object is a Boolean : ");
1426 	    if (cur->boolval) fprintf(output, "true\n");
1427 	    else fprintf(output, "false\n");
1428 	    break;
1429         case XPATH_NUMBER:
1430 	    switch (xmlXPathIsInf(cur->floatval)) {
1431 	    case 1:
1432 		fprintf(output, "Object is a number : Infinity\n");
1433 		break;
1434 	    case -1:
1435 		fprintf(output, "Object is a number : -Infinity\n");
1436 		break;
1437 	    default:
1438 		if (xmlXPathIsNaN(cur->floatval)) {
1439 		    fprintf(output, "Object is a number : NaN\n");
1440 		} else if (cur->floatval == 0) {
1441                     /* Omit sign for negative zero. */
1442 		    fprintf(output, "Object is a number : 0\n");
1443 		} else {
1444 		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
1445 		}
1446 	    }
1447 	    break;
1448         case XPATH_STRING:
1449 	    fprintf(output, "Object is a string : ");
1450 	    xmlDebugDumpString(output, cur->stringval);
1451 	    fprintf(output, "\n");
1452 	    break;
1453 #ifdef LIBXML_XPTR_LOCS_ENABLED
1454 	case XPATH_POINT:
1455 	    fprintf(output, "Object is a point : index %d in node", cur->index);
1456 	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1457 	    fprintf(output, "\n");
1458 	    break;
1459 	case XPATH_RANGE:
1460 	    if ((cur->user2 == NULL) ||
1461 		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1462 		fprintf(output, "Object is a collapsed range :\n");
1463 		fprintf(output, "%s", shift);
1464 		if (cur->index >= 0)
1465 		    fprintf(output, "index %d in ", cur->index);
1466 		fprintf(output, "node\n");
1467 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1468 			              depth + 1);
1469 	    } else  {
1470 		fprintf(output, "Object is a range :\n");
1471 		fprintf(output, "%s", shift);
1472 		fprintf(output, "From ");
1473 		if (cur->index >= 0)
1474 		    fprintf(output, "index %d in ", cur->index);
1475 		fprintf(output, "node\n");
1476 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1477 			              depth + 1);
1478 		fprintf(output, "%s", shift);
1479 		fprintf(output, "To ");
1480 		if (cur->index2 >= 0)
1481 		    fprintf(output, "index %d in ", cur->index2);
1482 		fprintf(output, "node\n");
1483 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1484 			              depth + 1);
1485 		fprintf(output, "\n");
1486 	    }
1487 	    break;
1488 	case XPATH_LOCATIONSET:
1489 	    fprintf(output, "Object is a Location Set:\n");
1490 	    xmlXPathDebugDumpLocationSet(output,
1491 		    (xmlLocationSetPtr) cur->user, depth);
1492 	    break;
1493 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1494 	case XPATH_USERS:
1495 	    fprintf(output, "Object is user defined\n");
1496 	    break;
1497     }
1498 }
1499 
1500 static void
xmlXPathDebugDumpStepOp(FILE * output,xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op,int depth)1501 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1502 	                     xmlXPathStepOpPtr op, int depth) {
1503     int i;
1504     char shift[100];
1505 
1506     for (i = 0;((i < depth) && (i < 25));i++)
1507         shift[2 * i] = shift[2 * i + 1] = ' ';
1508     shift[2 * i] = shift[2 * i + 1] = 0;
1509 
1510     fprintf(output, "%s", shift);
1511     if (op == NULL) {
1512 	fprintf(output, "Step is NULL\n");
1513 	return;
1514     }
1515     switch (op->op) {
1516         case XPATH_OP_END:
1517 	    fprintf(output, "END"); break;
1518         case XPATH_OP_AND:
1519 	    fprintf(output, "AND"); break;
1520         case XPATH_OP_OR:
1521 	    fprintf(output, "OR"); break;
1522         case XPATH_OP_EQUAL:
1523 	     if (op->value)
1524 		 fprintf(output, "EQUAL =");
1525 	     else
1526 		 fprintf(output, "EQUAL !=");
1527 	     break;
1528         case XPATH_OP_CMP:
1529 	     if (op->value)
1530 		 fprintf(output, "CMP <");
1531 	     else
1532 		 fprintf(output, "CMP >");
1533 	     if (!op->value2)
1534 		 fprintf(output, "=");
1535 	     break;
1536         case XPATH_OP_PLUS:
1537 	     if (op->value == 0)
1538 		 fprintf(output, "PLUS -");
1539 	     else if (op->value == 1)
1540 		 fprintf(output, "PLUS +");
1541 	     else if (op->value == 2)
1542 		 fprintf(output, "PLUS unary -");
1543 	     else if (op->value == 3)
1544 		 fprintf(output, "PLUS unary - -");
1545 	     break;
1546         case XPATH_OP_MULT:
1547 	     if (op->value == 0)
1548 		 fprintf(output, "MULT *");
1549 	     else if (op->value == 1)
1550 		 fprintf(output, "MULT div");
1551 	     else
1552 		 fprintf(output, "MULT mod");
1553 	     break;
1554         case XPATH_OP_UNION:
1555 	     fprintf(output, "UNION"); break;
1556         case XPATH_OP_ROOT:
1557 	     fprintf(output, "ROOT"); break;
1558         case XPATH_OP_NODE:
1559 	     fprintf(output, "NODE"); break;
1560         case XPATH_OP_SORT:
1561 	     fprintf(output, "SORT"); break;
1562         case XPATH_OP_COLLECT: {
1563 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1564 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1565 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1566 	    const xmlChar *prefix = op->value4;
1567 	    const xmlChar *name = op->value5;
1568 
1569 	    fprintf(output, "COLLECT ");
1570 	    switch (axis) {
1571 		case AXIS_ANCESTOR:
1572 		    fprintf(output, " 'ancestors' "); break;
1573 		case AXIS_ANCESTOR_OR_SELF:
1574 		    fprintf(output, " 'ancestors-or-self' "); break;
1575 		case AXIS_ATTRIBUTE:
1576 		    fprintf(output, " 'attributes' "); break;
1577 		case AXIS_CHILD:
1578 		    fprintf(output, " 'child' "); break;
1579 		case AXIS_DESCENDANT:
1580 		    fprintf(output, " 'descendant' "); break;
1581 		case AXIS_DESCENDANT_OR_SELF:
1582 		    fprintf(output, " 'descendant-or-self' "); break;
1583 		case AXIS_FOLLOWING:
1584 		    fprintf(output, " 'following' "); break;
1585 		case AXIS_FOLLOWING_SIBLING:
1586 		    fprintf(output, " 'following-siblings' "); break;
1587 		case AXIS_NAMESPACE:
1588 		    fprintf(output, " 'namespace' "); break;
1589 		case AXIS_PARENT:
1590 		    fprintf(output, " 'parent' "); break;
1591 		case AXIS_PRECEDING:
1592 		    fprintf(output, " 'preceding' "); break;
1593 		case AXIS_PRECEDING_SIBLING:
1594 		    fprintf(output, " 'preceding-sibling' "); break;
1595 		case AXIS_SELF:
1596 		    fprintf(output, " 'self' "); break;
1597 	    }
1598 	    switch (test) {
1599                 case NODE_TEST_NONE:
1600 		    fprintf(output, "'none' "); break;
1601                 case NODE_TEST_TYPE:
1602 		    fprintf(output, "'type' "); break;
1603                 case NODE_TEST_PI:
1604 		    fprintf(output, "'PI' "); break;
1605                 case NODE_TEST_ALL:
1606 		    fprintf(output, "'all' "); break;
1607                 case NODE_TEST_NS:
1608 		    fprintf(output, "'namespace' "); break;
1609                 case NODE_TEST_NAME:
1610 		    fprintf(output, "'name' "); break;
1611 	    }
1612 	    switch (type) {
1613                 case NODE_TYPE_NODE:
1614 		    fprintf(output, "'node' "); break;
1615                 case NODE_TYPE_COMMENT:
1616 		    fprintf(output, "'comment' "); break;
1617                 case NODE_TYPE_TEXT:
1618 		    fprintf(output, "'text' "); break;
1619                 case NODE_TYPE_PI:
1620 		    fprintf(output, "'PI' "); break;
1621 	    }
1622 	    if (prefix != NULL)
1623 		fprintf(output, "%s:", prefix);
1624 	    if (name != NULL)
1625 		fprintf(output, "%s", (const char *) name);
1626 	    break;
1627 
1628         }
1629 	case XPATH_OP_VALUE: {
1630 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1631 
1632 	    fprintf(output, "ELEM ");
1633 	    xmlXPathDebugDumpObject(output, object, 0);
1634 	    goto finish;
1635 	}
1636 	case XPATH_OP_VARIABLE: {
1637 	    const xmlChar *prefix = op->value5;
1638 	    const xmlChar *name = op->value4;
1639 
1640 	    if (prefix != NULL)
1641 		fprintf(output, "VARIABLE %s:%s", prefix, name);
1642 	    else
1643 		fprintf(output, "VARIABLE %s", name);
1644 	    break;
1645 	}
1646 	case XPATH_OP_FUNCTION: {
1647 	    int nbargs = op->value;
1648 	    const xmlChar *prefix = op->value5;
1649 	    const xmlChar *name = op->value4;
1650 
1651 	    if (prefix != NULL)
1652 		fprintf(output, "FUNCTION %s:%s(%d args)",
1653 			prefix, name, nbargs);
1654 	    else
1655 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1656 	    break;
1657 	}
1658         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1659         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1660         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1661 #ifdef LIBXML_XPTR_LOCS_ENABLED
1662         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1663 #endif
1664 	default:
1665         fprintf(output, "UNKNOWN %d\n", op->op); return;
1666     }
1667     fprintf(output, "\n");
1668 finish:
1669     if (op->ch1 >= 0)
1670 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1671     if (op->ch2 >= 0)
1672 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1673 }
1674 
1675 /**
1676  * xmlXPathDebugDumpCompExpr:
1677  * @output:  the FILE * for the output
1678  * @comp:  the precompiled XPath expression
1679  * @depth:  the indentation level.
1680  *
1681  * Dumps the tree of the compiled XPath expression.
1682  */
1683 void
xmlXPathDebugDumpCompExpr(FILE * output,xmlXPathCompExprPtr comp,int depth)1684 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1685 	                  int depth) {
1686     int i;
1687     char shift[100];
1688 
1689     if ((output == NULL) || (comp == NULL)) return;
1690 
1691     for (i = 0;((i < depth) && (i < 25));i++)
1692         shift[2 * i] = shift[2 * i + 1] = ' ';
1693     shift[2 * i] = shift[2 * i + 1] = 0;
1694 
1695     fprintf(output, "%s", shift);
1696 
1697 #ifdef XPATH_STREAMING
1698     if (comp->stream) {
1699         fprintf(output, "Streaming Expression\n");
1700     } else
1701 #endif
1702     {
1703         fprintf(output, "Compiled Expression : %d elements\n",
1704                 comp->nbStep);
1705         i = comp->last;
1706         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1707     }
1708 }
1709 
1710 #ifdef XP_DEBUG_OBJ_USAGE
1711 
1712 /*
1713 * XPath object usage related debugging variables.
1714 */
1715 static int xmlXPathDebugObjCounterUndefined = 0;
1716 static int xmlXPathDebugObjCounterNodeset = 0;
1717 static int xmlXPathDebugObjCounterBool = 0;
1718 static int xmlXPathDebugObjCounterNumber = 0;
1719 static int xmlXPathDebugObjCounterString = 0;
1720 static int xmlXPathDebugObjCounterPoint = 0;
1721 static int xmlXPathDebugObjCounterRange = 0;
1722 static int xmlXPathDebugObjCounterLocset = 0;
1723 static int xmlXPathDebugObjCounterUsers = 0;
1724 static int xmlXPathDebugObjCounterXSLTTree = 0;
1725 static int xmlXPathDebugObjCounterAll = 0;
1726 
1727 static int xmlXPathDebugObjTotalUndefined = 0;
1728 static int xmlXPathDebugObjTotalNodeset = 0;
1729 static int xmlXPathDebugObjTotalBool = 0;
1730 static int xmlXPathDebugObjTotalNumber = 0;
1731 static int xmlXPathDebugObjTotalString = 0;
1732 static int xmlXPathDebugObjTotalPoint = 0;
1733 static int xmlXPathDebugObjTotalRange = 0;
1734 static int xmlXPathDebugObjTotalLocset = 0;
1735 static int xmlXPathDebugObjTotalUsers = 0;
1736 static int xmlXPathDebugObjTotalXSLTTree = 0;
1737 static int xmlXPathDebugObjTotalAll = 0;
1738 
1739 static int xmlXPathDebugObjMaxUndefined = 0;
1740 static int xmlXPathDebugObjMaxNodeset = 0;
1741 static int xmlXPathDebugObjMaxBool = 0;
1742 static int xmlXPathDebugObjMaxNumber = 0;
1743 static int xmlXPathDebugObjMaxString = 0;
1744 static int xmlXPathDebugObjMaxPoint = 0;
1745 static int xmlXPathDebugObjMaxRange = 0;
1746 static int xmlXPathDebugObjMaxLocset = 0;
1747 static int xmlXPathDebugObjMaxUsers = 0;
1748 static int xmlXPathDebugObjMaxXSLTTree = 0;
1749 static int xmlXPathDebugObjMaxAll = 0;
1750 
1751 static void
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)1752 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1753 {
1754     if (ctxt != NULL) {
1755 	if (ctxt->cache != NULL) {
1756 	    xmlXPathContextCachePtr cache =
1757 		(xmlXPathContextCachePtr) ctxt->cache;
1758 
1759 	    cache->dbgCachedAll = 0;
1760 	    cache->dbgCachedNodeset = 0;
1761 	    cache->dbgCachedString = 0;
1762 	    cache->dbgCachedBool = 0;
1763 	    cache->dbgCachedNumber = 0;
1764 	    cache->dbgCachedPoint = 0;
1765 	    cache->dbgCachedRange = 0;
1766 	    cache->dbgCachedLocset = 0;
1767 	    cache->dbgCachedUsers = 0;
1768 	    cache->dbgCachedXSLTTree = 0;
1769 	    cache->dbgCachedUndefined = 0;
1770 
1771 	    cache->dbgReusedAll = 0;
1772 	    cache->dbgReusedNodeset = 0;
1773 	    cache->dbgReusedString = 0;
1774 	    cache->dbgReusedBool = 0;
1775 	    cache->dbgReusedNumber = 0;
1776 	    cache->dbgReusedPoint = 0;
1777 	    cache->dbgReusedRange = 0;
1778 	    cache->dbgReusedLocset = 0;
1779 	    cache->dbgReusedUsers = 0;
1780 	    cache->dbgReusedXSLTTree = 0;
1781 	    cache->dbgReusedUndefined = 0;
1782 	}
1783     }
1784 
1785     xmlXPathDebugObjCounterUndefined = 0;
1786     xmlXPathDebugObjCounterNodeset = 0;
1787     xmlXPathDebugObjCounterBool = 0;
1788     xmlXPathDebugObjCounterNumber = 0;
1789     xmlXPathDebugObjCounterString = 0;
1790     xmlXPathDebugObjCounterPoint = 0;
1791     xmlXPathDebugObjCounterRange = 0;
1792     xmlXPathDebugObjCounterLocset = 0;
1793     xmlXPathDebugObjCounterUsers = 0;
1794     xmlXPathDebugObjCounterXSLTTree = 0;
1795     xmlXPathDebugObjCounterAll = 0;
1796 
1797     xmlXPathDebugObjTotalUndefined = 0;
1798     xmlXPathDebugObjTotalNodeset = 0;
1799     xmlXPathDebugObjTotalBool = 0;
1800     xmlXPathDebugObjTotalNumber = 0;
1801     xmlXPathDebugObjTotalString = 0;
1802     xmlXPathDebugObjTotalPoint = 0;
1803     xmlXPathDebugObjTotalRange = 0;
1804     xmlXPathDebugObjTotalLocset = 0;
1805     xmlXPathDebugObjTotalUsers = 0;
1806     xmlXPathDebugObjTotalXSLTTree = 0;
1807     xmlXPathDebugObjTotalAll = 0;
1808 
1809     xmlXPathDebugObjMaxUndefined = 0;
1810     xmlXPathDebugObjMaxNodeset = 0;
1811     xmlXPathDebugObjMaxBool = 0;
1812     xmlXPathDebugObjMaxNumber = 0;
1813     xmlXPathDebugObjMaxString = 0;
1814     xmlXPathDebugObjMaxPoint = 0;
1815     xmlXPathDebugObjMaxRange = 0;
1816     xmlXPathDebugObjMaxLocset = 0;
1817     xmlXPathDebugObjMaxUsers = 0;
1818     xmlXPathDebugObjMaxXSLTTree = 0;
1819     xmlXPathDebugObjMaxAll = 0;
1820 
1821 }
1822 
1823 static void
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,xmlXPathObjectType objType)1824 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1825 			      xmlXPathObjectType objType)
1826 {
1827     int isCached = 0;
1828 
1829     if (ctxt != NULL) {
1830 	if (ctxt->cache != NULL) {
1831 	    xmlXPathContextCachePtr cache =
1832 		(xmlXPathContextCachePtr) ctxt->cache;
1833 
1834 	    isCached = 1;
1835 
1836 	    cache->dbgReusedAll++;
1837 	    switch (objType) {
1838 		case XPATH_UNDEFINED:
1839 		    cache->dbgReusedUndefined++;
1840 		    break;
1841 		case XPATH_NODESET:
1842 		    cache->dbgReusedNodeset++;
1843 		    break;
1844 		case XPATH_BOOLEAN:
1845 		    cache->dbgReusedBool++;
1846 		    break;
1847 		case XPATH_NUMBER:
1848 		    cache->dbgReusedNumber++;
1849 		    break;
1850 		case XPATH_STRING:
1851 		    cache->dbgReusedString++;
1852 		    break;
1853 #ifdef LIBXML_XPTR_LOCS_ENABLED
1854 		case XPATH_POINT:
1855 		    cache->dbgReusedPoint++;
1856 		    break;
1857 		case XPATH_RANGE:
1858 		    cache->dbgReusedRange++;
1859 		    break;
1860 		case XPATH_LOCATIONSET:
1861 		    cache->dbgReusedLocset++;
1862 		    break;
1863 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1864 		case XPATH_USERS:
1865 		    cache->dbgReusedUsers++;
1866 		    break;
1867 		case XPATH_XSLT_TREE:
1868 		    cache->dbgReusedXSLTTree++;
1869 		    break;
1870 		default:
1871 		    break;
1872 	    }
1873 	}
1874     }
1875 
1876     switch (objType) {
1877 	case XPATH_UNDEFINED:
1878 	    if (! isCached)
1879 		xmlXPathDebugObjTotalUndefined++;
1880 	    xmlXPathDebugObjCounterUndefined++;
1881 	    if (xmlXPathDebugObjCounterUndefined >
1882 		xmlXPathDebugObjMaxUndefined)
1883 		xmlXPathDebugObjMaxUndefined =
1884 		    xmlXPathDebugObjCounterUndefined;
1885 	    break;
1886 	case XPATH_NODESET:
1887 	    if (! isCached)
1888 		xmlXPathDebugObjTotalNodeset++;
1889 	    xmlXPathDebugObjCounterNodeset++;
1890 	    if (xmlXPathDebugObjCounterNodeset >
1891 		xmlXPathDebugObjMaxNodeset)
1892 		xmlXPathDebugObjMaxNodeset =
1893 		    xmlXPathDebugObjCounterNodeset;
1894 	    break;
1895 	case XPATH_BOOLEAN:
1896 	    if (! isCached)
1897 		xmlXPathDebugObjTotalBool++;
1898 	    xmlXPathDebugObjCounterBool++;
1899 	    if (xmlXPathDebugObjCounterBool >
1900 		xmlXPathDebugObjMaxBool)
1901 		xmlXPathDebugObjMaxBool =
1902 		    xmlXPathDebugObjCounterBool;
1903 	    break;
1904 	case XPATH_NUMBER:
1905 	    if (! isCached)
1906 		xmlXPathDebugObjTotalNumber++;
1907 	    xmlXPathDebugObjCounterNumber++;
1908 	    if (xmlXPathDebugObjCounterNumber >
1909 		xmlXPathDebugObjMaxNumber)
1910 		xmlXPathDebugObjMaxNumber =
1911 		    xmlXPathDebugObjCounterNumber;
1912 	    break;
1913 	case XPATH_STRING:
1914 	    if (! isCached)
1915 		xmlXPathDebugObjTotalString++;
1916 	    xmlXPathDebugObjCounterString++;
1917 	    if (xmlXPathDebugObjCounterString >
1918 		xmlXPathDebugObjMaxString)
1919 		xmlXPathDebugObjMaxString =
1920 		    xmlXPathDebugObjCounterString;
1921 	    break;
1922 #ifdef LIBXML_XPTR_LOCS_ENABLED
1923 	case XPATH_POINT:
1924 	    if (! isCached)
1925 		xmlXPathDebugObjTotalPoint++;
1926 	    xmlXPathDebugObjCounterPoint++;
1927 	    if (xmlXPathDebugObjCounterPoint >
1928 		xmlXPathDebugObjMaxPoint)
1929 		xmlXPathDebugObjMaxPoint =
1930 		    xmlXPathDebugObjCounterPoint;
1931 	    break;
1932 	case XPATH_RANGE:
1933 	    if (! isCached)
1934 		xmlXPathDebugObjTotalRange++;
1935 	    xmlXPathDebugObjCounterRange++;
1936 	    if (xmlXPathDebugObjCounterRange >
1937 		xmlXPathDebugObjMaxRange)
1938 		xmlXPathDebugObjMaxRange =
1939 		    xmlXPathDebugObjCounterRange;
1940 	    break;
1941 	case XPATH_LOCATIONSET:
1942 	    if (! isCached)
1943 		xmlXPathDebugObjTotalLocset++;
1944 	    xmlXPathDebugObjCounterLocset++;
1945 	    if (xmlXPathDebugObjCounterLocset >
1946 		xmlXPathDebugObjMaxLocset)
1947 		xmlXPathDebugObjMaxLocset =
1948 		    xmlXPathDebugObjCounterLocset;
1949 	    break;
1950 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1951 	case XPATH_USERS:
1952 	    if (! isCached)
1953 		xmlXPathDebugObjTotalUsers++;
1954 	    xmlXPathDebugObjCounterUsers++;
1955 	    if (xmlXPathDebugObjCounterUsers >
1956 		xmlXPathDebugObjMaxUsers)
1957 		xmlXPathDebugObjMaxUsers =
1958 		    xmlXPathDebugObjCounterUsers;
1959 	    break;
1960 	case XPATH_XSLT_TREE:
1961 	    if (! isCached)
1962 		xmlXPathDebugObjTotalXSLTTree++;
1963 	    xmlXPathDebugObjCounterXSLTTree++;
1964 	    if (xmlXPathDebugObjCounterXSLTTree >
1965 		xmlXPathDebugObjMaxXSLTTree)
1966 		xmlXPathDebugObjMaxXSLTTree =
1967 		    xmlXPathDebugObjCounterXSLTTree;
1968 	    break;
1969 	default:
1970 	    break;
1971     }
1972     if (! isCached)
1973 	xmlXPathDebugObjTotalAll++;
1974     xmlXPathDebugObjCounterAll++;
1975     if (xmlXPathDebugObjCounterAll >
1976 	xmlXPathDebugObjMaxAll)
1977 	xmlXPathDebugObjMaxAll =
1978 	    xmlXPathDebugObjCounterAll;
1979 }
1980 
1981 static void
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,xmlXPathObjectType objType)1982 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1983 			      xmlXPathObjectType objType)
1984 {
1985     int isCached = 0;
1986 
1987     if (ctxt != NULL) {
1988 	if (ctxt->cache != NULL) {
1989 	    xmlXPathContextCachePtr cache =
1990 		(xmlXPathContextCachePtr) ctxt->cache;
1991 
1992 	    isCached = 1;
1993 
1994 	    cache->dbgCachedAll++;
1995 	    switch (objType) {
1996 		case XPATH_UNDEFINED:
1997 		    cache->dbgCachedUndefined++;
1998 		    break;
1999 		case XPATH_NODESET:
2000 		    cache->dbgCachedNodeset++;
2001 		    break;
2002 		case XPATH_BOOLEAN:
2003 		    cache->dbgCachedBool++;
2004 		    break;
2005 		case XPATH_NUMBER:
2006 		    cache->dbgCachedNumber++;
2007 		    break;
2008 		case XPATH_STRING:
2009 		    cache->dbgCachedString++;
2010 		    break;
2011 #ifdef LIBXML_XPTR_LOCS_ENABLED
2012 		case XPATH_POINT:
2013 		    cache->dbgCachedPoint++;
2014 		    break;
2015 		case XPATH_RANGE:
2016 		    cache->dbgCachedRange++;
2017 		    break;
2018 		case XPATH_LOCATIONSET:
2019 		    cache->dbgCachedLocset++;
2020 		    break;
2021 #endif /* LIBXML_XPTR_LOCS_ENABLED */
2022 		case XPATH_USERS:
2023 		    cache->dbgCachedUsers++;
2024 		    break;
2025 		case XPATH_XSLT_TREE:
2026 		    cache->dbgCachedXSLTTree++;
2027 		    break;
2028 		default:
2029 		    break;
2030 	    }
2031 
2032 	}
2033     }
2034     switch (objType) {
2035 	case XPATH_UNDEFINED:
2036 	    xmlXPathDebugObjCounterUndefined--;
2037 	    break;
2038 	case XPATH_NODESET:
2039 	    xmlXPathDebugObjCounterNodeset--;
2040 	    break;
2041 	case XPATH_BOOLEAN:
2042 	    xmlXPathDebugObjCounterBool--;
2043 	    break;
2044 	case XPATH_NUMBER:
2045 	    xmlXPathDebugObjCounterNumber--;
2046 	    break;
2047 	case XPATH_STRING:
2048 	    xmlXPathDebugObjCounterString--;
2049 	    break;
2050 #ifdef LIBXML_XPTR_LOCS_ENABLED
2051 	case XPATH_POINT:
2052 	    xmlXPathDebugObjCounterPoint--;
2053 	    break;
2054 	case XPATH_RANGE:
2055 	    xmlXPathDebugObjCounterRange--;
2056 	    break;
2057 	case XPATH_LOCATIONSET:
2058 	    xmlXPathDebugObjCounterLocset--;
2059 	    break;
2060 #endif /* LIBXML_XPTR_LOCS_ENABLED */
2061 	case XPATH_USERS:
2062 	    xmlXPathDebugObjCounterUsers--;
2063 	    break;
2064 	case XPATH_XSLT_TREE:
2065 	    xmlXPathDebugObjCounterXSLTTree--;
2066 	    break;
2067 	default:
2068 	    break;
2069     }
2070     xmlXPathDebugObjCounterAll--;
2071 }
2072 
2073 static void
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)2074 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2075 {
2076     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2077 	reqXSLTTree, reqUndefined;
2078     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2079 	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2080     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2081 	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2082     int leftObjs = xmlXPathDebugObjCounterAll;
2083 
2084     reqAll = xmlXPathDebugObjTotalAll;
2085     reqNodeset = xmlXPathDebugObjTotalNodeset;
2086     reqString = xmlXPathDebugObjTotalString;
2087     reqBool = xmlXPathDebugObjTotalBool;
2088     reqNumber = xmlXPathDebugObjTotalNumber;
2089     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2090     reqUndefined = xmlXPathDebugObjTotalUndefined;
2091 
2092     printf("# XPath object usage:\n");
2093 
2094     if (ctxt != NULL) {
2095 	if (ctxt->cache != NULL) {
2096 	    xmlXPathContextCachePtr cache =
2097 		(xmlXPathContextCachePtr) ctxt->cache;
2098 
2099 	    reAll = cache->dbgReusedAll;
2100 	    reqAll += reAll;
2101 	    reNodeset = cache->dbgReusedNodeset;
2102 	    reqNodeset += reNodeset;
2103 	    reString = cache->dbgReusedString;
2104 	    reqString += reString;
2105 	    reBool = cache->dbgReusedBool;
2106 	    reqBool += reBool;
2107 	    reNumber = cache->dbgReusedNumber;
2108 	    reqNumber += reNumber;
2109 	    reXSLTTree = cache->dbgReusedXSLTTree;
2110 	    reqXSLTTree += reXSLTTree;
2111 	    reUndefined = cache->dbgReusedUndefined;
2112 	    reqUndefined += reUndefined;
2113 
2114 	    caAll = cache->dbgCachedAll;
2115 	    caBool = cache->dbgCachedBool;
2116 	    caNodeset = cache->dbgCachedNodeset;
2117 	    caString = cache->dbgCachedString;
2118 	    caNumber = cache->dbgCachedNumber;
2119 	    caXSLTTree = cache->dbgCachedXSLTTree;
2120 	    caUndefined = cache->dbgCachedUndefined;
2121 
2122 	    if (cache->nodesetObjs)
2123 		leftObjs -= cache->nodesetObjs->number;
2124 	    if (cache->stringObjs)
2125 		leftObjs -= cache->stringObjs->number;
2126 	    if (cache->booleanObjs)
2127 		leftObjs -= cache->booleanObjs->number;
2128 	    if (cache->numberObjs)
2129 		leftObjs -= cache->numberObjs->number;
2130 	    if (cache->miscObjs)
2131 		leftObjs -= cache->miscObjs->number;
2132 	}
2133     }
2134 
2135     printf("# all\n");
2136     printf("#   total  : %d\n", reqAll);
2137     printf("#   left  : %d\n", leftObjs);
2138     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2139     printf("#   reused : %d\n", reAll);
2140     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2141 
2142     printf("# node-sets\n");
2143     printf("#   total  : %d\n", reqNodeset);
2144     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2145     printf("#   reused : %d\n", reNodeset);
2146     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2147 
2148     printf("# strings\n");
2149     printf("#   total  : %d\n", reqString);
2150     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2151     printf("#   reused : %d\n", reString);
2152     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2153 
2154     printf("# booleans\n");
2155     printf("#   total  : %d\n", reqBool);
2156     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2157     printf("#   reused : %d\n", reBool);
2158     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2159 
2160     printf("# numbers\n");
2161     printf("#   total  : %d\n", reqNumber);
2162     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2163     printf("#   reused : %d\n", reNumber);
2164     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2165 
2166     printf("# XSLT result tree fragments\n");
2167     printf("#   total  : %d\n", reqXSLTTree);
2168     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2169     printf("#   reused : %d\n", reXSLTTree);
2170     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2171 
2172     printf("# undefined\n");
2173     printf("#   total  : %d\n", reqUndefined);
2174     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2175     printf("#   reused : %d\n", reUndefined);
2176     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2177 
2178 }
2179 
2180 #endif /* XP_DEBUG_OBJ_USAGE */
2181 
2182 #endif /* LIBXML_DEBUG_ENABLED */
2183 
2184 /************************************************************************
2185  *									*
2186  *			XPath object caching				*
2187  *									*
2188  ************************************************************************/
2189 
2190 /**
2191  * xmlXPathNewCache:
2192  *
2193  * Create a new object cache
2194  *
2195  * Returns the xmlXPathCache just allocated.
2196  */
2197 static xmlXPathContextCachePtr
xmlXPathNewCache(void)2198 xmlXPathNewCache(void)
2199 {
2200     xmlXPathContextCachePtr ret;
2201 
2202     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2203     if (ret == NULL) {
2204         xmlXPathErrMemory(NULL, "creating object cache\n");
2205 	return(NULL);
2206     }
2207     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2208     ret->maxNodeset = 100;
2209     ret->maxString = 100;
2210     ret->maxBoolean = 100;
2211     ret->maxNumber = 100;
2212     ret->maxMisc = 100;
2213     return(ret);
2214 }
2215 
2216 static void
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)2217 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2218 {
2219     int i;
2220     xmlXPathObjectPtr obj;
2221 
2222     if (list == NULL)
2223 	return;
2224 
2225     for (i = 0; i < list->number; i++) {
2226 	obj = list->items[i];
2227 	/*
2228 	* Note that it is already assured that we don't need to
2229 	* look out for namespace nodes in the node-set.
2230 	*/
2231 	if (obj->nodesetval != NULL) {
2232 	    if (obj->nodesetval->nodeTab != NULL)
2233 		xmlFree(obj->nodesetval->nodeTab);
2234 	    xmlFree(obj->nodesetval);
2235 	}
2236 	xmlFree(obj);
2237 #ifdef XP_DEBUG_OBJ_USAGE
2238 	xmlXPathDebugObjCounterAll--;
2239 #endif
2240     }
2241     xmlPointerListFree(list);
2242 }
2243 
2244 static void
xmlXPathFreeCache(xmlXPathContextCachePtr cache)2245 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2246 {
2247     if (cache == NULL)
2248 	return;
2249     if (cache->nodesetObjs)
2250 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2251     if (cache->stringObjs)
2252 	xmlXPathCacheFreeObjectList(cache->stringObjs);
2253     if (cache->booleanObjs)
2254 	xmlXPathCacheFreeObjectList(cache->booleanObjs);
2255     if (cache->numberObjs)
2256 	xmlXPathCacheFreeObjectList(cache->numberObjs);
2257     if (cache->miscObjs)
2258 	xmlXPathCacheFreeObjectList(cache->miscObjs);
2259     xmlFree(cache);
2260 }
2261 
2262 /**
2263  * xmlXPathContextSetCache:
2264  *
2265  * @ctxt:  the XPath context
2266  * @active: enables/disables (creates/frees) the cache
2267  * @value: a value with semantics dependent on @options
2268  * @options: options (currently only the value 0 is used)
2269  *
2270  * Creates/frees an object cache on the XPath context.
2271  * If activates XPath objects (xmlXPathObject) will be cached internally
2272  * to be reused.
2273  * @options:
2274  *   0: This will set the XPath object caching:
2275  *      @value:
2276  *        This will set the maximum number of XPath objects
2277  *        to be cached per slot
2278  *        There are 5 slots for: node-set, string, number, boolean, and
2279  *        misc objects. Use <0 for the default number (100).
2280  *   Other values for @options have currently no effect.
2281  *
2282  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2283  */
2284 int
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,int active,int value,int options)2285 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2286 			int active,
2287 			int value,
2288 			int options)
2289 {
2290     if (ctxt == NULL)
2291 	return(-1);
2292     if (active) {
2293 	xmlXPathContextCachePtr cache;
2294 
2295 	if (ctxt->cache == NULL) {
2296 	    ctxt->cache = xmlXPathNewCache();
2297 	    if (ctxt->cache == NULL)
2298 		return(-1);
2299 	}
2300 	cache = (xmlXPathContextCachePtr) ctxt->cache;
2301 	if (options == 0) {
2302 	    if (value < 0)
2303 		value = 100;
2304 	    cache->maxNodeset = value;
2305 	    cache->maxString = value;
2306 	    cache->maxNumber = value;
2307 	    cache->maxBoolean = value;
2308 	    cache->maxMisc = value;
2309 	}
2310     } else if (ctxt->cache != NULL) {
2311 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2312 	ctxt->cache = NULL;
2313     }
2314     return(0);
2315 }
2316 
2317 /**
2318  * xmlXPathCacheWrapNodeSet:
2319  * @ctxt: the XPath context
2320  * @val:  the NodePtr value
2321  *
2322  * This is the cached version of xmlXPathWrapNodeSet().
2323  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2324  *
2325  * Returns the created or reused object.
2326  */
2327 static xmlXPathObjectPtr
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt,xmlNodeSetPtr val)2328 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2329 {
2330     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2331 	xmlXPathContextCachePtr cache =
2332 	    (xmlXPathContextCachePtr) ctxt->cache;
2333 
2334 	if ((cache->miscObjs != NULL) &&
2335 	    (cache->miscObjs->number != 0))
2336 	{
2337 	    xmlXPathObjectPtr ret;
2338 
2339 	    ret = (xmlXPathObjectPtr)
2340 		cache->miscObjs->items[--cache->miscObjs->number];
2341 	    ret->type = XPATH_NODESET;
2342 	    ret->nodesetval = val;
2343 #ifdef XP_DEBUG_OBJ_USAGE
2344 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2345 #endif
2346 	    return(ret);
2347 	}
2348     }
2349 
2350     return(xmlXPathWrapNodeSet(val));
2351 
2352 }
2353 
2354 /**
2355  * xmlXPathCacheWrapString:
2356  * @ctxt: the XPath context
2357  * @val:  the xmlChar * value
2358  *
2359  * This is the cached version of xmlXPathWrapString().
2360  * Wraps the @val string into an XPath object.
2361  *
2362  * Returns the created or reused object.
2363  */
2364 static xmlXPathObjectPtr
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt,xmlChar * val)2365 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2366 {
2367     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2368 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2369 
2370 	if ((cache->stringObjs != NULL) &&
2371 	    (cache->stringObjs->number != 0))
2372 	{
2373 
2374 	    xmlXPathObjectPtr ret;
2375 
2376 	    ret = (xmlXPathObjectPtr)
2377 		cache->stringObjs->items[--cache->stringObjs->number];
2378 	    ret->type = XPATH_STRING;
2379 	    ret->stringval = val;
2380 #ifdef XP_DEBUG_OBJ_USAGE
2381 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2382 #endif
2383 	    return(ret);
2384 	} else if ((cache->miscObjs != NULL) &&
2385 	    (cache->miscObjs->number != 0))
2386 	{
2387 	    xmlXPathObjectPtr ret;
2388 	    /*
2389 	    * Fallback to misc-cache.
2390 	    */
2391 	    ret = (xmlXPathObjectPtr)
2392 		cache->miscObjs->items[--cache->miscObjs->number];
2393 
2394 	    ret->type = XPATH_STRING;
2395 	    ret->stringval = val;
2396 #ifdef XP_DEBUG_OBJ_USAGE
2397 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2398 #endif
2399 	    return(ret);
2400 	}
2401     }
2402     return(xmlXPathWrapString(val));
2403 }
2404 
2405 /**
2406  * xmlXPathCacheNewNodeSet:
2407  * @ctxt: the XPath context
2408  * @val:  the NodePtr value
2409  *
2410  * This is the cached version of xmlXPathNewNodeSet().
2411  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2412  * it with the single Node @val
2413  *
2414  * Returns the created or reused object.
2415  */
2416 static xmlXPathObjectPtr
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt,xmlNodePtr val)2417 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2418 {
2419     if ((ctxt != NULL) && (ctxt->cache)) {
2420 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2421 
2422 	if ((cache->nodesetObjs != NULL) &&
2423 	    (cache->nodesetObjs->number != 0))
2424 	{
2425 	    xmlXPathObjectPtr ret;
2426 	    /*
2427 	    * Use the nodeset-cache.
2428 	    */
2429 	    ret = (xmlXPathObjectPtr)
2430 		cache->nodesetObjs->items[--cache->nodesetObjs->number];
2431 	    ret->type = XPATH_NODESET;
2432 	    ret->boolval = 0;
2433 	    if (val) {
2434 		if ((ret->nodesetval->nodeMax == 0) ||
2435 		    (val->type == XML_NAMESPACE_DECL))
2436 		{
2437                     /* TODO: Check memory error. */
2438 		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2439 		} else {
2440 		    ret->nodesetval->nodeTab[0] = val;
2441 		    ret->nodesetval->nodeNr = 1;
2442 		}
2443 	    }
2444 #ifdef XP_DEBUG_OBJ_USAGE
2445 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2446 #endif
2447 	    return(ret);
2448 	} else if ((cache->miscObjs != NULL) &&
2449 	    (cache->miscObjs->number != 0))
2450 	{
2451 	    xmlXPathObjectPtr ret;
2452 	    /*
2453 	    * Fallback to misc-cache.
2454 	    */
2455 
2456 	    ret = (xmlXPathObjectPtr)
2457 		cache->miscObjs->items[--cache->miscObjs->number];
2458 
2459 	    ret->type = XPATH_NODESET;
2460 	    ret->boolval = 0;
2461 	    ret->nodesetval = xmlXPathNodeSetCreate(val);
2462 	    if (ret->nodesetval == NULL) {
2463 		ctxt->lastError.domain = XML_FROM_XPATH;
2464 		ctxt->lastError.code = XML_ERR_NO_MEMORY;
2465 		return(NULL);
2466 	    }
2467 #ifdef XP_DEBUG_OBJ_USAGE
2468 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2469 #endif
2470 	    return(ret);
2471 	}
2472     }
2473     return(xmlXPathNewNodeSet(val));
2474 }
2475 
2476 /**
2477  * xmlXPathCacheNewCString:
2478  * @ctxt: the XPath context
2479  * @val:  the char * value
2480  *
2481  * This is the cached version of xmlXPathNewCString().
2482  * Acquire an xmlXPathObjectPtr of type string and of value @val
2483  *
2484  * Returns the created or reused object.
2485  */
2486 static xmlXPathObjectPtr
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt,const char * val)2487 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2488 {
2489     if ((ctxt != NULL) && (ctxt->cache)) {
2490 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2491 
2492 	if ((cache->stringObjs != NULL) &&
2493 	    (cache->stringObjs->number != 0))
2494 	{
2495 	    xmlXPathObjectPtr ret;
2496 
2497 	    ret = (xmlXPathObjectPtr)
2498 		cache->stringObjs->items[--cache->stringObjs->number];
2499 
2500 	    ret->type = XPATH_STRING;
2501 	    ret->stringval = xmlStrdup(BAD_CAST val);
2502 #ifdef XP_DEBUG_OBJ_USAGE
2503 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2504 #endif
2505 	    return(ret);
2506 	} else if ((cache->miscObjs != NULL) &&
2507 	    (cache->miscObjs->number != 0))
2508 	{
2509 	    xmlXPathObjectPtr ret;
2510 
2511 	    ret = (xmlXPathObjectPtr)
2512 		cache->miscObjs->items[--cache->miscObjs->number];
2513 
2514 	    ret->type = XPATH_STRING;
2515 	    ret->stringval = xmlStrdup(BAD_CAST val);
2516 #ifdef XP_DEBUG_OBJ_USAGE
2517 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2518 #endif
2519 	    return(ret);
2520 	}
2521     }
2522     return(xmlXPathNewCString(val));
2523 }
2524 
2525 /**
2526  * xmlXPathCacheNewString:
2527  * @ctxt: the XPath context
2528  * @val:  the xmlChar * value
2529  *
2530  * This is the cached version of xmlXPathNewString().
2531  * Acquire an xmlXPathObjectPtr of type string and of value @val
2532  *
2533  * Returns the created or reused object.
2534  */
2535 static xmlXPathObjectPtr
xmlXPathCacheNewString(xmlXPathContextPtr ctxt,const xmlChar * val)2536 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2537 {
2538     if ((ctxt != NULL) && (ctxt->cache)) {
2539 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2540 
2541 	if ((cache->stringObjs != NULL) &&
2542 	    (cache->stringObjs->number != 0))
2543 	{
2544 	    xmlXPathObjectPtr ret;
2545 
2546 	    ret = (xmlXPathObjectPtr)
2547 		cache->stringObjs->items[--cache->stringObjs->number];
2548 	    ret->type = XPATH_STRING;
2549 	    if (val != NULL)
2550 		ret->stringval = xmlStrdup(val);
2551 	    else
2552 		ret->stringval = xmlStrdup((const xmlChar *)"");
2553 #ifdef XP_DEBUG_OBJ_USAGE
2554 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2555 #endif
2556 	    return(ret);
2557 	} else if ((cache->miscObjs != NULL) &&
2558 	    (cache->miscObjs->number != 0))
2559 	{
2560 	    xmlXPathObjectPtr ret;
2561 
2562 	    ret = (xmlXPathObjectPtr)
2563 		cache->miscObjs->items[--cache->miscObjs->number];
2564 
2565 	    ret->type = XPATH_STRING;
2566 	    if (val != NULL)
2567 		ret->stringval = xmlStrdup(val);
2568 	    else
2569 		ret->stringval = xmlStrdup((const xmlChar *)"");
2570 #ifdef XP_DEBUG_OBJ_USAGE
2571 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2572 #endif
2573 	    return(ret);
2574 	}
2575     }
2576     return(xmlXPathNewString(val));
2577 }
2578 
2579 /**
2580  * xmlXPathCacheNewBoolean:
2581  * @ctxt: the XPath context
2582  * @val:  the boolean value
2583  *
2584  * This is the cached version of xmlXPathNewBoolean().
2585  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2586  *
2587  * Returns the created or reused object.
2588  */
2589 static xmlXPathObjectPtr
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt,int val)2590 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2591 {
2592     if ((ctxt != NULL) && (ctxt->cache)) {
2593 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2594 
2595 	if ((cache->booleanObjs != NULL) &&
2596 	    (cache->booleanObjs->number != 0))
2597 	{
2598 	    xmlXPathObjectPtr ret;
2599 
2600 	    ret = (xmlXPathObjectPtr)
2601 		cache->booleanObjs->items[--cache->booleanObjs->number];
2602 	    ret->type = XPATH_BOOLEAN;
2603 	    ret->boolval = (val != 0);
2604 #ifdef XP_DEBUG_OBJ_USAGE
2605 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2606 #endif
2607 	    return(ret);
2608 	} else if ((cache->miscObjs != NULL) &&
2609 	    (cache->miscObjs->number != 0))
2610 	{
2611 	    xmlXPathObjectPtr ret;
2612 
2613 	    ret = (xmlXPathObjectPtr)
2614 		cache->miscObjs->items[--cache->miscObjs->number];
2615 
2616 	    ret->type = XPATH_BOOLEAN;
2617 	    ret->boolval = (val != 0);
2618 #ifdef XP_DEBUG_OBJ_USAGE
2619 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2620 #endif
2621 	    return(ret);
2622 	}
2623     }
2624     return(xmlXPathNewBoolean(val));
2625 }
2626 
2627 /**
2628  * xmlXPathCacheNewFloat:
2629  * @ctxt: the XPath context
2630  * @val:  the double value
2631  *
2632  * This is the cached version of xmlXPathNewFloat().
2633  * Acquires an xmlXPathObjectPtr of type double and of value @val
2634  *
2635  * Returns the created or reused object.
2636  */
2637 static xmlXPathObjectPtr
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt,double val)2638 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2639 {
2640      if ((ctxt != NULL) && (ctxt->cache)) {
2641 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2642 
2643 	if ((cache->numberObjs != NULL) &&
2644 	    (cache->numberObjs->number != 0))
2645 	{
2646 	    xmlXPathObjectPtr ret;
2647 
2648 	    ret = (xmlXPathObjectPtr)
2649 		cache->numberObjs->items[--cache->numberObjs->number];
2650 	    ret->type = XPATH_NUMBER;
2651 	    ret->floatval = val;
2652 #ifdef XP_DEBUG_OBJ_USAGE
2653 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2654 #endif
2655 	    return(ret);
2656 	} else if ((cache->miscObjs != NULL) &&
2657 	    (cache->miscObjs->number != 0))
2658 	{
2659 	    xmlXPathObjectPtr ret;
2660 
2661 	    ret = (xmlXPathObjectPtr)
2662 		cache->miscObjs->items[--cache->miscObjs->number];
2663 
2664 	    ret->type = XPATH_NUMBER;
2665 	    ret->floatval = val;
2666 #ifdef XP_DEBUG_OBJ_USAGE
2667 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2668 #endif
2669 	    return(ret);
2670 	}
2671     }
2672     return(xmlXPathNewFloat(val));
2673 }
2674 
2675 /**
2676  * xmlXPathCacheConvertString:
2677  * @ctxt: the XPath context
2678  * @val:  an XPath object
2679  *
2680  * This is the cached version of xmlXPathConvertString().
2681  * Converts an existing object to its string() equivalent
2682  *
2683  * Returns a created or reused object, the old one is freed (cached)
2684  *         (or the operation is done directly on @val)
2685  */
2686 
2687 static xmlXPathObjectPtr
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2688 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2689     xmlChar *res = NULL;
2690 
2691     if (val == NULL)
2692 	return(xmlXPathCacheNewCString(ctxt, ""));
2693 
2694     switch (val->type) {
2695     case XPATH_UNDEFINED:
2696 #ifdef DEBUG_EXPR
2697 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2698 #endif
2699 	break;
2700     case XPATH_NODESET:
2701     case XPATH_XSLT_TREE:
2702 	res = xmlXPathCastNodeSetToString(val->nodesetval);
2703 	break;
2704     case XPATH_STRING:
2705 	return(val);
2706     case XPATH_BOOLEAN:
2707 	res = xmlXPathCastBooleanToString(val->boolval);
2708 	break;
2709     case XPATH_NUMBER:
2710 	res = xmlXPathCastNumberToString(val->floatval);
2711 	break;
2712     case XPATH_USERS:
2713 #ifdef LIBXML_XPTR_LOCS_ENABLED
2714     case XPATH_POINT:
2715     case XPATH_RANGE:
2716     case XPATH_LOCATIONSET:
2717 #endif /* LIBXML_XPTR_LOCS_ENABLED */
2718 	TODO;
2719 	break;
2720     }
2721     xmlXPathReleaseObject(ctxt, val);
2722     if (res == NULL)
2723 	return(xmlXPathCacheNewCString(ctxt, ""));
2724     return(xmlXPathCacheWrapString(ctxt, res));
2725 }
2726 
2727 /**
2728  * xmlXPathCacheObjectCopy:
2729  * @ctxt: the XPath context
2730  * @val:  the original object
2731  *
2732  * This is the cached version of xmlXPathObjectCopy().
2733  * Acquire a copy of a given object
2734  *
2735  * Returns a created or reused created object.
2736  */
2737 static xmlXPathObjectPtr
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2738 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2739 {
2740     if (val == NULL)
2741 	return(NULL);
2742 
2743     if (XP_HAS_CACHE(ctxt)) {
2744 	switch (val->type) {
2745 	    case XPATH_NODESET:
2746 		return(xmlXPathCacheWrapNodeSet(ctxt,
2747 		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2748 	    case XPATH_STRING:
2749 		return(xmlXPathCacheNewString(ctxt, val->stringval));
2750 	    case XPATH_BOOLEAN:
2751 		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2752 	    case XPATH_NUMBER:
2753 		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2754 	    default:
2755 		break;
2756 	}
2757     }
2758     return(xmlXPathObjectCopy(val));
2759 }
2760 
2761 /**
2762  * xmlXPathCacheConvertBoolean:
2763  * @ctxt: the XPath context
2764  * @val:  an XPath object
2765  *
2766  * This is the cached version of xmlXPathConvertBoolean().
2767  * Converts an existing object to its boolean() equivalent
2768  *
2769  * Returns a created or reused object, the old one is freed (or the operation
2770  *         is done directly on @val)
2771  */
2772 static xmlXPathObjectPtr
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2773 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2774     xmlXPathObjectPtr ret;
2775 
2776     if (val == NULL)
2777 	return(xmlXPathCacheNewBoolean(ctxt, 0));
2778     if (val->type == XPATH_BOOLEAN)
2779 	return(val);
2780     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2781     xmlXPathReleaseObject(ctxt, val);
2782     return(ret);
2783 }
2784 
2785 /**
2786  * xmlXPathCacheConvertNumber:
2787  * @ctxt: the XPath context
2788  * @val:  an XPath object
2789  *
2790  * This is the cached version of xmlXPathConvertNumber().
2791  * Converts an existing object to its number() equivalent
2792  *
2793  * Returns a created or reused object, the old one is freed (or the operation
2794  *         is done directly on @val)
2795  */
2796 static xmlXPathObjectPtr
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2797 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2798     xmlXPathObjectPtr ret;
2799 
2800     if (val == NULL)
2801 	return(xmlXPathCacheNewFloat(ctxt, 0.0));
2802     if (val->type == XPATH_NUMBER)
2803 	return(val);
2804     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2805     xmlXPathReleaseObject(ctxt, val);
2806     return(ret);
2807 }
2808 
2809 /************************************************************************
2810  *									*
2811  *		Parser stacks related functions and macros		*
2812  *									*
2813  ************************************************************************/
2814 
2815 /**
2816  * xmlXPathSetFrame:
2817  * @ctxt: an XPath parser context
2818  *
2819  * Set the callee evaluation frame
2820  *
2821  * Returns the previous frame value to be restored once done
2822  */
2823 static int
xmlXPathSetFrame(xmlXPathParserContextPtr ctxt)2824 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2825     int ret;
2826 
2827     if (ctxt == NULL)
2828         return(0);
2829     ret = ctxt->valueFrame;
2830     ctxt->valueFrame = ctxt->valueNr;
2831     return(ret);
2832 }
2833 
2834 /**
2835  * xmlXPathPopFrame:
2836  * @ctxt: an XPath parser context
2837  * @frame: the previous frame value
2838  *
2839  * Remove the callee evaluation frame
2840  */
2841 static void
xmlXPathPopFrame(xmlXPathParserContextPtr ctxt,int frame)2842 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2843     if (ctxt == NULL)
2844         return;
2845     if (ctxt->valueNr < ctxt->valueFrame) {
2846         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2847     }
2848     ctxt->valueFrame = frame;
2849 }
2850 
2851 /**
2852  * valuePop:
2853  * @ctxt: an XPath evaluation context
2854  *
2855  * Pops the top XPath object from the value stack
2856  *
2857  * Returns the XPath object just removed
2858  */
2859 xmlXPathObjectPtr
valuePop(xmlXPathParserContextPtr ctxt)2860 valuePop(xmlXPathParserContextPtr ctxt)
2861 {
2862     xmlXPathObjectPtr ret;
2863 
2864     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2865         return (NULL);
2866 
2867     if (ctxt->valueNr <= ctxt->valueFrame) {
2868         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2869         return (NULL);
2870     }
2871 
2872     ctxt->valueNr--;
2873     if (ctxt->valueNr > 0)
2874         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2875     else
2876         ctxt->value = NULL;
2877     ret = ctxt->valueTab[ctxt->valueNr];
2878     ctxt->valueTab[ctxt->valueNr] = NULL;
2879     return (ret);
2880 }
2881 /**
2882  * valuePush:
2883  * @ctxt:  an XPath evaluation context
2884  * @value:  the XPath object
2885  *
2886  * Pushes a new XPath object on top of the value stack. If value is NULL,
2887  * a memory error is recorded in the parser context.
2888  *
2889  * Returns the number of items on the value stack, or -1 in case of error.
2890  */
2891 int
valuePush(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr value)2892 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2893 {
2894     if (ctxt == NULL) return(-1);
2895     if (value == NULL) {
2896         /*
2897          * A NULL value typically indicates that a memory allocation failed,
2898          * so we set ctxt->error here to propagate the error.
2899          */
2900 	ctxt->error = XPATH_MEMORY_ERROR;
2901         return(-1);
2902     }
2903     if (ctxt->valueNr >= ctxt->valueMax) {
2904         xmlXPathObjectPtr *tmp;
2905 
2906         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2907             xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2908             return (-1);
2909         }
2910         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2911                                              2 * ctxt->valueMax *
2912                                              sizeof(ctxt->valueTab[0]));
2913         if (tmp == NULL) {
2914             xmlXPathPErrMemory(ctxt, "pushing value\n");
2915             return (-1);
2916         }
2917         ctxt->valueMax *= 2;
2918 	ctxt->valueTab = tmp;
2919     }
2920     ctxt->valueTab[ctxt->valueNr] = value;
2921     ctxt->value = value;
2922     return (ctxt->valueNr++);
2923 }
2924 
2925 /**
2926  * xmlXPathPopBoolean:
2927  * @ctxt:  an XPath parser context
2928  *
2929  * Pops a boolean from the stack, handling conversion if needed.
2930  * Check error with #xmlXPathCheckError.
2931  *
2932  * Returns the boolean
2933  */
2934 int
xmlXPathPopBoolean(xmlXPathParserContextPtr ctxt)2935 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2936     xmlXPathObjectPtr obj;
2937     int ret;
2938 
2939     obj = valuePop(ctxt);
2940     if (obj == NULL) {
2941 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2942 	return(0);
2943     }
2944     if (obj->type != XPATH_BOOLEAN)
2945 	ret = xmlXPathCastToBoolean(obj);
2946     else
2947         ret = obj->boolval;
2948     xmlXPathReleaseObject(ctxt->context, obj);
2949     return(ret);
2950 }
2951 
2952 /**
2953  * xmlXPathPopNumber:
2954  * @ctxt:  an XPath parser context
2955  *
2956  * Pops a number from the stack, handling conversion if needed.
2957  * Check error with #xmlXPathCheckError.
2958  *
2959  * Returns the number
2960  */
2961 double
xmlXPathPopNumber(xmlXPathParserContextPtr ctxt)2962 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2963     xmlXPathObjectPtr obj;
2964     double ret;
2965 
2966     obj = valuePop(ctxt);
2967     if (obj == NULL) {
2968 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2969 	return(0);
2970     }
2971     if (obj->type != XPATH_NUMBER)
2972 	ret = xmlXPathCastToNumber(obj);
2973     else
2974         ret = obj->floatval;
2975     xmlXPathReleaseObject(ctxt->context, obj);
2976     return(ret);
2977 }
2978 
2979 /**
2980  * xmlXPathPopString:
2981  * @ctxt:  an XPath parser context
2982  *
2983  * Pops a string from the stack, handling conversion if needed.
2984  * Check error with #xmlXPathCheckError.
2985  *
2986  * Returns the string
2987  */
2988 xmlChar *
xmlXPathPopString(xmlXPathParserContextPtr ctxt)2989 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2990     xmlXPathObjectPtr obj;
2991     xmlChar * ret;
2992 
2993     obj = valuePop(ctxt);
2994     if (obj == NULL) {
2995 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2996 	return(NULL);
2997     }
2998     ret = xmlXPathCastToString(obj);	/* this does required strdup */
2999     /* TODO: needs refactoring somewhere else */
3000     if (obj->stringval == ret)
3001 	obj->stringval = NULL;
3002     xmlXPathReleaseObject(ctxt->context, obj);
3003     return(ret);
3004 }
3005 
3006 /**
3007  * xmlXPathPopNodeSet:
3008  * @ctxt:  an XPath parser context
3009  *
3010  * Pops a node-set from the stack, handling conversion if needed.
3011  * Check error with #xmlXPathCheckError.
3012  *
3013  * Returns the node-set
3014  */
3015 xmlNodeSetPtr
xmlXPathPopNodeSet(xmlXPathParserContextPtr ctxt)3016 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
3017     xmlXPathObjectPtr obj;
3018     xmlNodeSetPtr ret;
3019 
3020     if (ctxt == NULL) return(NULL);
3021     if (ctxt->value == NULL) {
3022 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3023 	return(NULL);
3024     }
3025     if (!xmlXPathStackIsNodeSet(ctxt)) {
3026 	xmlXPathSetTypeError(ctxt);
3027 	return(NULL);
3028     }
3029     obj = valuePop(ctxt);
3030     ret = obj->nodesetval;
3031 #if 0
3032     /* to fix memory leak of not clearing obj->user */
3033     if (obj->boolval && obj->user != NULL)
3034         xmlFreeNodeList((xmlNodePtr) obj->user);
3035 #endif
3036     obj->nodesetval = NULL;
3037     xmlXPathReleaseObject(ctxt->context, obj);
3038     return(ret);
3039 }
3040 
3041 /**
3042  * xmlXPathPopExternal:
3043  * @ctxt:  an XPath parser context
3044  *
3045  * Pops an external object from the stack, handling conversion if needed.
3046  * Check error with #xmlXPathCheckError.
3047  *
3048  * Returns the object
3049  */
3050 void *
xmlXPathPopExternal(xmlXPathParserContextPtr ctxt)3051 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3052     xmlXPathObjectPtr obj;
3053     void * ret;
3054 
3055     if ((ctxt == NULL) || (ctxt->value == NULL)) {
3056 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3057 	return(NULL);
3058     }
3059     if (ctxt->value->type != XPATH_USERS) {
3060 	xmlXPathSetTypeError(ctxt);
3061 	return(NULL);
3062     }
3063     obj = valuePop(ctxt);
3064     ret = obj->user;
3065     obj->user = NULL;
3066     xmlXPathReleaseObject(ctxt->context, obj);
3067     return(ret);
3068 }
3069 
3070 /*
3071  * Macros for accessing the content. Those should be used only by the parser,
3072  * and not exported.
3073  *
3074  * Dirty macros, i.e. one need to make assumption on the context to use them
3075  *
3076  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3077  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3078  *           in ISO-Latin or UTF-8.
3079  *           This should be used internally by the parser
3080  *           only to compare to ASCII values otherwise it would break when
3081  *           running with UTF-8 encoding.
3082  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3083  *           to compare on ASCII based substring.
3084  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3085  *           strings within the parser.
3086  *   CURRENT Returns the current char value, with the full decoding of
3087  *           UTF-8 if we are using this mode. It returns an int.
3088  *   NEXT    Skip to the next character, this does the proper decoding
3089  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3090  *           It returns the pointer to the current xmlChar.
3091  */
3092 
3093 #define CUR (*ctxt->cur)
3094 #define SKIP(val) ctxt->cur += (val)
3095 #define NXT(val) ctxt->cur[(val)]
3096 #define CUR_PTR ctxt->cur
3097 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3098 
3099 #define COPY_BUF(l,b,i,v)                                              \
3100     if (l == 1) b[i++] = (xmlChar) v;                                  \
3101     else i += xmlCopyChar(l,&b[i],v)
3102 
3103 #define NEXTL(l)  ctxt->cur += l
3104 
3105 #define SKIP_BLANKS							\
3106     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3107 
3108 #define CURRENT (*ctxt->cur)
3109 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3110 
3111 
3112 #ifndef DBL_DIG
3113 #define DBL_DIG 16
3114 #endif
3115 #ifndef DBL_EPSILON
3116 #define DBL_EPSILON 1E-9
3117 #endif
3118 
3119 #define UPPER_DOUBLE 1E9
3120 #define LOWER_DOUBLE 1E-5
3121 #define	LOWER_DOUBLE_EXP 5
3122 
3123 #define INTEGER_DIGITS DBL_DIG
3124 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3125 #define EXPONENT_DIGITS (3 + 2)
3126 
3127 /**
3128  * xmlXPathFormatNumber:
3129  * @number:     number to format
3130  * @buffer:     output buffer
3131  * @buffersize: size of output buffer
3132  *
3133  * Convert the number into a string representation.
3134  */
3135 static void
xmlXPathFormatNumber(double number,char buffer[],int buffersize)3136 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3137 {
3138     switch (xmlXPathIsInf(number)) {
3139     case 1:
3140 	if (buffersize > (int)sizeof("Infinity"))
3141 	    snprintf(buffer, buffersize, "Infinity");
3142 	break;
3143     case -1:
3144 	if (buffersize > (int)sizeof("-Infinity"))
3145 	    snprintf(buffer, buffersize, "-Infinity");
3146 	break;
3147     default:
3148 	if (xmlXPathIsNaN(number)) {
3149 	    if (buffersize > (int)sizeof("NaN"))
3150 		snprintf(buffer, buffersize, "NaN");
3151 	} else if (number == 0) {
3152             /* Omit sign for negative zero. */
3153 	    snprintf(buffer, buffersize, "0");
3154 	} else if ((number > INT_MIN) && (number < INT_MAX) &&
3155                    (number == (int) number)) {
3156 	    char work[30];
3157 	    char *ptr, *cur;
3158 	    int value = (int) number;
3159 
3160             ptr = &buffer[0];
3161 	    if (value == 0) {
3162 		*ptr++ = '0';
3163 	    } else {
3164 		snprintf(work, 29, "%d", value);
3165 		cur = &work[0];
3166 		while ((*cur) && (ptr - buffer < buffersize)) {
3167 		    *ptr++ = *cur++;
3168 		}
3169 	    }
3170 	    if (ptr - buffer < buffersize) {
3171 		*ptr = 0;
3172 	    } else if (buffersize > 0) {
3173 		ptr--;
3174 		*ptr = 0;
3175 	    }
3176 	} else {
3177 	    /*
3178 	      For the dimension of work,
3179 	          DBL_DIG is number of significant digits
3180 		  EXPONENT is only needed for "scientific notation"
3181 	          3 is sign, decimal point, and terminating zero
3182 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3183 	      Note that this dimension is slightly (a few characters)
3184 	      larger than actually necessary.
3185 	    */
3186 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3187 	    int integer_place, fraction_place;
3188 	    char *ptr;
3189 	    char *after_fraction;
3190 	    double absolute_value;
3191 	    int size;
3192 
3193 	    absolute_value = fabs(number);
3194 
3195 	    /*
3196 	     * First choose format - scientific or regular floating point.
3197 	     * In either case, result is in work, and after_fraction points
3198 	     * just past the fractional part.
3199 	    */
3200 	    if ( ((absolute_value > UPPER_DOUBLE) ||
3201 		  (absolute_value < LOWER_DOUBLE)) &&
3202 		 (absolute_value != 0.0) ) {
3203 		/* Use scientific notation */
3204 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3205 		fraction_place = DBL_DIG - 1;
3206 		size = snprintf(work, sizeof(work),"%*.*e",
3207 			 integer_place, fraction_place, number);
3208 		while ((size > 0) && (work[size] != 'e')) size--;
3209 
3210 	    }
3211 	    else {
3212 		/* Use regular notation */
3213 		if (absolute_value > 0.0) {
3214 		    integer_place = (int)log10(absolute_value);
3215 		    if (integer_place > 0)
3216 		        fraction_place = DBL_DIG - integer_place - 1;
3217 		    else
3218 		        fraction_place = DBL_DIG - integer_place;
3219 		} else {
3220 		    fraction_place = 1;
3221 		}
3222 		size = snprintf(work, sizeof(work), "%0.*f",
3223 				fraction_place, number);
3224 	    }
3225 
3226 	    /* Remove leading spaces sometimes inserted by snprintf */
3227 	    while (work[0] == ' ') {
3228 	        for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3229 		size--;
3230 	    }
3231 
3232 	    /* Remove fractional trailing zeroes */
3233 	    after_fraction = work + size;
3234 	    ptr = after_fraction;
3235 	    while (*(--ptr) == '0')
3236 		;
3237 	    if (*ptr != '.')
3238 	        ptr++;
3239 	    while ((*ptr++ = *after_fraction++) != 0);
3240 
3241 	    /* Finally copy result back to caller */
3242 	    size = strlen(work) + 1;
3243 	    if (size > buffersize) {
3244 		work[buffersize - 1] = 0;
3245 		size = buffersize;
3246 	    }
3247 	    memmove(buffer, work, size);
3248 	}
3249 	break;
3250     }
3251 }
3252 
3253 
3254 /************************************************************************
3255  *									*
3256  *			Routines to handle NodeSets			*
3257  *									*
3258  ************************************************************************/
3259 
3260 /**
3261  * xmlXPathOrderDocElems:
3262  * @doc:  an input document
3263  *
3264  * Call this routine to speed up XPath computation on static documents.
3265  * This stamps all the element nodes with the document order
3266  * Like for line information, the order is kept in the element->content
3267  * field, the value stored is actually - the node number (starting at -1)
3268  * to be able to differentiate from line numbers.
3269  *
3270  * Returns the number of elements found in the document or -1 in case
3271  *    of error.
3272  */
3273 long
xmlXPathOrderDocElems(xmlDocPtr doc)3274 xmlXPathOrderDocElems(xmlDocPtr doc) {
3275     ptrdiff_t count = 0;
3276     xmlNodePtr cur;
3277 
3278     if (doc == NULL)
3279 	return(-1);
3280     cur = doc->children;
3281     while (cur != NULL) {
3282 	if (cur->type == XML_ELEMENT_NODE) {
3283 	    cur->content = (void *) (-(++count));
3284 	    if (cur->children != NULL) {
3285 		cur = cur->children;
3286 		continue;
3287 	    }
3288 	}
3289 	if (cur->next != NULL) {
3290 	    cur = cur->next;
3291 	    continue;
3292 	}
3293 	do {
3294 	    cur = cur->parent;
3295 	    if (cur == NULL)
3296 		break;
3297 	    if (cur == (xmlNodePtr) doc) {
3298 		cur = NULL;
3299 		break;
3300 	    }
3301 	    if (cur->next != NULL) {
3302 		cur = cur->next;
3303 		break;
3304 	    }
3305 	} while (cur != NULL);
3306     }
3307     return((long) count);
3308 }
3309 
3310 /**
3311  * xmlXPathCmpNodes:
3312  * @node1:  the first node
3313  * @node2:  the second node
3314  *
3315  * Compare two nodes w.r.t document order
3316  *
3317  * Returns -2 in case of error 1 if first point < second point, 0 if
3318  *         it's the same node, -1 otherwise
3319  */
3320 int
xmlXPathCmpNodes(xmlNodePtr node1,xmlNodePtr node2)3321 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3322     int depth1, depth2;
3323     int attr1 = 0, attr2 = 0;
3324     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3325     xmlNodePtr cur, root;
3326 
3327     if ((node1 == NULL) || (node2 == NULL))
3328 	return(-2);
3329     /*
3330      * a couple of optimizations which will avoid computations in most cases
3331      */
3332     if (node1 == node2)		/* trivial case */
3333 	return(0);
3334     if (node1->type == XML_ATTRIBUTE_NODE) {
3335 	attr1 = 1;
3336 	attrNode1 = node1;
3337 	node1 = node1->parent;
3338     }
3339     if (node2->type == XML_ATTRIBUTE_NODE) {
3340 	attr2 = 1;
3341 	attrNode2 = node2;
3342 	node2 = node2->parent;
3343     }
3344     if (node1 == node2) {
3345 	if (attr1 == attr2) {
3346 	    /* not required, but we keep attributes in order */
3347 	    if (attr1 != 0) {
3348 	        cur = attrNode2->prev;
3349 		while (cur != NULL) {
3350 		    if (cur == attrNode1)
3351 		        return (1);
3352 		    cur = cur->prev;
3353 		}
3354 		return (-1);
3355 	    }
3356 	    return(0);
3357 	}
3358 	if (attr2 == 1)
3359 	    return(1);
3360 	return(-1);
3361     }
3362     if ((node1->type == XML_NAMESPACE_DECL) ||
3363         (node2->type == XML_NAMESPACE_DECL))
3364 	return(1);
3365     if (node1 == node2->prev)
3366 	return(1);
3367     if (node1 == node2->next)
3368 	return(-1);
3369 
3370     /*
3371      * Speedup using document order if available.
3372      */
3373     if ((node1->type == XML_ELEMENT_NODE) &&
3374 	(node2->type == XML_ELEMENT_NODE) &&
3375 	(0 > (ptrdiff_t) node1->content) &&
3376 	(0 > (ptrdiff_t) node2->content) &&
3377 	(node1->doc == node2->doc)) {
3378 	ptrdiff_t l1, l2;
3379 
3380 	l1 = -((ptrdiff_t) node1->content);
3381 	l2 = -((ptrdiff_t) node2->content);
3382 	if (l1 < l2)
3383 	    return(1);
3384 	if (l1 > l2)
3385 	    return(-1);
3386     }
3387 
3388     /*
3389      * compute depth to root
3390      */
3391     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3392 	if (cur->parent == node1)
3393 	    return(1);
3394 	depth2++;
3395     }
3396     root = cur;
3397     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3398 	if (cur->parent == node2)
3399 	    return(-1);
3400 	depth1++;
3401     }
3402     /*
3403      * Distinct document (or distinct entities :-( ) case.
3404      */
3405     if (root != cur) {
3406 	return(-2);
3407     }
3408     /*
3409      * get the nearest common ancestor.
3410      */
3411     while (depth1 > depth2) {
3412 	depth1--;
3413 	node1 = node1->parent;
3414     }
3415     while (depth2 > depth1) {
3416 	depth2--;
3417 	node2 = node2->parent;
3418     }
3419     while (node1->parent != node2->parent) {
3420 	node1 = node1->parent;
3421 	node2 = node2->parent;
3422 	/* should not happen but just in case ... */
3423 	if ((node1 == NULL) || (node2 == NULL))
3424 	    return(-2);
3425     }
3426     /*
3427      * Find who's first.
3428      */
3429     if (node1 == node2->prev)
3430 	return(1);
3431     if (node1 == node2->next)
3432 	return(-1);
3433     /*
3434      * Speedup using document order if available.
3435      */
3436     if ((node1->type == XML_ELEMENT_NODE) &&
3437 	(node2->type == XML_ELEMENT_NODE) &&
3438 	(0 > (ptrdiff_t) node1->content) &&
3439 	(0 > (ptrdiff_t) node2->content) &&
3440 	(node1->doc == node2->doc)) {
3441 	ptrdiff_t l1, l2;
3442 
3443 	l1 = -((ptrdiff_t) node1->content);
3444 	l2 = -((ptrdiff_t) node2->content);
3445 	if (l1 < l2)
3446 	    return(1);
3447 	if (l1 > l2)
3448 	    return(-1);
3449     }
3450 
3451     for (cur = node1->next;cur != NULL;cur = cur->next)
3452 	if (cur == node2)
3453 	    return(1);
3454     return(-1); /* assume there is no sibling list corruption */
3455 }
3456 
3457 /**
3458  * xmlXPathNodeSetSort:
3459  * @set:  the node set
3460  *
3461  * Sort the node set in document order
3462  */
3463 void
xmlXPathNodeSetSort(xmlNodeSetPtr set)3464 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3465 #ifndef WITH_TIM_SORT
3466     int i, j, incr, len;
3467     xmlNodePtr tmp;
3468 #endif
3469 
3470     if (set == NULL)
3471 	return;
3472 
3473 #ifndef WITH_TIM_SORT
3474     /*
3475      * Use the old Shell's sort implementation to sort the node-set
3476      * Timsort ought to be quite faster
3477      */
3478     len = set->nodeNr;
3479     for (incr = len / 2; incr > 0; incr /= 2) {
3480 	for (i = incr; i < len; i++) {
3481 	    j = i - incr;
3482 	    while (j >= 0) {
3483 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3484 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
3485 			set->nodeTab[j + incr]) == -1)
3486 #else
3487 		if (xmlXPathCmpNodes(set->nodeTab[j],
3488 			set->nodeTab[j + incr]) == -1)
3489 #endif
3490 		{
3491 		    tmp = set->nodeTab[j];
3492 		    set->nodeTab[j] = set->nodeTab[j + incr];
3493 		    set->nodeTab[j + incr] = tmp;
3494 		    j -= incr;
3495 		} else
3496 		    break;
3497 	    }
3498 	}
3499     }
3500 #else /* WITH_TIM_SORT */
3501     libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3502 #endif /* WITH_TIM_SORT */
3503 }
3504 
3505 #define XML_NODESET_DEFAULT	10
3506 /**
3507  * xmlXPathNodeSetDupNs:
3508  * @node:  the parent node of the namespace XPath node
3509  * @ns:  the libxml namespace declaration node.
3510  *
3511  * Namespace node in libxml don't match the XPath semantic. In a node set
3512  * the namespace nodes are duplicated and the next pointer is set to the
3513  * parent node in the XPath semantic.
3514  *
3515  * Returns the newly created object.
3516  */
3517 static xmlNodePtr
xmlXPathNodeSetDupNs(xmlNodePtr node,xmlNsPtr ns)3518 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3519     xmlNsPtr cur;
3520 
3521     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3522 	return(NULL);
3523     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3524 	return((xmlNodePtr) ns);
3525 
3526     /*
3527      * Allocate a new Namespace and fill the fields.
3528      */
3529     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3530     if (cur == NULL) {
3531         xmlXPathErrMemory(NULL, "duplicating namespace\n");
3532 	return(NULL);
3533     }
3534     memset(cur, 0, sizeof(xmlNs));
3535     cur->type = XML_NAMESPACE_DECL;
3536     if (ns->href != NULL)
3537 	cur->href = xmlStrdup(ns->href);
3538     if (ns->prefix != NULL)
3539 	cur->prefix = xmlStrdup(ns->prefix);
3540     cur->next = (xmlNsPtr) node;
3541     return((xmlNodePtr) cur);
3542 }
3543 
3544 /**
3545  * xmlXPathNodeSetFreeNs:
3546  * @ns:  the XPath namespace node found in a nodeset.
3547  *
3548  * Namespace nodes in libxml don't match the XPath semantic. In a node set
3549  * the namespace nodes are duplicated and the next pointer is set to the
3550  * parent node in the XPath semantic. Check if such a node needs to be freed
3551  */
3552 void
xmlXPathNodeSetFreeNs(xmlNsPtr ns)3553 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3554     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3555 	return;
3556 
3557     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3558 	if (ns->href != NULL)
3559 	    xmlFree((xmlChar *)ns->href);
3560 	if (ns->prefix != NULL)
3561 	    xmlFree((xmlChar *)ns->prefix);
3562 	xmlFree(ns);
3563     }
3564 }
3565 
3566 /**
3567  * xmlXPathNodeSetCreate:
3568  * @val:  an initial xmlNodePtr, or NULL
3569  *
3570  * Create a new xmlNodeSetPtr of type double and of value @val
3571  *
3572  * Returns the newly created object.
3573  */
3574 xmlNodeSetPtr
xmlXPathNodeSetCreate(xmlNodePtr val)3575 xmlXPathNodeSetCreate(xmlNodePtr val) {
3576     xmlNodeSetPtr ret;
3577 
3578     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3579     if (ret == NULL) {
3580         xmlXPathErrMemory(NULL, "creating nodeset\n");
3581 	return(NULL);
3582     }
3583     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3584     if (val != NULL) {
3585         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3586 					     sizeof(xmlNodePtr));
3587 	if (ret->nodeTab == NULL) {
3588 	    xmlXPathErrMemory(NULL, "creating nodeset\n");
3589 	    xmlFree(ret);
3590 	    return(NULL);
3591 	}
3592 	memset(ret->nodeTab, 0 ,
3593 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3594         ret->nodeMax = XML_NODESET_DEFAULT;
3595 	if (val->type == XML_NAMESPACE_DECL) {
3596 	    xmlNsPtr ns = (xmlNsPtr) val;
3597 
3598             /* TODO: Check memory error. */
3599 	    ret->nodeTab[ret->nodeNr++] =
3600 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3601 	} else
3602 	    ret->nodeTab[ret->nodeNr++] = val;
3603     }
3604     return(ret);
3605 }
3606 
3607 /**
3608  * xmlXPathNodeSetContains:
3609  * @cur:  the node-set
3610  * @val:  the node
3611  *
3612  * checks whether @cur contains @val
3613  *
3614  * Returns true (1) if @cur contains @val, false (0) otherwise
3615  */
3616 int
xmlXPathNodeSetContains(xmlNodeSetPtr cur,xmlNodePtr val)3617 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3618     int i;
3619 
3620     if ((cur == NULL) || (val == NULL)) return(0);
3621     if (val->type == XML_NAMESPACE_DECL) {
3622 	for (i = 0; i < cur->nodeNr; i++) {
3623 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3624 		xmlNsPtr ns1, ns2;
3625 
3626 		ns1 = (xmlNsPtr) val;
3627 		ns2 = (xmlNsPtr) cur->nodeTab[i];
3628 		if (ns1 == ns2)
3629 		    return(1);
3630 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3631 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
3632 		    return(1);
3633 	    }
3634 	}
3635     } else {
3636 	for (i = 0; i < cur->nodeNr; i++) {
3637 	    if (cur->nodeTab[i] == val)
3638 		return(1);
3639 	}
3640     }
3641     return(0);
3642 }
3643 
3644 /**
3645  * xmlXPathNodeSetAddNs:
3646  * @cur:  the initial node set
3647  * @node:  the hosting node
3648  * @ns:  a the namespace node
3649  *
3650  * add a new namespace node to an existing NodeSet
3651  *
3652  * Returns 0 in case of success and -1 in case of error
3653  */
3654 int
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur,xmlNodePtr node,xmlNsPtr ns)3655 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3656     int i;
3657 
3658 
3659     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3660         (ns->type != XML_NAMESPACE_DECL) ||
3661 	(node->type != XML_ELEMENT_NODE))
3662 	return(-1);
3663 
3664     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3665     /*
3666      * prevent duplicates
3667      */
3668     for (i = 0;i < cur->nodeNr;i++) {
3669         if ((cur->nodeTab[i] != NULL) &&
3670 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3671 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3672 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3673 	    return(0);
3674     }
3675 
3676     /*
3677      * grow the nodeTab if needed
3678      */
3679     if (cur->nodeMax == 0) {
3680         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3681 					     sizeof(xmlNodePtr));
3682 	if (cur->nodeTab == NULL) {
3683 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3684 	    return(-1);
3685 	}
3686 	memset(cur->nodeTab, 0 ,
3687 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3688         cur->nodeMax = XML_NODESET_DEFAULT;
3689     } else if (cur->nodeNr == cur->nodeMax) {
3690         xmlNodePtr *temp;
3691 
3692         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3693             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3694             return(-1);
3695         }
3696 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3697 				      sizeof(xmlNodePtr));
3698 	if (temp == NULL) {
3699 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3700 	    return(-1);
3701 	}
3702         cur->nodeMax *= 2;
3703 	cur->nodeTab = temp;
3704     }
3705     /* TODO: Check memory error. */
3706     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3707     return(0);
3708 }
3709 
3710 /**
3711  * xmlXPathNodeSetAdd:
3712  * @cur:  the initial node set
3713  * @val:  a new xmlNodePtr
3714  *
3715  * add a new xmlNodePtr to an existing NodeSet
3716  *
3717  * Returns 0 in case of success, and -1 in case of error
3718  */
3719 int
xmlXPathNodeSetAdd(xmlNodeSetPtr cur,xmlNodePtr val)3720 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3721     int i;
3722 
3723     if ((cur == NULL) || (val == NULL)) return(-1);
3724 
3725     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3726     /*
3727      * prevent duplicates
3728      */
3729     for (i = 0;i < cur->nodeNr;i++)
3730         if (cur->nodeTab[i] == val) return(0);
3731 
3732     /*
3733      * grow the nodeTab if needed
3734      */
3735     if (cur->nodeMax == 0) {
3736         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3737 					     sizeof(xmlNodePtr));
3738 	if (cur->nodeTab == NULL) {
3739 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3740 	    return(-1);
3741 	}
3742 	memset(cur->nodeTab, 0 ,
3743 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3744         cur->nodeMax = XML_NODESET_DEFAULT;
3745     } else if (cur->nodeNr == cur->nodeMax) {
3746         xmlNodePtr *temp;
3747 
3748         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3749             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3750             return(-1);
3751         }
3752 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3753 				      sizeof(xmlNodePtr));
3754 	if (temp == NULL) {
3755 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3756 	    return(-1);
3757 	}
3758         cur->nodeMax *= 2;
3759 	cur->nodeTab = temp;
3760     }
3761     if (val->type == XML_NAMESPACE_DECL) {
3762 	xmlNsPtr ns = (xmlNsPtr) val;
3763 
3764         /* TODO: Check memory error. */
3765 	cur->nodeTab[cur->nodeNr++] =
3766 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3767     } else
3768 	cur->nodeTab[cur->nodeNr++] = val;
3769     return(0);
3770 }
3771 
3772 /**
3773  * xmlXPathNodeSetAddUnique:
3774  * @cur:  the initial node set
3775  * @val:  a new xmlNodePtr
3776  *
3777  * add a new xmlNodePtr to an existing NodeSet, optimized version
3778  * when we are sure the node is not already in the set.
3779  *
3780  * Returns 0 in case of success and -1 in case of failure
3781  */
3782 int
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur,xmlNodePtr val)3783 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3784     if ((cur == NULL) || (val == NULL)) return(-1);
3785 
3786     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3787     /*
3788      * grow the nodeTab if needed
3789      */
3790     if (cur->nodeMax == 0) {
3791         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3792 					     sizeof(xmlNodePtr));
3793 	if (cur->nodeTab == NULL) {
3794 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3795 	    return(-1);
3796 	}
3797 	memset(cur->nodeTab, 0 ,
3798 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3799         cur->nodeMax = XML_NODESET_DEFAULT;
3800     } else if (cur->nodeNr == cur->nodeMax) {
3801         xmlNodePtr *temp;
3802 
3803         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3804             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3805             return(-1);
3806         }
3807 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3808 				      sizeof(xmlNodePtr));
3809 	if (temp == NULL) {
3810 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3811 	    return(-1);
3812 	}
3813 	cur->nodeTab = temp;
3814         cur->nodeMax *= 2;
3815     }
3816     if (val->type == XML_NAMESPACE_DECL) {
3817 	xmlNsPtr ns = (xmlNsPtr) val;
3818 
3819         /* TODO: Check memory error. */
3820 	cur->nodeTab[cur->nodeNr++] =
3821 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3822     } else
3823 	cur->nodeTab[cur->nodeNr++] = val;
3824     return(0);
3825 }
3826 
3827 /**
3828  * xmlXPathNodeSetMerge:
3829  * @val1:  the first NodeSet or NULL
3830  * @val2:  the second NodeSet
3831  *
3832  * Merges two nodesets, all nodes from @val2 are added to @val1
3833  * if @val1 is NULL, a new set is created and copied from @val2
3834  *
3835  * Returns @val1 once extended or NULL in case of error.
3836  */
3837 xmlNodeSetPtr
xmlXPathNodeSetMerge(xmlNodeSetPtr val1,xmlNodeSetPtr val2)3838 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3839     int i, j, initNr, skip;
3840     xmlNodePtr n1, n2;
3841 
3842     if (val2 == NULL) return(val1);
3843     if (val1 == NULL) {
3844 	val1 = xmlXPathNodeSetCreate(NULL);
3845     if (val1 == NULL)
3846         return (NULL);
3847 #if 0
3848 	/*
3849 	* TODO: The optimization won't work in every case, since
3850 	*  those nasty namespace nodes need to be added with
3851 	*  xmlXPathNodeSetDupNs() to the set; thus a pure
3852 	*  memcpy is not possible.
3853 	*  If there was a flag on the nodesetval, indicating that
3854 	*  some temporary nodes are in, that would be helpful.
3855 	*/
3856 	/*
3857 	* Optimization: Create an equally sized node-set
3858 	* and memcpy the content.
3859 	*/
3860 	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3861 	if (val1 == NULL)
3862 	    return(NULL);
3863 	if (val2->nodeNr != 0) {
3864 	    if (val2->nodeNr == 1)
3865 		*(val1->nodeTab) = *(val2->nodeTab);
3866 	    else {
3867 		memcpy(val1->nodeTab, val2->nodeTab,
3868 		    val2->nodeNr * sizeof(xmlNodePtr));
3869 	    }
3870 	    val1->nodeNr = val2->nodeNr;
3871 	}
3872 	return(val1);
3873 #endif
3874     }
3875 
3876     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3877     initNr = val1->nodeNr;
3878 
3879     for (i = 0;i < val2->nodeNr;i++) {
3880 	n2 = val2->nodeTab[i];
3881 	/*
3882 	 * check against duplicates
3883 	 */
3884 	skip = 0;
3885 	for (j = 0; j < initNr; j++) {
3886 	    n1 = val1->nodeTab[j];
3887 	    if (n1 == n2) {
3888 		skip = 1;
3889 		break;
3890 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3891 		       (n2->type == XML_NAMESPACE_DECL)) {
3892 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3893 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3894 			((xmlNsPtr) n2)->prefix)))
3895 		{
3896 		    skip = 1;
3897 		    break;
3898 		}
3899 	    }
3900 	}
3901 	if (skip)
3902 	    continue;
3903 
3904 	/*
3905 	 * grow the nodeTab if needed
3906 	 */
3907 	if (val1->nodeMax == 0) {
3908 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3909 						    sizeof(xmlNodePtr));
3910 	    if (val1->nodeTab == NULL) {
3911 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3912 		return(NULL);
3913 	    }
3914 	    memset(val1->nodeTab, 0 ,
3915 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3916 	    val1->nodeMax = XML_NODESET_DEFAULT;
3917 	} else if (val1->nodeNr == val1->nodeMax) {
3918 	    xmlNodePtr *temp;
3919 
3920             if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3921                 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3922                 return(NULL);
3923             }
3924 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3925 					     sizeof(xmlNodePtr));
3926 	    if (temp == NULL) {
3927 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3928 		return(NULL);
3929 	    }
3930 	    val1->nodeTab = temp;
3931 	    val1->nodeMax *= 2;
3932 	}
3933 	if (n2->type == XML_NAMESPACE_DECL) {
3934 	    xmlNsPtr ns = (xmlNsPtr) n2;
3935 
3936             /* TODO: Check memory error. */
3937 	    val1->nodeTab[val1->nodeNr++] =
3938 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3939 	} else
3940 	    val1->nodeTab[val1->nodeNr++] = n2;
3941     }
3942 
3943     return(val1);
3944 }
3945 
3946 
3947 /**
3948  * xmlXPathNodeSetMergeAndClear:
3949  * @set1:  the first NodeSet or NULL
3950  * @set2:  the second NodeSet
3951  *
3952  * Merges two nodesets, all nodes from @set2 are added to @set1.
3953  * Checks for duplicate nodes. Clears set2.
3954  *
3955  * Returns @set1 once extended or NULL in case of error.
3956  */
3957 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1,xmlNodeSetPtr set2)3958 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3959 {
3960     {
3961 	int i, j, initNbSet1;
3962 	xmlNodePtr n1, n2;
3963 
3964 	initNbSet1 = set1->nodeNr;
3965 	for (i = 0;i < set2->nodeNr;i++) {
3966 	    n2 = set2->nodeTab[i];
3967 	    /*
3968 	    * Skip duplicates.
3969 	    */
3970 	    for (j = 0; j < initNbSet1; j++) {
3971 		n1 = set1->nodeTab[j];
3972 		if (n1 == n2) {
3973 		    goto skip_node;
3974 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
3975 		    (n2->type == XML_NAMESPACE_DECL))
3976 		{
3977 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3978 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
3979 			((xmlNsPtr) n2)->prefix)))
3980 		    {
3981 			/*
3982 			* Free the namespace node.
3983 			*/
3984 			set2->nodeTab[i] = NULL;
3985 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3986 			goto skip_node;
3987 		    }
3988 		}
3989 	    }
3990 	    /*
3991 	    * grow the nodeTab if needed
3992 	    */
3993 	    if (set1->nodeMax == 0) {
3994 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3995 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3996 		if (set1->nodeTab == NULL) {
3997 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3998 		    return(NULL);
3999 		}
4000 		memset(set1->nodeTab, 0,
4001 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4002 		set1->nodeMax = XML_NODESET_DEFAULT;
4003 	    } else if (set1->nodeNr >= set1->nodeMax) {
4004 		xmlNodePtr *temp;
4005 
4006                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4007                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4008                     return(NULL);
4009                 }
4010 		temp = (xmlNodePtr *) xmlRealloc(
4011 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4012 		if (temp == NULL) {
4013 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4014 		    return(NULL);
4015 		}
4016 		set1->nodeTab = temp;
4017 		set1->nodeMax *= 2;
4018 	    }
4019 	    set1->nodeTab[set1->nodeNr++] = n2;
4020 skip_node:
4021 	    {}
4022 	}
4023     }
4024     set2->nodeNr = 0;
4025     return(set1);
4026 }
4027 
4028 /**
4029  * xmlXPathNodeSetMergeAndClearNoDupls:
4030  * @set1:  the first NodeSet or NULL
4031  * @set2:  the second NodeSet
4032  *
4033  * Merges two nodesets, all nodes from @set2 are added to @set1.
4034  * Doesn't check for duplicate nodes. Clears set2.
4035  *
4036  * Returns @set1 once extended or NULL in case of error.
4037  */
4038 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1,xmlNodeSetPtr set2)4039 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
4040 {
4041     {
4042 	int i;
4043 	xmlNodePtr n2;
4044 
4045 	for (i = 0;i < set2->nodeNr;i++) {
4046 	    n2 = set2->nodeTab[i];
4047 	    if (set1->nodeMax == 0) {
4048 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4049 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4050 		if (set1->nodeTab == NULL) {
4051 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4052 		    return(NULL);
4053 		}
4054 		memset(set1->nodeTab, 0,
4055 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4056 		set1->nodeMax = XML_NODESET_DEFAULT;
4057 	    } else if (set1->nodeNr >= set1->nodeMax) {
4058 		xmlNodePtr *temp;
4059 
4060                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4061                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4062                     return(NULL);
4063                 }
4064 		temp = (xmlNodePtr *) xmlRealloc(
4065 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4066 		if (temp == NULL) {
4067 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4068 		    return(NULL);
4069 		}
4070 		set1->nodeTab = temp;
4071 		set1->nodeMax *= 2;
4072 	    }
4073 	    set1->nodeTab[set1->nodeNr++] = n2;
4074 	}
4075     }
4076     set2->nodeNr = 0;
4077     return(set1);
4078 }
4079 
4080 /**
4081  * xmlXPathNodeSetDel:
4082  * @cur:  the initial node set
4083  * @val:  an xmlNodePtr
4084  *
4085  * Removes an xmlNodePtr from an existing NodeSet
4086  */
4087 void
xmlXPathNodeSetDel(xmlNodeSetPtr cur,xmlNodePtr val)4088 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4089     int i;
4090 
4091     if (cur == NULL) return;
4092     if (val == NULL) return;
4093 
4094     /*
4095      * find node in nodeTab
4096      */
4097     for (i = 0;i < cur->nodeNr;i++)
4098         if (cur->nodeTab[i] == val) break;
4099 
4100     if (i >= cur->nodeNr) {	/* not found */
4101 #ifdef DEBUG
4102         xmlGenericError(xmlGenericErrorContext,
4103 	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4104 		val->name);
4105 #endif
4106         return;
4107     }
4108     if ((cur->nodeTab[i] != NULL) &&
4109 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4110 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4111     cur->nodeNr--;
4112     for (;i < cur->nodeNr;i++)
4113         cur->nodeTab[i] = cur->nodeTab[i + 1];
4114     cur->nodeTab[cur->nodeNr] = NULL;
4115 }
4116 
4117 /**
4118  * xmlXPathNodeSetRemove:
4119  * @cur:  the initial node set
4120  * @val:  the index to remove
4121  *
4122  * Removes an entry from an existing NodeSet list.
4123  */
4124 void
xmlXPathNodeSetRemove(xmlNodeSetPtr cur,int val)4125 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4126     if (cur == NULL) return;
4127     if (val >= cur->nodeNr) return;
4128     if ((cur->nodeTab[val] != NULL) &&
4129 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4130 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4131     cur->nodeNr--;
4132     for (;val < cur->nodeNr;val++)
4133         cur->nodeTab[val] = cur->nodeTab[val + 1];
4134     cur->nodeTab[cur->nodeNr] = NULL;
4135 }
4136 
4137 /**
4138  * xmlXPathFreeNodeSet:
4139  * @obj:  the xmlNodeSetPtr to free
4140  *
4141  * Free the NodeSet compound (not the actual nodes !).
4142  */
4143 void
xmlXPathFreeNodeSet(xmlNodeSetPtr obj)4144 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4145     if (obj == NULL) return;
4146     if (obj->nodeTab != NULL) {
4147 	int i;
4148 
4149 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
4150 	for (i = 0;i < obj->nodeNr;i++)
4151 	    if ((obj->nodeTab[i] != NULL) &&
4152 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4153 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4154 	xmlFree(obj->nodeTab);
4155     }
4156     xmlFree(obj);
4157 }
4158 
4159 /**
4160  * xmlXPathNodeSetClearFromPos:
4161  * @set: the node set to be cleared
4162  * @pos: the start position to clear from
4163  *
4164  * Clears the list from temporary XPath objects (e.g. namespace nodes
4165  * are feed) starting with the entry at @pos, but does *not* free the list
4166  * itself. Sets the length of the list to @pos.
4167  */
4168 static void
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set,int pos,int hasNsNodes)4169 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4170 {
4171     if ((set == NULL) || (pos >= set->nodeNr))
4172 	return;
4173     else if ((hasNsNodes)) {
4174 	int i;
4175 	xmlNodePtr node;
4176 
4177 	for (i = pos; i < set->nodeNr; i++) {
4178 	    node = set->nodeTab[i];
4179 	    if ((node != NULL) &&
4180 		(node->type == XML_NAMESPACE_DECL))
4181 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4182 	}
4183     }
4184     set->nodeNr = pos;
4185 }
4186 
4187 /**
4188  * xmlXPathNodeSetClear:
4189  * @set:  the node set to clear
4190  *
4191  * Clears the list from all temporary XPath objects (e.g. namespace nodes
4192  * are feed), but does *not* free the list itself. Sets the length of the
4193  * list to 0.
4194  */
4195 static void
xmlXPathNodeSetClear(xmlNodeSetPtr set,int hasNsNodes)4196 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4197 {
4198     xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4199 }
4200 
4201 /**
4202  * xmlXPathNodeSetKeepLast:
4203  * @set: the node set to be cleared
4204  *
4205  * Move the last node to the first position and clear temporary XPath objects
4206  * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4207  * to 1.
4208  */
4209 static void
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)4210 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4211 {
4212     int i;
4213     xmlNodePtr node;
4214 
4215     if ((set == NULL) || (set->nodeNr <= 1))
4216 	return;
4217     for (i = 0; i < set->nodeNr - 1; i++) {
4218         node = set->nodeTab[i];
4219         if ((node != NULL) &&
4220             (node->type == XML_NAMESPACE_DECL))
4221             xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4222     }
4223     set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4224     set->nodeNr = 1;
4225 }
4226 
4227 /**
4228  * xmlXPathFreeValueTree:
4229  * @obj:  the xmlNodeSetPtr to free
4230  *
4231  * Free the NodeSet compound and the actual tree, this is different
4232  * from xmlXPathFreeNodeSet()
4233  */
4234 static void
xmlXPathFreeValueTree(xmlNodeSetPtr obj)4235 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4236     int i;
4237 
4238     if (obj == NULL) return;
4239 
4240     if (obj->nodeTab != NULL) {
4241 	for (i = 0;i < obj->nodeNr;i++) {
4242 	    if (obj->nodeTab[i] != NULL) {
4243 		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4244 		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4245 		} else {
4246 		    xmlFreeNodeList(obj->nodeTab[i]);
4247 		}
4248 	    }
4249 	}
4250 	xmlFree(obj->nodeTab);
4251     }
4252     xmlFree(obj);
4253 }
4254 
4255 #if defined(DEBUG) || defined(DEBUG_STEP)
4256 /**
4257  * xmlGenericErrorContextNodeSet:
4258  * @output:  a FILE * for the output
4259  * @obj:  the xmlNodeSetPtr to display
4260  *
4261  * Quick display of a NodeSet
4262  */
4263 void
xmlGenericErrorContextNodeSet(FILE * output,xmlNodeSetPtr obj)4264 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4265     int i;
4266 
4267     if (output == NULL) output = xmlGenericErrorContext;
4268     if (obj == NULL)  {
4269         fprintf(output, "NodeSet == NULL !\n");
4270 	return;
4271     }
4272     if (obj->nodeNr == 0) {
4273         fprintf(output, "NodeSet is empty\n");
4274 	return;
4275     }
4276     if (obj->nodeTab == NULL) {
4277 	fprintf(output, " nodeTab == NULL !\n");
4278 	return;
4279     }
4280     for (i = 0; i < obj->nodeNr; i++) {
4281         if (obj->nodeTab[i] == NULL) {
4282 	    fprintf(output, " NULL !\n");
4283 	    return;
4284         }
4285 	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4286 	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4287 	    fprintf(output, " /");
4288 	else if (obj->nodeTab[i]->name == NULL)
4289 	    fprintf(output, " noname!");
4290 	else fprintf(output, " %s", obj->nodeTab[i]->name);
4291     }
4292     fprintf(output, "\n");
4293 }
4294 #endif
4295 
4296 /**
4297  * xmlXPathNewNodeSet:
4298  * @val:  the NodePtr value
4299  *
4300  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4301  * it with the single Node @val
4302  *
4303  * Returns the newly created object.
4304  */
4305 xmlXPathObjectPtr
xmlXPathNewNodeSet(xmlNodePtr val)4306 xmlXPathNewNodeSet(xmlNodePtr val) {
4307     xmlXPathObjectPtr ret;
4308 
4309     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4310     if (ret == NULL) {
4311         xmlXPathErrMemory(NULL, "creating nodeset\n");
4312 	return(NULL);
4313     }
4314     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4315     ret->type = XPATH_NODESET;
4316     ret->boolval = 0;
4317     /* TODO: Check memory error. */
4318     ret->nodesetval = xmlXPathNodeSetCreate(val);
4319     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4320 #ifdef XP_DEBUG_OBJ_USAGE
4321     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4322 #endif
4323     return(ret);
4324 }
4325 
4326 /**
4327  * xmlXPathNewValueTree:
4328  * @val:  the NodePtr value
4329  *
4330  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4331  * it with the tree root @val
4332  *
4333  * Returns the newly created object.
4334  */
4335 xmlXPathObjectPtr
xmlXPathNewValueTree(xmlNodePtr val)4336 xmlXPathNewValueTree(xmlNodePtr val) {
4337     xmlXPathObjectPtr ret;
4338 
4339     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4340     if (ret == NULL) {
4341         xmlXPathErrMemory(NULL, "creating result value tree\n");
4342 	return(NULL);
4343     }
4344     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4345     ret->type = XPATH_XSLT_TREE;
4346     ret->boolval = 1;
4347     ret->user = (void *) val;
4348     ret->nodesetval = xmlXPathNodeSetCreate(val);
4349 #ifdef XP_DEBUG_OBJ_USAGE
4350     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4351 #endif
4352     return(ret);
4353 }
4354 
4355 /**
4356  * xmlXPathNewNodeSetList:
4357  * @val:  an existing NodeSet
4358  *
4359  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4360  * it with the Nodeset @val
4361  *
4362  * Returns the newly created object.
4363  */
4364 xmlXPathObjectPtr
xmlXPathNewNodeSetList(xmlNodeSetPtr val)4365 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4366 {
4367     xmlXPathObjectPtr ret;
4368     int i;
4369 
4370     if (val == NULL)
4371         ret = NULL;
4372     else if (val->nodeTab == NULL)
4373         ret = xmlXPathNewNodeSet(NULL);
4374     else {
4375         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4376         if (ret) {
4377             for (i = 1; i < val->nodeNr; ++i) {
4378                 /* TODO: Propagate memory error. */
4379                 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4380 		    < 0) break;
4381 	    }
4382 	}
4383     }
4384 
4385     return (ret);
4386 }
4387 
4388 /**
4389  * xmlXPathWrapNodeSet:
4390  * @val:  the NodePtr value
4391  *
4392  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4393  *
4394  * Returns the newly created object.
4395  */
4396 xmlXPathObjectPtr
xmlXPathWrapNodeSet(xmlNodeSetPtr val)4397 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4398     xmlXPathObjectPtr ret;
4399 
4400     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4401     if (ret == NULL) {
4402         xmlXPathErrMemory(NULL, "creating node set object\n");
4403 	return(NULL);
4404     }
4405     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4406     ret->type = XPATH_NODESET;
4407     ret->nodesetval = val;
4408 #ifdef XP_DEBUG_OBJ_USAGE
4409     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4410 #endif
4411     return(ret);
4412 }
4413 
4414 /**
4415  * xmlXPathFreeNodeSetList:
4416  * @obj:  an existing NodeSetList object
4417  *
4418  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4419  * the list contrary to xmlXPathFreeObject().
4420  */
4421 void
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj)4422 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4423     if (obj == NULL) return;
4424 #ifdef XP_DEBUG_OBJ_USAGE
4425     xmlXPathDebugObjUsageReleased(NULL, obj->type);
4426 #endif
4427     xmlFree(obj);
4428 }
4429 
4430 /**
4431  * xmlXPathDifference:
4432  * @nodes1:  a node-set
4433  * @nodes2:  a node-set
4434  *
4435  * Implements the EXSLT - Sets difference() function:
4436  *    node-set set:difference (node-set, node-set)
4437  *
4438  * Returns the difference between the two node sets, or nodes1 if
4439  *         nodes2 is empty
4440  */
4441 xmlNodeSetPtr
xmlXPathDifference(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4442 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4443     xmlNodeSetPtr ret;
4444     int i, l1;
4445     xmlNodePtr cur;
4446 
4447     if (xmlXPathNodeSetIsEmpty(nodes2))
4448 	return(nodes1);
4449 
4450     /* TODO: Check memory error. */
4451     ret = xmlXPathNodeSetCreate(NULL);
4452     if (xmlXPathNodeSetIsEmpty(nodes1))
4453 	return(ret);
4454 
4455     l1 = xmlXPathNodeSetGetLength(nodes1);
4456 
4457     for (i = 0; i < l1; i++) {
4458 	cur = xmlXPathNodeSetItem(nodes1, i);
4459 	if (!xmlXPathNodeSetContains(nodes2, cur)) {
4460             /* TODO: Propagate memory error. */
4461 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4462 	        break;
4463 	}
4464     }
4465     return(ret);
4466 }
4467 
4468 /**
4469  * xmlXPathIntersection:
4470  * @nodes1:  a node-set
4471  * @nodes2:  a node-set
4472  *
4473  * Implements the EXSLT - Sets intersection() function:
4474  *    node-set set:intersection (node-set, node-set)
4475  *
4476  * Returns a node set comprising the nodes that are within both the
4477  *         node sets passed as arguments
4478  */
4479 xmlNodeSetPtr
xmlXPathIntersection(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4480 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4481     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4482     int i, l1;
4483     xmlNodePtr cur;
4484 
4485     if (ret == NULL)
4486         return(ret);
4487     if (xmlXPathNodeSetIsEmpty(nodes1))
4488 	return(ret);
4489     if (xmlXPathNodeSetIsEmpty(nodes2))
4490 	return(ret);
4491 
4492     l1 = xmlXPathNodeSetGetLength(nodes1);
4493 
4494     for (i = 0; i < l1; i++) {
4495 	cur = xmlXPathNodeSetItem(nodes1, i);
4496 	if (xmlXPathNodeSetContains(nodes2, cur)) {
4497             /* TODO: Propagate memory error. */
4498 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4499 	        break;
4500 	}
4501     }
4502     return(ret);
4503 }
4504 
4505 /**
4506  * xmlXPathDistinctSorted:
4507  * @nodes:  a node-set, sorted by document order
4508  *
4509  * Implements the EXSLT - Sets distinct() function:
4510  *    node-set set:distinct (node-set)
4511  *
4512  * Returns a subset of the nodes contained in @nodes, or @nodes if
4513  *         it is empty
4514  */
4515 xmlNodeSetPtr
xmlXPathDistinctSorted(xmlNodeSetPtr nodes)4516 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4517     xmlNodeSetPtr ret;
4518     xmlHashTablePtr hash;
4519     int i, l;
4520     xmlChar * strval;
4521     xmlNodePtr cur;
4522 
4523     if (xmlXPathNodeSetIsEmpty(nodes))
4524 	return(nodes);
4525 
4526     ret = xmlXPathNodeSetCreate(NULL);
4527     if (ret == NULL)
4528         return(ret);
4529     l = xmlXPathNodeSetGetLength(nodes);
4530     hash = xmlHashCreate (l);
4531     for (i = 0; i < l; i++) {
4532 	cur = xmlXPathNodeSetItem(nodes, i);
4533 	strval = xmlXPathCastNodeToString(cur);
4534 	if (xmlHashLookup(hash, strval) == NULL) {
4535 	    xmlHashAddEntry(hash, strval, strval);
4536             /* TODO: Propagate memory error. */
4537 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4538 	        break;
4539 	} else {
4540 	    xmlFree(strval);
4541 	}
4542     }
4543     xmlHashFree(hash, xmlHashDefaultDeallocator);
4544     return(ret);
4545 }
4546 
4547 /**
4548  * xmlXPathDistinct:
4549  * @nodes:  a node-set
4550  *
4551  * Implements the EXSLT - Sets distinct() function:
4552  *    node-set set:distinct (node-set)
4553  * @nodes is sorted by document order, then #exslSetsDistinctSorted
4554  * is called with the sorted node-set
4555  *
4556  * Returns a subset of the nodes contained in @nodes, or @nodes if
4557  *         it is empty
4558  */
4559 xmlNodeSetPtr
xmlXPathDistinct(xmlNodeSetPtr nodes)4560 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4561     if (xmlXPathNodeSetIsEmpty(nodes))
4562 	return(nodes);
4563 
4564     xmlXPathNodeSetSort(nodes);
4565     return(xmlXPathDistinctSorted(nodes));
4566 }
4567 
4568 /**
4569  * xmlXPathHasSameNodes:
4570  * @nodes1:  a node-set
4571  * @nodes2:  a node-set
4572  *
4573  * Implements the EXSLT - Sets has-same-nodes function:
4574  *    boolean set:has-same-node(node-set, node-set)
4575  *
4576  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4577  *         otherwise
4578  */
4579 int
xmlXPathHasSameNodes(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4580 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4581     int i, l;
4582     xmlNodePtr cur;
4583 
4584     if (xmlXPathNodeSetIsEmpty(nodes1) ||
4585 	xmlXPathNodeSetIsEmpty(nodes2))
4586 	return(0);
4587 
4588     l = xmlXPathNodeSetGetLength(nodes1);
4589     for (i = 0; i < l; i++) {
4590 	cur = xmlXPathNodeSetItem(nodes1, i);
4591 	if (xmlXPathNodeSetContains(nodes2, cur))
4592 	    return(1);
4593     }
4594     return(0);
4595 }
4596 
4597 /**
4598  * xmlXPathNodeLeadingSorted:
4599  * @nodes: a node-set, sorted by document order
4600  * @node: a node
4601  *
4602  * Implements the EXSLT - Sets leading() function:
4603  *    node-set set:leading (node-set, node-set)
4604  *
4605  * Returns the nodes in @nodes that precede @node in document order,
4606  *         @nodes if @node is NULL or an empty node-set if @nodes
4607  *         doesn't contain @node
4608  */
4609 xmlNodeSetPtr
xmlXPathNodeLeadingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4610 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4611     int i, l;
4612     xmlNodePtr cur;
4613     xmlNodeSetPtr ret;
4614 
4615     if (node == NULL)
4616 	return(nodes);
4617 
4618     ret = xmlXPathNodeSetCreate(NULL);
4619     if (ret == NULL)
4620         return(ret);
4621     if (xmlXPathNodeSetIsEmpty(nodes) ||
4622 	(!xmlXPathNodeSetContains(nodes, node)))
4623 	return(ret);
4624 
4625     l = xmlXPathNodeSetGetLength(nodes);
4626     for (i = 0; i < l; i++) {
4627 	cur = xmlXPathNodeSetItem(nodes, i);
4628 	if (cur == node)
4629 	    break;
4630         /* TODO: Propagate memory error. */
4631 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4632 	    break;
4633     }
4634     return(ret);
4635 }
4636 
4637 /**
4638  * xmlXPathNodeLeading:
4639  * @nodes:  a node-set
4640  * @node:  a node
4641  *
4642  * Implements the EXSLT - Sets leading() function:
4643  *    node-set set:leading (node-set, node-set)
4644  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4645  * is called.
4646  *
4647  * Returns the nodes in @nodes that precede @node in document order,
4648  *         @nodes if @node is NULL or an empty node-set if @nodes
4649  *         doesn't contain @node
4650  */
4651 xmlNodeSetPtr
xmlXPathNodeLeading(xmlNodeSetPtr nodes,xmlNodePtr node)4652 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4653     xmlXPathNodeSetSort(nodes);
4654     return(xmlXPathNodeLeadingSorted(nodes, node));
4655 }
4656 
4657 /**
4658  * xmlXPathLeadingSorted:
4659  * @nodes1:  a node-set, sorted by document order
4660  * @nodes2:  a node-set, sorted by document order
4661  *
4662  * Implements the EXSLT - Sets leading() function:
4663  *    node-set set:leading (node-set, node-set)
4664  *
4665  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4666  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4667  *         an empty node-set if @nodes1 doesn't contain @nodes2
4668  */
4669 xmlNodeSetPtr
xmlXPathLeadingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4670 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4671     if (xmlXPathNodeSetIsEmpty(nodes2))
4672 	return(nodes1);
4673     return(xmlXPathNodeLeadingSorted(nodes1,
4674 				     xmlXPathNodeSetItem(nodes2, 1)));
4675 }
4676 
4677 /**
4678  * xmlXPathLeading:
4679  * @nodes1:  a node-set
4680  * @nodes2:  a node-set
4681  *
4682  * Implements the EXSLT - Sets leading() function:
4683  *    node-set set:leading (node-set, node-set)
4684  * @nodes1 and @nodes2 are sorted by document order, then
4685  * #exslSetsLeadingSorted is called.
4686  *
4687  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4688  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4689  *         an empty node-set if @nodes1 doesn't contain @nodes2
4690  */
4691 xmlNodeSetPtr
xmlXPathLeading(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4692 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4693     if (xmlXPathNodeSetIsEmpty(nodes2))
4694 	return(nodes1);
4695     if (xmlXPathNodeSetIsEmpty(nodes1))
4696 	return(xmlXPathNodeSetCreate(NULL));
4697     xmlXPathNodeSetSort(nodes1);
4698     xmlXPathNodeSetSort(nodes2);
4699     return(xmlXPathNodeLeadingSorted(nodes1,
4700 				     xmlXPathNodeSetItem(nodes2, 1)));
4701 }
4702 
4703 /**
4704  * xmlXPathNodeTrailingSorted:
4705  * @nodes: a node-set, sorted by document order
4706  * @node: a node
4707  *
4708  * Implements the EXSLT - Sets trailing() function:
4709  *    node-set set:trailing (node-set, node-set)
4710  *
4711  * Returns the nodes in @nodes that follow @node in document order,
4712  *         @nodes if @node is NULL or an empty node-set if @nodes
4713  *         doesn't contain @node
4714  */
4715 xmlNodeSetPtr
xmlXPathNodeTrailingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4716 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4717     int i, l;
4718     xmlNodePtr cur;
4719     xmlNodeSetPtr ret;
4720 
4721     if (node == NULL)
4722 	return(nodes);
4723 
4724     ret = xmlXPathNodeSetCreate(NULL);
4725     if (ret == NULL)
4726         return(ret);
4727     if (xmlXPathNodeSetIsEmpty(nodes) ||
4728 	(!xmlXPathNodeSetContains(nodes, node)))
4729 	return(ret);
4730 
4731     l = xmlXPathNodeSetGetLength(nodes);
4732     for (i = l - 1; i >= 0; i--) {
4733 	cur = xmlXPathNodeSetItem(nodes, i);
4734 	if (cur == node)
4735 	    break;
4736         /* TODO: Propagate memory error. */
4737 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4738 	    break;
4739     }
4740     xmlXPathNodeSetSort(ret);	/* bug 413451 */
4741     return(ret);
4742 }
4743 
4744 /**
4745  * xmlXPathNodeTrailing:
4746  * @nodes:  a node-set
4747  * @node:  a node
4748  *
4749  * Implements the EXSLT - Sets trailing() function:
4750  *    node-set set:trailing (node-set, node-set)
4751  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4752  * is called.
4753  *
4754  * Returns the nodes in @nodes that follow @node in document order,
4755  *         @nodes if @node is NULL or an empty node-set if @nodes
4756  *         doesn't contain @node
4757  */
4758 xmlNodeSetPtr
xmlXPathNodeTrailing(xmlNodeSetPtr nodes,xmlNodePtr node)4759 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4760     xmlXPathNodeSetSort(nodes);
4761     return(xmlXPathNodeTrailingSorted(nodes, node));
4762 }
4763 
4764 /**
4765  * xmlXPathTrailingSorted:
4766  * @nodes1:  a node-set, sorted by document order
4767  * @nodes2:  a node-set, sorted by document order
4768  *
4769  * Implements the EXSLT - Sets trailing() function:
4770  *    node-set set:trailing (node-set, node-set)
4771  *
4772  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4773  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4774  *         an empty node-set if @nodes1 doesn't contain @nodes2
4775  */
4776 xmlNodeSetPtr
xmlXPathTrailingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4777 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4778     if (xmlXPathNodeSetIsEmpty(nodes2))
4779 	return(nodes1);
4780     return(xmlXPathNodeTrailingSorted(nodes1,
4781 				      xmlXPathNodeSetItem(nodes2, 0)));
4782 }
4783 
4784 /**
4785  * xmlXPathTrailing:
4786  * @nodes1:  a node-set
4787  * @nodes2:  a node-set
4788  *
4789  * Implements the EXSLT - Sets trailing() function:
4790  *    node-set set:trailing (node-set, node-set)
4791  * @nodes1 and @nodes2 are sorted by document order, then
4792  * #xmlXPathTrailingSorted is called.
4793  *
4794  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4795  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4796  *         an empty node-set if @nodes1 doesn't contain @nodes2
4797  */
4798 xmlNodeSetPtr
xmlXPathTrailing(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4799 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4800     if (xmlXPathNodeSetIsEmpty(nodes2))
4801 	return(nodes1);
4802     if (xmlXPathNodeSetIsEmpty(nodes1))
4803 	return(xmlXPathNodeSetCreate(NULL));
4804     xmlXPathNodeSetSort(nodes1);
4805     xmlXPathNodeSetSort(nodes2);
4806     return(xmlXPathNodeTrailingSorted(nodes1,
4807 				      xmlXPathNodeSetItem(nodes2, 0)));
4808 }
4809 
4810 /************************************************************************
4811  *									*
4812  *		Routines to handle extra functions			*
4813  *									*
4814  ************************************************************************/
4815 
4816 /**
4817  * xmlXPathRegisterFunc:
4818  * @ctxt:  the XPath context
4819  * @name:  the function name
4820  * @f:  the function implementation or NULL
4821  *
4822  * Register a new function. If @f is NULL it unregisters the function
4823  *
4824  * Returns 0 in case of success, -1 in case of error
4825  */
4826 int
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathFunction f)4827 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4828 		     xmlXPathFunction f) {
4829     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4830 }
4831 
4832 /**
4833  * xmlXPathRegisterFuncNS:
4834  * @ctxt:  the XPath context
4835  * @name:  the function name
4836  * @ns_uri:  the function namespace URI
4837  * @f:  the function implementation or NULL
4838  *
4839  * Register a new function. If @f is NULL it unregisters the function
4840  *
4841  * Returns 0 in case of success, -1 in case of error
4842  */
4843 int
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathFunction f)4844 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4845 		       const xmlChar *ns_uri, xmlXPathFunction f) {
4846     if (ctxt == NULL)
4847 	return(-1);
4848     if (name == NULL)
4849 	return(-1);
4850 
4851     if (ctxt->funcHash == NULL)
4852 	ctxt->funcHash = xmlHashCreate(0);
4853     if (ctxt->funcHash == NULL)
4854 	return(-1);
4855     if (f == NULL)
4856         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4857 XML_IGNORE_PEDANTIC_WARNINGS
4858     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4859 XML_POP_WARNINGS
4860 }
4861 
4862 /**
4863  * xmlXPathRegisterFuncLookup:
4864  * @ctxt:  the XPath context
4865  * @f:  the lookup function
4866  * @funcCtxt:  the lookup data
4867  *
4868  * Registers an external mechanism to do function lookup.
4869  */
4870 void
xmlXPathRegisterFuncLookup(xmlXPathContextPtr ctxt,xmlXPathFuncLookupFunc f,void * funcCtxt)4871 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4872 			    xmlXPathFuncLookupFunc f,
4873 			    void *funcCtxt) {
4874     if (ctxt == NULL)
4875 	return;
4876     ctxt->funcLookupFunc = f;
4877     ctxt->funcLookupData = funcCtxt;
4878 }
4879 
4880 /**
4881  * xmlXPathFunctionLookup:
4882  * @ctxt:  the XPath context
4883  * @name:  the function name
4884  *
4885  * Search in the Function array of the context for the given
4886  * function.
4887  *
4888  * Returns the xmlXPathFunction or NULL if not found
4889  */
4890 xmlXPathFunction
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt,const xmlChar * name)4891 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4892     if (ctxt == NULL)
4893 	return (NULL);
4894 
4895     if (ctxt->funcLookupFunc != NULL) {
4896 	xmlXPathFunction ret;
4897 	xmlXPathFuncLookupFunc f;
4898 
4899 	f = ctxt->funcLookupFunc;
4900 	ret = f(ctxt->funcLookupData, name, NULL);
4901 	if (ret != NULL)
4902 	    return(ret);
4903     }
4904     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4905 }
4906 
4907 /**
4908  * xmlXPathFunctionLookupNS:
4909  * @ctxt:  the XPath context
4910  * @name:  the function name
4911  * @ns_uri:  the function namespace URI
4912  *
4913  * Search in the Function array of the context for the given
4914  * function.
4915  *
4916  * Returns the xmlXPathFunction or NULL if not found
4917  */
4918 xmlXPathFunction
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4919 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4920 			 const xmlChar *ns_uri) {
4921     xmlXPathFunction ret;
4922 
4923     if (ctxt == NULL)
4924 	return(NULL);
4925     if (name == NULL)
4926 	return(NULL);
4927 
4928     if (ctxt->funcLookupFunc != NULL) {
4929 	xmlXPathFuncLookupFunc f;
4930 
4931 	f = ctxt->funcLookupFunc;
4932 	ret = f(ctxt->funcLookupData, name, ns_uri);
4933 	if (ret != NULL)
4934 	    return(ret);
4935     }
4936 
4937     if (ctxt->funcHash == NULL)
4938 	return(NULL);
4939 
4940 XML_IGNORE_PEDANTIC_WARNINGS
4941     ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4942 XML_POP_WARNINGS
4943     return(ret);
4944 }
4945 
4946 /**
4947  * xmlXPathRegisteredFuncsCleanup:
4948  * @ctxt:  the XPath context
4949  *
4950  * Cleanup the XPath context data associated to registered functions
4951  */
4952 void
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt)4953 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4954     if (ctxt == NULL)
4955 	return;
4956 
4957     xmlHashFree(ctxt->funcHash, NULL);
4958     ctxt->funcHash = NULL;
4959 }
4960 
4961 /************************************************************************
4962  *									*
4963  *			Routines to handle Variables			*
4964  *									*
4965  ************************************************************************/
4966 
4967 /**
4968  * xmlXPathRegisterVariable:
4969  * @ctxt:  the XPath context
4970  * @name:  the variable name
4971  * @value:  the variable value or NULL
4972  *
4973  * Register a new variable value. If @value is NULL it unregisters
4974  * the variable
4975  *
4976  * Returns 0 in case of success, -1 in case of error
4977  */
4978 int
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathObjectPtr value)4979 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4980 			 xmlXPathObjectPtr value) {
4981     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4982 }
4983 
4984 /**
4985  * xmlXPathRegisterVariableNS:
4986  * @ctxt:  the XPath context
4987  * @name:  the variable name
4988  * @ns_uri:  the variable namespace URI
4989  * @value:  the variable value or NULL
4990  *
4991  * Register a new variable value. If @value is NULL it unregisters
4992  * the variable
4993  *
4994  * Returns 0 in case of success, -1 in case of error
4995  */
4996 int
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathObjectPtr value)4997 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4998 			   const xmlChar *ns_uri,
4999 			   xmlXPathObjectPtr value) {
5000     if (ctxt == NULL)
5001 	return(-1);
5002     if (name == NULL)
5003 	return(-1);
5004 
5005     if (ctxt->varHash == NULL)
5006 	ctxt->varHash = xmlHashCreate(0);
5007     if (ctxt->varHash == NULL)
5008 	return(-1);
5009     if (value == NULL)
5010         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5011 	                           xmlXPathFreeObjectEntry));
5012     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5013 			       (void *) value, xmlXPathFreeObjectEntry));
5014 }
5015 
5016 /**
5017  * xmlXPathRegisterVariableLookup:
5018  * @ctxt:  the XPath context
5019  * @f:  the lookup function
5020  * @data:  the lookup data
5021  *
5022  * register an external mechanism to do variable lookup
5023  */
5024 void
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,xmlXPathVariableLookupFunc f,void * data)5025 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5026 	 xmlXPathVariableLookupFunc f, void *data) {
5027     if (ctxt == NULL)
5028 	return;
5029     ctxt->varLookupFunc = f;
5030     ctxt->varLookupData = data;
5031 }
5032 
5033 /**
5034  * xmlXPathVariableLookup:
5035  * @ctxt:  the XPath context
5036  * @name:  the variable name
5037  *
5038  * Search in the Variable array of the context for the given
5039  * variable value.
5040  *
5041  * Returns a copy of the value or NULL if not found
5042  */
5043 xmlXPathObjectPtr
xmlXPathVariableLookup(xmlXPathContextPtr ctxt,const xmlChar * name)5044 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5045     if (ctxt == NULL)
5046 	return(NULL);
5047 
5048     if (ctxt->varLookupFunc != NULL) {
5049 	xmlXPathObjectPtr ret;
5050 
5051 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5052 	        (ctxt->varLookupData, name, NULL);
5053 	return(ret);
5054     }
5055     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5056 }
5057 
5058 /**
5059  * xmlXPathVariableLookupNS:
5060  * @ctxt:  the XPath context
5061  * @name:  the variable name
5062  * @ns_uri:  the variable namespace URI
5063  *
5064  * Search in the Variable array of the context for the given
5065  * variable value.
5066  *
5067  * Returns the a copy of the value or NULL if not found
5068  */
5069 xmlXPathObjectPtr
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)5070 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5071 			 const xmlChar *ns_uri) {
5072     if (ctxt == NULL)
5073 	return(NULL);
5074 
5075     if (ctxt->varLookupFunc != NULL) {
5076 	xmlXPathObjectPtr ret;
5077 
5078 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5079 	        (ctxt->varLookupData, name, ns_uri);
5080 	if (ret != NULL) return(ret);
5081     }
5082 
5083     if (ctxt->varHash == NULL)
5084 	return(NULL);
5085     if (name == NULL)
5086 	return(NULL);
5087 
5088     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5089 		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5090 }
5091 
5092 /**
5093  * xmlXPathRegisteredVariablesCleanup:
5094  * @ctxt:  the XPath context
5095  *
5096  * Cleanup the XPath context data associated to registered variables
5097  */
5098 void
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt)5099 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5100     if (ctxt == NULL)
5101 	return;
5102 
5103     xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5104     ctxt->varHash = NULL;
5105 }
5106 
5107 /**
5108  * xmlXPathRegisterNs:
5109  * @ctxt:  the XPath context
5110  * @prefix:  the namespace prefix cannot be NULL or empty string
5111  * @ns_uri:  the namespace name
5112  *
5113  * Register a new namespace. If @ns_uri is NULL it unregisters
5114  * the namespace
5115  *
5116  * Returns 0 in case of success, -1 in case of error
5117  */
5118 int
xmlXPathRegisterNs(xmlXPathContextPtr ctxt,const xmlChar * prefix,const xmlChar * ns_uri)5119 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5120 			   const xmlChar *ns_uri) {
5121     if (ctxt == NULL)
5122 	return(-1);
5123     if (prefix == NULL)
5124 	return(-1);
5125     if (prefix[0] == 0)
5126 	return(-1);
5127 
5128     if (ctxt->nsHash == NULL)
5129 	ctxt->nsHash = xmlHashCreate(10);
5130     if (ctxt->nsHash == NULL)
5131 	return(-1);
5132     if (ns_uri == NULL)
5133         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5134 	                          xmlHashDefaultDeallocator));
5135     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5136 			      xmlHashDefaultDeallocator));
5137 }
5138 
5139 /**
5140  * xmlXPathNsLookup:
5141  * @ctxt:  the XPath context
5142  * @prefix:  the namespace prefix value
5143  *
5144  * Search in the namespace declaration array of the context for the given
5145  * namespace name associated to the given prefix
5146  *
5147  * Returns the value or NULL if not found
5148  */
5149 const xmlChar *
xmlXPathNsLookup(xmlXPathContextPtr ctxt,const xmlChar * prefix)5150 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5151     if (ctxt == NULL)
5152 	return(NULL);
5153     if (prefix == NULL)
5154 	return(NULL);
5155 
5156 #ifdef XML_XML_NAMESPACE
5157     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5158 	return(XML_XML_NAMESPACE);
5159 #endif
5160 
5161     if (ctxt->namespaces != NULL) {
5162 	int i;
5163 
5164 	for (i = 0;i < ctxt->nsNr;i++) {
5165 	    if ((ctxt->namespaces[i] != NULL) &&
5166 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5167 		return(ctxt->namespaces[i]->href);
5168 	}
5169     }
5170 
5171     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5172 }
5173 
5174 /**
5175  * xmlXPathRegisteredNsCleanup:
5176  * @ctxt:  the XPath context
5177  *
5178  * Cleanup the XPath context data associated to registered variables
5179  */
5180 void
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt)5181 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5182     if (ctxt == NULL)
5183 	return;
5184 
5185     xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5186     ctxt->nsHash = NULL;
5187 }
5188 
5189 /************************************************************************
5190  *									*
5191  *			Routines to handle Values			*
5192  *									*
5193  ************************************************************************/
5194 
5195 /* Allocations are terrible, one needs to optimize all this !!! */
5196 
5197 /**
5198  * xmlXPathNewFloat:
5199  * @val:  the double value
5200  *
5201  * Create a new xmlXPathObjectPtr of type double and of value @val
5202  *
5203  * Returns the newly created object.
5204  */
5205 xmlXPathObjectPtr
xmlXPathNewFloat(double val)5206 xmlXPathNewFloat(double val) {
5207     xmlXPathObjectPtr ret;
5208 
5209     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5210     if (ret == NULL) {
5211         xmlXPathErrMemory(NULL, "creating float object\n");
5212 	return(NULL);
5213     }
5214     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5215     ret->type = XPATH_NUMBER;
5216     ret->floatval = val;
5217 #ifdef XP_DEBUG_OBJ_USAGE
5218     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5219 #endif
5220     return(ret);
5221 }
5222 
5223 /**
5224  * xmlXPathNewBoolean:
5225  * @val:  the boolean value
5226  *
5227  * Create a new xmlXPathObjectPtr of type boolean and of value @val
5228  *
5229  * Returns the newly created object.
5230  */
5231 xmlXPathObjectPtr
xmlXPathNewBoolean(int val)5232 xmlXPathNewBoolean(int val) {
5233     xmlXPathObjectPtr ret;
5234 
5235     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5236     if (ret == NULL) {
5237         xmlXPathErrMemory(NULL, "creating boolean object\n");
5238 	return(NULL);
5239     }
5240     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5241     ret->type = XPATH_BOOLEAN;
5242     ret->boolval = (val != 0);
5243 #ifdef XP_DEBUG_OBJ_USAGE
5244     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5245 #endif
5246     return(ret);
5247 }
5248 
5249 /**
5250  * xmlXPathNewString:
5251  * @val:  the xmlChar * value
5252  *
5253  * Create a new xmlXPathObjectPtr of type string and of value @val
5254  *
5255  * Returns the newly created object.
5256  */
5257 xmlXPathObjectPtr
xmlXPathNewString(const xmlChar * val)5258 xmlXPathNewString(const xmlChar *val) {
5259     xmlXPathObjectPtr ret;
5260 
5261     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5262     if (ret == NULL) {
5263         xmlXPathErrMemory(NULL, "creating string object\n");
5264 	return(NULL);
5265     }
5266     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5267     ret->type = XPATH_STRING;
5268     if (val != NULL)
5269 	ret->stringval = xmlStrdup(val);
5270     else
5271 	ret->stringval = xmlStrdup((const xmlChar *)"");
5272 #ifdef XP_DEBUG_OBJ_USAGE
5273     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5274 #endif
5275     return(ret);
5276 }
5277 
5278 /**
5279  * xmlXPathWrapString:
5280  * @val:  the xmlChar * value
5281  *
5282  * Wraps the @val string into an XPath object.
5283  *
5284  * Returns the newly created object.
5285  */
5286 xmlXPathObjectPtr
xmlXPathWrapString(xmlChar * val)5287 xmlXPathWrapString (xmlChar *val) {
5288     xmlXPathObjectPtr ret;
5289 
5290     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5291     if (ret == NULL) {
5292         xmlXPathErrMemory(NULL, "creating string object\n");
5293 	return(NULL);
5294     }
5295     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5296     ret->type = XPATH_STRING;
5297     ret->stringval = val;
5298 #ifdef XP_DEBUG_OBJ_USAGE
5299     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5300 #endif
5301     return(ret);
5302 }
5303 
5304 /**
5305  * xmlXPathNewCString:
5306  * @val:  the char * value
5307  *
5308  * Create a new xmlXPathObjectPtr of type string and of value @val
5309  *
5310  * Returns the newly created object.
5311  */
5312 xmlXPathObjectPtr
xmlXPathNewCString(const char * val)5313 xmlXPathNewCString(const char *val) {
5314     xmlXPathObjectPtr ret;
5315 
5316     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5317     if (ret == NULL) {
5318         xmlXPathErrMemory(NULL, "creating string object\n");
5319 	return(NULL);
5320     }
5321     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5322     ret->type = XPATH_STRING;
5323     ret->stringval = xmlStrdup(BAD_CAST val);
5324 #ifdef XP_DEBUG_OBJ_USAGE
5325     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5326 #endif
5327     return(ret);
5328 }
5329 
5330 /**
5331  * xmlXPathWrapCString:
5332  * @val:  the char * value
5333  *
5334  * Wraps a string into an XPath object.
5335  *
5336  * Returns the newly created object.
5337  */
5338 xmlXPathObjectPtr
xmlXPathWrapCString(char * val)5339 xmlXPathWrapCString (char * val) {
5340     return(xmlXPathWrapString((xmlChar *)(val)));
5341 }
5342 
5343 /**
5344  * xmlXPathWrapExternal:
5345  * @val:  the user data
5346  *
5347  * Wraps the @val data into an XPath object.
5348  *
5349  * Returns the newly created object.
5350  */
5351 xmlXPathObjectPtr
xmlXPathWrapExternal(void * val)5352 xmlXPathWrapExternal (void *val) {
5353     xmlXPathObjectPtr ret;
5354 
5355     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5356     if (ret == NULL) {
5357         xmlXPathErrMemory(NULL, "creating user object\n");
5358 	return(NULL);
5359     }
5360     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5361     ret->type = XPATH_USERS;
5362     ret->user = val;
5363 #ifdef XP_DEBUG_OBJ_USAGE
5364     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5365 #endif
5366     return(ret);
5367 }
5368 
5369 /**
5370  * xmlXPathObjectCopy:
5371  * @val:  the original object
5372  *
5373  * allocate a new copy of a given object
5374  *
5375  * Returns the newly created object.
5376  */
5377 xmlXPathObjectPtr
xmlXPathObjectCopy(xmlXPathObjectPtr val)5378 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5379     xmlXPathObjectPtr ret;
5380 
5381     if (val == NULL)
5382 	return(NULL);
5383 
5384     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5385     if (ret == NULL) {
5386         xmlXPathErrMemory(NULL, "copying object\n");
5387 	return(NULL);
5388     }
5389     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5390 #ifdef XP_DEBUG_OBJ_USAGE
5391     xmlXPathDebugObjUsageRequested(NULL, val->type);
5392 #endif
5393     switch (val->type) {
5394 	case XPATH_BOOLEAN:
5395 	case XPATH_NUMBER:
5396 #ifdef LIBXML_XPTR_LOCS_ENABLED
5397 	case XPATH_POINT:
5398 	case XPATH_RANGE:
5399 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5400 	    break;
5401 	case XPATH_STRING:
5402 	    ret->stringval = xmlStrdup(val->stringval);
5403 	    break;
5404 	case XPATH_XSLT_TREE:
5405 #if 0
5406 /*
5407   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5408   this previous handling is no longer correct, and can cause some serious
5409   problems (ref. bug 145547)
5410 */
5411 	    if ((val->nodesetval != NULL) &&
5412 		(val->nodesetval->nodeTab != NULL)) {
5413 		xmlNodePtr cur, tmp;
5414 		xmlDocPtr top;
5415 
5416 		ret->boolval = 1;
5417 		top =  xmlNewDoc(NULL);
5418 		top->name = (char *)
5419 		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
5420 		ret->user = top;
5421 		if (top != NULL) {
5422 		    top->doc = top;
5423 		    cur = val->nodesetval->nodeTab[0]->children;
5424 		    while (cur != NULL) {
5425 			tmp = xmlDocCopyNode(cur, top, 1);
5426 			xmlAddChild((xmlNodePtr) top, tmp);
5427 			cur = cur->next;
5428 		    }
5429 		}
5430 
5431 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5432 	    } else
5433 		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5434 	    /* Deallocate the copied tree value */
5435 	    break;
5436 #endif
5437 	case XPATH_NODESET:
5438             /* TODO: Check memory error. */
5439 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5440 	    /* Do not deallocate the copied tree value */
5441 	    ret->boolval = 0;
5442 	    break;
5443 #ifdef LIBXML_XPTR_LOCS_ENABLED
5444 	case XPATH_LOCATIONSET:
5445 	{
5446 	    xmlLocationSetPtr loc = val->user;
5447 	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5448 	    break;
5449 	}
5450 #endif
5451         case XPATH_USERS:
5452 	    ret->user = val->user;
5453 	    break;
5454         case XPATH_UNDEFINED:
5455 	    xmlGenericError(xmlGenericErrorContext,
5456 		    "xmlXPathObjectCopy: unsupported type %d\n",
5457 		    val->type);
5458 	    break;
5459     }
5460     return(ret);
5461 }
5462 
5463 /**
5464  * xmlXPathFreeObject:
5465  * @obj:  the object to free
5466  *
5467  * Free up an xmlXPathObjectPtr object.
5468  */
5469 void
xmlXPathFreeObject(xmlXPathObjectPtr obj)5470 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5471     if (obj == NULL) return;
5472     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5473 	if (obj->boolval) {
5474 #if 0
5475 	    if (obj->user != NULL) {
5476                 xmlXPathFreeNodeSet(obj->nodesetval);
5477 		xmlFreeNodeList((xmlNodePtr) obj->user);
5478 	    } else
5479 #endif
5480 	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5481 	    if (obj->nodesetval != NULL)
5482 		xmlXPathFreeValueTree(obj->nodesetval);
5483 	} else {
5484 	    if (obj->nodesetval != NULL)
5485 		xmlXPathFreeNodeSet(obj->nodesetval);
5486 	}
5487 #ifdef LIBXML_XPTR_LOCS_ENABLED
5488     } else if (obj->type == XPATH_LOCATIONSET) {
5489 	if (obj->user != NULL)
5490 	    xmlXPtrFreeLocationSet(obj->user);
5491 #endif
5492     } else if (obj->type == XPATH_STRING) {
5493 	if (obj->stringval != NULL)
5494 	    xmlFree(obj->stringval);
5495     }
5496 #ifdef XP_DEBUG_OBJ_USAGE
5497     xmlXPathDebugObjUsageReleased(NULL, obj->type);
5498 #endif
5499     xmlFree(obj);
5500 }
5501 
5502 static void
xmlXPathFreeObjectEntry(void * obj,const xmlChar * name ATTRIBUTE_UNUSED)5503 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5504     xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5505 }
5506 
5507 /**
5508  * xmlXPathReleaseObject:
5509  * @obj:  the xmlXPathObjectPtr to free or to cache
5510  *
5511  * Depending on the state of the cache this frees the given
5512  * XPath object or stores it in the cache.
5513  */
5514 static void
xmlXPathReleaseObject(xmlXPathContextPtr ctxt,xmlXPathObjectPtr obj)5515 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5516 {
5517 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5518 	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5519     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5520 
5521 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5522 
5523     if (obj == NULL)
5524 	return;
5525     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5526 	 xmlXPathFreeObject(obj);
5527     } else {
5528 	xmlXPathContextCachePtr cache =
5529 	    (xmlXPathContextCachePtr) ctxt->cache;
5530 
5531 	switch (obj->type) {
5532 	    case XPATH_NODESET:
5533 	    case XPATH_XSLT_TREE:
5534 		if (obj->nodesetval != NULL) {
5535 		    if (obj->boolval) {
5536 			/*
5537 			* It looks like the @boolval is used for
5538 			* evaluation if this an XSLT Result Tree Fragment.
5539 			* TODO: Check if this assumption is correct.
5540 			*/
5541 			obj->type = XPATH_XSLT_TREE; /* just for debugging */
5542 			xmlXPathFreeValueTree(obj->nodesetval);
5543 			obj->nodesetval = NULL;
5544 		    } else if ((obj->nodesetval->nodeMax <= 40) &&
5545 			(XP_CACHE_WANTS(cache->nodesetObjs,
5546 					cache->maxNodeset)))
5547 		    {
5548 			XP_CACHE_ADD(cache->nodesetObjs, obj);
5549 			goto obj_cached;
5550 		    } else {
5551 			xmlXPathFreeNodeSet(obj->nodesetval);
5552 			obj->nodesetval = NULL;
5553 		    }
5554 		}
5555 		break;
5556 	    case XPATH_STRING:
5557 		if (obj->stringval != NULL)
5558 		    xmlFree(obj->stringval);
5559 
5560 		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5561 		    XP_CACHE_ADD(cache->stringObjs, obj);
5562 		    goto obj_cached;
5563 		}
5564 		break;
5565 	    case XPATH_BOOLEAN:
5566 		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5567 		    XP_CACHE_ADD(cache->booleanObjs, obj);
5568 		    goto obj_cached;
5569 		}
5570 		break;
5571 	    case XPATH_NUMBER:
5572 		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5573 		    XP_CACHE_ADD(cache->numberObjs, obj);
5574 		    goto obj_cached;
5575 		}
5576 		break;
5577 #ifdef LIBXML_XPTR_LOCS_ENABLED
5578 	    case XPATH_LOCATIONSET:
5579 		if (obj->user != NULL) {
5580 		    xmlXPtrFreeLocationSet(obj->user);
5581 		}
5582 		goto free_obj;
5583 #endif
5584 	    default:
5585 		goto free_obj;
5586 	}
5587 
5588 	/*
5589 	* Fallback to adding to the misc-objects slot.
5590 	*/
5591 	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5592 	    XP_CACHE_ADD(cache->miscObjs, obj);
5593 	} else
5594 	    goto free_obj;
5595 
5596 obj_cached:
5597 
5598 #ifdef XP_DEBUG_OBJ_USAGE
5599 	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5600 #endif
5601 
5602 	if (obj->nodesetval != NULL) {
5603 	    xmlNodeSetPtr tmpset = obj->nodesetval;
5604 
5605 	    /*
5606 	    * TODO: Due to those nasty ns-nodes, we need to traverse
5607 	    *  the list and free the ns-nodes.
5608 	    * URGENT TODO: Check if it's actually slowing things down.
5609 	    *  Maybe we shouldn't try to preserve the list.
5610 	    */
5611 	    if (tmpset->nodeNr > 1) {
5612 		int i;
5613 		xmlNodePtr node;
5614 
5615 		for (i = 0; i < tmpset->nodeNr; i++) {
5616 		    node = tmpset->nodeTab[i];
5617 		    if ((node != NULL) &&
5618 			(node->type == XML_NAMESPACE_DECL))
5619 		    {
5620 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5621 		    }
5622 		}
5623 	    } else if (tmpset->nodeNr == 1) {
5624 		if ((tmpset->nodeTab[0] != NULL) &&
5625 		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5626 		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5627 	    }
5628 	    tmpset->nodeNr = 0;
5629 	    memset(obj, 0, sizeof(xmlXPathObject));
5630 	    obj->nodesetval = tmpset;
5631 	} else
5632 	    memset(obj, 0, sizeof(xmlXPathObject));
5633 
5634 	return;
5635 
5636 free_obj:
5637 	/*
5638 	* Cache is full; free the object.
5639 	*/
5640 	if (obj->nodesetval != NULL)
5641 	    xmlXPathFreeNodeSet(obj->nodesetval);
5642 #ifdef XP_DEBUG_OBJ_USAGE
5643 	xmlXPathDebugObjUsageReleased(NULL, obj->type);
5644 #endif
5645 	xmlFree(obj);
5646     }
5647     return;
5648 }
5649 
5650 
5651 /************************************************************************
5652  *									*
5653  *			Type Casting Routines				*
5654  *									*
5655  ************************************************************************/
5656 
5657 /**
5658  * xmlXPathCastBooleanToString:
5659  * @val:  a boolean
5660  *
5661  * Converts a boolean to its string value.
5662  *
5663  * Returns a newly allocated string.
5664  */
5665 xmlChar *
xmlXPathCastBooleanToString(int val)5666 xmlXPathCastBooleanToString (int val) {
5667     xmlChar *ret;
5668     if (val)
5669 	ret = xmlStrdup((const xmlChar *) "true");
5670     else
5671 	ret = xmlStrdup((const xmlChar *) "false");
5672     return(ret);
5673 }
5674 
5675 /**
5676  * xmlXPathCastNumberToString:
5677  * @val:  a number
5678  *
5679  * Converts a number to its string value.
5680  *
5681  * Returns a newly allocated string.
5682  */
5683 xmlChar *
xmlXPathCastNumberToString(double val)5684 xmlXPathCastNumberToString (double val) {
5685     xmlChar *ret;
5686     switch (xmlXPathIsInf(val)) {
5687     case 1:
5688 	ret = xmlStrdup((const xmlChar *) "Infinity");
5689 	break;
5690     case -1:
5691 	ret = xmlStrdup((const xmlChar *) "-Infinity");
5692 	break;
5693     default:
5694 	if (xmlXPathIsNaN(val)) {
5695 	    ret = xmlStrdup((const xmlChar *) "NaN");
5696 	} else if (val == 0) {
5697             /* Omit sign for negative zero. */
5698 	    ret = xmlStrdup((const xmlChar *) "0");
5699 	} else {
5700 	    /* could be improved */
5701 	    char buf[100];
5702 	    xmlXPathFormatNumber(val, buf, 99);
5703 	    buf[99] = 0;
5704 	    ret = xmlStrdup((const xmlChar *) buf);
5705 	}
5706     }
5707     return(ret);
5708 }
5709 
5710 /**
5711  * xmlXPathCastNodeToString:
5712  * @node:  a node
5713  *
5714  * Converts a node to its string value.
5715  *
5716  * Returns a newly allocated string.
5717  */
5718 xmlChar *
xmlXPathCastNodeToString(xmlNodePtr node)5719 xmlXPathCastNodeToString (xmlNodePtr node) {
5720 xmlChar *ret;
5721     if ((ret = xmlNodeGetContent(node)) == NULL)
5722 	ret = xmlStrdup((const xmlChar *) "");
5723     return(ret);
5724 }
5725 
5726 /**
5727  * xmlXPathCastNodeSetToString:
5728  * @ns:  a node-set
5729  *
5730  * Converts a node-set to its string value.
5731  *
5732  * Returns a newly allocated string.
5733  */
5734 xmlChar *
xmlXPathCastNodeSetToString(xmlNodeSetPtr ns)5735 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5736     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5737 	return(xmlStrdup((const xmlChar *) ""));
5738 
5739     if (ns->nodeNr > 1)
5740 	xmlXPathNodeSetSort(ns);
5741     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5742 }
5743 
5744 /**
5745  * xmlXPathCastToString:
5746  * @val:  an XPath object
5747  *
5748  * Converts an existing object to its string() equivalent
5749  *
5750  * Returns the allocated string value of the object, NULL in case of error.
5751  *         It's up to the caller to free the string memory with xmlFree().
5752  */
5753 xmlChar *
xmlXPathCastToString(xmlXPathObjectPtr val)5754 xmlXPathCastToString(xmlXPathObjectPtr val) {
5755     xmlChar *ret = NULL;
5756 
5757     if (val == NULL)
5758 	return(xmlStrdup((const xmlChar *) ""));
5759     switch (val->type) {
5760 	case XPATH_UNDEFINED:
5761 #ifdef DEBUG_EXPR
5762 	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5763 #endif
5764 	    ret = xmlStrdup((const xmlChar *) "");
5765 	    break;
5766         case XPATH_NODESET:
5767         case XPATH_XSLT_TREE:
5768 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
5769 	    break;
5770 	case XPATH_STRING:
5771 	    return(xmlStrdup(val->stringval));
5772         case XPATH_BOOLEAN:
5773 	    ret = xmlXPathCastBooleanToString(val->boolval);
5774 	    break;
5775 	case XPATH_NUMBER: {
5776 	    ret = xmlXPathCastNumberToString(val->floatval);
5777 	    break;
5778 	}
5779 	case XPATH_USERS:
5780 #ifdef LIBXML_XPTR_LOCS_ENABLED
5781 	case XPATH_POINT:
5782 	case XPATH_RANGE:
5783 	case XPATH_LOCATIONSET:
5784 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5785 	    TODO
5786 	    ret = xmlStrdup((const xmlChar *) "");
5787 	    break;
5788     }
5789     return(ret);
5790 }
5791 
5792 /**
5793  * xmlXPathConvertString:
5794  * @val:  an XPath object
5795  *
5796  * Converts an existing object to its string() equivalent
5797  *
5798  * Returns the new object, the old one is freed (or the operation
5799  *         is done directly on @val)
5800  */
5801 xmlXPathObjectPtr
xmlXPathConvertString(xmlXPathObjectPtr val)5802 xmlXPathConvertString(xmlXPathObjectPtr val) {
5803     xmlChar *res = NULL;
5804 
5805     if (val == NULL)
5806 	return(xmlXPathNewCString(""));
5807 
5808     switch (val->type) {
5809     case XPATH_UNDEFINED:
5810 #ifdef DEBUG_EXPR
5811 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5812 #endif
5813 	break;
5814     case XPATH_NODESET:
5815     case XPATH_XSLT_TREE:
5816 	res = xmlXPathCastNodeSetToString(val->nodesetval);
5817 	break;
5818     case XPATH_STRING:
5819 	return(val);
5820     case XPATH_BOOLEAN:
5821 	res = xmlXPathCastBooleanToString(val->boolval);
5822 	break;
5823     case XPATH_NUMBER:
5824 	res = xmlXPathCastNumberToString(val->floatval);
5825 	break;
5826     case XPATH_USERS:
5827 #ifdef LIBXML_XPTR_LOCS_ENABLED
5828     case XPATH_POINT:
5829     case XPATH_RANGE:
5830     case XPATH_LOCATIONSET:
5831 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5832 	TODO;
5833 	break;
5834     }
5835     xmlXPathFreeObject(val);
5836     if (res == NULL)
5837 	return(xmlXPathNewCString(""));
5838     return(xmlXPathWrapString(res));
5839 }
5840 
5841 /**
5842  * xmlXPathCastBooleanToNumber:
5843  * @val:  a boolean
5844  *
5845  * Converts a boolean to its number value
5846  *
5847  * Returns the number value
5848  */
5849 double
xmlXPathCastBooleanToNumber(int val)5850 xmlXPathCastBooleanToNumber(int val) {
5851     if (val)
5852 	return(1.0);
5853     return(0.0);
5854 }
5855 
5856 /**
5857  * xmlXPathCastStringToNumber:
5858  * @val:  a string
5859  *
5860  * Converts a string to its number value
5861  *
5862  * Returns the number value
5863  */
5864 double
xmlXPathCastStringToNumber(const xmlChar * val)5865 xmlXPathCastStringToNumber(const xmlChar * val) {
5866     return(xmlXPathStringEvalNumber(val));
5867 }
5868 
5869 /**
5870  * xmlXPathCastNodeToNumber:
5871  * @node:  a node
5872  *
5873  * Converts a node to its number value
5874  *
5875  * Returns the number value
5876  */
5877 double
xmlXPathCastNodeToNumber(xmlNodePtr node)5878 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5879     xmlChar *strval;
5880     double ret;
5881 
5882     if (node == NULL)
5883 	return(xmlXPathNAN);
5884     strval = xmlXPathCastNodeToString(node);
5885     if (strval == NULL)
5886 	return(xmlXPathNAN);
5887     ret = xmlXPathCastStringToNumber(strval);
5888     xmlFree(strval);
5889 
5890     return(ret);
5891 }
5892 
5893 /**
5894  * xmlXPathCastNodeSetToNumber:
5895  * @ns:  a node-set
5896  *
5897  * Converts a node-set to its number value
5898  *
5899  * Returns the number value
5900  */
5901 double
xmlXPathCastNodeSetToNumber(xmlNodeSetPtr ns)5902 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5903     xmlChar *str;
5904     double ret;
5905 
5906     if (ns == NULL)
5907 	return(xmlXPathNAN);
5908     str = xmlXPathCastNodeSetToString(ns);
5909     ret = xmlXPathCastStringToNumber(str);
5910     xmlFree(str);
5911     return(ret);
5912 }
5913 
5914 /**
5915  * xmlXPathCastToNumber:
5916  * @val:  an XPath object
5917  *
5918  * Converts an XPath object to its number value
5919  *
5920  * Returns the number value
5921  */
5922 double
xmlXPathCastToNumber(xmlXPathObjectPtr val)5923 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5924     double ret = 0.0;
5925 
5926     if (val == NULL)
5927 	return(xmlXPathNAN);
5928     switch (val->type) {
5929     case XPATH_UNDEFINED:
5930 #ifdef DEBUG_EXPR
5931 	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5932 #endif
5933 	ret = xmlXPathNAN;
5934 	break;
5935     case XPATH_NODESET:
5936     case XPATH_XSLT_TREE:
5937 	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5938 	break;
5939     case XPATH_STRING:
5940 	ret = xmlXPathCastStringToNumber(val->stringval);
5941 	break;
5942     case XPATH_NUMBER:
5943 	ret = val->floatval;
5944 	break;
5945     case XPATH_BOOLEAN:
5946 	ret = xmlXPathCastBooleanToNumber(val->boolval);
5947 	break;
5948     case XPATH_USERS:
5949 #ifdef LIBXML_XPTR_LOCS_ENABLED
5950     case XPATH_POINT:
5951     case XPATH_RANGE:
5952     case XPATH_LOCATIONSET:
5953 #endif /* LIBXML_XPTR_LOCS_ENABLED */
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 #ifdef LIBXML_XPTR_LOCS_ENABLED
6064     case XPATH_POINT:
6065     case XPATH_RANGE:
6066     case XPATH_LOCATIONSET:
6067 #endif /* LIBXML_XPTR_LOCS_ENABLED */
6068 	TODO;
6069 	ret = 0;
6070 	break;
6071     }
6072     return(ret);
6073 }
6074 
6075 
6076 /**
6077  * xmlXPathConvertBoolean:
6078  * @val:  an XPath object
6079  *
6080  * Converts an existing object to its boolean() equivalent
6081  *
6082  * Returns the new object, the old one is freed (or the operation
6083  *         is done directly on @val)
6084  */
6085 xmlXPathObjectPtr
xmlXPathConvertBoolean(xmlXPathObjectPtr val)6086 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6087     xmlXPathObjectPtr ret;
6088 
6089     if (val == NULL)
6090 	return(xmlXPathNewBoolean(0));
6091     if (val->type == XPATH_BOOLEAN)
6092 	return(val);
6093     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6094     xmlXPathFreeObject(val);
6095     return(ret);
6096 }
6097 
6098 /************************************************************************
6099  *									*
6100  *		Routines to handle XPath contexts			*
6101  *									*
6102  ************************************************************************/
6103 
6104 /**
6105  * xmlXPathNewContext:
6106  * @doc:  the XML document
6107  *
6108  * Create a new xmlXPathContext
6109  *
6110  * Returns the xmlXPathContext just allocated. The caller will need to free it.
6111  */
6112 xmlXPathContextPtr
xmlXPathNewContext(xmlDocPtr doc)6113 xmlXPathNewContext(xmlDocPtr doc) {
6114     xmlXPathContextPtr ret;
6115 
6116     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6117     if (ret == NULL) {
6118         xmlXPathErrMemory(NULL, "creating context\n");
6119 	return(NULL);
6120     }
6121     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6122     ret->doc = doc;
6123     ret->node = NULL;
6124 
6125     ret->varHash = NULL;
6126 
6127     ret->nb_types = 0;
6128     ret->max_types = 0;
6129     ret->types = NULL;
6130 
6131     ret->funcHash = xmlHashCreate(0);
6132 
6133     ret->nb_axis = 0;
6134     ret->max_axis = 0;
6135     ret->axis = NULL;
6136 
6137     ret->nsHash = NULL;
6138     ret->user = NULL;
6139 
6140     ret->contextSize = -1;
6141     ret->proximityPosition = -1;
6142 
6143 #ifdef XP_DEFAULT_CACHE_ON
6144     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6145 	xmlXPathFreeContext(ret);
6146 	return(NULL);
6147     }
6148 #endif
6149 
6150     xmlXPathRegisterAllFunctions(ret);
6151 
6152     return(ret);
6153 }
6154 
6155 /**
6156  * xmlXPathFreeContext:
6157  * @ctxt:  the context to free
6158  *
6159  * Free up an xmlXPathContext
6160  */
6161 void
xmlXPathFreeContext(xmlXPathContextPtr ctxt)6162 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6163     if (ctxt == NULL) return;
6164 
6165     if (ctxt->cache != NULL)
6166 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6167     xmlXPathRegisteredNsCleanup(ctxt);
6168     xmlXPathRegisteredFuncsCleanup(ctxt);
6169     xmlXPathRegisteredVariablesCleanup(ctxt);
6170     xmlResetError(&ctxt->lastError);
6171     xmlFree(ctxt);
6172 }
6173 
6174 /************************************************************************
6175  *									*
6176  *		Routines to handle XPath parser contexts		*
6177  *									*
6178  ************************************************************************/
6179 
6180 #define CHECK_CTXT(ctxt)						\
6181     if (ctxt == NULL) {						\
6182 	__xmlRaiseError(NULL, NULL, NULL,				\
6183 		NULL, NULL, XML_FROM_XPATH,				\
6184 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6185 		__FILE__, __LINE__,					\
6186 		NULL, NULL, NULL, 0, 0,					\
6187 		"NULL context pointer\n");				\
6188 	return(NULL);							\
6189     }									\
6190 
6191 #define CHECK_CTXT_NEG(ctxt)						\
6192     if (ctxt == NULL) {						\
6193 	__xmlRaiseError(NULL, NULL, NULL,				\
6194 		NULL, NULL, XML_FROM_XPATH,				\
6195 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6196 		__FILE__, __LINE__,					\
6197 		NULL, NULL, NULL, 0, 0,					\
6198 		"NULL context pointer\n");				\
6199 	return(-1);							\
6200     }									\
6201 
6202 
6203 #define CHECK_CONTEXT(ctxt)						\
6204     if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
6205         (ctxt->doc->children == NULL)) {				\
6206 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
6207 	return(NULL);							\
6208     }
6209 
6210 
6211 /**
6212  * xmlXPathNewParserContext:
6213  * @str:  the XPath expression
6214  * @ctxt:  the XPath context
6215  *
6216  * Create a new xmlXPathParserContext
6217  *
6218  * Returns the xmlXPathParserContext just allocated.
6219  */
6220 xmlXPathParserContextPtr
xmlXPathNewParserContext(const xmlChar * str,xmlXPathContextPtr ctxt)6221 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6222     xmlXPathParserContextPtr ret;
6223 
6224     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6225     if (ret == NULL) {
6226         xmlXPathErrMemory(ctxt, "creating parser context\n");
6227 	return(NULL);
6228     }
6229     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6230     ret->cur = ret->base = str;
6231     ret->context = ctxt;
6232 
6233     ret->comp = xmlXPathNewCompExpr();
6234     if (ret->comp == NULL) {
6235 	xmlFree(ret->valueTab);
6236 	xmlFree(ret);
6237 	return(NULL);
6238     }
6239     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6240         ret->comp->dict = ctxt->dict;
6241 	xmlDictReference(ret->comp->dict);
6242     }
6243 
6244     return(ret);
6245 }
6246 
6247 /**
6248  * xmlXPathCompParserContext:
6249  * @comp:  the XPath compiled expression
6250  * @ctxt:  the XPath context
6251  *
6252  * Create a new xmlXPathParserContext when processing a compiled expression
6253  *
6254  * Returns the xmlXPathParserContext just allocated.
6255  */
6256 static xmlXPathParserContextPtr
xmlXPathCompParserContext(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)6257 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6258     xmlXPathParserContextPtr ret;
6259 
6260     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6261     if (ret == NULL) {
6262         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6263 	return(NULL);
6264     }
6265     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6266 
6267     /* Allocate the value stack */
6268     ret->valueTab = (xmlXPathObjectPtr *)
6269                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6270     if (ret->valueTab == NULL) {
6271 	xmlFree(ret);
6272 	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6273 	return(NULL);
6274     }
6275     ret->valueNr = 0;
6276     ret->valueMax = 10;
6277     ret->value = NULL;
6278     ret->valueFrame = 0;
6279 
6280     ret->context = ctxt;
6281     ret->comp = comp;
6282 
6283     return(ret);
6284 }
6285 
6286 /**
6287  * xmlXPathFreeParserContext:
6288  * @ctxt:  the context to free
6289  *
6290  * Free up an xmlXPathParserContext
6291  */
6292 void
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt)6293 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6294     int i;
6295 
6296     if (ctxt->valueTab != NULL) {
6297         for (i = 0; i < ctxt->valueNr; i++) {
6298             if (ctxt->context)
6299                 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6300             else
6301                 xmlXPathFreeObject(ctxt->valueTab[i]);
6302         }
6303         xmlFree(ctxt->valueTab);
6304     }
6305     if (ctxt->comp != NULL) {
6306 #ifdef XPATH_STREAMING
6307 	if (ctxt->comp->stream != NULL) {
6308 	    xmlFreePatternList(ctxt->comp->stream);
6309 	    ctxt->comp->stream = NULL;
6310 	}
6311 #endif
6312 	xmlXPathFreeCompExpr(ctxt->comp);
6313     }
6314     xmlFree(ctxt);
6315 }
6316 
6317 /************************************************************************
6318  *									*
6319  *		The implicit core function library			*
6320  *									*
6321  ************************************************************************/
6322 
6323 /**
6324  * xmlXPathNodeValHash:
6325  * @node:  a node pointer
6326  *
6327  * Function computing the beginning of the string value of the node,
6328  * used to speed up comparisons
6329  *
6330  * Returns an int usable as a hash
6331  */
6332 static unsigned int
xmlXPathNodeValHash(xmlNodePtr node)6333 xmlXPathNodeValHash(xmlNodePtr node) {
6334     int len = 2;
6335     const xmlChar * string = NULL;
6336     xmlNodePtr tmp = NULL;
6337     unsigned int ret = 0;
6338 
6339     if (node == NULL)
6340 	return(0);
6341 
6342     if (node->type == XML_DOCUMENT_NODE) {
6343 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
6344 	if (tmp == NULL)
6345 	    node = node->children;
6346 	else
6347 	    node = tmp;
6348 
6349 	if (node == NULL)
6350 	    return(0);
6351     }
6352 
6353     switch (node->type) {
6354 	case XML_COMMENT_NODE:
6355 	case XML_PI_NODE:
6356 	case XML_CDATA_SECTION_NODE:
6357 	case XML_TEXT_NODE:
6358 	    string = node->content;
6359 	    if (string == NULL)
6360 		return(0);
6361 	    if (string[0] == 0)
6362 		return(0);
6363 	    return(((unsigned int) string[0]) +
6364 		   (((unsigned int) string[1]) << 8));
6365 	case XML_NAMESPACE_DECL:
6366 	    string = ((xmlNsPtr)node)->href;
6367 	    if (string == NULL)
6368 		return(0);
6369 	    if (string[0] == 0)
6370 		return(0);
6371 	    return(((unsigned int) string[0]) +
6372 		   (((unsigned int) string[1]) << 8));
6373 	case XML_ATTRIBUTE_NODE:
6374 	    tmp = ((xmlAttrPtr) node)->children;
6375 	    break;
6376 	case XML_ELEMENT_NODE:
6377 	    tmp = node->children;
6378 	    break;
6379 	default:
6380 	    return(0);
6381     }
6382     while (tmp != NULL) {
6383 	switch (tmp->type) {
6384 	    case XML_CDATA_SECTION_NODE:
6385 	    case XML_TEXT_NODE:
6386 		string = tmp->content;
6387 		break;
6388 	    default:
6389                 string = NULL;
6390 		break;
6391 	}
6392 	if ((string != NULL) && (string[0] != 0)) {
6393 	    if (len == 1) {
6394 		return(ret + (((unsigned int) string[0]) << 8));
6395 	    }
6396 	    if (string[1] == 0) {
6397 		len = 1;
6398 		ret = (unsigned int) string[0];
6399 	    } else {
6400 		return(((unsigned int) string[0]) +
6401 		       (((unsigned int) string[1]) << 8));
6402 	    }
6403 	}
6404 	/*
6405 	 * Skip to next node
6406 	 */
6407 	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6408 	    if (tmp->children->type != XML_ENTITY_DECL) {
6409 		tmp = tmp->children;
6410 		continue;
6411 	    }
6412 	}
6413 	if (tmp == node)
6414 	    break;
6415 
6416 	if (tmp->next != NULL) {
6417 	    tmp = tmp->next;
6418 	    continue;
6419 	}
6420 
6421 	do {
6422 	    tmp = tmp->parent;
6423 	    if (tmp == NULL)
6424 		break;
6425 	    if (tmp == node) {
6426 		tmp = NULL;
6427 		break;
6428 	    }
6429 	    if (tmp->next != NULL) {
6430 		tmp = tmp->next;
6431 		break;
6432 	    }
6433 	} while (tmp != NULL);
6434     }
6435     return(ret);
6436 }
6437 
6438 /**
6439  * xmlXPathStringHash:
6440  * @string:  a string
6441  *
6442  * Function computing the beginning of the string value of the node,
6443  * used to speed up comparisons
6444  *
6445  * Returns an int usable as a hash
6446  */
6447 static unsigned int
xmlXPathStringHash(const xmlChar * string)6448 xmlXPathStringHash(const xmlChar * string) {
6449     if (string == NULL)
6450 	return((unsigned int) 0);
6451     if (string[0] == 0)
6452 	return(0);
6453     return(((unsigned int) string[0]) +
6454 	   (((unsigned int) string[1]) << 8));
6455 }
6456 
6457 /**
6458  * xmlXPathCompareNodeSetFloat:
6459  * @ctxt:  the XPath Parser context
6460  * @inf:  less than (1) or greater than (0)
6461  * @strict:  is the comparison strict
6462  * @arg:  the node set
6463  * @f:  the value
6464  *
6465  * Implement the compare operation between a nodeset and a number
6466  *     @ns < @val    (1, 1, ...
6467  *     @ns <= @val   (1, 0, ...
6468  *     @ns > @val    (0, 1, ...
6469  *     @ns >= @val   (0, 0, ...
6470  *
6471  * If one object to be compared is a node-set and the other is a number,
6472  * then the comparison will be true if and only if there is a node in the
6473  * node-set such that the result of performing the comparison on the number
6474  * to be compared and on the result of converting the string-value of that
6475  * node to a number using the number function is true.
6476  *
6477  * Returns 0 or 1 depending on the results of the test.
6478  */
6479 static int
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr f)6480 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6481 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6482     int i, ret = 0;
6483     xmlNodeSetPtr ns;
6484     xmlChar *str2;
6485 
6486     if ((f == NULL) || (arg == NULL) ||
6487 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6488 	xmlXPathReleaseObject(ctxt->context, arg);
6489 	xmlXPathReleaseObject(ctxt->context, f);
6490         return(0);
6491     }
6492     ns = arg->nodesetval;
6493     if (ns != NULL) {
6494 	for (i = 0;i < ns->nodeNr;i++) {
6495 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6496 	     if (str2 != NULL) {
6497 		 valuePush(ctxt,
6498 			   xmlXPathCacheNewString(ctxt->context, str2));
6499 		 xmlFree(str2);
6500 		 xmlXPathNumberFunction(ctxt, 1);
6501 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6502 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6503 		 if (ret)
6504 		     break;
6505 	     }
6506 	}
6507     }
6508     xmlXPathReleaseObject(ctxt->context, arg);
6509     xmlXPathReleaseObject(ctxt->context, f);
6510     return(ret);
6511 }
6512 
6513 /**
6514  * xmlXPathCompareNodeSetString:
6515  * @ctxt:  the XPath Parser context
6516  * @inf:  less than (1) or greater than (0)
6517  * @strict:  is the comparison strict
6518  * @arg:  the node set
6519  * @s:  the value
6520  *
6521  * Implement the compare operation between a nodeset and a string
6522  *     @ns < @val    (1, 1, ...
6523  *     @ns <= @val   (1, 0, ...
6524  *     @ns > @val    (0, 1, ...
6525  *     @ns >= @val   (0, 0, ...
6526  *
6527  * If one object to be compared is a node-set and the other is a string,
6528  * then the comparison will be true if and only if there is a node in
6529  * the node-set such that the result of performing the comparison on the
6530  * string-value of the node and the other string is true.
6531  *
6532  * Returns 0 or 1 depending on the results of the test.
6533  */
6534 static int
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr s)6535 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6536 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6537     int i, ret = 0;
6538     xmlNodeSetPtr ns;
6539     xmlChar *str2;
6540 
6541     if ((s == NULL) || (arg == NULL) ||
6542 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6543 	xmlXPathReleaseObject(ctxt->context, arg);
6544 	xmlXPathReleaseObject(ctxt->context, s);
6545         return(0);
6546     }
6547     ns = arg->nodesetval;
6548     if (ns != NULL) {
6549 	for (i = 0;i < ns->nodeNr;i++) {
6550 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6551 	     if (str2 != NULL) {
6552 		 valuePush(ctxt,
6553 			   xmlXPathCacheNewString(ctxt->context, str2));
6554 		 xmlFree(str2);
6555 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6556 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6557 		 if (ret)
6558 		     break;
6559 	     }
6560 	}
6561     }
6562     xmlXPathReleaseObject(ctxt->context, arg);
6563     xmlXPathReleaseObject(ctxt->context, s);
6564     return(ret);
6565 }
6566 
6567 /**
6568  * xmlXPathCompareNodeSets:
6569  * @inf:  less than (1) or greater than (0)
6570  * @strict:  is the comparison strict
6571  * @arg1:  the first node set object
6572  * @arg2:  the second node set object
6573  *
6574  * Implement the compare operation on nodesets:
6575  *
6576  * If both objects to be compared are node-sets, then the comparison
6577  * will be true if and only if there is a node in the first node-set
6578  * and a node in the second node-set such that the result of performing
6579  * the comparison on the string-values of the two nodes is true.
6580  * ....
6581  * When neither object to be compared is a node-set and the operator
6582  * is <=, <, >= or >, then the objects are compared by converting both
6583  * objects to numbers and comparing the numbers according to IEEE 754.
6584  * ....
6585  * The number function converts its argument to a number as follows:
6586  *  - a string that consists of optional whitespace followed by an
6587  *    optional minus sign followed by a Number followed by whitespace
6588  *    is converted to the IEEE 754 number that is nearest (according
6589  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6590  *    represented by the string; any other string is converted to NaN
6591  *
6592  * Conclusion all nodes need to be converted first to their string value
6593  * and then the comparison must be done when possible
6594  */
6595 static int
xmlXPathCompareNodeSets(int inf,int strict,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6596 xmlXPathCompareNodeSets(int inf, int strict,
6597 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6598     int i, j, init = 0;
6599     double val1;
6600     double *values2;
6601     int ret = 0;
6602     xmlNodeSetPtr ns1;
6603     xmlNodeSetPtr ns2;
6604 
6605     if ((arg1 == NULL) ||
6606 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6607 	xmlXPathFreeObject(arg2);
6608         return(0);
6609     }
6610     if ((arg2 == NULL) ||
6611 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6612 	xmlXPathFreeObject(arg1);
6613 	xmlXPathFreeObject(arg2);
6614         return(0);
6615     }
6616 
6617     ns1 = arg1->nodesetval;
6618     ns2 = arg2->nodesetval;
6619 
6620     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6621 	xmlXPathFreeObject(arg1);
6622 	xmlXPathFreeObject(arg2);
6623 	return(0);
6624     }
6625     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6626 	xmlXPathFreeObject(arg1);
6627 	xmlXPathFreeObject(arg2);
6628 	return(0);
6629     }
6630 
6631     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6632     if (values2 == NULL) {
6633         /* TODO: Propagate memory error. */
6634         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6635 	xmlXPathFreeObject(arg1);
6636 	xmlXPathFreeObject(arg2);
6637 	return(0);
6638     }
6639     for (i = 0;i < ns1->nodeNr;i++) {
6640 	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6641 	if (xmlXPathIsNaN(val1))
6642 	    continue;
6643 	for (j = 0;j < ns2->nodeNr;j++) {
6644 	    if (init == 0) {
6645 		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6646 	    }
6647 	    if (xmlXPathIsNaN(values2[j]))
6648 		continue;
6649 	    if (inf && strict)
6650 		ret = (val1 < values2[j]);
6651 	    else if (inf && !strict)
6652 		ret = (val1 <= values2[j]);
6653 	    else if (!inf && strict)
6654 		ret = (val1 > values2[j]);
6655 	    else if (!inf && !strict)
6656 		ret = (val1 >= values2[j]);
6657 	    if (ret)
6658 		break;
6659 	}
6660 	if (ret)
6661 	    break;
6662 	init = 1;
6663     }
6664     xmlFree(values2);
6665     xmlXPathFreeObject(arg1);
6666     xmlXPathFreeObject(arg2);
6667     return(ret);
6668 }
6669 
6670 /**
6671  * xmlXPathCompareNodeSetValue:
6672  * @ctxt:  the XPath Parser context
6673  * @inf:  less than (1) or greater than (0)
6674  * @strict:  is the comparison strict
6675  * @arg:  the node set
6676  * @val:  the value
6677  *
6678  * Implement the compare operation between a nodeset and a value
6679  *     @ns < @val    (1, 1, ...
6680  *     @ns <= @val   (1, 0, ...
6681  *     @ns > @val    (0, 1, ...
6682  *     @ns >= @val   (0, 0, ...
6683  *
6684  * If one object to be compared is a node-set and the other is a boolean,
6685  * then the comparison will be true if and only if the result of performing
6686  * the comparison on the boolean and on the result of converting
6687  * the node-set to a boolean using the boolean function is true.
6688  *
6689  * Returns 0 or 1 depending on the results of the test.
6690  */
6691 static int
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr val)6692 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6693 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6694     if ((val == NULL) || (arg == NULL) ||
6695 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6696         return(0);
6697 
6698     switch(val->type) {
6699         case XPATH_NUMBER:
6700 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6701         case XPATH_NODESET:
6702         case XPATH_XSLT_TREE:
6703 	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6704         case XPATH_STRING:
6705 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6706         case XPATH_BOOLEAN:
6707 	    valuePush(ctxt, arg);
6708 	    xmlXPathBooleanFunction(ctxt, 1);
6709 	    valuePush(ctxt, val);
6710 	    return(xmlXPathCompareValues(ctxt, inf, strict));
6711 	default:
6712             xmlGenericError(xmlGenericErrorContext,
6713                     "xmlXPathCompareNodeSetValue: Can't compare node set "
6714                     "and object of type %d\n",
6715                     val->type);
6716             xmlXPathReleaseObject(ctxt->context, arg);
6717             xmlXPathReleaseObject(ctxt->context, val);
6718             XP_ERROR0(XPATH_INVALID_TYPE);
6719     }
6720     return(0);
6721 }
6722 
6723 /**
6724  * xmlXPathEqualNodeSetString:
6725  * @arg:  the nodeset object argument
6726  * @str:  the string to compare to.
6727  * @neq:  flag to show whether for '=' (0) or '!=' (1)
6728  *
6729  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6730  * If one object to be compared is a node-set and the other is a string,
6731  * then the comparison will be true if and only if there is a node in
6732  * the node-set such that the result of performing the comparison on the
6733  * string-value of the node and the other string is true.
6734  *
6735  * Returns 0 or 1 depending on the results of the test.
6736  */
6737 static int
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg,const xmlChar * str,int neq)6738 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6739 {
6740     int i;
6741     xmlNodeSetPtr ns;
6742     xmlChar *str2;
6743     unsigned int hash;
6744 
6745     if ((str == NULL) || (arg == NULL) ||
6746         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6747         return (0);
6748     ns = arg->nodesetval;
6749     /*
6750      * A NULL nodeset compared with a string is always false
6751      * (since there is no node equal, and no node not equal)
6752      */
6753     if ((ns == NULL) || (ns->nodeNr <= 0) )
6754         return (0);
6755     hash = xmlXPathStringHash(str);
6756     for (i = 0; i < ns->nodeNr; i++) {
6757         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6758             str2 = xmlNodeGetContent(ns->nodeTab[i]);
6759             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6760                 xmlFree(str2);
6761 		if (neq)
6762 		    continue;
6763                 return (1);
6764 	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6765 		if (neq)
6766 		    continue;
6767                 return (1);
6768             } else if (neq) {
6769 		if (str2 != NULL)
6770 		    xmlFree(str2);
6771 		return (1);
6772 	    }
6773             if (str2 != NULL)
6774                 xmlFree(str2);
6775         } else if (neq)
6776 	    return (1);
6777     }
6778     return (0);
6779 }
6780 
6781 /**
6782  * xmlXPathEqualNodeSetFloat:
6783  * @arg:  the nodeset object argument
6784  * @f:  the float to compare to
6785  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6786  *
6787  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6788  * If one object to be compared is a node-set and the other is a number,
6789  * then the comparison will be true if and only if there is a node in
6790  * the node-set such that the result of performing the comparison on the
6791  * number to be compared and on the result of converting the string-value
6792  * of that node to a number using the number function is true.
6793  *
6794  * Returns 0 or 1 depending on the results of the test.
6795  */
6796 static int
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,double f,int neq)6797 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6798     xmlXPathObjectPtr arg, double f, int neq) {
6799   int i, ret=0;
6800   xmlNodeSetPtr ns;
6801   xmlChar *str2;
6802   xmlXPathObjectPtr val;
6803   double v;
6804 
6805     if ((arg == NULL) ||
6806 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6807         return(0);
6808 
6809     ns = arg->nodesetval;
6810     if (ns != NULL) {
6811 	for (i=0;i<ns->nodeNr;i++) {
6812 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6813 	    if (str2 != NULL) {
6814 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6815 		xmlFree(str2);
6816 		xmlXPathNumberFunction(ctxt, 1);
6817 		val = valuePop(ctxt);
6818 		v = val->floatval;
6819 		xmlXPathReleaseObject(ctxt->context, val);
6820 		if (!xmlXPathIsNaN(v)) {
6821 		    if ((!neq) && (v==f)) {
6822 			ret = 1;
6823 			break;
6824 		    } else if ((neq) && (v!=f)) {
6825 			ret = 1;
6826 			break;
6827 		    }
6828 		} else {	/* NaN is unequal to any value */
6829 		    if (neq)
6830 			ret = 1;
6831 		}
6832 	    }
6833 	}
6834     }
6835 
6836     return(ret);
6837 }
6838 
6839 
6840 /**
6841  * xmlXPathEqualNodeSets:
6842  * @arg1:  first nodeset object argument
6843  * @arg2:  second nodeset object argument
6844  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6845  *
6846  * Implement the equal / not equal operation on XPath nodesets:
6847  * @arg1 == @arg2  or  @arg1 != @arg2
6848  * If both objects to be compared are node-sets, then the comparison
6849  * will be true if and only if there is a node in the first node-set and
6850  * a node in the second node-set such that the result of performing the
6851  * comparison on the string-values of the two nodes is true.
6852  *
6853  * (needless to say, this is a costly operation)
6854  *
6855  * Returns 0 or 1 depending on the results of the test.
6856  */
6857 static int
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2,int neq)6858 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6859     int i, j;
6860     unsigned int *hashs1;
6861     unsigned int *hashs2;
6862     xmlChar **values1;
6863     xmlChar **values2;
6864     int ret = 0;
6865     xmlNodeSetPtr ns1;
6866     xmlNodeSetPtr ns2;
6867 
6868     if ((arg1 == NULL) ||
6869 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6870         return(0);
6871     if ((arg2 == NULL) ||
6872 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6873         return(0);
6874 
6875     ns1 = arg1->nodesetval;
6876     ns2 = arg2->nodesetval;
6877 
6878     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6879 	return(0);
6880     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6881 	return(0);
6882 
6883     /*
6884      * for equal, check if there is a node pertaining to both sets
6885      */
6886     if (neq == 0)
6887 	for (i = 0;i < ns1->nodeNr;i++)
6888 	    for (j = 0;j < ns2->nodeNr;j++)
6889 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
6890 		    return(1);
6891 
6892     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6893     if (values1 == NULL) {
6894         /* TODO: Propagate memory error. */
6895         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6896 	return(0);
6897     }
6898     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6899     if (hashs1 == NULL) {
6900         /* TODO: Propagate memory error. */
6901         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6902 	xmlFree(values1);
6903 	return(0);
6904     }
6905     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6906     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6907     if (values2 == NULL) {
6908         /* TODO: Propagate memory error. */
6909         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6910 	xmlFree(hashs1);
6911 	xmlFree(values1);
6912 	return(0);
6913     }
6914     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6915     if (hashs2 == NULL) {
6916         /* TODO: Propagate memory error. */
6917         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6918 	xmlFree(hashs1);
6919 	xmlFree(values1);
6920 	xmlFree(values2);
6921 	return(0);
6922     }
6923     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6924     for (i = 0;i < ns1->nodeNr;i++) {
6925 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6926 	for (j = 0;j < ns2->nodeNr;j++) {
6927 	    if (i == 0)
6928 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6929 	    if (hashs1[i] != hashs2[j]) {
6930 		if (neq) {
6931 		    ret = 1;
6932 		    break;
6933 		}
6934 	    }
6935 	    else {
6936 		if (values1[i] == NULL)
6937 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6938 		if (values2[j] == NULL)
6939 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6940 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6941 		if (ret)
6942 		    break;
6943 	    }
6944 	}
6945 	if (ret)
6946 	    break;
6947     }
6948     for (i = 0;i < ns1->nodeNr;i++)
6949 	if (values1[i] != NULL)
6950 	    xmlFree(values1[i]);
6951     for (j = 0;j < ns2->nodeNr;j++)
6952 	if (values2[j] != NULL)
6953 	    xmlFree(values2[j]);
6954     xmlFree(values1);
6955     xmlFree(values2);
6956     xmlFree(hashs1);
6957     xmlFree(hashs2);
6958     return(ret);
6959 }
6960 
6961 static int
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6962 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6963   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6964     int ret = 0;
6965     /*
6966      *At this point we are assured neither arg1 nor arg2
6967      *is a nodeset, so we can just pick the appropriate routine.
6968      */
6969     switch (arg1->type) {
6970         case XPATH_UNDEFINED:
6971 #ifdef DEBUG_EXPR
6972 	    xmlGenericError(xmlGenericErrorContext,
6973 		    "Equal: undefined\n");
6974 #endif
6975 	    break;
6976         case XPATH_BOOLEAN:
6977 	    switch (arg2->type) {
6978 	        case XPATH_UNDEFINED:
6979 #ifdef DEBUG_EXPR
6980 		    xmlGenericError(xmlGenericErrorContext,
6981 			    "Equal: undefined\n");
6982 #endif
6983 		    break;
6984 		case XPATH_BOOLEAN:
6985 #ifdef DEBUG_EXPR
6986 		    xmlGenericError(xmlGenericErrorContext,
6987 			    "Equal: %d boolean %d \n",
6988 			    arg1->boolval, arg2->boolval);
6989 #endif
6990 		    ret = (arg1->boolval == arg2->boolval);
6991 		    break;
6992 		case XPATH_NUMBER:
6993 		    ret = (arg1->boolval ==
6994 			   xmlXPathCastNumberToBoolean(arg2->floatval));
6995 		    break;
6996 		case XPATH_STRING:
6997 		    if ((arg2->stringval == NULL) ||
6998 			(arg2->stringval[0] == 0)) ret = 0;
6999 		    else
7000 			ret = 1;
7001 		    ret = (arg1->boolval == ret);
7002 		    break;
7003 		case XPATH_USERS:
7004 #ifdef LIBXML_XPTR_LOCS_ENABLED
7005 		case XPATH_POINT:
7006 		case XPATH_RANGE:
7007 		case XPATH_LOCATIONSET:
7008 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7009 		    TODO
7010 		    break;
7011 		case XPATH_NODESET:
7012 		case XPATH_XSLT_TREE:
7013 		    break;
7014 	    }
7015 	    break;
7016         case XPATH_NUMBER:
7017 	    switch (arg2->type) {
7018 	        case XPATH_UNDEFINED:
7019 #ifdef DEBUG_EXPR
7020 		    xmlGenericError(xmlGenericErrorContext,
7021 			    "Equal: undefined\n");
7022 #endif
7023 		    break;
7024 		case XPATH_BOOLEAN:
7025 		    ret = (arg2->boolval==
7026 			   xmlXPathCastNumberToBoolean(arg1->floatval));
7027 		    break;
7028 		case XPATH_STRING:
7029 		    valuePush(ctxt, arg2);
7030 		    xmlXPathNumberFunction(ctxt, 1);
7031 		    arg2 = valuePop(ctxt);
7032                     /* Falls through. */
7033 		case XPATH_NUMBER:
7034 		    /* Hand check NaN and Infinity equalities */
7035 		    if (xmlXPathIsNaN(arg1->floatval) ||
7036 			    xmlXPathIsNaN(arg2->floatval)) {
7037 		        ret = 0;
7038 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7039 		        if (xmlXPathIsInf(arg2->floatval) == 1)
7040 			    ret = 1;
7041 			else
7042 			    ret = 0;
7043 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7044 			if (xmlXPathIsInf(arg2->floatval) == -1)
7045 			    ret = 1;
7046 			else
7047 			    ret = 0;
7048 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7049 			if (xmlXPathIsInf(arg1->floatval) == 1)
7050 			    ret = 1;
7051 			else
7052 			    ret = 0;
7053 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7054 			if (xmlXPathIsInf(arg1->floatval) == -1)
7055 			    ret = 1;
7056 			else
7057 			    ret = 0;
7058 		    } else {
7059 		        ret = (arg1->floatval == arg2->floatval);
7060 		    }
7061 		    break;
7062 		case XPATH_USERS:
7063 #ifdef LIBXML_XPTR_LOCS_ENABLED
7064 		case XPATH_POINT:
7065 		case XPATH_RANGE:
7066 		case XPATH_LOCATIONSET:
7067 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7068 		    TODO
7069 		    break;
7070 		case XPATH_NODESET:
7071 		case XPATH_XSLT_TREE:
7072 		    break;
7073 	    }
7074 	    break;
7075         case XPATH_STRING:
7076 	    switch (arg2->type) {
7077 	        case XPATH_UNDEFINED:
7078 #ifdef DEBUG_EXPR
7079 		    xmlGenericError(xmlGenericErrorContext,
7080 			    "Equal: undefined\n");
7081 #endif
7082 		    break;
7083 		case XPATH_BOOLEAN:
7084 		    if ((arg1->stringval == NULL) ||
7085 			(arg1->stringval[0] == 0)) ret = 0;
7086 		    else
7087 			ret = 1;
7088 		    ret = (arg2->boolval == ret);
7089 		    break;
7090 		case XPATH_STRING:
7091 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7092 		    break;
7093 		case XPATH_NUMBER:
7094 		    valuePush(ctxt, arg1);
7095 		    xmlXPathNumberFunction(ctxt, 1);
7096 		    arg1 = valuePop(ctxt);
7097 		    /* Hand check NaN and Infinity equalities */
7098 		    if (xmlXPathIsNaN(arg1->floatval) ||
7099 			    xmlXPathIsNaN(arg2->floatval)) {
7100 		        ret = 0;
7101 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7102 			if (xmlXPathIsInf(arg2->floatval) == 1)
7103 			    ret = 1;
7104 			else
7105 			    ret = 0;
7106 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7107 			if (xmlXPathIsInf(arg2->floatval) == -1)
7108 			    ret = 1;
7109 			else
7110 			    ret = 0;
7111 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7112 			if (xmlXPathIsInf(arg1->floatval) == 1)
7113 			    ret = 1;
7114 			else
7115 			    ret = 0;
7116 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7117 			if (xmlXPathIsInf(arg1->floatval) == -1)
7118 			    ret = 1;
7119 			else
7120 			    ret = 0;
7121 		    } else {
7122 		        ret = (arg1->floatval == arg2->floatval);
7123 		    }
7124 		    break;
7125 		case XPATH_USERS:
7126 #ifdef LIBXML_XPTR_LOCS_ENABLED
7127 		case XPATH_POINT:
7128 		case XPATH_RANGE:
7129 		case XPATH_LOCATIONSET:
7130 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7131 		    TODO
7132 		    break;
7133 		case XPATH_NODESET:
7134 		case XPATH_XSLT_TREE:
7135 		    break;
7136 	    }
7137 	    break;
7138         case XPATH_USERS:
7139 #ifdef LIBXML_XPTR_LOCS_ENABLED
7140 	case XPATH_POINT:
7141 	case XPATH_RANGE:
7142 	case XPATH_LOCATIONSET:
7143 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7144 	    TODO
7145 	    break;
7146 	case XPATH_NODESET:
7147 	case XPATH_XSLT_TREE:
7148 	    break;
7149     }
7150     xmlXPathReleaseObject(ctxt->context, arg1);
7151     xmlXPathReleaseObject(ctxt->context, arg2);
7152     return(ret);
7153 }
7154 
7155 /**
7156  * xmlXPathEqualValues:
7157  * @ctxt:  the XPath Parser context
7158  *
7159  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7160  *
7161  * Returns 0 or 1 depending on the results of the test.
7162  */
7163 int
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt)7164 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7165     xmlXPathObjectPtr arg1, arg2, argtmp;
7166     int ret = 0;
7167 
7168     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7169     arg2 = valuePop(ctxt);
7170     arg1 = valuePop(ctxt);
7171     if ((arg1 == NULL) || (arg2 == NULL)) {
7172 	if (arg1 != NULL)
7173 	    xmlXPathReleaseObject(ctxt->context, arg1);
7174 	else
7175 	    xmlXPathReleaseObject(ctxt->context, arg2);
7176 	XP_ERROR0(XPATH_INVALID_OPERAND);
7177     }
7178 
7179     if (arg1 == arg2) {
7180 #ifdef DEBUG_EXPR
7181         xmlGenericError(xmlGenericErrorContext,
7182 		"Equal: by pointer\n");
7183 #endif
7184 	xmlXPathFreeObject(arg1);
7185         return(1);
7186     }
7187 
7188     /*
7189      *If either argument is a nodeset, it's a 'special case'
7190      */
7191     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7192       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7193 	/*
7194 	 *Hack it to assure arg1 is the nodeset
7195 	 */
7196 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7197 		argtmp = arg2;
7198 		arg2 = arg1;
7199 		arg1 = argtmp;
7200 	}
7201 	switch (arg2->type) {
7202 	    case XPATH_UNDEFINED:
7203 #ifdef DEBUG_EXPR
7204 		xmlGenericError(xmlGenericErrorContext,
7205 			"Equal: undefined\n");
7206 #endif
7207 		break;
7208 	    case XPATH_NODESET:
7209 	    case XPATH_XSLT_TREE:
7210 		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7211 		break;
7212 	    case XPATH_BOOLEAN:
7213 		if ((arg1->nodesetval == NULL) ||
7214 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7215 		else
7216 		    ret = 1;
7217 		ret = (ret == arg2->boolval);
7218 		break;
7219 	    case XPATH_NUMBER:
7220 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7221 		break;
7222 	    case XPATH_STRING:
7223 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7224 		break;
7225 	    case XPATH_USERS:
7226 #ifdef LIBXML_XPTR_LOCS_ENABLED
7227 	    case XPATH_POINT:
7228 	    case XPATH_RANGE:
7229 	    case XPATH_LOCATIONSET:
7230 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7231 		TODO
7232 		break;
7233 	}
7234 	xmlXPathReleaseObject(ctxt->context, arg1);
7235 	xmlXPathReleaseObject(ctxt->context, arg2);
7236 	return(ret);
7237     }
7238 
7239     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7240 }
7241 
7242 /**
7243  * xmlXPathNotEqualValues:
7244  * @ctxt:  the XPath Parser context
7245  *
7246  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7247  *
7248  * Returns 0 or 1 depending on the results of the test.
7249  */
7250 int
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt)7251 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7252     xmlXPathObjectPtr arg1, arg2, argtmp;
7253     int ret = 0;
7254 
7255     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7256     arg2 = valuePop(ctxt);
7257     arg1 = valuePop(ctxt);
7258     if ((arg1 == NULL) || (arg2 == NULL)) {
7259 	if (arg1 != NULL)
7260 	    xmlXPathReleaseObject(ctxt->context, arg1);
7261 	else
7262 	    xmlXPathReleaseObject(ctxt->context, arg2);
7263 	XP_ERROR0(XPATH_INVALID_OPERAND);
7264     }
7265 
7266     if (arg1 == arg2) {
7267 #ifdef DEBUG_EXPR
7268         xmlGenericError(xmlGenericErrorContext,
7269 		"NotEqual: by pointer\n");
7270 #endif
7271 	xmlXPathReleaseObject(ctxt->context, arg1);
7272         return(0);
7273     }
7274 
7275     /*
7276      *If either argument is a nodeset, it's a 'special case'
7277      */
7278     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7279       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7280 	/*
7281 	 *Hack it to assure arg1 is the nodeset
7282 	 */
7283 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7284 		argtmp = arg2;
7285 		arg2 = arg1;
7286 		arg1 = argtmp;
7287 	}
7288 	switch (arg2->type) {
7289 	    case XPATH_UNDEFINED:
7290 #ifdef DEBUG_EXPR
7291 		xmlGenericError(xmlGenericErrorContext,
7292 			"NotEqual: undefined\n");
7293 #endif
7294 		break;
7295 	    case XPATH_NODESET:
7296 	    case XPATH_XSLT_TREE:
7297 		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7298 		break;
7299 	    case XPATH_BOOLEAN:
7300 		if ((arg1->nodesetval == NULL) ||
7301 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7302 		else
7303 		    ret = 1;
7304 		ret = (ret != arg2->boolval);
7305 		break;
7306 	    case XPATH_NUMBER:
7307 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7308 		break;
7309 	    case XPATH_STRING:
7310 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7311 		break;
7312 	    case XPATH_USERS:
7313 #ifdef LIBXML_XPTR_LOCS_ENABLED
7314 	    case XPATH_POINT:
7315 	    case XPATH_RANGE:
7316 	    case XPATH_LOCATIONSET:
7317 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7318 		TODO
7319 		break;
7320 	}
7321 	xmlXPathReleaseObject(ctxt->context, arg1);
7322 	xmlXPathReleaseObject(ctxt->context, arg2);
7323 	return(ret);
7324     }
7325 
7326     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7327 }
7328 
7329 /**
7330  * xmlXPathCompareValues:
7331  * @ctxt:  the XPath Parser context
7332  * @inf:  less than (1) or greater than (0)
7333  * @strict:  is the comparison strict
7334  *
7335  * Implement the compare operation on XPath objects:
7336  *     @arg1 < @arg2    (1, 1, ...
7337  *     @arg1 <= @arg2   (1, 0, ...
7338  *     @arg1 > @arg2    (0, 1, ...
7339  *     @arg1 >= @arg2   (0, 0, ...
7340  *
7341  * When neither object to be compared is a node-set and the operator is
7342  * <=, <, >=, >, then the objects are compared by converted both objects
7343  * to numbers and comparing the numbers according to IEEE 754. The <
7344  * comparison will be true if and only if the first number is less than the
7345  * second number. The <= comparison will be true if and only if the first
7346  * number is less than or equal to the second number. The > comparison
7347  * will be true if and only if the first number is greater than the second
7348  * number. The >= comparison will be true if and only if the first number
7349  * is greater than or equal to the second number.
7350  *
7351  * Returns 1 if the comparison succeeded, 0 if it failed
7352  */
7353 int
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt,int inf,int strict)7354 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7355     int ret = 0, arg1i = 0, arg2i = 0;
7356     xmlXPathObjectPtr arg1, arg2;
7357 
7358     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7359     arg2 = valuePop(ctxt);
7360     arg1 = valuePop(ctxt);
7361     if ((arg1 == NULL) || (arg2 == NULL)) {
7362 	if (arg1 != NULL)
7363 	    xmlXPathReleaseObject(ctxt->context, arg1);
7364 	else
7365 	    xmlXPathReleaseObject(ctxt->context, arg2);
7366 	XP_ERROR0(XPATH_INVALID_OPERAND);
7367     }
7368 
7369     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7370       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7371 	/*
7372 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7373 	 * are not freed from within this routine; they will be freed from the
7374 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7375 	 */
7376 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7377 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7378 	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7379 	} else {
7380 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7381 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7382 			                          arg1, arg2);
7383 	    } else {
7384 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7385 			                          arg2, arg1);
7386 	    }
7387 	}
7388 	return(ret);
7389     }
7390 
7391     if (arg1->type != XPATH_NUMBER) {
7392 	valuePush(ctxt, arg1);
7393 	xmlXPathNumberFunction(ctxt, 1);
7394 	arg1 = valuePop(ctxt);
7395     }
7396     if (arg1->type != XPATH_NUMBER) {
7397 	xmlXPathFreeObject(arg1);
7398 	xmlXPathFreeObject(arg2);
7399 	XP_ERROR0(XPATH_INVALID_OPERAND);
7400     }
7401     if (arg2->type != XPATH_NUMBER) {
7402 	valuePush(ctxt, arg2);
7403 	xmlXPathNumberFunction(ctxt, 1);
7404 	arg2 = valuePop(ctxt);
7405     }
7406     if (arg2->type != XPATH_NUMBER) {
7407 	xmlXPathReleaseObject(ctxt->context, arg1);
7408 	xmlXPathReleaseObject(ctxt->context, arg2);
7409 	XP_ERROR0(XPATH_INVALID_OPERAND);
7410     }
7411     /*
7412      * Add tests for infinity and nan
7413      * => feedback on 3.4 for Inf and NaN
7414      */
7415     /* Hand check NaN and Infinity comparisons */
7416     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7417 	ret=0;
7418     } else {
7419 	arg1i=xmlXPathIsInf(arg1->floatval);
7420 	arg2i=xmlXPathIsInf(arg2->floatval);
7421 	if (inf && strict) {
7422 	    if ((arg1i == -1 && arg2i != -1) ||
7423 		(arg2i == 1 && arg1i != 1)) {
7424 		ret = 1;
7425 	    } else if (arg1i == 0 && arg2i == 0) {
7426 		ret = (arg1->floatval < arg2->floatval);
7427 	    } else {
7428 		ret = 0;
7429 	    }
7430 	}
7431 	else if (inf && !strict) {
7432 	    if (arg1i == -1 || arg2i == 1) {
7433 		ret = 1;
7434 	    } else if (arg1i == 0 && arg2i == 0) {
7435 		ret = (arg1->floatval <= arg2->floatval);
7436 	    } else {
7437 		ret = 0;
7438 	    }
7439 	}
7440 	else if (!inf && strict) {
7441 	    if ((arg1i == 1 && arg2i != 1) ||
7442 		(arg2i == -1 && arg1i != -1)) {
7443 		ret = 1;
7444 	    } else if (arg1i == 0 && arg2i == 0) {
7445 		ret = (arg1->floatval > arg2->floatval);
7446 	    } else {
7447 		ret = 0;
7448 	    }
7449 	}
7450 	else if (!inf && !strict) {
7451 	    if (arg1i == 1 || arg2i == -1) {
7452 		ret = 1;
7453 	    } else if (arg1i == 0 && arg2i == 0) {
7454 		ret = (arg1->floatval >= arg2->floatval);
7455 	    } else {
7456 		ret = 0;
7457 	    }
7458 	}
7459     }
7460     xmlXPathReleaseObject(ctxt->context, arg1);
7461     xmlXPathReleaseObject(ctxt->context, arg2);
7462     return(ret);
7463 }
7464 
7465 /**
7466  * xmlXPathValueFlipSign:
7467  * @ctxt:  the XPath Parser context
7468  *
7469  * Implement the unary - operation on an XPath object
7470  * The numeric operators convert their operands to numbers as if
7471  * by calling the number function.
7472  */
7473 void
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt)7474 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7475     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7476     CAST_TO_NUMBER;
7477     CHECK_TYPE(XPATH_NUMBER);
7478     ctxt->value->floatval = -ctxt->value->floatval;
7479 }
7480 
7481 /**
7482  * xmlXPathAddValues:
7483  * @ctxt:  the XPath Parser context
7484  *
7485  * Implement the add operation on XPath objects:
7486  * The numeric operators convert their operands to numbers as if
7487  * by calling the number function.
7488  */
7489 void
xmlXPathAddValues(xmlXPathParserContextPtr ctxt)7490 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7491     xmlXPathObjectPtr arg;
7492     double val;
7493 
7494     arg = valuePop(ctxt);
7495     if (arg == NULL)
7496 	XP_ERROR(XPATH_INVALID_OPERAND);
7497     val = xmlXPathCastToNumber(arg);
7498     xmlXPathReleaseObject(ctxt->context, arg);
7499     CAST_TO_NUMBER;
7500     CHECK_TYPE(XPATH_NUMBER);
7501     ctxt->value->floatval += val;
7502 }
7503 
7504 /**
7505  * xmlXPathSubValues:
7506  * @ctxt:  the XPath Parser context
7507  *
7508  * Implement the subtraction operation on XPath objects:
7509  * The numeric operators convert their operands to numbers as if
7510  * by calling the number function.
7511  */
7512 void
xmlXPathSubValues(xmlXPathParserContextPtr ctxt)7513 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7514     xmlXPathObjectPtr arg;
7515     double val;
7516 
7517     arg = valuePop(ctxt);
7518     if (arg == NULL)
7519 	XP_ERROR(XPATH_INVALID_OPERAND);
7520     val = xmlXPathCastToNumber(arg);
7521     xmlXPathReleaseObject(ctxt->context, arg);
7522     CAST_TO_NUMBER;
7523     CHECK_TYPE(XPATH_NUMBER);
7524     ctxt->value->floatval -= val;
7525 }
7526 
7527 /**
7528  * xmlXPathMultValues:
7529  * @ctxt:  the XPath Parser context
7530  *
7531  * Implement the multiply operation on XPath objects:
7532  * The numeric operators convert their operands to numbers as if
7533  * by calling the number function.
7534  */
7535 void
xmlXPathMultValues(xmlXPathParserContextPtr ctxt)7536 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7537     xmlXPathObjectPtr arg;
7538     double val;
7539 
7540     arg = valuePop(ctxt);
7541     if (arg == NULL)
7542 	XP_ERROR(XPATH_INVALID_OPERAND);
7543     val = xmlXPathCastToNumber(arg);
7544     xmlXPathReleaseObject(ctxt->context, arg);
7545     CAST_TO_NUMBER;
7546     CHECK_TYPE(XPATH_NUMBER);
7547     ctxt->value->floatval *= val;
7548 }
7549 
7550 /**
7551  * xmlXPathDivValues:
7552  * @ctxt:  the XPath Parser context
7553  *
7554  * Implement the div operation on XPath objects @arg1 / @arg2:
7555  * The numeric operators convert their operands to numbers as if
7556  * by calling the number function.
7557  */
7558 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
7559 void
xmlXPathDivValues(xmlXPathParserContextPtr ctxt)7560 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7561     xmlXPathObjectPtr arg;
7562     double val;
7563 
7564     arg = valuePop(ctxt);
7565     if (arg == NULL)
7566 	XP_ERROR(XPATH_INVALID_OPERAND);
7567     val = xmlXPathCastToNumber(arg);
7568     xmlXPathReleaseObject(ctxt->context, arg);
7569     CAST_TO_NUMBER;
7570     CHECK_TYPE(XPATH_NUMBER);
7571     ctxt->value->floatval /= val;
7572 }
7573 
7574 /**
7575  * xmlXPathModValues:
7576  * @ctxt:  the XPath Parser context
7577  *
7578  * Implement the mod operation on XPath objects: @arg1 / @arg2
7579  * The numeric operators convert their operands to numbers as if
7580  * by calling the number function.
7581  */
7582 void
xmlXPathModValues(xmlXPathParserContextPtr ctxt)7583 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7584     xmlXPathObjectPtr arg;
7585     double arg1, arg2;
7586 
7587     arg = valuePop(ctxt);
7588     if (arg == NULL)
7589 	XP_ERROR(XPATH_INVALID_OPERAND);
7590     arg2 = xmlXPathCastToNumber(arg);
7591     xmlXPathReleaseObject(ctxt->context, arg);
7592     CAST_TO_NUMBER;
7593     CHECK_TYPE(XPATH_NUMBER);
7594     arg1 = ctxt->value->floatval;
7595     if (arg2 == 0)
7596 	ctxt->value->floatval = xmlXPathNAN;
7597     else {
7598 	ctxt->value->floatval = fmod(arg1, arg2);
7599     }
7600 }
7601 
7602 /************************************************************************
7603  *									*
7604  *		The traversal functions					*
7605  *									*
7606  ************************************************************************/
7607 
7608 /*
7609  * A traversal function enumerates nodes along an axis.
7610  * Initially it must be called with NULL, and it indicates
7611  * termination on the axis by returning NULL.
7612  */
7613 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7614                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7615 
7616 /*
7617  * xmlXPathTraversalFunctionExt:
7618  * A traversal function enumerates nodes along an axis.
7619  * Initially it must be called with NULL, and it indicates
7620  * termination on the axis by returning NULL.
7621  * The context node of the traversal is specified via @contextNode.
7622  */
7623 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7624                     (xmlNodePtr cur, xmlNodePtr contextNode);
7625 
7626 /*
7627  * xmlXPathNodeSetMergeFunction:
7628  * Used for merging node sets in xmlXPathCollectAndTest().
7629  */
7630 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7631 		    (xmlNodeSetPtr, xmlNodeSetPtr);
7632 
7633 
7634 /**
7635  * xmlXPathNextSelf:
7636  * @ctxt:  the XPath Parser context
7637  * @cur:  the current node in the traversal
7638  *
7639  * Traversal function for the "self" direction
7640  * The self axis contains just the context node itself
7641  *
7642  * Returns the next element following that axis
7643  */
7644 xmlNodePtr
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7645 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7646     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7647     if (cur == NULL)
7648         return(ctxt->context->node);
7649     return(NULL);
7650 }
7651 
7652 /**
7653  * xmlXPathNextChild:
7654  * @ctxt:  the XPath Parser context
7655  * @cur:  the current node in the traversal
7656  *
7657  * Traversal function for the "child" direction
7658  * The child axis contains the children of the context node in document order.
7659  *
7660  * Returns the next element following that axis
7661  */
7662 xmlNodePtr
xmlXPathNextChild(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7663 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7664     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7665     if (cur == NULL) {
7666 	if (ctxt->context->node == NULL) return(NULL);
7667 	switch (ctxt->context->node->type) {
7668             case XML_ELEMENT_NODE:
7669             case XML_TEXT_NODE:
7670             case XML_CDATA_SECTION_NODE:
7671             case XML_ENTITY_REF_NODE:
7672             case XML_ENTITY_NODE:
7673             case XML_PI_NODE:
7674             case XML_COMMENT_NODE:
7675             case XML_NOTATION_NODE:
7676             case XML_DTD_NODE:
7677 		return(ctxt->context->node->children);
7678             case XML_DOCUMENT_NODE:
7679             case XML_DOCUMENT_TYPE_NODE:
7680             case XML_DOCUMENT_FRAG_NODE:
7681             case XML_HTML_DOCUMENT_NODE:
7682 		return(((xmlDocPtr) ctxt->context->node)->children);
7683 	    case XML_ELEMENT_DECL:
7684 	    case XML_ATTRIBUTE_DECL:
7685 	    case XML_ENTITY_DECL:
7686             case XML_ATTRIBUTE_NODE:
7687 	    case XML_NAMESPACE_DECL:
7688 	    case XML_XINCLUDE_START:
7689 	    case XML_XINCLUDE_END:
7690 		return(NULL);
7691 	}
7692 	return(NULL);
7693     }
7694     if ((cur->type == XML_DOCUMENT_NODE) ||
7695         (cur->type == XML_HTML_DOCUMENT_NODE))
7696 	return(NULL);
7697     return(cur->next);
7698 }
7699 
7700 /**
7701  * xmlXPathNextChildElement:
7702  * @ctxt:  the XPath Parser context
7703  * @cur:  the current node in the traversal
7704  *
7705  * Traversal function for the "child" direction and nodes of type element.
7706  * The child axis contains the children of the context node in document order.
7707  *
7708  * Returns the next element following that axis
7709  */
7710 static xmlNodePtr
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7711 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7712     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7713     if (cur == NULL) {
7714 	cur = ctxt->context->node;
7715 	if (cur == NULL) return(NULL);
7716 	/*
7717 	* Get the first element child.
7718 	*/
7719 	switch (cur->type) {
7720             case XML_ELEMENT_NODE:
7721 	    case XML_DOCUMENT_FRAG_NODE:
7722 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7723             case XML_ENTITY_NODE:
7724 		cur = cur->children;
7725 		if (cur != NULL) {
7726 		    if (cur->type == XML_ELEMENT_NODE)
7727 			return(cur);
7728 		    do {
7729 			cur = cur->next;
7730 		    } while ((cur != NULL) &&
7731 			(cur->type != XML_ELEMENT_NODE));
7732 		    return(cur);
7733 		}
7734 		return(NULL);
7735             case XML_DOCUMENT_NODE:
7736             case XML_HTML_DOCUMENT_NODE:
7737 		return(xmlDocGetRootElement((xmlDocPtr) cur));
7738 	    default:
7739 		return(NULL);
7740 	}
7741 	return(NULL);
7742     }
7743     /*
7744     * Get the next sibling element node.
7745     */
7746     switch (cur->type) {
7747 	case XML_ELEMENT_NODE:
7748 	case XML_TEXT_NODE:
7749 	case XML_ENTITY_REF_NODE:
7750 	case XML_ENTITY_NODE:
7751 	case XML_CDATA_SECTION_NODE:
7752 	case XML_PI_NODE:
7753 	case XML_COMMENT_NODE:
7754 	case XML_XINCLUDE_END:
7755 	    break;
7756 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7757 	default:
7758 	    return(NULL);
7759     }
7760     if (cur->next != NULL) {
7761 	if (cur->next->type == XML_ELEMENT_NODE)
7762 	    return(cur->next);
7763 	cur = cur->next;
7764 	do {
7765 	    cur = cur->next;
7766 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7767 	return(cur);
7768     }
7769     return(NULL);
7770 }
7771 
7772 #if 0
7773 /**
7774  * xmlXPathNextDescendantOrSelfElemParent:
7775  * @ctxt:  the XPath Parser context
7776  * @cur:  the current node in the traversal
7777  *
7778  * Traversal function for the "descendant-or-self" axis.
7779  * Additionally it returns only nodes which can be parents of
7780  * element nodes.
7781  *
7782  *
7783  * Returns the next element following that axis
7784  */
7785 static xmlNodePtr
7786 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7787 				       xmlNodePtr contextNode)
7788 {
7789     if (cur == NULL) {
7790 	if (contextNode == NULL)
7791 	    return(NULL);
7792 	switch (contextNode->type) {
7793 	    case XML_ELEMENT_NODE:
7794 	    case XML_XINCLUDE_START:
7795 	    case XML_DOCUMENT_FRAG_NODE:
7796 	    case XML_DOCUMENT_NODE:
7797 	    case XML_HTML_DOCUMENT_NODE:
7798 		return(contextNode);
7799 	    default:
7800 		return(NULL);
7801 	}
7802 	return(NULL);
7803     } else {
7804 	xmlNodePtr start = cur;
7805 
7806 	while (cur != NULL) {
7807 	    switch (cur->type) {
7808 		case XML_ELEMENT_NODE:
7809 		/* TODO: OK to have XInclude here? */
7810 		case XML_XINCLUDE_START:
7811 		case XML_DOCUMENT_FRAG_NODE:
7812 		    if (cur != start)
7813 			return(cur);
7814 		    if (cur->children != NULL) {
7815 			cur = cur->children;
7816 			continue;
7817 		    }
7818 		    break;
7819 		/* Not sure if we need those here. */
7820 		case XML_DOCUMENT_NODE:
7821 		case XML_HTML_DOCUMENT_NODE:
7822 		    if (cur != start)
7823 			return(cur);
7824 		    return(xmlDocGetRootElement((xmlDocPtr) cur));
7825 		default:
7826 		    break;
7827 	    }
7828 
7829 next_sibling:
7830 	    if ((cur == NULL) || (cur == contextNode))
7831 		return(NULL);
7832 	    if (cur->next != NULL) {
7833 		cur = cur->next;
7834 	    } else {
7835 		cur = cur->parent;
7836 		goto next_sibling;
7837 	    }
7838 	}
7839     }
7840     return(NULL);
7841 }
7842 #endif
7843 
7844 /**
7845  * xmlXPathNextDescendant:
7846  * @ctxt:  the XPath Parser context
7847  * @cur:  the current node in the traversal
7848  *
7849  * Traversal function for the "descendant" direction
7850  * the descendant axis contains the descendants of the context node in document
7851  * order; a descendant is a child or a child of a child and so on.
7852  *
7853  * Returns the next element following that axis
7854  */
7855 xmlNodePtr
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7856 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7857     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7858     if (cur == NULL) {
7859 	if (ctxt->context->node == NULL)
7860 	    return(NULL);
7861 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7862 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7863 	    return(NULL);
7864 
7865         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7866 	    return(ctxt->context->doc->children);
7867         return(ctxt->context->node->children);
7868     }
7869 
7870     if (cur->type == XML_NAMESPACE_DECL)
7871         return(NULL);
7872     if (cur->children != NULL) {
7873 	/*
7874 	 * Do not descend on entities declarations
7875 	 */
7876 	if (cur->children->type != XML_ENTITY_DECL) {
7877 	    cur = cur->children;
7878 	    /*
7879 	     * Skip DTDs
7880 	     */
7881 	    if (cur->type != XML_DTD_NODE)
7882 		return(cur);
7883 	}
7884     }
7885 
7886     if (cur == ctxt->context->node) return(NULL);
7887 
7888     while (cur->next != NULL) {
7889 	cur = cur->next;
7890 	if ((cur->type != XML_ENTITY_DECL) &&
7891 	    (cur->type != XML_DTD_NODE))
7892 	    return(cur);
7893     }
7894 
7895     do {
7896         cur = cur->parent;
7897 	if (cur == NULL) break;
7898 	if (cur == ctxt->context->node) return(NULL);
7899 	if (cur->next != NULL) {
7900 	    cur = cur->next;
7901 	    return(cur);
7902 	}
7903     } while (cur != NULL);
7904     return(cur);
7905 }
7906 
7907 /**
7908  * xmlXPathNextDescendantOrSelf:
7909  * @ctxt:  the XPath Parser context
7910  * @cur:  the current node in the traversal
7911  *
7912  * Traversal function for the "descendant-or-self" direction
7913  * the descendant-or-self axis contains the context node and the descendants
7914  * of the context node in document order; thus the context node is the first
7915  * node on the axis, and the first child of the context node is the second node
7916  * on the axis
7917  *
7918  * Returns the next element following that axis
7919  */
7920 xmlNodePtr
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7921 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7922     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7923     if (cur == NULL)
7924         return(ctxt->context->node);
7925 
7926     if (ctxt->context->node == NULL)
7927         return(NULL);
7928     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7929         (ctxt->context->node->type == XML_NAMESPACE_DECL))
7930         return(NULL);
7931 
7932     return(xmlXPathNextDescendant(ctxt, cur));
7933 }
7934 
7935 /**
7936  * xmlXPathNextParent:
7937  * @ctxt:  the XPath Parser context
7938  * @cur:  the current node in the traversal
7939  *
7940  * Traversal function for the "parent" direction
7941  * The parent axis contains the parent of the context node, if there is one.
7942  *
7943  * Returns the next element following that axis
7944  */
7945 xmlNodePtr
xmlXPathNextParent(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7946 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7947     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7948     /*
7949      * the parent of an attribute or namespace node is the element
7950      * to which the attribute or namespace node is attached
7951      * Namespace handling !!!
7952      */
7953     if (cur == NULL) {
7954 	if (ctxt->context->node == NULL) return(NULL);
7955 	switch (ctxt->context->node->type) {
7956             case XML_ELEMENT_NODE:
7957             case XML_TEXT_NODE:
7958             case XML_CDATA_SECTION_NODE:
7959             case XML_ENTITY_REF_NODE:
7960             case XML_ENTITY_NODE:
7961             case XML_PI_NODE:
7962             case XML_COMMENT_NODE:
7963             case XML_NOTATION_NODE:
7964             case XML_DTD_NODE:
7965 	    case XML_ELEMENT_DECL:
7966 	    case XML_ATTRIBUTE_DECL:
7967 	    case XML_XINCLUDE_START:
7968 	    case XML_XINCLUDE_END:
7969 	    case XML_ENTITY_DECL:
7970 		if (ctxt->context->node->parent == NULL)
7971 		    return((xmlNodePtr) ctxt->context->doc);
7972 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7973 		    ((ctxt->context->node->parent->name[0] == ' ') ||
7974 		     (xmlStrEqual(ctxt->context->node->parent->name,
7975 				 BAD_CAST "fake node libxslt"))))
7976 		    return(NULL);
7977 		return(ctxt->context->node->parent);
7978             case XML_ATTRIBUTE_NODE: {
7979 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7980 
7981 		return(att->parent);
7982 	    }
7983             case XML_DOCUMENT_NODE:
7984             case XML_DOCUMENT_TYPE_NODE:
7985             case XML_DOCUMENT_FRAG_NODE:
7986             case XML_HTML_DOCUMENT_NODE:
7987                 return(NULL);
7988 	    case XML_NAMESPACE_DECL: {
7989 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7990 
7991 		if ((ns->next != NULL) &&
7992 		    (ns->next->type != XML_NAMESPACE_DECL))
7993 		    return((xmlNodePtr) ns->next);
7994                 return(NULL);
7995 	    }
7996 	}
7997     }
7998     return(NULL);
7999 }
8000 
8001 /**
8002  * xmlXPathNextAncestor:
8003  * @ctxt:  the XPath Parser context
8004  * @cur:  the current node in the traversal
8005  *
8006  * Traversal function for the "ancestor" direction
8007  * the ancestor axis contains the ancestors of the context node; the ancestors
8008  * of the context node consist of the parent of context node and the parent's
8009  * parent and so on; the nodes are ordered in reverse document order; thus the
8010  * parent is the first node on the axis, and the parent's parent is the second
8011  * node on the axis
8012  *
8013  * Returns the next element following that axis
8014  */
8015 xmlNodePtr
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8016 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8017     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8018     /*
8019      * the parent of an attribute or namespace node is the element
8020      * to which the attribute or namespace node is attached
8021      * !!!!!!!!!!!!!
8022      */
8023     if (cur == NULL) {
8024 	if (ctxt->context->node == NULL) return(NULL);
8025 	switch (ctxt->context->node->type) {
8026             case XML_ELEMENT_NODE:
8027             case XML_TEXT_NODE:
8028             case XML_CDATA_SECTION_NODE:
8029             case XML_ENTITY_REF_NODE:
8030             case XML_ENTITY_NODE:
8031             case XML_PI_NODE:
8032             case XML_COMMENT_NODE:
8033 	    case XML_DTD_NODE:
8034 	    case XML_ELEMENT_DECL:
8035 	    case XML_ATTRIBUTE_DECL:
8036 	    case XML_ENTITY_DECL:
8037             case XML_NOTATION_NODE:
8038 	    case XML_XINCLUDE_START:
8039 	    case XML_XINCLUDE_END:
8040 		if (ctxt->context->node->parent == NULL)
8041 		    return((xmlNodePtr) ctxt->context->doc);
8042 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8043 		    ((ctxt->context->node->parent->name[0] == ' ') ||
8044 		     (xmlStrEqual(ctxt->context->node->parent->name,
8045 				 BAD_CAST "fake node libxslt"))))
8046 		    return(NULL);
8047 		return(ctxt->context->node->parent);
8048             case XML_ATTRIBUTE_NODE: {
8049 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8050 
8051 		return(tmp->parent);
8052 	    }
8053             case XML_DOCUMENT_NODE:
8054             case XML_DOCUMENT_TYPE_NODE:
8055             case XML_DOCUMENT_FRAG_NODE:
8056             case XML_HTML_DOCUMENT_NODE:
8057                 return(NULL);
8058 	    case XML_NAMESPACE_DECL: {
8059 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8060 
8061 		if ((ns->next != NULL) &&
8062 		    (ns->next->type != XML_NAMESPACE_DECL))
8063 		    return((xmlNodePtr) ns->next);
8064 		/* Bad, how did that namespace end up here ? */
8065                 return(NULL);
8066 	    }
8067 	}
8068 	return(NULL);
8069     }
8070     if (cur == ctxt->context->doc->children)
8071 	return((xmlNodePtr) ctxt->context->doc);
8072     if (cur == (xmlNodePtr) ctxt->context->doc)
8073 	return(NULL);
8074     switch (cur->type) {
8075 	case XML_ELEMENT_NODE:
8076 	case XML_TEXT_NODE:
8077 	case XML_CDATA_SECTION_NODE:
8078 	case XML_ENTITY_REF_NODE:
8079 	case XML_ENTITY_NODE:
8080 	case XML_PI_NODE:
8081 	case XML_COMMENT_NODE:
8082 	case XML_NOTATION_NODE:
8083 	case XML_DTD_NODE:
8084         case XML_ELEMENT_DECL:
8085         case XML_ATTRIBUTE_DECL:
8086         case XML_ENTITY_DECL:
8087 	case XML_XINCLUDE_START:
8088 	case XML_XINCLUDE_END:
8089 	    if (cur->parent == NULL)
8090 		return(NULL);
8091 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
8092 		((cur->parent->name[0] == ' ') ||
8093 		 (xmlStrEqual(cur->parent->name,
8094 			      BAD_CAST "fake node libxslt"))))
8095 		return(NULL);
8096 	    return(cur->parent);
8097 	case XML_ATTRIBUTE_NODE: {
8098 	    xmlAttrPtr att = (xmlAttrPtr) cur;
8099 
8100 	    return(att->parent);
8101 	}
8102 	case XML_NAMESPACE_DECL: {
8103 	    xmlNsPtr ns = (xmlNsPtr) cur;
8104 
8105 	    if ((ns->next != NULL) &&
8106 	        (ns->next->type != XML_NAMESPACE_DECL))
8107 	        return((xmlNodePtr) ns->next);
8108 	    /* Bad, how did that namespace end up here ? */
8109             return(NULL);
8110 	}
8111 	case XML_DOCUMENT_NODE:
8112 	case XML_DOCUMENT_TYPE_NODE:
8113 	case XML_DOCUMENT_FRAG_NODE:
8114 	case XML_HTML_DOCUMENT_NODE:
8115 	    return(NULL);
8116     }
8117     return(NULL);
8118 }
8119 
8120 /**
8121  * xmlXPathNextAncestorOrSelf:
8122  * @ctxt:  the XPath Parser context
8123  * @cur:  the current node in the traversal
8124  *
8125  * Traversal function for the "ancestor-or-self" direction
8126  * he ancestor-or-self axis contains the context node and ancestors of
8127  * the context node in reverse document order; thus the context node is
8128  * the first node on the axis, and the context node's parent the second;
8129  * parent here is defined the same as with the parent axis.
8130  *
8131  * Returns the next element following that axis
8132  */
8133 xmlNodePtr
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8134 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8135     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8136     if (cur == NULL)
8137         return(ctxt->context->node);
8138     return(xmlXPathNextAncestor(ctxt, cur));
8139 }
8140 
8141 /**
8142  * xmlXPathNextFollowingSibling:
8143  * @ctxt:  the XPath Parser context
8144  * @cur:  the current node in the traversal
8145  *
8146  * Traversal function for the "following-sibling" direction
8147  * The following-sibling axis contains the following siblings of the context
8148  * node in document order.
8149  *
8150  * Returns the next element following that axis
8151  */
8152 xmlNodePtr
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8153 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8154     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8155     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8156 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8157 	return(NULL);
8158     if (cur == (xmlNodePtr) ctxt->context->doc)
8159         return(NULL);
8160     if (cur == NULL)
8161         return(ctxt->context->node->next);
8162     return(cur->next);
8163 }
8164 
8165 /**
8166  * xmlXPathNextPrecedingSibling:
8167  * @ctxt:  the XPath Parser context
8168  * @cur:  the current node in the traversal
8169  *
8170  * Traversal function for the "preceding-sibling" direction
8171  * The preceding-sibling axis contains the preceding siblings of the context
8172  * node in reverse document order; the first preceding sibling is first on the
8173  * axis; the sibling preceding that node is the second on the axis and so on.
8174  *
8175  * Returns the next element following that axis
8176  */
8177 xmlNodePtr
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8178 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8179     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8180     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8181 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8182 	return(NULL);
8183     if (cur == (xmlNodePtr) ctxt->context->doc)
8184         return(NULL);
8185     if (cur == NULL)
8186         return(ctxt->context->node->prev);
8187     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8188 	cur = cur->prev;
8189 	if (cur == NULL)
8190 	    return(ctxt->context->node->prev);
8191     }
8192     return(cur->prev);
8193 }
8194 
8195 /**
8196  * xmlXPathNextFollowing:
8197  * @ctxt:  the XPath Parser context
8198  * @cur:  the current node in the traversal
8199  *
8200  * Traversal function for the "following" direction
8201  * The following axis contains all nodes in the same document as the context
8202  * node that are after the context node in document order, excluding any
8203  * descendants and excluding attribute nodes and namespace nodes; the nodes
8204  * are ordered in document order
8205  *
8206  * Returns the next element following that axis
8207  */
8208 xmlNodePtr
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8209 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8210     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8211     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8212         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8213         return(cur->children);
8214 
8215     if (cur == NULL) {
8216         cur = ctxt->context->node;
8217         if (cur->type == XML_ATTRIBUTE_NODE) {
8218             cur = cur->parent;
8219         } else if (cur->type == XML_NAMESPACE_DECL) {
8220             xmlNsPtr ns = (xmlNsPtr) cur;
8221 
8222             if ((ns->next == NULL) ||
8223                 (ns->next->type == XML_NAMESPACE_DECL))
8224                 return (NULL);
8225             cur = (xmlNodePtr) ns->next;
8226         }
8227     }
8228     if (cur == NULL) return(NULL) ; /* ERROR */
8229     if (cur->next != NULL) return(cur->next) ;
8230     do {
8231         cur = cur->parent;
8232         if (cur == NULL) break;
8233         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8234         if (cur->next != NULL) return(cur->next);
8235     } while (cur != NULL);
8236     return(cur);
8237 }
8238 
8239 /*
8240  * xmlXPathIsAncestor:
8241  * @ancestor:  the ancestor node
8242  * @node:  the current node
8243  *
8244  * Check that @ancestor is a @node's ancestor
8245  *
8246  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8247  */
8248 static int
xmlXPathIsAncestor(xmlNodePtr ancestor,xmlNodePtr node)8249 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8250     if ((ancestor == NULL) || (node == NULL)) return(0);
8251     if (node->type == XML_NAMESPACE_DECL)
8252         return(0);
8253     if (ancestor->type == XML_NAMESPACE_DECL)
8254         return(0);
8255     /* nodes need to be in the same document */
8256     if (ancestor->doc != node->doc) return(0);
8257     /* avoid searching if ancestor or node is the root node */
8258     if (ancestor == (xmlNodePtr) node->doc) return(1);
8259     if (node == (xmlNodePtr) ancestor->doc) return(0);
8260     while (node->parent != NULL) {
8261         if (node->parent == ancestor)
8262             return(1);
8263 	node = node->parent;
8264     }
8265     return(0);
8266 }
8267 
8268 /**
8269  * xmlXPathNextPreceding:
8270  * @ctxt:  the XPath Parser context
8271  * @cur:  the current node in the traversal
8272  *
8273  * Traversal function for the "preceding" direction
8274  * the preceding axis contains all nodes in the same document as the context
8275  * node that are before the context node in document order, excluding any
8276  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8277  * ordered in reverse document order
8278  *
8279  * Returns the next element following that axis
8280  */
8281 xmlNodePtr
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8282 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8283 {
8284     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8285     if (cur == NULL) {
8286         cur = ctxt->context->node;
8287         if (cur->type == XML_ATTRIBUTE_NODE) {
8288             cur = cur->parent;
8289         } else if (cur->type == XML_NAMESPACE_DECL) {
8290             xmlNsPtr ns = (xmlNsPtr) cur;
8291 
8292             if ((ns->next == NULL) ||
8293                 (ns->next->type == XML_NAMESPACE_DECL))
8294                 return (NULL);
8295             cur = (xmlNodePtr) ns->next;
8296         }
8297     }
8298     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8299 	return (NULL);
8300     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8301 	cur = cur->prev;
8302     do {
8303         if (cur->prev != NULL) {
8304             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8305             return (cur);
8306         }
8307 
8308         cur = cur->parent;
8309         if (cur == NULL)
8310             return (NULL);
8311         if (cur == ctxt->context->doc->children)
8312             return (NULL);
8313     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8314     return (cur);
8315 }
8316 
8317 /**
8318  * xmlXPathNextPrecedingInternal:
8319  * @ctxt:  the XPath Parser context
8320  * @cur:  the current node in the traversal
8321  *
8322  * Traversal function for the "preceding" direction
8323  * the preceding axis contains all nodes in the same document as the context
8324  * node that are before the context node in document order, excluding any
8325  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8326  * ordered in reverse document order
8327  * This is a faster implementation but internal only since it requires a
8328  * state kept in the parser context: ctxt->ancestor.
8329  *
8330  * Returns the next element following that axis
8331  */
8332 static xmlNodePtr
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8333 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8334                               xmlNodePtr cur)
8335 {
8336     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8337     if (cur == NULL) {
8338         cur = ctxt->context->node;
8339         if (cur == NULL)
8340             return (NULL);
8341         if (cur->type == XML_ATTRIBUTE_NODE) {
8342             cur = cur->parent;
8343         } else if (cur->type == XML_NAMESPACE_DECL) {
8344             xmlNsPtr ns = (xmlNsPtr) cur;
8345 
8346             if ((ns->next == NULL) ||
8347                 (ns->next->type == XML_NAMESPACE_DECL))
8348                 return (NULL);
8349             cur = (xmlNodePtr) ns->next;
8350         }
8351         ctxt->ancestor = cur->parent;
8352     }
8353     if (cur->type == XML_NAMESPACE_DECL)
8354         return(NULL);
8355     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8356 	cur = cur->prev;
8357     while (cur->prev == NULL) {
8358         cur = cur->parent;
8359         if (cur == NULL)
8360             return (NULL);
8361         if (cur == ctxt->context->doc->children)
8362             return (NULL);
8363         if (cur != ctxt->ancestor)
8364             return (cur);
8365         ctxt->ancestor = cur->parent;
8366     }
8367     cur = cur->prev;
8368     while (cur->last != NULL)
8369         cur = cur->last;
8370     return (cur);
8371 }
8372 
8373 /**
8374  * xmlXPathNextNamespace:
8375  * @ctxt:  the XPath Parser context
8376  * @cur:  the current attribute in the traversal
8377  *
8378  * Traversal function for the "namespace" direction
8379  * the namespace axis contains the namespace nodes of the context node;
8380  * the order of nodes on this axis is implementation-defined; the axis will
8381  * be empty unless the context node is an element
8382  *
8383  * We keep the XML namespace node at the end of the list.
8384  *
8385  * Returns the next element following that axis
8386  */
8387 xmlNodePtr
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8388 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8389     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8390     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8391     if (cur == NULL) {
8392         if (ctxt->context->tmpNsList != NULL)
8393 	    xmlFree(ctxt->context->tmpNsList);
8394 	ctxt->context->tmpNsList =
8395 	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8396 	ctxt->context->tmpNsNr = 0;
8397 	if (ctxt->context->tmpNsList != NULL) {
8398 	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8399 		ctxt->context->tmpNsNr++;
8400 	    }
8401 	}
8402 	return((xmlNodePtr) xmlXPathXMLNamespace);
8403     }
8404     if (ctxt->context->tmpNsNr > 0) {
8405 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8406     } else {
8407 	if (ctxt->context->tmpNsList != NULL)
8408 	    xmlFree(ctxt->context->tmpNsList);
8409 	ctxt->context->tmpNsList = NULL;
8410 	return(NULL);
8411     }
8412 }
8413 
8414 /**
8415  * xmlXPathNextAttribute:
8416  * @ctxt:  the XPath Parser context
8417  * @cur:  the current attribute in the traversal
8418  *
8419  * Traversal function for the "attribute" direction
8420  * TODO: support DTD inherited default attributes
8421  *
8422  * Returns the next element following that axis
8423  */
8424 xmlNodePtr
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8425 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8426     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8427     if (ctxt->context->node == NULL)
8428 	return(NULL);
8429     if (ctxt->context->node->type != XML_ELEMENT_NODE)
8430 	return(NULL);
8431     if (cur == NULL) {
8432         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8433 	    return(NULL);
8434         return((xmlNodePtr)ctxt->context->node->properties);
8435     }
8436     return((xmlNodePtr)cur->next);
8437 }
8438 
8439 /************************************************************************
8440  *									*
8441  *		NodeTest Functions					*
8442  *									*
8443  ************************************************************************/
8444 
8445 #define IS_FUNCTION			200
8446 
8447 
8448 /************************************************************************
8449  *									*
8450  *		Implicit tree core function library			*
8451  *									*
8452  ************************************************************************/
8453 
8454 /**
8455  * xmlXPathRoot:
8456  * @ctxt:  the XPath Parser context
8457  *
8458  * Initialize the context to the root of the document
8459  */
8460 void
xmlXPathRoot(xmlXPathParserContextPtr ctxt)8461 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8462     if ((ctxt == NULL) || (ctxt->context == NULL))
8463 	return;
8464     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8465 	(xmlNodePtr) ctxt->context->doc));
8466 }
8467 
8468 /************************************************************************
8469  *									*
8470  *		The explicit core function library			*
8471  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
8472  *									*
8473  ************************************************************************/
8474 
8475 
8476 /**
8477  * xmlXPathLastFunction:
8478  * @ctxt:  the XPath Parser context
8479  * @nargs:  the number of arguments
8480  *
8481  * Implement the last() XPath function
8482  *    number last()
8483  * The last function returns the number of nodes in the context node list.
8484  */
8485 void
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt,int nargs)8486 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8487     CHECK_ARITY(0);
8488     if (ctxt->context->contextSize >= 0) {
8489 	valuePush(ctxt,
8490 	    xmlXPathCacheNewFloat(ctxt->context,
8491 		(double) ctxt->context->contextSize));
8492 #ifdef DEBUG_EXPR
8493 	xmlGenericError(xmlGenericErrorContext,
8494 		"last() : %d\n", ctxt->context->contextSize);
8495 #endif
8496     } else {
8497 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8498     }
8499 }
8500 
8501 /**
8502  * xmlXPathPositionFunction:
8503  * @ctxt:  the XPath Parser context
8504  * @nargs:  the number of arguments
8505  *
8506  * Implement the position() XPath function
8507  *    number position()
8508  * The position function returns the position of the context node in the
8509  * context node list. The first position is 1, and so the last position
8510  * will be equal to last().
8511  */
8512 void
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt,int nargs)8513 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8514     CHECK_ARITY(0);
8515     if (ctxt->context->proximityPosition >= 0) {
8516 	valuePush(ctxt,
8517 	      xmlXPathCacheNewFloat(ctxt->context,
8518 		(double) ctxt->context->proximityPosition));
8519 #ifdef DEBUG_EXPR
8520 	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8521 		ctxt->context->proximityPosition);
8522 #endif
8523     } else {
8524 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8525     }
8526 }
8527 
8528 /**
8529  * xmlXPathCountFunction:
8530  * @ctxt:  the XPath Parser context
8531  * @nargs:  the number of arguments
8532  *
8533  * Implement the count() XPath function
8534  *    number count(node-set)
8535  */
8536 void
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt,int nargs)8537 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8538     xmlXPathObjectPtr cur;
8539 
8540     CHECK_ARITY(1);
8541     if ((ctxt->value == NULL) ||
8542 	((ctxt->value->type != XPATH_NODESET) &&
8543 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8544 	XP_ERROR(XPATH_INVALID_TYPE);
8545     cur = valuePop(ctxt);
8546 
8547     if ((cur == NULL) || (cur->nodesetval == NULL))
8548 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8549     else
8550 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8551 	    (double) cur->nodesetval->nodeNr));
8552     xmlXPathReleaseObject(ctxt->context, cur);
8553 }
8554 
8555 /**
8556  * xmlXPathGetElementsByIds:
8557  * @doc:  the document
8558  * @ids:  a whitespace separated list of IDs
8559  *
8560  * Selects elements by their unique ID.
8561  *
8562  * Returns a node-set of selected elements.
8563  */
8564 static xmlNodeSetPtr
xmlXPathGetElementsByIds(xmlDocPtr doc,const xmlChar * ids)8565 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8566     xmlNodeSetPtr ret;
8567     const xmlChar *cur = ids;
8568     xmlChar *ID;
8569     xmlAttrPtr attr;
8570     xmlNodePtr elem = NULL;
8571 
8572     if (ids == NULL) return(NULL);
8573 
8574     ret = xmlXPathNodeSetCreate(NULL);
8575     if (ret == NULL)
8576         return(ret);
8577 
8578     while (IS_BLANK_CH(*cur)) cur++;
8579     while (*cur != 0) {
8580 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8581 	    cur++;
8582 
8583         ID = xmlStrndup(ids, cur - ids);
8584 	if (ID != NULL) {
8585 	    /*
8586 	     * We used to check the fact that the value passed
8587 	     * was an NCName, but this generated much troubles for
8588 	     * me and Aleksey Sanin, people blatantly violated that
8589 	     * constraint, like Visa3D spec.
8590 	     * if (xmlValidateNCName(ID, 1) == 0)
8591 	     */
8592 	    attr = xmlGetID(doc, ID);
8593 	    if (attr != NULL) {
8594 		if (attr->type == XML_ATTRIBUTE_NODE)
8595 		    elem = attr->parent;
8596 		else if (attr->type == XML_ELEMENT_NODE)
8597 		    elem = (xmlNodePtr) attr;
8598 		else
8599 		    elem = NULL;
8600                 /* TODO: Check memory error. */
8601 		if (elem != NULL)
8602 		    xmlXPathNodeSetAdd(ret, elem);
8603 	    }
8604 	    xmlFree(ID);
8605 	}
8606 
8607 	while (IS_BLANK_CH(*cur)) cur++;
8608 	ids = cur;
8609     }
8610     return(ret);
8611 }
8612 
8613 /**
8614  * xmlXPathIdFunction:
8615  * @ctxt:  the XPath Parser context
8616  * @nargs:  the number of arguments
8617  *
8618  * Implement the id() XPath function
8619  *    node-set id(object)
8620  * The id function selects elements by their unique ID
8621  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8622  * then the result is the union of the result of applying id to the
8623  * string value of each of the nodes in the argument node-set. When the
8624  * argument to id is of any other type, the argument is converted to a
8625  * string as if by a call to the string function; the string is split
8626  * into a whitespace-separated list of tokens (whitespace is any sequence
8627  * of characters matching the production S); the result is a node-set
8628  * containing the elements in the same document as the context node that
8629  * have a unique ID equal to any of the tokens in the list.
8630  */
8631 void
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt,int nargs)8632 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8633     xmlChar *tokens;
8634     xmlNodeSetPtr ret;
8635     xmlXPathObjectPtr obj;
8636 
8637     CHECK_ARITY(1);
8638     obj = valuePop(ctxt);
8639     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8640     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8641 	xmlNodeSetPtr ns;
8642 	int i;
8643 
8644         /* TODO: Check memory error. */
8645 	ret = xmlXPathNodeSetCreate(NULL);
8646 
8647 	if (obj->nodesetval != NULL) {
8648 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8649 		tokens =
8650 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8651 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8652                 /* TODO: Check memory error. */
8653 		ret = xmlXPathNodeSetMerge(ret, ns);
8654 		xmlXPathFreeNodeSet(ns);
8655 		if (tokens != NULL)
8656 		    xmlFree(tokens);
8657 	    }
8658 	}
8659 	xmlXPathReleaseObject(ctxt->context, obj);
8660 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8661 	return;
8662     }
8663     obj = xmlXPathCacheConvertString(ctxt->context, obj);
8664     if (obj == NULL) return;
8665     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8666     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8667     xmlXPathReleaseObject(ctxt->context, obj);
8668     return;
8669 }
8670 
8671 /**
8672  * xmlXPathLocalNameFunction:
8673  * @ctxt:  the XPath Parser context
8674  * @nargs:  the number of arguments
8675  *
8676  * Implement the local-name() XPath function
8677  *    string local-name(node-set?)
8678  * The local-name function returns a string containing the local part
8679  * of the name of the node in the argument node-set that is first in
8680  * document order. If the node-set is empty or the first node has no
8681  * name, an empty string is returned. If the argument is omitted it
8682  * defaults to the context node.
8683  */
8684 void
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8685 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8686     xmlXPathObjectPtr cur;
8687 
8688     if (ctxt == NULL) return;
8689 
8690     if (nargs == 0) {
8691 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8692 	    ctxt->context->node));
8693 	nargs = 1;
8694     }
8695 
8696     CHECK_ARITY(1);
8697     if ((ctxt->value == NULL) ||
8698 	((ctxt->value->type != XPATH_NODESET) &&
8699 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8700 	XP_ERROR(XPATH_INVALID_TYPE);
8701     cur = valuePop(ctxt);
8702 
8703     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8704 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8705     } else {
8706 	int i = 0; /* Should be first in document order !!!!! */
8707 	switch (cur->nodesetval->nodeTab[i]->type) {
8708 	case XML_ELEMENT_NODE:
8709 	case XML_ATTRIBUTE_NODE:
8710 	case XML_PI_NODE:
8711 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8712 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8713 	    else
8714 		valuePush(ctxt,
8715 		      xmlXPathCacheNewString(ctxt->context,
8716 			cur->nodesetval->nodeTab[i]->name));
8717 	    break;
8718 	case XML_NAMESPACE_DECL:
8719 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8720 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8721 	    break;
8722 	default:
8723 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8724 	}
8725     }
8726     xmlXPathReleaseObject(ctxt->context, cur);
8727 }
8728 
8729 /**
8730  * xmlXPathNamespaceURIFunction:
8731  * @ctxt:  the XPath Parser context
8732  * @nargs:  the number of arguments
8733  *
8734  * Implement the namespace-uri() XPath function
8735  *    string namespace-uri(node-set?)
8736  * The namespace-uri function returns a string containing the
8737  * namespace URI of the expanded name of the node in the argument
8738  * node-set that is first in document order. If the node-set is empty,
8739  * the first node has no name, or the expanded name has no namespace
8740  * URI, an empty string is returned. If the argument is omitted it
8741  * defaults to the context node.
8742  */
8743 void
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt,int nargs)8744 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8745     xmlXPathObjectPtr cur;
8746 
8747     if (ctxt == NULL) return;
8748 
8749     if (nargs == 0) {
8750 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8751 	    ctxt->context->node));
8752 	nargs = 1;
8753     }
8754     CHECK_ARITY(1);
8755     if ((ctxt->value == NULL) ||
8756 	((ctxt->value->type != XPATH_NODESET) &&
8757 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8758 	XP_ERROR(XPATH_INVALID_TYPE);
8759     cur = valuePop(ctxt);
8760 
8761     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8762 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8763     } else {
8764 	int i = 0; /* Should be first in document order !!!!! */
8765 	switch (cur->nodesetval->nodeTab[i]->type) {
8766 	case XML_ELEMENT_NODE:
8767 	case XML_ATTRIBUTE_NODE:
8768 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
8769 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8770 	    else
8771 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8772 			  cur->nodesetval->nodeTab[i]->ns->href));
8773 	    break;
8774 	default:
8775 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8776 	}
8777     }
8778     xmlXPathReleaseObject(ctxt->context, cur);
8779 }
8780 
8781 /**
8782  * xmlXPathNameFunction:
8783  * @ctxt:  the XPath Parser context
8784  * @nargs:  the number of arguments
8785  *
8786  * Implement the name() XPath function
8787  *    string name(node-set?)
8788  * The name function returns a string containing a QName representing
8789  * the name of the node in the argument node-set that is first in document
8790  * order. The QName must represent the name with respect to the namespace
8791  * declarations in effect on the node whose name is being represented.
8792  * Typically, this will be the form in which the name occurred in the XML
8793  * source. This need not be the case if there are namespace declarations
8794  * in effect on the node that associate multiple prefixes with the same
8795  * namespace. However, an implementation may include information about
8796  * the original prefix in its representation of nodes; in this case, an
8797  * implementation can ensure that the returned string is always the same
8798  * as the QName used in the XML source. If the argument it omitted it
8799  * defaults to the context node.
8800  * Libxml keep the original prefix so the "real qualified name" used is
8801  * returned.
8802  */
8803 static void
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8804 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8805 {
8806     xmlXPathObjectPtr cur;
8807 
8808     if (nargs == 0) {
8809 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8810 	    ctxt->context->node));
8811         nargs = 1;
8812     }
8813 
8814     CHECK_ARITY(1);
8815     if ((ctxt->value == NULL) ||
8816         ((ctxt->value->type != XPATH_NODESET) &&
8817          (ctxt->value->type != XPATH_XSLT_TREE)))
8818         XP_ERROR(XPATH_INVALID_TYPE);
8819     cur = valuePop(ctxt);
8820 
8821     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8822         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8823     } else {
8824         int i = 0;              /* Should be first in document order !!!!! */
8825 
8826         switch (cur->nodesetval->nodeTab[i]->type) {
8827             case XML_ELEMENT_NODE:
8828             case XML_ATTRIBUTE_NODE:
8829 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8830 		    valuePush(ctxt,
8831 			xmlXPathCacheNewCString(ctxt->context, ""));
8832 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8833                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8834 		    valuePush(ctxt,
8835 		        xmlXPathCacheNewString(ctxt->context,
8836 			    cur->nodesetval->nodeTab[i]->name));
8837 		} else {
8838 		    xmlChar *fullname;
8839 
8840 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8841 				     cur->nodesetval->nodeTab[i]->ns->prefix,
8842 				     NULL, 0);
8843 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
8844 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8845 		    if (fullname == NULL) {
8846 			XP_ERROR(XPATH_MEMORY_ERROR);
8847 		    }
8848 		    valuePush(ctxt, xmlXPathCacheWrapString(
8849 			ctxt->context, fullname));
8850                 }
8851                 break;
8852             default:
8853 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8854 		    cur->nodesetval->nodeTab[i]));
8855                 xmlXPathLocalNameFunction(ctxt, 1);
8856         }
8857     }
8858     xmlXPathReleaseObject(ctxt->context, cur);
8859 }
8860 
8861 
8862 /**
8863  * xmlXPathStringFunction:
8864  * @ctxt:  the XPath Parser context
8865  * @nargs:  the number of arguments
8866  *
8867  * Implement the string() XPath function
8868  *    string string(object?)
8869  * The string function converts an object to a string as follows:
8870  *    - A node-set is converted to a string by returning the value of
8871  *      the node in the node-set that is first in document order.
8872  *      If the node-set is empty, an empty string is returned.
8873  *    - A number is converted to a string as follows
8874  *      + NaN is converted to the string NaN
8875  *      + positive zero is converted to the string 0
8876  *      + negative zero is converted to the string 0
8877  *      + positive infinity is converted to the string Infinity
8878  *      + negative infinity is converted to the string -Infinity
8879  *      + if the number is an integer, the number is represented in
8880  *        decimal form as a Number with no decimal point and no leading
8881  *        zeros, preceded by a minus sign (-) if the number is negative
8882  *      + otherwise, the number is represented in decimal form as a
8883  *        Number including a decimal point with at least one digit
8884  *        before the decimal point and at least one digit after the
8885  *        decimal point, preceded by a minus sign (-) if the number
8886  *        is negative; there must be no leading zeros before the decimal
8887  *        point apart possibly from the one required digit immediately
8888  *        before the decimal point; beyond the one required digit
8889  *        after the decimal point there must be as many, but only as
8890  *        many, more digits as are needed to uniquely distinguish the
8891  *        number from all other IEEE 754 numeric values.
8892  *    - The boolean false value is converted to the string false.
8893  *      The boolean true value is converted to the string true.
8894  *
8895  * If the argument is omitted, it defaults to a node-set with the
8896  * context node as its only member.
8897  */
8898 void
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt,int nargs)8899 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8900     xmlXPathObjectPtr cur;
8901 
8902     if (ctxt == NULL) return;
8903     if (nargs == 0) {
8904     valuePush(ctxt,
8905 	xmlXPathCacheWrapString(ctxt->context,
8906 	    xmlXPathCastNodeToString(ctxt->context->node)));
8907 	return;
8908     }
8909 
8910     CHECK_ARITY(1);
8911     cur = valuePop(ctxt);
8912     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8913     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8914 }
8915 
8916 /**
8917  * xmlXPathStringLengthFunction:
8918  * @ctxt:  the XPath Parser context
8919  * @nargs:  the number of arguments
8920  *
8921  * Implement the string-length() XPath function
8922  *    number string-length(string?)
8923  * The string-length returns the number of characters in the string
8924  * (see [3.6 Strings]). If the argument is omitted, it defaults to
8925  * the context node converted to a string, in other words the value
8926  * of the context node.
8927  */
8928 void
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt,int nargs)8929 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8930     xmlXPathObjectPtr cur;
8931 
8932     if (nargs == 0) {
8933         if ((ctxt == NULL) || (ctxt->context == NULL))
8934 	    return;
8935 	if (ctxt->context->node == NULL) {
8936 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8937 	} else {
8938 	    xmlChar *content;
8939 
8940 	    content = xmlXPathCastNodeToString(ctxt->context->node);
8941 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8942 		xmlUTF8Strlen(content)));
8943 	    xmlFree(content);
8944 	}
8945 	return;
8946     }
8947     CHECK_ARITY(1);
8948     CAST_TO_STRING;
8949     CHECK_TYPE(XPATH_STRING);
8950     cur = valuePop(ctxt);
8951     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8952 	xmlUTF8Strlen(cur->stringval)));
8953     xmlXPathReleaseObject(ctxt->context, cur);
8954 }
8955 
8956 /**
8957  * xmlXPathConcatFunction:
8958  * @ctxt:  the XPath Parser context
8959  * @nargs:  the number of arguments
8960  *
8961  * Implement the concat() XPath function
8962  *    string concat(string, string, string*)
8963  * The concat function returns the concatenation of its arguments.
8964  */
8965 void
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt,int nargs)8966 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8967     xmlXPathObjectPtr cur, newobj;
8968     xmlChar *tmp;
8969 
8970     if (ctxt == NULL) return;
8971     if (nargs < 2) {
8972 	CHECK_ARITY(2);
8973     }
8974 
8975     CAST_TO_STRING;
8976     cur = valuePop(ctxt);
8977     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8978 	xmlXPathReleaseObject(ctxt->context, cur);
8979 	return;
8980     }
8981     nargs--;
8982 
8983     while (nargs > 0) {
8984 	CAST_TO_STRING;
8985 	newobj = valuePop(ctxt);
8986 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8987 	    xmlXPathReleaseObject(ctxt->context, newobj);
8988 	    xmlXPathReleaseObject(ctxt->context, cur);
8989 	    XP_ERROR(XPATH_INVALID_TYPE);
8990 	}
8991 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
8992 	newobj->stringval = cur->stringval;
8993 	cur->stringval = tmp;
8994 	xmlXPathReleaseObject(ctxt->context, newobj);
8995 	nargs--;
8996     }
8997     valuePush(ctxt, cur);
8998 }
8999 
9000 /**
9001  * xmlXPathContainsFunction:
9002  * @ctxt:  the XPath Parser context
9003  * @nargs:  the number of arguments
9004  *
9005  * Implement the contains() XPath function
9006  *    boolean contains(string, string)
9007  * The contains function returns true if the first argument string
9008  * contains the second argument string, and otherwise returns false.
9009  */
9010 void
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt,int nargs)9011 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9012     xmlXPathObjectPtr hay, needle;
9013 
9014     CHECK_ARITY(2);
9015     CAST_TO_STRING;
9016     CHECK_TYPE(XPATH_STRING);
9017     needle = valuePop(ctxt);
9018     CAST_TO_STRING;
9019     hay = valuePop(ctxt);
9020 
9021     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9022 	xmlXPathReleaseObject(ctxt->context, hay);
9023 	xmlXPathReleaseObject(ctxt->context, needle);
9024 	XP_ERROR(XPATH_INVALID_TYPE);
9025     }
9026     if (xmlStrstr(hay->stringval, needle->stringval))
9027 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9028     else
9029 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9030     xmlXPathReleaseObject(ctxt->context, hay);
9031     xmlXPathReleaseObject(ctxt->context, needle);
9032 }
9033 
9034 /**
9035  * xmlXPathStartsWithFunction:
9036  * @ctxt:  the XPath Parser context
9037  * @nargs:  the number of arguments
9038  *
9039  * Implement the starts-with() XPath function
9040  *    boolean starts-with(string, string)
9041  * The starts-with function returns true if the first argument string
9042  * starts with the second argument string, and otherwise returns false.
9043  */
9044 void
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt,int nargs)9045 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9046     xmlXPathObjectPtr hay, needle;
9047     int n;
9048 
9049     CHECK_ARITY(2);
9050     CAST_TO_STRING;
9051     CHECK_TYPE(XPATH_STRING);
9052     needle = valuePop(ctxt);
9053     CAST_TO_STRING;
9054     hay = valuePop(ctxt);
9055 
9056     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9057 	xmlXPathReleaseObject(ctxt->context, hay);
9058 	xmlXPathReleaseObject(ctxt->context, needle);
9059 	XP_ERROR(XPATH_INVALID_TYPE);
9060     }
9061     n = xmlStrlen(needle->stringval);
9062     if (xmlStrncmp(hay->stringval, needle->stringval, n))
9063         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9064     else
9065         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9066     xmlXPathReleaseObject(ctxt->context, hay);
9067     xmlXPathReleaseObject(ctxt->context, needle);
9068 }
9069 
9070 /**
9071  * xmlXPathSubstringFunction:
9072  * @ctxt:  the XPath Parser context
9073  * @nargs:  the number of arguments
9074  *
9075  * Implement the substring() XPath function
9076  *    string substring(string, number, number?)
9077  * The substring function returns the substring of the first argument
9078  * starting at the position specified in the second argument with
9079  * length specified in the third argument. For example,
9080  * substring("12345",2,3) returns "234". If the third argument is not
9081  * specified, it returns the substring starting at the position specified
9082  * in the second argument and continuing to the end of the string. For
9083  * example, substring("12345",2) returns "2345".  More precisely, each
9084  * character in the string (see [3.6 Strings]) is considered to have a
9085  * numeric position: the position of the first character is 1, the position
9086  * of the second character is 2 and so on. The returned substring contains
9087  * those characters for which the position of the character is greater than
9088  * or equal to the second argument and, if the third argument is specified,
9089  * less than the sum of the second and third arguments; the comparisons
9090  * and addition used for the above follow the standard IEEE 754 rules. Thus:
9091  *  - substring("12345", 1.5, 2.6) returns "234"
9092  *  - substring("12345", 0, 3) returns "12"
9093  *  - substring("12345", 0 div 0, 3) returns ""
9094  *  - substring("12345", 1, 0 div 0) returns ""
9095  *  - substring("12345", -42, 1 div 0) returns "12345"
9096  *  - substring("12345", -1 div 0, 1 div 0) returns ""
9097  */
9098 void
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt,int nargs)9099 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9100     xmlXPathObjectPtr str, start, len;
9101     double le=0, in;
9102     int i = 1, j = INT_MAX;
9103 
9104     if (nargs < 2) {
9105 	CHECK_ARITY(2);
9106     }
9107     if (nargs > 3) {
9108 	CHECK_ARITY(3);
9109     }
9110     /*
9111      * take care of possible last (position) argument
9112     */
9113     if (nargs == 3) {
9114 	CAST_TO_NUMBER;
9115 	CHECK_TYPE(XPATH_NUMBER);
9116 	len = valuePop(ctxt);
9117 	le = len->floatval;
9118 	xmlXPathReleaseObject(ctxt->context, len);
9119     }
9120 
9121     CAST_TO_NUMBER;
9122     CHECK_TYPE(XPATH_NUMBER);
9123     start = valuePop(ctxt);
9124     in = start->floatval;
9125     xmlXPathReleaseObject(ctxt->context, start);
9126     CAST_TO_STRING;
9127     CHECK_TYPE(XPATH_STRING);
9128     str = valuePop(ctxt);
9129 
9130     if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9131         i = INT_MAX;
9132     } else if (in >= 1.0) {
9133         i = (int)in;
9134         if (in - floor(in) >= 0.5)
9135             i += 1;
9136     }
9137 
9138     if (nargs == 3) {
9139         double rin, rle, end;
9140 
9141         rin = floor(in);
9142         if (in - rin >= 0.5)
9143             rin += 1.0;
9144 
9145         rle = floor(le);
9146         if (le - rle >= 0.5)
9147             rle += 1.0;
9148 
9149         end = rin + rle;
9150         if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9151             j = 1;
9152         } else if (end < INT_MAX) {
9153             j = (int)end;
9154         }
9155     }
9156 
9157     if (i < j) {
9158         xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
9159 	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9160 	xmlFree(ret);
9161     } else {
9162 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9163     }
9164 
9165     xmlXPathReleaseObject(ctxt->context, str);
9166 }
9167 
9168 /**
9169  * xmlXPathSubstringBeforeFunction:
9170  * @ctxt:  the XPath Parser context
9171  * @nargs:  the number of arguments
9172  *
9173  * Implement the substring-before() XPath function
9174  *    string substring-before(string, string)
9175  * The substring-before function returns the substring of the first
9176  * argument string that precedes the first occurrence of the second
9177  * argument string in the first argument string, or the empty string
9178  * if the first argument string does not contain the second argument
9179  * string. For example, substring-before("1999/04/01","/") returns 1999.
9180  */
9181 void
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt,int nargs)9182 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9183   xmlXPathObjectPtr str;
9184   xmlXPathObjectPtr find;
9185   xmlBufPtr target;
9186   const xmlChar *point;
9187   int offset;
9188 
9189   CHECK_ARITY(2);
9190   CAST_TO_STRING;
9191   find = valuePop(ctxt);
9192   CAST_TO_STRING;
9193   str = valuePop(ctxt);
9194 
9195   target = xmlBufCreate();
9196   if (target) {
9197     point = xmlStrstr(str->stringval, find->stringval);
9198     if (point) {
9199       offset = (int)(point - str->stringval);
9200       xmlBufAdd(target, str->stringval, offset);
9201     }
9202     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9203 	xmlBufContent(target)));
9204     xmlBufFree(target);
9205   }
9206   xmlXPathReleaseObject(ctxt->context, str);
9207   xmlXPathReleaseObject(ctxt->context, find);
9208 }
9209 
9210 /**
9211  * xmlXPathSubstringAfterFunction:
9212  * @ctxt:  the XPath Parser context
9213  * @nargs:  the number of arguments
9214  *
9215  * Implement the substring-after() XPath function
9216  *    string substring-after(string, string)
9217  * The substring-after function returns the substring of the first
9218  * argument string that follows the first occurrence of the second
9219  * argument string in the first argument string, or the empty stringi
9220  * if the first argument string does not contain the second argument
9221  * string. For example, substring-after("1999/04/01","/") returns 04/01,
9222  * and substring-after("1999/04/01","19") returns 99/04/01.
9223  */
9224 void
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt,int nargs)9225 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9226   xmlXPathObjectPtr str;
9227   xmlXPathObjectPtr find;
9228   xmlBufPtr target;
9229   const xmlChar *point;
9230   int offset;
9231 
9232   CHECK_ARITY(2);
9233   CAST_TO_STRING;
9234   find = valuePop(ctxt);
9235   CAST_TO_STRING;
9236   str = valuePop(ctxt);
9237 
9238   target = xmlBufCreate();
9239   if (target) {
9240     point = xmlStrstr(str->stringval, find->stringval);
9241     if (point) {
9242       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9243       xmlBufAdd(target, &str->stringval[offset],
9244 		   xmlStrlen(str->stringval) - offset);
9245     }
9246     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9247 	xmlBufContent(target)));
9248     xmlBufFree(target);
9249   }
9250   xmlXPathReleaseObject(ctxt->context, str);
9251   xmlXPathReleaseObject(ctxt->context, find);
9252 }
9253 
9254 /**
9255  * xmlXPathNormalizeFunction:
9256  * @ctxt:  the XPath Parser context
9257  * @nargs:  the number of arguments
9258  *
9259  * Implement the normalize-space() XPath function
9260  *    string normalize-space(string?)
9261  * The normalize-space function returns the argument string with white
9262  * space normalized by stripping leading and trailing whitespace
9263  * and replacing sequences of whitespace characters by a single
9264  * space. Whitespace characters are the same allowed by the S production
9265  * in XML. If the argument is omitted, it defaults to the context
9266  * node converted to a string, in other words the value of the context node.
9267  */
9268 void
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt,int nargs)9269 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9270     xmlChar *source, *target;
9271     int blank;
9272 
9273     if (ctxt == NULL) return;
9274     if (nargs == 0) {
9275         /* Use current context node */
9276         valuePush(ctxt,
9277             xmlXPathCacheWrapString(ctxt->context,
9278                 xmlXPathCastNodeToString(ctxt->context->node)));
9279         nargs = 1;
9280     }
9281 
9282     CHECK_ARITY(1);
9283     CAST_TO_STRING;
9284     CHECK_TYPE(XPATH_STRING);
9285     source = ctxt->value->stringval;
9286     if (source == NULL)
9287         return;
9288     target = source;
9289 
9290     /* Skip leading whitespaces */
9291     while (IS_BLANK_CH(*source))
9292         source++;
9293 
9294     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9295     blank = 0;
9296     while (*source) {
9297         if (IS_BLANK_CH(*source)) {
9298 	    blank = 1;
9299         } else {
9300             if (blank) {
9301                 *target++ = 0x20;
9302                 blank = 0;
9303             }
9304             *target++ = *source;
9305         }
9306         source++;
9307     }
9308     *target = 0;
9309 }
9310 
9311 /**
9312  * xmlXPathTranslateFunction:
9313  * @ctxt:  the XPath Parser context
9314  * @nargs:  the number of arguments
9315  *
9316  * Implement the translate() XPath function
9317  *    string translate(string, string, string)
9318  * The translate function returns the first argument string with
9319  * occurrences of characters in the second argument string replaced
9320  * by the character at the corresponding position in the third argument
9321  * string. For example, translate("bar","abc","ABC") returns the string
9322  * BAr. If there is a character in the second argument string with no
9323  * character at a corresponding position in the third argument string
9324  * (because the second argument string is longer than the third argument
9325  * string), then occurrences of that character in the first argument
9326  * string are removed. For example, translate("--aaa--","abc-","ABC")
9327  * returns "AAA". If a character occurs more than once in second
9328  * argument string, then the first occurrence determines the replacement
9329  * character. If the third argument string is longer than the second
9330  * argument string, then excess characters are ignored.
9331  */
9332 void
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt,int nargs)9333 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9334     xmlXPathObjectPtr str;
9335     xmlXPathObjectPtr from;
9336     xmlXPathObjectPtr to;
9337     xmlBufPtr target;
9338     int offset, max;
9339     xmlChar ch;
9340     const xmlChar *point;
9341     xmlChar *cptr;
9342 
9343     CHECK_ARITY(3);
9344 
9345     CAST_TO_STRING;
9346     to = valuePop(ctxt);
9347     CAST_TO_STRING;
9348     from = valuePop(ctxt);
9349     CAST_TO_STRING;
9350     str = valuePop(ctxt);
9351 
9352     target = xmlBufCreate();
9353     if (target) {
9354 	max = xmlUTF8Strlen(to->stringval);
9355 	for (cptr = str->stringval; (ch=*cptr); ) {
9356 	    offset = xmlUTF8Strloc(from->stringval, cptr);
9357 	    if (offset >= 0) {
9358 		if (offset < max) {
9359 		    point = xmlUTF8Strpos(to->stringval, offset);
9360 		    if (point)
9361 			xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9362 		}
9363 	    } else
9364 		xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9365 
9366 	    /* Step to next character in input */
9367 	    cptr++;
9368 	    if ( ch & 0x80 ) {
9369 		/* if not simple ascii, verify proper format */
9370 		if ( (ch & 0xc0) != 0xc0 ) {
9371 		    xmlGenericError(xmlGenericErrorContext,
9372 			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
9373                     /* not asserting an XPath error is probably better */
9374 		    break;
9375 		}
9376 		/* then skip over remaining bytes for this char */
9377 		while ( (ch <<= 1) & 0x80 )
9378 		    if ( (*cptr++ & 0xc0) != 0x80 ) {
9379 			xmlGenericError(xmlGenericErrorContext,
9380 			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9381                         /* not asserting an XPath error is probably better */
9382 			break;
9383 		    }
9384 		if (ch & 0x80) /* must have had error encountered */
9385 		    break;
9386 	    }
9387 	}
9388     }
9389     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9390 	xmlBufContent(target)));
9391     xmlBufFree(target);
9392     xmlXPathReleaseObject(ctxt->context, str);
9393     xmlXPathReleaseObject(ctxt->context, from);
9394     xmlXPathReleaseObject(ctxt->context, to);
9395 }
9396 
9397 /**
9398  * xmlXPathBooleanFunction:
9399  * @ctxt:  the XPath Parser context
9400  * @nargs:  the number of arguments
9401  *
9402  * Implement the boolean() XPath function
9403  *    boolean boolean(object)
9404  * The boolean function converts its argument to a boolean as follows:
9405  *    - a number is true if and only if it is neither positive or
9406  *      negative zero nor NaN
9407  *    - a node-set is true if and only if it is non-empty
9408  *    - a string is true if and only if its length is non-zero
9409  */
9410 void
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt,int nargs)9411 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9412     xmlXPathObjectPtr cur;
9413 
9414     CHECK_ARITY(1);
9415     cur = valuePop(ctxt);
9416     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9417     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9418     valuePush(ctxt, cur);
9419 }
9420 
9421 /**
9422  * xmlXPathNotFunction:
9423  * @ctxt:  the XPath Parser context
9424  * @nargs:  the number of arguments
9425  *
9426  * Implement the not() XPath function
9427  *    boolean not(boolean)
9428  * The not function returns true if its argument is false,
9429  * and false otherwise.
9430  */
9431 void
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt,int nargs)9432 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9433     CHECK_ARITY(1);
9434     CAST_TO_BOOLEAN;
9435     CHECK_TYPE(XPATH_BOOLEAN);
9436     ctxt->value->boolval = ! ctxt->value->boolval;
9437 }
9438 
9439 /**
9440  * xmlXPathTrueFunction:
9441  * @ctxt:  the XPath Parser context
9442  * @nargs:  the number of arguments
9443  *
9444  * Implement the true() XPath function
9445  *    boolean true()
9446  */
9447 void
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt,int nargs)9448 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9449     CHECK_ARITY(0);
9450     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9451 }
9452 
9453 /**
9454  * xmlXPathFalseFunction:
9455  * @ctxt:  the XPath Parser context
9456  * @nargs:  the number of arguments
9457  *
9458  * Implement the false() XPath function
9459  *    boolean false()
9460  */
9461 void
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt,int nargs)9462 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9463     CHECK_ARITY(0);
9464     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9465 }
9466 
9467 /**
9468  * xmlXPathLangFunction:
9469  * @ctxt:  the XPath Parser context
9470  * @nargs:  the number of arguments
9471  *
9472  * Implement the lang() XPath function
9473  *    boolean lang(string)
9474  * The lang function returns true or false depending on whether the
9475  * language of the context node as specified by xml:lang attributes
9476  * is the same as or is a sublanguage of the language specified by
9477  * the argument string. The language of the context node is determined
9478  * by the value of the xml:lang attribute on the context node, or, if
9479  * the context node has no xml:lang attribute, by the value of the
9480  * xml:lang attribute on the nearest ancestor of the context node that
9481  * has an xml:lang attribute. If there is no such attribute, then lang
9482  * returns false. If there is such an attribute, then lang returns
9483  * true if the attribute value is equal to the argument ignoring case,
9484  * or if there is some suffix starting with - such that the attribute
9485  * value is equal to the argument ignoring that suffix of the attribute
9486  * value and ignoring case.
9487  */
9488 void
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt,int nargs)9489 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9490     xmlXPathObjectPtr val = NULL;
9491     const xmlChar *theLang = NULL;
9492     const xmlChar *lang;
9493     int ret = 0;
9494     int i;
9495 
9496     CHECK_ARITY(1);
9497     CAST_TO_STRING;
9498     CHECK_TYPE(XPATH_STRING);
9499     val = valuePop(ctxt);
9500     lang = val->stringval;
9501     theLang = xmlNodeGetLang(ctxt->context->node);
9502     if ((theLang != NULL) && (lang != NULL)) {
9503         for (i = 0;lang[i] != 0;i++)
9504 	    if (toupper(lang[i]) != toupper(theLang[i]))
9505 	        goto not_equal;
9506 	if ((theLang[i] == 0) || (theLang[i] == '-'))
9507 	    ret = 1;
9508     }
9509 not_equal:
9510     if (theLang != NULL)
9511 	xmlFree((void *)theLang);
9512 
9513     xmlXPathReleaseObject(ctxt->context, val);
9514     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9515 }
9516 
9517 /**
9518  * xmlXPathNumberFunction:
9519  * @ctxt:  the XPath Parser context
9520  * @nargs:  the number of arguments
9521  *
9522  * Implement the number() XPath function
9523  *    number number(object?)
9524  */
9525 void
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt,int nargs)9526 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9527     xmlXPathObjectPtr cur;
9528     double res;
9529 
9530     if (ctxt == NULL) return;
9531     if (nargs == 0) {
9532 	if (ctxt->context->node == NULL) {
9533 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9534 	} else {
9535 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9536 
9537 	    res = xmlXPathStringEvalNumber(content);
9538 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9539 	    xmlFree(content);
9540 	}
9541 	return;
9542     }
9543 
9544     CHECK_ARITY(1);
9545     cur = valuePop(ctxt);
9546     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9547 }
9548 
9549 /**
9550  * xmlXPathSumFunction:
9551  * @ctxt:  the XPath Parser context
9552  * @nargs:  the number of arguments
9553  *
9554  * Implement the sum() XPath function
9555  *    number sum(node-set)
9556  * The sum function returns the sum of the values of the nodes in
9557  * the argument node-set.
9558  */
9559 void
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt,int nargs)9560 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9561     xmlXPathObjectPtr cur;
9562     int i;
9563     double res = 0.0;
9564 
9565     CHECK_ARITY(1);
9566     if ((ctxt->value == NULL) ||
9567 	((ctxt->value->type != XPATH_NODESET) &&
9568 	 (ctxt->value->type != XPATH_XSLT_TREE)))
9569 	XP_ERROR(XPATH_INVALID_TYPE);
9570     cur = valuePop(ctxt);
9571 
9572     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9573 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9574 	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9575 	}
9576     }
9577     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9578     xmlXPathReleaseObject(ctxt->context, cur);
9579 }
9580 
9581 /**
9582  * xmlXPathFloorFunction:
9583  * @ctxt:  the XPath Parser context
9584  * @nargs:  the number of arguments
9585  *
9586  * Implement the floor() XPath function
9587  *    number floor(number)
9588  * The floor function returns the largest (closest to positive infinity)
9589  * number that is not greater than the argument and that is an integer.
9590  */
9591 void
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt,int nargs)9592 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9593     CHECK_ARITY(1);
9594     CAST_TO_NUMBER;
9595     CHECK_TYPE(XPATH_NUMBER);
9596 
9597     ctxt->value->floatval = floor(ctxt->value->floatval);
9598 }
9599 
9600 /**
9601  * xmlXPathCeilingFunction:
9602  * @ctxt:  the XPath Parser context
9603  * @nargs:  the number of arguments
9604  *
9605  * Implement the ceiling() XPath function
9606  *    number ceiling(number)
9607  * The ceiling function returns the smallest (closest to negative infinity)
9608  * number that is not less than the argument and that is an integer.
9609  */
9610 void
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt,int nargs)9611 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9612     CHECK_ARITY(1);
9613     CAST_TO_NUMBER;
9614     CHECK_TYPE(XPATH_NUMBER);
9615 
9616 #ifdef _AIX
9617     /* Work around buggy ceil() function on AIX */
9618     ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
9619 #else
9620     ctxt->value->floatval = ceil(ctxt->value->floatval);
9621 #endif
9622 }
9623 
9624 /**
9625  * xmlXPathRoundFunction:
9626  * @ctxt:  the XPath Parser context
9627  * @nargs:  the number of arguments
9628  *
9629  * Implement the round() XPath function
9630  *    number round(number)
9631  * The round function returns the number that is closest to the
9632  * argument and that is an integer. If there are two such numbers,
9633  * then the one that is closest to positive infinity is returned.
9634  */
9635 void
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt,int nargs)9636 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9637     double f;
9638 
9639     CHECK_ARITY(1);
9640     CAST_TO_NUMBER;
9641     CHECK_TYPE(XPATH_NUMBER);
9642 
9643     f = ctxt->value->floatval;
9644 
9645     if ((f >= -0.5) && (f < 0.5)) {
9646         /* Handles negative zero. */
9647         ctxt->value->floatval *= 0.0;
9648     }
9649     else {
9650         double rounded = floor(f);
9651         if (f - rounded >= 0.5)
9652             rounded += 1.0;
9653         ctxt->value->floatval = rounded;
9654     }
9655 }
9656 
9657 /************************************************************************
9658  *									*
9659  *			The Parser					*
9660  *									*
9661  ************************************************************************/
9662 
9663 /*
9664  * a few forward declarations since we use a recursive call based
9665  * implementation.
9666  */
9667 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9668 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9669 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9670 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9671 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9672 	                                  int qualified);
9673 
9674 /**
9675  * xmlXPathCurrentChar:
9676  * @ctxt:  the XPath parser context
9677  * @cur:  pointer to the beginning of the char
9678  * @len:  pointer to the length of the char read
9679  *
9680  * The current char value, if using UTF-8 this may actually span multiple
9681  * bytes in the input buffer.
9682  *
9683  * Returns the current char value and its length
9684  */
9685 
9686 static int
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt,int * len)9687 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9688     unsigned char c;
9689     unsigned int val;
9690     const xmlChar *cur;
9691 
9692     if (ctxt == NULL)
9693 	return(0);
9694     cur = ctxt->cur;
9695 
9696     /*
9697      * We are supposed to handle UTF8, check it's valid
9698      * From rfc2044: encoding of the Unicode values on UTF-8:
9699      *
9700      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9701      * 0000 0000-0000 007F   0xxxxxxx
9702      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9703      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9704      *
9705      * Check for the 0x110000 limit too
9706      */
9707     c = *cur;
9708     if (c & 0x80) {
9709 	if ((cur[1] & 0xc0) != 0x80)
9710 	    goto encoding_error;
9711 	if ((c & 0xe0) == 0xe0) {
9712 
9713 	    if ((cur[2] & 0xc0) != 0x80)
9714 		goto encoding_error;
9715 	    if ((c & 0xf0) == 0xf0) {
9716 		if (((c & 0xf8) != 0xf0) ||
9717 		    ((cur[3] & 0xc0) != 0x80))
9718 		    goto encoding_error;
9719 		/* 4-byte code */
9720 		*len = 4;
9721 		val = (cur[0] & 0x7) << 18;
9722 		val |= (cur[1] & 0x3f) << 12;
9723 		val |= (cur[2] & 0x3f) << 6;
9724 		val |= cur[3] & 0x3f;
9725 	    } else {
9726 	      /* 3-byte code */
9727 		*len = 3;
9728 		val = (cur[0] & 0xf) << 12;
9729 		val |= (cur[1] & 0x3f) << 6;
9730 		val |= cur[2] & 0x3f;
9731 	    }
9732 	} else {
9733 	  /* 2-byte code */
9734 	    *len = 2;
9735 	    val = (cur[0] & 0x1f) << 6;
9736 	    val |= cur[1] & 0x3f;
9737 	}
9738 	if (!IS_CHAR(val)) {
9739 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9740 	}
9741 	return(val);
9742     } else {
9743 	/* 1-byte code */
9744 	*len = 1;
9745 	return((int) *cur);
9746     }
9747 encoding_error:
9748     /*
9749      * If we detect an UTF8 error that probably means that the
9750      * input encoding didn't get properly advertised in the
9751      * declaration header. Report the error and switch the encoding
9752      * to ISO-Latin-1 (if you don't like this policy, just declare the
9753      * encoding !)
9754      */
9755     *len = 0;
9756     XP_ERROR0(XPATH_ENCODING_ERROR);
9757 }
9758 
9759 /**
9760  * xmlXPathParseNCName:
9761  * @ctxt:  the XPath Parser context
9762  *
9763  * parse an XML namespace non qualified name.
9764  *
9765  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9766  *
9767  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9768  *                       CombiningChar | Extender
9769  *
9770  * Returns the namespace name or NULL
9771  */
9772 
9773 xmlChar *
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt)9774 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9775     const xmlChar *in;
9776     xmlChar *ret;
9777     int count = 0;
9778 
9779     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9780     /*
9781      * Accelerator for simple ASCII names
9782      */
9783     in = ctxt->cur;
9784     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9785 	((*in >= 0x41) && (*in <= 0x5A)) ||
9786 	(*in == '_')) {
9787 	in++;
9788 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9789 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9790 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9791 	       (*in == '_') || (*in == '.') ||
9792 	       (*in == '-'))
9793 	    in++;
9794 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9795             (*in == '[') || (*in == ']') || (*in == ':') ||
9796             (*in == '@') || (*in == '*')) {
9797 	    count = in - ctxt->cur;
9798 	    if (count == 0)
9799 		return(NULL);
9800 	    ret = xmlStrndup(ctxt->cur, count);
9801 	    ctxt->cur = in;
9802 	    return(ret);
9803 	}
9804     }
9805     return(xmlXPathParseNameComplex(ctxt, 0));
9806 }
9807 
9808 
9809 /**
9810  * xmlXPathParseQName:
9811  * @ctxt:  the XPath Parser context
9812  * @prefix:  a xmlChar **
9813  *
9814  * parse an XML qualified name
9815  *
9816  * [NS 5] QName ::= (Prefix ':')? LocalPart
9817  *
9818  * [NS 6] Prefix ::= NCName
9819  *
9820  * [NS 7] LocalPart ::= NCName
9821  *
9822  * Returns the function returns the local part, and prefix is updated
9823  *   to get the Prefix if any.
9824  */
9825 
9826 static xmlChar *
xmlXPathParseQName(xmlXPathParserContextPtr ctxt,xmlChar ** prefix)9827 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9828     xmlChar *ret = NULL;
9829 
9830     *prefix = NULL;
9831     ret = xmlXPathParseNCName(ctxt);
9832     if (ret && CUR == ':') {
9833         *prefix = ret;
9834 	NEXT;
9835 	ret = xmlXPathParseNCName(ctxt);
9836     }
9837     return(ret);
9838 }
9839 
9840 /**
9841  * xmlXPathParseName:
9842  * @ctxt:  the XPath Parser context
9843  *
9844  * parse an XML name
9845  *
9846  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9847  *                  CombiningChar | Extender
9848  *
9849  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9850  *
9851  * Returns the namespace name or NULL
9852  */
9853 
9854 xmlChar *
xmlXPathParseName(xmlXPathParserContextPtr ctxt)9855 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9856     const xmlChar *in;
9857     xmlChar *ret;
9858     size_t count = 0;
9859 
9860     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9861     /*
9862      * Accelerator for simple ASCII names
9863      */
9864     in = ctxt->cur;
9865     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9866 	((*in >= 0x41) && (*in <= 0x5A)) ||
9867 	(*in == '_') || (*in == ':')) {
9868 	in++;
9869 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9870 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9871 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9872 	       (*in == '_') || (*in == '-') ||
9873 	       (*in == ':') || (*in == '.'))
9874 	    in++;
9875 	if ((*in > 0) && (*in < 0x80)) {
9876 	    count = in - ctxt->cur;
9877             if (count > XML_MAX_NAME_LENGTH) {
9878                 ctxt->cur = in;
9879                 XP_ERRORNULL(XPATH_EXPR_ERROR);
9880             }
9881 	    ret = xmlStrndup(ctxt->cur, count);
9882 	    ctxt->cur = in;
9883 	    return(ret);
9884 	}
9885     }
9886     return(xmlXPathParseNameComplex(ctxt, 1));
9887 }
9888 
9889 static xmlChar *
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,int qualified)9890 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9891     xmlChar buf[XML_MAX_NAMELEN + 5];
9892     int len = 0, l;
9893     int c;
9894 
9895     /*
9896      * Handler for more complex cases
9897      */
9898     c = CUR_CHAR(l);
9899     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9900         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9901         (c == '*') || /* accelerators */
9902 	(!IS_LETTER(c) && (c != '_') &&
9903          ((!qualified) || (c != ':')))) {
9904 	return(NULL);
9905     }
9906 
9907     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9908 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9909             (c == '.') || (c == '-') ||
9910 	    (c == '_') || ((qualified) && (c == ':')) ||
9911 	    (IS_COMBINING(c)) ||
9912 	    (IS_EXTENDER(c)))) {
9913 	COPY_BUF(l,buf,len,c);
9914 	NEXTL(l);
9915 	c = CUR_CHAR(l);
9916 	if (len >= XML_MAX_NAMELEN) {
9917 	    /*
9918 	     * Okay someone managed to make a huge name, so he's ready to pay
9919 	     * for the processing speed.
9920 	     */
9921 	    xmlChar *buffer;
9922 	    int max = len * 2;
9923 
9924             if (len > XML_MAX_NAME_LENGTH) {
9925                 XP_ERRORNULL(XPATH_EXPR_ERROR);
9926             }
9927 	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9928 	    if (buffer == NULL) {
9929 		XP_ERRORNULL(XPATH_MEMORY_ERROR);
9930 	    }
9931 	    memcpy(buffer, buf, len);
9932 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9933 		   (c == '.') || (c == '-') ||
9934 		   (c == '_') || ((qualified) && (c == ':')) ||
9935 		   (IS_COMBINING(c)) ||
9936 		   (IS_EXTENDER(c))) {
9937 		if (len + 10 > max) {
9938                     xmlChar *tmp;
9939                     if (max > XML_MAX_NAME_LENGTH) {
9940                         xmlFree(buffer);
9941                         XP_ERRORNULL(XPATH_EXPR_ERROR);
9942                     }
9943 		    max *= 2;
9944 		    tmp = (xmlChar *) xmlRealloc(buffer,
9945 			                         max * sizeof(xmlChar));
9946 		    if (tmp == NULL) {
9947                         xmlFree(buffer);
9948 			XP_ERRORNULL(XPATH_MEMORY_ERROR);
9949 		    }
9950                     buffer = tmp;
9951 		}
9952 		COPY_BUF(l,buffer,len,c);
9953 		NEXTL(l);
9954 		c = CUR_CHAR(l);
9955 	    }
9956 	    buffer[len] = 0;
9957 	    return(buffer);
9958 	}
9959     }
9960     if (len == 0)
9961 	return(NULL);
9962     return(xmlStrndup(buf, len));
9963 }
9964 
9965 #define MAX_FRAC 20
9966 
9967 /**
9968  * xmlXPathStringEvalNumber:
9969  * @str:  A string to scan
9970  *
9971  *  [30a]  Float  ::= Number ('e' Digits?)?
9972  *
9973  *  [30]   Number ::=   Digits ('.' Digits?)?
9974  *                    | '.' Digits
9975  *  [31]   Digits ::=   [0-9]+
9976  *
9977  * Compile a Number in the string
9978  * In complement of the Number expression, this function also handles
9979  * negative values : '-' Number.
9980  *
9981  * Returns the double value.
9982  */
9983 double
xmlXPathStringEvalNumber(const xmlChar * str)9984 xmlXPathStringEvalNumber(const xmlChar *str) {
9985     const xmlChar *cur = str;
9986     double ret;
9987     int ok = 0;
9988     int isneg = 0;
9989     int exponent = 0;
9990     int is_exponent_negative = 0;
9991 #ifdef __GNUC__
9992     unsigned long tmp = 0;
9993     double temp;
9994 #endif
9995     if (cur == NULL) return(0);
9996     while (IS_BLANK_CH(*cur)) cur++;
9997     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9998         return(xmlXPathNAN);
9999     }
10000     if (*cur == '-') {
10001 	isneg = 1;
10002 	cur++;
10003     }
10004 
10005 #ifdef __GNUC__
10006     /*
10007      * tmp/temp is a workaround against a gcc compiler bug
10008      * http://veillard.com/gcc.bug
10009      */
10010     ret = 0;
10011     while ((*cur >= '0') && (*cur <= '9')) {
10012 	ret = ret * 10;
10013 	tmp = (*cur - '0');
10014 	ok = 1;
10015 	cur++;
10016 	temp = (double) tmp;
10017 	ret = ret + temp;
10018     }
10019 #else
10020     ret = 0;
10021     while ((*cur >= '0') && (*cur <= '9')) {
10022 	ret = ret * 10 + (*cur - '0');
10023 	ok = 1;
10024 	cur++;
10025     }
10026 #endif
10027 
10028     if (*cur == '.') {
10029 	int v, frac = 0, max;
10030 	double fraction = 0;
10031 
10032         cur++;
10033 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10034 	    return(xmlXPathNAN);
10035 	}
10036         while (*cur == '0') {
10037 	    frac = frac + 1;
10038 	    cur++;
10039         }
10040         max = frac + MAX_FRAC;
10041 	while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10042 	    v = (*cur - '0');
10043 	    fraction = fraction * 10 + v;
10044 	    frac = frac + 1;
10045 	    cur++;
10046 	}
10047 	fraction /= pow(10.0, frac);
10048 	ret = ret + fraction;
10049 	while ((*cur >= '0') && (*cur <= '9'))
10050 	    cur++;
10051     }
10052     if ((*cur == 'e') || (*cur == 'E')) {
10053       cur++;
10054       if (*cur == '-') {
10055 	is_exponent_negative = 1;
10056 	cur++;
10057       } else if (*cur == '+') {
10058         cur++;
10059       }
10060       while ((*cur >= '0') && (*cur <= '9')) {
10061         if (exponent < 1000000)
10062 	  exponent = exponent * 10 + (*cur - '0');
10063 	cur++;
10064       }
10065     }
10066     while (IS_BLANK_CH(*cur)) cur++;
10067     if (*cur != 0) return(xmlXPathNAN);
10068     if (isneg) ret = -ret;
10069     if (is_exponent_negative) exponent = -exponent;
10070     ret *= pow(10.0, (double)exponent);
10071     return(ret);
10072 }
10073 
10074 /**
10075  * xmlXPathCompNumber:
10076  * @ctxt:  the XPath Parser context
10077  *
10078  *  [30]   Number ::=   Digits ('.' Digits?)?
10079  *                    | '.' Digits
10080  *  [31]   Digits ::=   [0-9]+
10081  *
10082  * Compile a Number, then push it on the stack
10083  *
10084  */
10085 static void
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)10086 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10087 {
10088     double ret = 0.0;
10089     int ok = 0;
10090     int exponent = 0;
10091     int is_exponent_negative = 0;
10092     xmlXPathObjectPtr num;
10093 #ifdef __GNUC__
10094     unsigned long tmp = 0;
10095     double temp;
10096 #endif
10097 
10098     CHECK_ERROR;
10099     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10100         XP_ERROR(XPATH_NUMBER_ERROR);
10101     }
10102 #ifdef __GNUC__
10103     /*
10104      * tmp/temp is a workaround against a gcc compiler bug
10105      * http://veillard.com/gcc.bug
10106      */
10107     ret = 0;
10108     while ((CUR >= '0') && (CUR <= '9')) {
10109 	ret = ret * 10;
10110 	tmp = (CUR - '0');
10111         ok = 1;
10112         NEXT;
10113 	temp = (double) tmp;
10114 	ret = ret + temp;
10115     }
10116 #else
10117     ret = 0;
10118     while ((CUR >= '0') && (CUR <= '9')) {
10119 	ret = ret * 10 + (CUR - '0');
10120 	ok = 1;
10121 	NEXT;
10122     }
10123 #endif
10124     if (CUR == '.') {
10125 	int v, frac = 0, max;
10126 	double fraction = 0;
10127 
10128         NEXT;
10129         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10130             XP_ERROR(XPATH_NUMBER_ERROR);
10131         }
10132         while (CUR == '0') {
10133             frac = frac + 1;
10134             NEXT;
10135         }
10136         max = frac + MAX_FRAC;
10137         while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10138 	    v = (CUR - '0');
10139 	    fraction = fraction * 10 + v;
10140 	    frac = frac + 1;
10141             NEXT;
10142         }
10143         fraction /= pow(10.0, frac);
10144         ret = ret + fraction;
10145         while ((CUR >= '0') && (CUR <= '9'))
10146             NEXT;
10147     }
10148     if ((CUR == 'e') || (CUR == 'E')) {
10149         NEXT;
10150         if (CUR == '-') {
10151             is_exponent_negative = 1;
10152             NEXT;
10153         } else if (CUR == '+') {
10154 	    NEXT;
10155 	}
10156         while ((CUR >= '0') && (CUR <= '9')) {
10157             if (exponent < 1000000)
10158                 exponent = exponent * 10 + (CUR - '0');
10159             NEXT;
10160         }
10161         if (is_exponent_negative)
10162             exponent = -exponent;
10163         ret *= pow(10.0, (double) exponent);
10164     }
10165     num = xmlXPathCacheNewFloat(ctxt->context, ret);
10166     if (num == NULL) {
10167 	ctxt->error = XPATH_MEMORY_ERROR;
10168     } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
10169                               NULL) == -1) {
10170         xmlXPathReleaseObject(ctxt->context, num);
10171     }
10172 }
10173 
10174 /**
10175  * xmlXPathParseLiteral:
10176  * @ctxt:  the XPath Parser context
10177  *
10178  * Parse a Literal
10179  *
10180  *  [29]   Literal ::=   '"' [^"]* '"'
10181  *                    | "'" [^']* "'"
10182  *
10183  * Returns the value found or NULL in case of error
10184  */
10185 static xmlChar *
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt)10186 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10187     const xmlChar *q;
10188     xmlChar *ret = NULL;
10189 
10190     if (CUR == '"') {
10191         NEXT;
10192 	q = CUR_PTR;
10193 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10194 	    NEXT;
10195 	if (!IS_CHAR_CH(CUR)) {
10196 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10197 	} else {
10198 	    ret = xmlStrndup(q, CUR_PTR - q);
10199 	    NEXT;
10200         }
10201     } else if (CUR == '\'') {
10202         NEXT;
10203 	q = CUR_PTR;
10204 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10205 	    NEXT;
10206 	if (!IS_CHAR_CH(CUR)) {
10207 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10208 	} else {
10209 	    ret = xmlStrndup(q, CUR_PTR - q);
10210 	    NEXT;
10211         }
10212     } else {
10213 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10214     }
10215     return(ret);
10216 }
10217 
10218 /**
10219  * xmlXPathCompLiteral:
10220  * @ctxt:  the XPath Parser context
10221  *
10222  * Parse a Literal and push it on the stack.
10223  *
10224  *  [29]   Literal ::=   '"' [^"]* '"'
10225  *                    | "'" [^']* "'"
10226  *
10227  * TODO: xmlXPathCompLiteral memory allocation could be improved.
10228  */
10229 static void
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt)10230 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10231     const xmlChar *q;
10232     xmlChar *ret = NULL;
10233     xmlXPathObjectPtr lit;
10234 
10235     if (CUR == '"') {
10236         NEXT;
10237 	q = CUR_PTR;
10238 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10239 	    NEXT;
10240 	if (!IS_CHAR_CH(CUR)) {
10241 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10242 	} else {
10243 	    ret = xmlStrndup(q, CUR_PTR - q);
10244 	    NEXT;
10245         }
10246     } else if (CUR == '\'') {
10247         NEXT;
10248 	q = CUR_PTR;
10249 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10250 	    NEXT;
10251 	if (!IS_CHAR_CH(CUR)) {
10252 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10253 	} else {
10254 	    ret = xmlStrndup(q, CUR_PTR - q);
10255 	    NEXT;
10256         }
10257     } else {
10258 	XP_ERROR(XPATH_START_LITERAL_ERROR);
10259     }
10260     if (ret == NULL) return;
10261     lit = xmlXPathCacheNewString(ctxt->context, ret);
10262     if (lit == NULL) {
10263 	ctxt->error = XPATH_MEMORY_ERROR;
10264     } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10265                               NULL) == -1) {
10266         xmlXPathReleaseObject(ctxt->context, lit);
10267     }
10268     xmlFree(ret);
10269 }
10270 
10271 /**
10272  * xmlXPathCompVariableReference:
10273  * @ctxt:  the XPath Parser context
10274  *
10275  * Parse a VariableReference, evaluate it and push it on the stack.
10276  *
10277  * The variable bindings consist of a mapping from variable names
10278  * to variable values. The value of a variable is an object, which can be
10279  * of any of the types that are possible for the value of an expression,
10280  * and may also be of additional types not specified here.
10281  *
10282  * Early evaluation is possible since:
10283  * The variable bindings [...] used to evaluate a subexpression are
10284  * always the same as those used to evaluate the containing expression.
10285  *
10286  *  [36]   VariableReference ::=   '$' QName
10287  */
10288 static void
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt)10289 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10290     xmlChar *name;
10291     xmlChar *prefix;
10292 
10293     SKIP_BLANKS;
10294     if (CUR != '$') {
10295 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10296     }
10297     NEXT;
10298     name = xmlXPathParseQName(ctxt, &prefix);
10299     if (name == NULL) {
10300         xmlFree(prefix);
10301 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10302     }
10303     ctxt->comp->last = -1;
10304     if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
10305         xmlFree(prefix);
10306         xmlFree(name);
10307     }
10308     SKIP_BLANKS;
10309     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10310 	XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10311     }
10312 }
10313 
10314 /**
10315  * xmlXPathIsNodeType:
10316  * @name:  a name string
10317  *
10318  * Is the name given a NodeType one.
10319  *
10320  *  [38]   NodeType ::=   'comment'
10321  *                    | 'text'
10322  *                    | 'processing-instruction'
10323  *                    | 'node'
10324  *
10325  * Returns 1 if true 0 otherwise
10326  */
10327 int
xmlXPathIsNodeType(const xmlChar * name)10328 xmlXPathIsNodeType(const xmlChar *name) {
10329     if (name == NULL)
10330 	return(0);
10331 
10332     if (xmlStrEqual(name, BAD_CAST "node"))
10333 	return(1);
10334     if (xmlStrEqual(name, BAD_CAST "text"))
10335 	return(1);
10336     if (xmlStrEqual(name, BAD_CAST "comment"))
10337 	return(1);
10338     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10339 	return(1);
10340     return(0);
10341 }
10342 
10343 /**
10344  * xmlXPathCompFunctionCall:
10345  * @ctxt:  the XPath Parser context
10346  *
10347  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10348  *  [17]   Argument ::=   Expr
10349  *
10350  * Compile a function call, the evaluation of all arguments are
10351  * pushed on the stack
10352  */
10353 static void
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt)10354 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10355     xmlChar *name;
10356     xmlChar *prefix;
10357     int nbargs = 0;
10358     int sort = 1;
10359 
10360     name = xmlXPathParseQName(ctxt, &prefix);
10361     if (name == NULL) {
10362 	xmlFree(prefix);
10363 	XP_ERROR(XPATH_EXPR_ERROR);
10364     }
10365     SKIP_BLANKS;
10366 #ifdef DEBUG_EXPR
10367     if (prefix == NULL)
10368 	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10369 			name);
10370     else
10371 	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10372 			prefix, name);
10373 #endif
10374 
10375     if (CUR != '(') {
10376 	xmlFree(name);
10377 	xmlFree(prefix);
10378 	XP_ERROR(XPATH_EXPR_ERROR);
10379     }
10380     NEXT;
10381     SKIP_BLANKS;
10382 
10383     /*
10384     * Optimization for count(): we don't need the node-set to be sorted.
10385     */
10386     if ((prefix == NULL) && (name[0] == 'c') &&
10387 	xmlStrEqual(name, BAD_CAST "count"))
10388     {
10389 	sort = 0;
10390     }
10391     ctxt->comp->last = -1;
10392     if (CUR != ')') {
10393 	while (CUR != 0) {
10394 	    int op1 = ctxt->comp->last;
10395 	    ctxt->comp->last = -1;
10396 	    xmlXPathCompileExpr(ctxt, sort);
10397 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
10398 		xmlFree(name);
10399 		xmlFree(prefix);
10400 		return;
10401 	    }
10402 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10403 	    nbargs++;
10404 	    if (CUR == ')') break;
10405 	    if (CUR != ',') {
10406 		xmlFree(name);
10407 		xmlFree(prefix);
10408 		XP_ERROR(XPATH_EXPR_ERROR);
10409 	    }
10410 	    NEXT;
10411 	    SKIP_BLANKS;
10412 	}
10413     }
10414     if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
10415         xmlFree(prefix);
10416         xmlFree(name);
10417     }
10418     NEXT;
10419     SKIP_BLANKS;
10420 }
10421 
10422 /**
10423  * xmlXPathCompPrimaryExpr:
10424  * @ctxt:  the XPath Parser context
10425  *
10426  *  [15]   PrimaryExpr ::=   VariableReference
10427  *                | '(' Expr ')'
10428  *                | Literal
10429  *                | Number
10430  *                | FunctionCall
10431  *
10432  * Compile a primary expression.
10433  */
10434 static void
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt)10435 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10436     SKIP_BLANKS;
10437     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10438     else if (CUR == '(') {
10439 	NEXT;
10440 	SKIP_BLANKS;
10441 	xmlXPathCompileExpr(ctxt, 1);
10442 	CHECK_ERROR;
10443 	if (CUR != ')') {
10444 	    XP_ERROR(XPATH_EXPR_ERROR);
10445 	}
10446 	NEXT;
10447 	SKIP_BLANKS;
10448     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10449 	xmlXPathCompNumber(ctxt);
10450     } else if ((CUR == '\'') || (CUR == '"')) {
10451 	xmlXPathCompLiteral(ctxt);
10452     } else {
10453 	xmlXPathCompFunctionCall(ctxt);
10454     }
10455     SKIP_BLANKS;
10456 }
10457 
10458 /**
10459  * xmlXPathCompFilterExpr:
10460  * @ctxt:  the XPath Parser context
10461  *
10462  *  [20]   FilterExpr ::=   PrimaryExpr
10463  *               | FilterExpr Predicate
10464  *
10465  * Compile a filter expression.
10466  * Square brackets are used to filter expressions in the same way that
10467  * they are used in location paths. It is an error if the expression to
10468  * be filtered does not evaluate to a node-set. The context node list
10469  * used for evaluating the expression in square brackets is the node-set
10470  * to be filtered listed in document order.
10471  */
10472 
10473 static void
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt)10474 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10475     xmlXPathCompPrimaryExpr(ctxt);
10476     CHECK_ERROR;
10477     SKIP_BLANKS;
10478 
10479     while (CUR == '[') {
10480 	xmlXPathCompPredicate(ctxt, 1);
10481 	SKIP_BLANKS;
10482     }
10483 
10484 
10485 }
10486 
10487 /**
10488  * xmlXPathScanName:
10489  * @ctxt:  the XPath Parser context
10490  *
10491  * Trickery: parse an XML name but without consuming the input flow
10492  * Needed to avoid insanity in the parser state.
10493  *
10494  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10495  *                  CombiningChar | Extender
10496  *
10497  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10498  *
10499  * [6] Names ::= Name (S Name)*
10500  *
10501  * Returns the Name parsed or NULL
10502  */
10503 
10504 static xmlChar *
xmlXPathScanName(xmlXPathParserContextPtr ctxt)10505 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10506     int l;
10507     int c;
10508     const xmlChar *cur;
10509     xmlChar *ret;
10510 
10511     cur = ctxt->cur;
10512 
10513     c = CUR_CHAR(l);
10514     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10515 	(!IS_LETTER(c) && (c != '_') &&
10516          (c != ':'))) {
10517 	return(NULL);
10518     }
10519 
10520     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10521 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10522             (c == '.') || (c == '-') ||
10523 	    (c == '_') || (c == ':') ||
10524 	    (IS_COMBINING(c)) ||
10525 	    (IS_EXTENDER(c)))) {
10526 	NEXTL(l);
10527 	c = CUR_CHAR(l);
10528     }
10529     ret = xmlStrndup(cur, ctxt->cur - cur);
10530     ctxt->cur = cur;
10531     return(ret);
10532 }
10533 
10534 /**
10535  * xmlXPathCompPathExpr:
10536  * @ctxt:  the XPath Parser context
10537  *
10538  *  [19]   PathExpr ::=   LocationPath
10539  *               | FilterExpr
10540  *               | FilterExpr '/' RelativeLocationPath
10541  *               | FilterExpr '//' RelativeLocationPath
10542  *
10543  * Compile a path expression.
10544  * The / operator and // operators combine an arbitrary expression
10545  * and a relative location path. It is an error if the expression
10546  * does not evaluate to a node-set.
10547  * The / operator does composition in the same way as when / is
10548  * used in a location path. As in location paths, // is short for
10549  * /descendant-or-self::node()/.
10550  */
10551 
10552 static void
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt)10553 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10554     int lc = 1;           /* Should we branch to LocationPath ?         */
10555     xmlChar *name = NULL; /* we may have to preparse a name to find out */
10556 
10557     SKIP_BLANKS;
10558     if ((CUR == '$') || (CUR == '(') ||
10559 	(IS_ASCII_DIGIT(CUR)) ||
10560         (CUR == '\'') || (CUR == '"') ||
10561 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10562 	lc = 0;
10563     } else if (CUR == '*') {
10564 	/* relative or absolute location path */
10565 	lc = 1;
10566     } else if (CUR == '/') {
10567 	/* relative or absolute location path */
10568 	lc = 1;
10569     } else if (CUR == '@') {
10570 	/* relative abbreviated attribute location path */
10571 	lc = 1;
10572     } else if (CUR == '.') {
10573 	/* relative abbreviated attribute location path */
10574 	lc = 1;
10575     } else {
10576 	/*
10577 	 * Problem is finding if we have a name here whether it's:
10578 	 *   - a nodetype
10579 	 *   - a function call in which case it's followed by '('
10580 	 *   - an axis in which case it's followed by ':'
10581 	 *   - a element name
10582 	 * We do an a priori analysis here rather than having to
10583 	 * maintain parsed token content through the recursive function
10584 	 * calls. This looks uglier but makes the code easier to
10585 	 * read/write/debug.
10586 	 */
10587 	SKIP_BLANKS;
10588 	name = xmlXPathScanName(ctxt);
10589 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10590 #ifdef DEBUG_STEP
10591 	    xmlGenericError(xmlGenericErrorContext,
10592 		    "PathExpr: Axis\n");
10593 #endif
10594 	    lc = 1;
10595 	    xmlFree(name);
10596 	} else if (name != NULL) {
10597 	    int len =xmlStrlen(name);
10598 
10599 
10600 	    while (NXT(len) != 0) {
10601 		if (NXT(len) == '/') {
10602 		    /* element name */
10603 #ifdef DEBUG_STEP
10604 		    xmlGenericError(xmlGenericErrorContext,
10605 			    "PathExpr: AbbrRelLocation\n");
10606 #endif
10607 		    lc = 1;
10608 		    break;
10609 		} else if (IS_BLANK_CH(NXT(len))) {
10610 		    /* ignore blanks */
10611 		    ;
10612 		} else if (NXT(len) == ':') {
10613 #ifdef DEBUG_STEP
10614 		    xmlGenericError(xmlGenericErrorContext,
10615 			    "PathExpr: AbbrRelLocation\n");
10616 #endif
10617 		    lc = 1;
10618 		    break;
10619 		} else if ((NXT(len) == '(')) {
10620 		    /* Node Type or Function */
10621 		    if (xmlXPathIsNodeType(name)) {
10622 #ifdef DEBUG_STEP
10623 		        xmlGenericError(xmlGenericErrorContext,
10624 				"PathExpr: Type search\n");
10625 #endif
10626 			lc = 1;
10627 #ifdef LIBXML_XPTR_LOCS_ENABLED
10628                     } else if (ctxt->xptr &&
10629                                xmlStrEqual(name, BAD_CAST "range-to")) {
10630                         lc = 1;
10631 #endif
10632 		    } else {
10633 #ifdef DEBUG_STEP
10634 		        xmlGenericError(xmlGenericErrorContext,
10635 				"PathExpr: function call\n");
10636 #endif
10637 			lc = 0;
10638 		    }
10639                     break;
10640 		} else if ((NXT(len) == '[')) {
10641 		    /* element name */
10642 #ifdef DEBUG_STEP
10643 		    xmlGenericError(xmlGenericErrorContext,
10644 			    "PathExpr: AbbrRelLocation\n");
10645 #endif
10646 		    lc = 1;
10647 		    break;
10648 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10649 			   (NXT(len) == '=')) {
10650 		    lc = 1;
10651 		    break;
10652 		} else {
10653 		    lc = 1;
10654 		    break;
10655 		}
10656 		len++;
10657 	    }
10658 	    if (NXT(len) == 0) {
10659 #ifdef DEBUG_STEP
10660 		xmlGenericError(xmlGenericErrorContext,
10661 			"PathExpr: AbbrRelLocation\n");
10662 #endif
10663 		/* element name */
10664 		lc = 1;
10665 	    }
10666 	    xmlFree(name);
10667 	} else {
10668 	    /* make sure all cases are covered explicitly */
10669 	    XP_ERROR(XPATH_EXPR_ERROR);
10670 	}
10671     }
10672 
10673     if (lc) {
10674 	if (CUR == '/') {
10675 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10676 	} else {
10677 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10678 	}
10679 	xmlXPathCompLocationPath(ctxt);
10680     } else {
10681 	xmlXPathCompFilterExpr(ctxt);
10682 	CHECK_ERROR;
10683 	if ((CUR == '/') && (NXT(1) == '/')) {
10684 	    SKIP(2);
10685 	    SKIP_BLANKS;
10686 
10687 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10688 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10689 
10690 	    xmlXPathCompRelativeLocationPath(ctxt);
10691 	} else if (CUR == '/') {
10692 	    xmlXPathCompRelativeLocationPath(ctxt);
10693 	}
10694     }
10695     SKIP_BLANKS;
10696 }
10697 
10698 /**
10699  * xmlXPathCompUnionExpr:
10700  * @ctxt:  the XPath Parser context
10701  *
10702  *  [18]   UnionExpr ::=   PathExpr
10703  *               | UnionExpr '|' PathExpr
10704  *
10705  * Compile an union expression.
10706  */
10707 
10708 static void
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt)10709 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10710     xmlXPathCompPathExpr(ctxt);
10711     CHECK_ERROR;
10712     SKIP_BLANKS;
10713     while (CUR == '|') {
10714 	int op1 = ctxt->comp->last;
10715 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10716 
10717 	NEXT;
10718 	SKIP_BLANKS;
10719 	xmlXPathCompPathExpr(ctxt);
10720 
10721 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10722 
10723 	SKIP_BLANKS;
10724     }
10725 }
10726 
10727 /**
10728  * xmlXPathCompUnaryExpr:
10729  * @ctxt:  the XPath Parser context
10730  *
10731  *  [27]   UnaryExpr ::=   UnionExpr
10732  *                   | '-' UnaryExpr
10733  *
10734  * Compile an unary expression.
10735  */
10736 
10737 static void
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt)10738 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10739     int minus = 0;
10740     int found = 0;
10741 
10742     SKIP_BLANKS;
10743     while (CUR == '-') {
10744         minus = 1 - minus;
10745 	found = 1;
10746 	NEXT;
10747 	SKIP_BLANKS;
10748     }
10749 
10750     xmlXPathCompUnionExpr(ctxt);
10751     CHECK_ERROR;
10752     if (found) {
10753 	if (minus)
10754 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10755 	else
10756 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10757     }
10758 }
10759 
10760 /**
10761  * xmlXPathCompMultiplicativeExpr:
10762  * @ctxt:  the XPath Parser context
10763  *
10764  *  [26]   MultiplicativeExpr ::=   UnaryExpr
10765  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10766  *                   | MultiplicativeExpr 'div' UnaryExpr
10767  *                   | MultiplicativeExpr 'mod' UnaryExpr
10768  *  [34]   MultiplyOperator ::=   '*'
10769  *
10770  * Compile an Additive expression.
10771  */
10772 
10773 static void
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt)10774 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10775     xmlXPathCompUnaryExpr(ctxt);
10776     CHECK_ERROR;
10777     SKIP_BLANKS;
10778     while ((CUR == '*') ||
10779            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10780            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10781 	int op = -1;
10782 	int op1 = ctxt->comp->last;
10783 
10784         if (CUR == '*') {
10785 	    op = 0;
10786 	    NEXT;
10787 	} else if (CUR == 'd') {
10788 	    op = 1;
10789 	    SKIP(3);
10790 	} else if (CUR == 'm') {
10791 	    op = 2;
10792 	    SKIP(3);
10793 	}
10794 	SKIP_BLANKS;
10795         xmlXPathCompUnaryExpr(ctxt);
10796 	CHECK_ERROR;
10797 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10798 	SKIP_BLANKS;
10799     }
10800 }
10801 
10802 /**
10803  * xmlXPathCompAdditiveExpr:
10804  * @ctxt:  the XPath Parser context
10805  *
10806  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10807  *                   | AdditiveExpr '+' MultiplicativeExpr
10808  *                   | AdditiveExpr '-' MultiplicativeExpr
10809  *
10810  * Compile an Additive expression.
10811  */
10812 
10813 static void
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt)10814 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10815 
10816     xmlXPathCompMultiplicativeExpr(ctxt);
10817     CHECK_ERROR;
10818     SKIP_BLANKS;
10819     while ((CUR == '+') || (CUR == '-')) {
10820 	int plus;
10821 	int op1 = ctxt->comp->last;
10822 
10823         if (CUR == '+') plus = 1;
10824 	else plus = 0;
10825 	NEXT;
10826 	SKIP_BLANKS;
10827         xmlXPathCompMultiplicativeExpr(ctxt);
10828 	CHECK_ERROR;
10829 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10830 	SKIP_BLANKS;
10831     }
10832 }
10833 
10834 /**
10835  * xmlXPathCompRelationalExpr:
10836  * @ctxt:  the XPath Parser context
10837  *
10838  *  [24]   RelationalExpr ::=   AdditiveExpr
10839  *                 | RelationalExpr '<' AdditiveExpr
10840  *                 | RelationalExpr '>' AdditiveExpr
10841  *                 | RelationalExpr '<=' AdditiveExpr
10842  *                 | RelationalExpr '>=' AdditiveExpr
10843  *
10844  *  A <= B > C is allowed ? Answer from James, yes with
10845  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10846  *  which is basically what got implemented.
10847  *
10848  * Compile a Relational expression, then push the result
10849  * on the stack
10850  */
10851 
10852 static void
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt)10853 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10854     xmlXPathCompAdditiveExpr(ctxt);
10855     CHECK_ERROR;
10856     SKIP_BLANKS;
10857     while ((CUR == '<') || (CUR == '>')) {
10858 	int inf, strict;
10859 	int op1 = ctxt->comp->last;
10860 
10861         if (CUR == '<') inf = 1;
10862 	else inf = 0;
10863 	if (NXT(1) == '=') strict = 0;
10864 	else strict = 1;
10865 	NEXT;
10866 	if (!strict) NEXT;
10867 	SKIP_BLANKS;
10868         xmlXPathCompAdditiveExpr(ctxt);
10869 	CHECK_ERROR;
10870 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10871 	SKIP_BLANKS;
10872     }
10873 }
10874 
10875 /**
10876  * xmlXPathCompEqualityExpr:
10877  * @ctxt:  the XPath Parser context
10878  *
10879  *  [23]   EqualityExpr ::=   RelationalExpr
10880  *                 | EqualityExpr '=' RelationalExpr
10881  *                 | EqualityExpr '!=' RelationalExpr
10882  *
10883  *  A != B != C is allowed ? Answer from James, yes with
10884  *  (RelationalExpr = RelationalExpr) = RelationalExpr
10885  *  (RelationalExpr != RelationalExpr) != RelationalExpr
10886  *  which is basically what got implemented.
10887  *
10888  * Compile an Equality expression.
10889  *
10890  */
10891 static void
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt)10892 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10893     xmlXPathCompRelationalExpr(ctxt);
10894     CHECK_ERROR;
10895     SKIP_BLANKS;
10896     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10897 	int eq;
10898 	int op1 = ctxt->comp->last;
10899 
10900         if (CUR == '=') eq = 1;
10901 	else eq = 0;
10902 	NEXT;
10903 	if (!eq) NEXT;
10904 	SKIP_BLANKS;
10905         xmlXPathCompRelationalExpr(ctxt);
10906 	CHECK_ERROR;
10907 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10908 	SKIP_BLANKS;
10909     }
10910 }
10911 
10912 /**
10913  * xmlXPathCompAndExpr:
10914  * @ctxt:  the XPath Parser context
10915  *
10916  *  [22]   AndExpr ::=   EqualityExpr
10917  *                 | AndExpr 'and' EqualityExpr
10918  *
10919  * Compile an AND expression.
10920  *
10921  */
10922 static void
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt)10923 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10924     xmlXPathCompEqualityExpr(ctxt);
10925     CHECK_ERROR;
10926     SKIP_BLANKS;
10927     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10928 	int op1 = ctxt->comp->last;
10929         SKIP(3);
10930 	SKIP_BLANKS;
10931         xmlXPathCompEqualityExpr(ctxt);
10932 	CHECK_ERROR;
10933 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10934 	SKIP_BLANKS;
10935     }
10936 }
10937 
10938 /**
10939  * xmlXPathCompileExpr:
10940  * @ctxt:  the XPath Parser context
10941  *
10942  *  [14]   Expr ::=   OrExpr
10943  *  [21]   OrExpr ::=   AndExpr
10944  *                 | OrExpr 'or' AndExpr
10945  *
10946  * Parse and compile an expression
10947  */
10948 static void
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt,int sort)10949 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10950     xmlXPathContextPtr xpctxt = ctxt->context;
10951 
10952     if (xpctxt != NULL) {
10953         if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10954             XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10955         /*
10956          * Parsing a single '(' pushes about 10 functions on the call stack
10957          * before recursing!
10958          */
10959         xpctxt->depth += 10;
10960     }
10961 
10962     xmlXPathCompAndExpr(ctxt);
10963     CHECK_ERROR;
10964     SKIP_BLANKS;
10965     while ((CUR == 'o') && (NXT(1) == 'r')) {
10966 	int op1 = ctxt->comp->last;
10967         SKIP(2);
10968 	SKIP_BLANKS;
10969         xmlXPathCompAndExpr(ctxt);
10970 	CHECK_ERROR;
10971 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10972 	SKIP_BLANKS;
10973     }
10974     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10975 	/* more ops could be optimized too */
10976 	/*
10977 	* This is the main place to eliminate sorting for
10978 	* operations which don't require a sorted node-set.
10979 	* E.g. count().
10980 	*/
10981 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10982     }
10983 
10984     if (xpctxt != NULL)
10985         xpctxt->depth -= 10;
10986 }
10987 
10988 /**
10989  * xmlXPathCompPredicate:
10990  * @ctxt:  the XPath Parser context
10991  * @filter:  act as a filter
10992  *
10993  *  [8]   Predicate ::=   '[' PredicateExpr ']'
10994  *  [9]   PredicateExpr ::=   Expr
10995  *
10996  * Compile a predicate expression
10997  */
10998 static void
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt,int filter)10999 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11000     int op1 = ctxt->comp->last;
11001 
11002     SKIP_BLANKS;
11003     if (CUR != '[') {
11004 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11005     }
11006     NEXT;
11007     SKIP_BLANKS;
11008 
11009     ctxt->comp->last = -1;
11010     /*
11011     * This call to xmlXPathCompileExpr() will deactivate sorting
11012     * of the predicate result.
11013     * TODO: Sorting is still activated for filters, since I'm not
11014     *  sure if needed. Normally sorting should not be needed, since
11015     *  a filter can only diminish the number of items in a sequence,
11016     *  but won't change its order; so if the initial sequence is sorted,
11017     *  subsequent sorting is not needed.
11018     */
11019     if (! filter)
11020 	xmlXPathCompileExpr(ctxt, 0);
11021     else
11022 	xmlXPathCompileExpr(ctxt, 1);
11023     CHECK_ERROR;
11024 
11025     if (CUR != ']') {
11026 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11027     }
11028 
11029     if (filter)
11030 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11031     else
11032 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11033 
11034     NEXT;
11035     SKIP_BLANKS;
11036 }
11037 
11038 /**
11039  * xmlXPathCompNodeTest:
11040  * @ctxt:  the XPath Parser context
11041  * @test:  pointer to a xmlXPathTestVal
11042  * @type:  pointer to a xmlXPathTypeVal
11043  * @prefix:  placeholder for a possible name prefix
11044  *
11045  * [7] NodeTest ::=   NameTest
11046  *		    | NodeType '(' ')'
11047  *		    | 'processing-instruction' '(' Literal ')'
11048  *
11049  * [37] NameTest ::=  '*'
11050  *		    | NCName ':' '*'
11051  *		    | QName
11052  * [38] NodeType ::= 'comment'
11053  *		   | 'text'
11054  *		   | 'processing-instruction'
11055  *		   | 'node'
11056  *
11057  * Returns the name found and updates @test, @type and @prefix appropriately
11058  */
11059 static xmlChar *
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt,xmlXPathTestVal * test,xmlXPathTypeVal * type,xmlChar ** prefix,xmlChar * name)11060 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11061 	             xmlXPathTypeVal *type, xmlChar **prefix,
11062 		     xmlChar *name) {
11063     int blanks;
11064 
11065     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11066 	STRANGE;
11067 	return(NULL);
11068     }
11069     *type = (xmlXPathTypeVal) 0;
11070     *test = (xmlXPathTestVal) 0;
11071     *prefix = NULL;
11072     SKIP_BLANKS;
11073 
11074     if ((name == NULL) && (CUR == '*')) {
11075 	/*
11076 	 * All elements
11077 	 */
11078 	NEXT;
11079 	*test = NODE_TEST_ALL;
11080 	return(NULL);
11081     }
11082 
11083     if (name == NULL)
11084 	name = xmlXPathParseNCName(ctxt);
11085     if (name == NULL) {
11086 	XP_ERRORNULL(XPATH_EXPR_ERROR);
11087     }
11088 
11089     blanks = IS_BLANK_CH(CUR);
11090     SKIP_BLANKS;
11091     if (CUR == '(') {
11092 	NEXT;
11093 	/*
11094 	 * NodeType or PI search
11095 	 */
11096 	if (xmlStrEqual(name, BAD_CAST "comment"))
11097 	    *type = NODE_TYPE_COMMENT;
11098 	else if (xmlStrEqual(name, BAD_CAST "node"))
11099 	    *type = NODE_TYPE_NODE;
11100 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11101 	    *type = NODE_TYPE_PI;
11102 	else if (xmlStrEqual(name, BAD_CAST "text"))
11103 	    *type = NODE_TYPE_TEXT;
11104 	else {
11105 	    if (name != NULL)
11106 		xmlFree(name);
11107 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11108 	}
11109 
11110 	*test = NODE_TEST_TYPE;
11111 
11112 	SKIP_BLANKS;
11113 	if (*type == NODE_TYPE_PI) {
11114 	    /*
11115 	     * Specific case: search a PI by name.
11116 	     */
11117 	    if (name != NULL)
11118 		xmlFree(name);
11119 	    name = NULL;
11120 	    if (CUR != ')') {
11121 		name = xmlXPathParseLiteral(ctxt);
11122                 if (name == NULL) {
11123 	            XP_ERRORNULL(XPATH_EXPR_ERROR);
11124                 }
11125 		*test = NODE_TEST_PI;
11126 		SKIP_BLANKS;
11127 	    }
11128 	}
11129 	if (CUR != ')') {
11130 	    if (name != NULL)
11131 		xmlFree(name);
11132 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11133 	}
11134 	NEXT;
11135 	return(name);
11136     }
11137     *test = NODE_TEST_NAME;
11138     if ((!blanks) && (CUR == ':')) {
11139 	NEXT;
11140 
11141 	/*
11142 	 * Since currently the parser context don't have a
11143 	 * namespace list associated:
11144 	 * The namespace name for this prefix can be computed
11145 	 * only at evaluation time. The compilation is done
11146 	 * outside of any context.
11147 	 */
11148 #if 0
11149 	*prefix = xmlXPathNsLookup(ctxt->context, name);
11150 	if (name != NULL)
11151 	    xmlFree(name);
11152 	if (*prefix == NULL) {
11153 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11154 	}
11155 #else
11156 	*prefix = name;
11157 #endif
11158 
11159 	if (CUR == '*') {
11160 	    /*
11161 	     * All elements
11162 	     */
11163 	    NEXT;
11164 	    *test = NODE_TEST_ALL;
11165 	    return(NULL);
11166 	}
11167 
11168 	name = xmlXPathParseNCName(ctxt);
11169 	if (name == NULL) {
11170 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11171 	}
11172     }
11173     return(name);
11174 }
11175 
11176 /**
11177  * xmlXPathIsAxisName:
11178  * @name:  a preparsed name token
11179  *
11180  * [6] AxisName ::=   'ancestor'
11181  *                  | 'ancestor-or-self'
11182  *                  | 'attribute'
11183  *                  | 'child'
11184  *                  | 'descendant'
11185  *                  | 'descendant-or-self'
11186  *                  | 'following'
11187  *                  | 'following-sibling'
11188  *                  | 'namespace'
11189  *                  | 'parent'
11190  *                  | 'preceding'
11191  *                  | 'preceding-sibling'
11192  *                  | 'self'
11193  *
11194  * Returns the axis or 0
11195  */
11196 static xmlXPathAxisVal
xmlXPathIsAxisName(const xmlChar * name)11197 xmlXPathIsAxisName(const xmlChar *name) {
11198     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11199     switch (name[0]) {
11200 	case 'a':
11201 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
11202 		ret = AXIS_ANCESTOR;
11203 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11204 		ret = AXIS_ANCESTOR_OR_SELF;
11205 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
11206 		ret = AXIS_ATTRIBUTE;
11207 	    break;
11208 	case 'c':
11209 	    if (xmlStrEqual(name, BAD_CAST "child"))
11210 		ret = AXIS_CHILD;
11211 	    break;
11212 	case 'd':
11213 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
11214 		ret = AXIS_DESCENDANT;
11215 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11216 		ret = AXIS_DESCENDANT_OR_SELF;
11217 	    break;
11218 	case 'f':
11219 	    if (xmlStrEqual(name, BAD_CAST "following"))
11220 		ret = AXIS_FOLLOWING;
11221 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11222 		ret = AXIS_FOLLOWING_SIBLING;
11223 	    break;
11224 	case 'n':
11225 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
11226 		ret = AXIS_NAMESPACE;
11227 	    break;
11228 	case 'p':
11229 	    if (xmlStrEqual(name, BAD_CAST "parent"))
11230 		ret = AXIS_PARENT;
11231 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
11232 		ret = AXIS_PRECEDING;
11233 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11234 		ret = AXIS_PRECEDING_SIBLING;
11235 	    break;
11236 	case 's':
11237 	    if (xmlStrEqual(name, BAD_CAST "self"))
11238 		ret = AXIS_SELF;
11239 	    break;
11240     }
11241     return(ret);
11242 }
11243 
11244 /**
11245  * xmlXPathCompStep:
11246  * @ctxt:  the XPath Parser context
11247  *
11248  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11249  *                  | AbbreviatedStep
11250  *
11251  * [12] AbbreviatedStep ::=   '.' | '..'
11252  *
11253  * [5] AxisSpecifier ::= AxisName '::'
11254  *                  | AbbreviatedAxisSpecifier
11255  *
11256  * [13] AbbreviatedAxisSpecifier ::= '@'?
11257  *
11258  * Modified for XPtr range support as:
11259  *
11260  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11261  *                     | AbbreviatedStep
11262  *                     | 'range-to' '(' Expr ')' Predicate*
11263  *
11264  * Compile one step in a Location Path
11265  * A location step of . is short for self::node(). This is
11266  * particularly useful in conjunction with //. For example, the
11267  * location path .//para is short for
11268  * self::node()/descendant-or-self::node()/child::para
11269  * and so will select all para descendant elements of the context
11270  * node.
11271  * Similarly, a location step of .. is short for parent::node().
11272  * For example, ../title is short for parent::node()/child::title
11273  * and so will select the title children of the parent of the context
11274  * node.
11275  */
11276 static void
xmlXPathCompStep(xmlXPathParserContextPtr ctxt)11277 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11278 #ifdef LIBXML_XPTR_LOCS_ENABLED
11279     int rangeto = 0;
11280     int op2 = -1;
11281 #endif
11282 
11283     SKIP_BLANKS;
11284     if ((CUR == '.') && (NXT(1) == '.')) {
11285 	SKIP(2);
11286 	SKIP_BLANKS;
11287 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11288 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11289     } else if (CUR == '.') {
11290 	NEXT;
11291 	SKIP_BLANKS;
11292     } else {
11293 	xmlChar *name = NULL;
11294 	xmlChar *prefix = NULL;
11295 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
11296 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11297 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11298 	int op1;
11299 
11300 	/*
11301 	 * The modification needed for XPointer change to the production
11302 	 */
11303 #ifdef LIBXML_XPTR_LOCS_ENABLED
11304 	if (ctxt->xptr) {
11305 	    name = xmlXPathParseNCName(ctxt);
11306 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11307                 op2 = ctxt->comp->last;
11308 		xmlFree(name);
11309 		SKIP_BLANKS;
11310 		if (CUR != '(') {
11311 		    XP_ERROR(XPATH_EXPR_ERROR);
11312 		}
11313 		NEXT;
11314 		SKIP_BLANKS;
11315 
11316 		xmlXPathCompileExpr(ctxt, 1);
11317 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11318 		CHECK_ERROR;
11319 
11320 		SKIP_BLANKS;
11321 		if (CUR != ')') {
11322 		    XP_ERROR(XPATH_EXPR_ERROR);
11323 		}
11324 		NEXT;
11325 		rangeto = 1;
11326 		goto eval_predicates;
11327 	    }
11328 	}
11329 #endif
11330 	if (CUR == '*') {
11331 	    axis = AXIS_CHILD;
11332 	} else {
11333 	    if (name == NULL)
11334 		name = xmlXPathParseNCName(ctxt);
11335 	    if (name != NULL) {
11336 		axis = xmlXPathIsAxisName(name);
11337 		if (axis != 0) {
11338 		    SKIP_BLANKS;
11339 		    if ((CUR == ':') && (NXT(1) == ':')) {
11340 			SKIP(2);
11341 			xmlFree(name);
11342 			name = NULL;
11343 		    } else {
11344 			/* an element name can conflict with an axis one :-\ */
11345 			axis = AXIS_CHILD;
11346 		    }
11347 		} else {
11348 		    axis = AXIS_CHILD;
11349 		}
11350 	    } else if (CUR == '@') {
11351 		NEXT;
11352 		axis = AXIS_ATTRIBUTE;
11353 	    } else {
11354 		axis = AXIS_CHILD;
11355 	    }
11356 	}
11357 
11358         if (ctxt->error != XPATH_EXPRESSION_OK) {
11359             xmlFree(name);
11360             return;
11361         }
11362 
11363 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11364 	if (test == 0)
11365 	    return;
11366 
11367         if ((prefix != NULL) && (ctxt->context != NULL) &&
11368 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11369 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11370 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11371 	    }
11372 	}
11373 #ifdef DEBUG_STEP
11374 	xmlGenericError(xmlGenericErrorContext,
11375 		"Basis : computing new set\n");
11376 #endif
11377 
11378 #ifdef DEBUG_STEP
11379 	xmlGenericError(xmlGenericErrorContext, "Basis : ");
11380 	if (ctxt->value == NULL)
11381 	    xmlGenericError(xmlGenericErrorContext, "no value\n");
11382 	else if (ctxt->value->nodesetval == NULL)
11383 	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
11384 	else
11385 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11386 #endif
11387 
11388 #ifdef LIBXML_XPTR_LOCS_ENABLED
11389 eval_predicates:
11390 #endif
11391 	op1 = ctxt->comp->last;
11392 	ctxt->comp->last = -1;
11393 
11394 	SKIP_BLANKS;
11395 	while (CUR == '[') {
11396 	    xmlXPathCompPredicate(ctxt, 0);
11397 	}
11398 
11399 #ifdef LIBXML_XPTR_LOCS_ENABLED
11400 	if (rangeto) {
11401 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11402 	} else
11403 #endif
11404         if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11405                            test, type, (void *)prefix, (void *)name) == -1) {
11406             xmlFree(prefix);
11407             xmlFree(name);
11408         }
11409     }
11410 #ifdef DEBUG_STEP
11411     xmlGenericError(xmlGenericErrorContext, "Step : ");
11412     if (ctxt->value == NULL)
11413 	xmlGenericError(xmlGenericErrorContext, "no value\n");
11414     else if (ctxt->value->nodesetval == NULL)
11415 	xmlGenericError(xmlGenericErrorContext, "Empty\n");
11416     else
11417 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11418 		ctxt->value->nodesetval);
11419 #endif
11420 }
11421 
11422 /**
11423  * xmlXPathCompRelativeLocationPath:
11424  * @ctxt:  the XPath Parser context
11425  *
11426  *  [3]   RelativeLocationPath ::=   Step
11427  *                     | RelativeLocationPath '/' Step
11428  *                     | AbbreviatedRelativeLocationPath
11429  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11430  *
11431  * Compile a relative location path.
11432  */
11433 static void
xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt)11434 xmlXPathCompRelativeLocationPath
11435 (xmlXPathParserContextPtr ctxt) {
11436     SKIP_BLANKS;
11437     if ((CUR == '/') && (NXT(1) == '/')) {
11438 	SKIP(2);
11439 	SKIP_BLANKS;
11440 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11441 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11442     } else if (CUR == '/') {
11443 	    NEXT;
11444 	SKIP_BLANKS;
11445     }
11446     xmlXPathCompStep(ctxt);
11447     CHECK_ERROR;
11448     SKIP_BLANKS;
11449     while (CUR == '/') {
11450 	if ((CUR == '/') && (NXT(1) == '/')) {
11451 	    SKIP(2);
11452 	    SKIP_BLANKS;
11453 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11454 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11455 	    xmlXPathCompStep(ctxt);
11456 	} else if (CUR == '/') {
11457 	    NEXT;
11458 	    SKIP_BLANKS;
11459 	    xmlXPathCompStep(ctxt);
11460 	}
11461 	SKIP_BLANKS;
11462     }
11463 }
11464 
11465 /**
11466  * xmlXPathCompLocationPath:
11467  * @ctxt:  the XPath Parser context
11468  *
11469  *  [1]   LocationPath ::=   RelativeLocationPath
11470  *                     | AbsoluteLocationPath
11471  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11472  *                     | AbbreviatedAbsoluteLocationPath
11473  *  [10]   AbbreviatedAbsoluteLocationPath ::=
11474  *                           '//' RelativeLocationPath
11475  *
11476  * Compile a location path
11477  *
11478  * // is short for /descendant-or-self::node()/. For example,
11479  * //para is short for /descendant-or-self::node()/child::para and
11480  * so will select any para element in the document (even a para element
11481  * that is a document element will be selected by //para since the
11482  * document element node is a child of the root node); div//para is
11483  * short for div/descendant-or-self::node()/child::para and so will
11484  * select all para descendants of div children.
11485  */
11486 static void
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt)11487 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11488     SKIP_BLANKS;
11489     if (CUR != '/') {
11490         xmlXPathCompRelativeLocationPath(ctxt);
11491     } else {
11492 	while (CUR == '/') {
11493 	    if ((CUR == '/') && (NXT(1) == '/')) {
11494 		SKIP(2);
11495 		SKIP_BLANKS;
11496 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11497 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11498 		xmlXPathCompRelativeLocationPath(ctxt);
11499 	    } else if (CUR == '/') {
11500 		NEXT;
11501 		SKIP_BLANKS;
11502 		if ((CUR != 0 ) &&
11503 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11504 		     (CUR == '@') || (CUR == '*')))
11505 		    xmlXPathCompRelativeLocationPath(ctxt);
11506 	    }
11507 	    CHECK_ERROR;
11508 	}
11509     }
11510 }
11511 
11512 /************************************************************************
11513  *									*
11514  *		XPath precompiled expression evaluation			*
11515  *									*
11516  ************************************************************************/
11517 
11518 static int
11519 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11520 
11521 #ifdef DEBUG_STEP
11522 static void
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,int nbNodes)11523 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11524 			  int nbNodes)
11525 {
11526     xmlGenericError(xmlGenericErrorContext, "new step : ");
11527     switch (op->value) {
11528         case AXIS_ANCESTOR:
11529             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11530             break;
11531         case AXIS_ANCESTOR_OR_SELF:
11532             xmlGenericError(xmlGenericErrorContext,
11533                             "axis 'ancestors-or-self' ");
11534             break;
11535         case AXIS_ATTRIBUTE:
11536             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11537             break;
11538         case AXIS_CHILD:
11539             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11540             break;
11541         case AXIS_DESCENDANT:
11542             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11543             break;
11544         case AXIS_DESCENDANT_OR_SELF:
11545             xmlGenericError(xmlGenericErrorContext,
11546                             "axis 'descendant-or-self' ");
11547             break;
11548         case AXIS_FOLLOWING:
11549             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11550             break;
11551         case AXIS_FOLLOWING_SIBLING:
11552             xmlGenericError(xmlGenericErrorContext,
11553                             "axis 'following-siblings' ");
11554             break;
11555         case AXIS_NAMESPACE:
11556             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11557             break;
11558         case AXIS_PARENT:
11559             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11560             break;
11561         case AXIS_PRECEDING:
11562             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11563             break;
11564         case AXIS_PRECEDING_SIBLING:
11565             xmlGenericError(xmlGenericErrorContext,
11566                             "axis 'preceding-sibling' ");
11567             break;
11568         case AXIS_SELF:
11569             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11570             break;
11571     }
11572     xmlGenericError(xmlGenericErrorContext,
11573 	" context contains %d nodes\n", nbNodes);
11574     switch (op->value2) {
11575         case NODE_TEST_NONE:
11576             xmlGenericError(xmlGenericErrorContext,
11577                             "           searching for none !!!\n");
11578             break;
11579         case NODE_TEST_TYPE:
11580             xmlGenericError(xmlGenericErrorContext,
11581                             "           searching for type %d\n", op->value3);
11582             break;
11583         case NODE_TEST_PI:
11584             xmlGenericError(xmlGenericErrorContext,
11585                             "           searching for PI !!!\n");
11586             break;
11587         case NODE_TEST_ALL:
11588             xmlGenericError(xmlGenericErrorContext,
11589                             "           searching for *\n");
11590             break;
11591         case NODE_TEST_NS:
11592             xmlGenericError(xmlGenericErrorContext,
11593                             "           searching for namespace %s\n",
11594                             op->value5);
11595             break;
11596         case NODE_TEST_NAME:
11597             xmlGenericError(xmlGenericErrorContext,
11598                             "           searching for name %s\n", op->value5);
11599             if (op->value4)
11600                 xmlGenericError(xmlGenericErrorContext,
11601                                 "           with namespace %s\n", op->value4);
11602             break;
11603     }
11604     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11605 }
11606 #endif /* DEBUG_STEP */
11607 
11608 /**
11609  * xmlXPathNodeSetFilter:
11610  * @ctxt:  the XPath Parser context
11611  * @set: the node set to filter
11612  * @filterOpIndex: the index of the predicate/filter op
11613  * @minPos: minimum position in the filtered set (1-based)
11614  * @maxPos: maximum position in the filtered set (1-based)
11615  * @hasNsNodes: true if the node set may contain namespace nodes
11616  *
11617  * Filter a node set, keeping only nodes for which the predicate expression
11618  * matches. Afterwards, keep only nodes between minPos and maxPos in the
11619  * filtered result.
11620  */
11621 static void
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,xmlNodeSetPtr set,int filterOpIndex,int minPos,int maxPos,int hasNsNodes)11622 xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11623 		      xmlNodeSetPtr set,
11624 		      int filterOpIndex,
11625                       int minPos, int maxPos,
11626 		      int hasNsNodes)
11627 {
11628     xmlXPathContextPtr xpctxt;
11629     xmlNodePtr oldnode;
11630     xmlDocPtr olddoc;
11631     xmlXPathStepOpPtr filterOp;
11632     int oldcs, oldpp;
11633     int i, j, pos;
11634 
11635     if ((set == NULL) || (set->nodeNr == 0))
11636         return;
11637 
11638     /*
11639     * Check if the node set contains a sufficient number of nodes for
11640     * the requested range.
11641     */
11642     if (set->nodeNr < minPos) {
11643         xmlXPathNodeSetClear(set, hasNsNodes);
11644         return;
11645     }
11646 
11647     xpctxt = ctxt->context;
11648     oldnode = xpctxt->node;
11649     olddoc = xpctxt->doc;
11650     oldcs = xpctxt->contextSize;
11651     oldpp = xpctxt->proximityPosition;
11652     filterOp = &ctxt->comp->steps[filterOpIndex];
11653 
11654     xpctxt->contextSize = set->nodeNr;
11655 
11656     for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11657         xmlNodePtr node = set->nodeTab[i];
11658         int res;
11659 
11660         xpctxt->node = node;
11661         xpctxt->proximityPosition = i + 1;
11662 
11663         /*
11664         * Also set the xpath document in case things like
11665         * key() are evaluated in the predicate.
11666         *
11667         * TODO: Get real doc for namespace nodes.
11668         */
11669         if ((node->type != XML_NAMESPACE_DECL) &&
11670             (node->doc != NULL))
11671             xpctxt->doc = node->doc;
11672 
11673         res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11674 
11675         if (ctxt->error != XPATH_EXPRESSION_OK)
11676             break;
11677         if (res < 0) {
11678             /* Shouldn't happen */
11679             xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11680             break;
11681         }
11682 
11683         if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11684             if (i != j) {
11685                 set->nodeTab[j] = node;
11686                 set->nodeTab[i] = NULL;
11687             }
11688 
11689             j += 1;
11690         } else {
11691             /* Remove the entry from the initial node set. */
11692             set->nodeTab[i] = NULL;
11693             if (node->type == XML_NAMESPACE_DECL)
11694                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11695         }
11696 
11697         if (res != 0) {
11698             if (pos == maxPos) {
11699                 i += 1;
11700                 break;
11701             }
11702 
11703             pos += 1;
11704         }
11705     }
11706 
11707     /* Free remaining nodes. */
11708     if (hasNsNodes) {
11709         for (; i < set->nodeNr; i++) {
11710             xmlNodePtr node = set->nodeTab[i];
11711             if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11712                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11713         }
11714     }
11715 
11716     set->nodeNr = j;
11717 
11718     /* If too many elements were removed, shrink table to preserve memory. */
11719     if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11720         (set->nodeNr < set->nodeMax / 2)) {
11721         xmlNodePtr *tmp;
11722         int nodeMax = set->nodeNr;
11723 
11724         if (nodeMax < XML_NODESET_DEFAULT)
11725             nodeMax = XML_NODESET_DEFAULT;
11726         tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11727                 nodeMax * sizeof(xmlNodePtr));
11728         if (tmp == NULL) {
11729             xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11730         } else {
11731             set->nodeTab = tmp;
11732             set->nodeMax = nodeMax;
11733         }
11734     }
11735 
11736     xpctxt->node = oldnode;
11737     xpctxt->doc = olddoc;
11738     xpctxt->contextSize = oldcs;
11739     xpctxt->proximityPosition = oldpp;
11740 }
11741 
11742 #ifdef LIBXML_XPTR_LOCS_ENABLED
11743 /**
11744  * xmlXPathLocationSetFilter:
11745  * @ctxt:  the XPath Parser context
11746  * @locset: the location set to filter
11747  * @filterOpIndex: the index of the predicate/filter op
11748  * @minPos: minimum position in the filtered set (1-based)
11749  * @maxPos: maximum position in the filtered set (1-based)
11750  *
11751  * Filter a location set, keeping only nodes for which the predicate
11752  * expression matches. Afterwards, keep only nodes between minPos and maxPos
11753  * in the filtered result.
11754  */
11755 static void
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,xmlLocationSetPtr locset,int filterOpIndex,int minPos,int maxPos)11756 xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11757 		          xmlLocationSetPtr locset,
11758 		          int filterOpIndex,
11759                           int minPos, int maxPos)
11760 {
11761     xmlXPathContextPtr xpctxt;
11762     xmlNodePtr oldnode;
11763     xmlDocPtr olddoc;
11764     xmlXPathStepOpPtr filterOp;
11765     int oldcs, oldpp;
11766     int i, j, pos;
11767 
11768     if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11769         return;
11770 
11771     xpctxt = ctxt->context;
11772     oldnode = xpctxt->node;
11773     olddoc = xpctxt->doc;
11774     oldcs = xpctxt->contextSize;
11775     oldpp = xpctxt->proximityPosition;
11776     filterOp = &ctxt->comp->steps[filterOpIndex];
11777 
11778     xpctxt->contextSize = locset->locNr;
11779 
11780     for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11781         xmlNodePtr contextNode = locset->locTab[i]->user;
11782         int res;
11783 
11784         xpctxt->node = contextNode;
11785         xpctxt->proximityPosition = i + 1;
11786 
11787         /*
11788         * Also set the xpath document in case things like
11789         * key() are evaluated in the predicate.
11790         *
11791         * TODO: Get real doc for namespace nodes.
11792         */
11793         if ((contextNode->type != XML_NAMESPACE_DECL) &&
11794             (contextNode->doc != NULL))
11795             xpctxt->doc = contextNode->doc;
11796 
11797         res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11798 
11799         if (ctxt->error != XPATH_EXPRESSION_OK)
11800             break;
11801         if (res < 0) {
11802             /* Shouldn't happen */
11803             xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11804             break;
11805         }
11806 
11807         if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11808             if (i != j) {
11809                 locset->locTab[j] = locset->locTab[i];
11810                 locset->locTab[i] = NULL;
11811             }
11812 
11813             j += 1;
11814         } else {
11815             /* Remove the entry from the initial location set. */
11816             xmlXPathFreeObject(locset->locTab[i]);
11817             locset->locTab[i] = NULL;
11818         }
11819 
11820         if (res != 0) {
11821             if (pos == maxPos) {
11822                 i += 1;
11823                 break;
11824             }
11825 
11826             pos += 1;
11827         }
11828     }
11829 
11830     /* Free remaining nodes. */
11831     for (; i < locset->locNr; i++)
11832         xmlXPathFreeObject(locset->locTab[i]);
11833 
11834     locset->locNr = j;
11835 
11836     /* If too many elements were removed, shrink table to preserve memory. */
11837     if ((locset->locMax > XML_NODESET_DEFAULT) &&
11838         (locset->locNr < locset->locMax / 2)) {
11839         xmlXPathObjectPtr *tmp;
11840         int locMax = locset->locNr;
11841 
11842         if (locMax < XML_NODESET_DEFAULT)
11843             locMax = XML_NODESET_DEFAULT;
11844         tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11845                 locMax * sizeof(xmlXPathObjectPtr));
11846         if (tmp == NULL) {
11847             xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11848         } else {
11849             locset->locTab = tmp;
11850             locset->locMax = locMax;
11851         }
11852     }
11853 
11854     xpctxt->node = oldnode;
11855     xpctxt->doc = olddoc;
11856     xpctxt->contextSize = oldcs;
11857     xpctxt->proximityPosition = oldpp;
11858 }
11859 #endif /* LIBXML_XPTR_LOCS_ENABLED */
11860 
11861 /**
11862  * xmlXPathCompOpEvalPredicate:
11863  * @ctxt:  the XPath Parser context
11864  * @op: the predicate op
11865  * @set: the node set to filter
11866  * @minPos: minimum position in the filtered set (1-based)
11867  * @maxPos: maximum position in the filtered set (1-based)
11868  * @hasNsNodes: true if the node set may contain namespace nodes
11869  *
11870  * Filter a node set, keeping only nodes for which the sequence of predicate
11871  * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11872  * in the filtered result.
11873  */
11874 static void
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int minPos,int maxPos,int hasNsNodes)11875 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11876 			    xmlXPathStepOpPtr op,
11877 			    xmlNodeSetPtr set,
11878                             int minPos, int maxPos,
11879 			    int hasNsNodes)
11880 {
11881     if (op->ch1 != -1) {
11882 	xmlXPathCompExprPtr comp = ctxt->comp;
11883 	/*
11884 	* Process inner predicates first.
11885 	*/
11886 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11887             xmlGenericError(xmlGenericErrorContext,
11888                 "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11889             XP_ERROR(XPATH_INVALID_OPERAND);
11890 	}
11891         if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11892             XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11893         ctxt->context->depth += 1;
11894 	xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11895                                     1, set->nodeNr, hasNsNodes);
11896         ctxt->context->depth -= 1;
11897 	CHECK_ERROR;
11898     }
11899 
11900     if (op->ch2 != -1)
11901         xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11902 }
11903 
11904 static int
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int * maxPos)11905 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11906 			    xmlXPathStepOpPtr op,
11907 			    int *maxPos)
11908 {
11909 
11910     xmlXPathStepOpPtr exprOp;
11911 
11912     /*
11913     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11914     */
11915 
11916     /*
11917     * If not -1, then ch1 will point to:
11918     * 1) For predicates (XPATH_OP_PREDICATE):
11919     *    - an inner predicate operator
11920     * 2) For filters (XPATH_OP_FILTER):
11921     *    - an inner filter operator OR
11922     *    - an expression selecting the node set.
11923     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11924     */
11925     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11926 	return(0);
11927 
11928     if (op->ch2 != -1) {
11929 	exprOp = &ctxt->comp->steps[op->ch2];
11930     } else
11931 	return(0);
11932 
11933     if ((exprOp != NULL) &&
11934 	(exprOp->op == XPATH_OP_VALUE) &&
11935 	(exprOp->value4 != NULL) &&
11936 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11937     {
11938         double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11939 
11940 	/*
11941 	* We have a "[n]" predicate here.
11942 	* TODO: Unfortunately this simplistic test here is not
11943 	* able to detect a position() predicate in compound
11944 	* expressions like "[@attr = 'a" and position() = 1],
11945 	* and even not the usage of position() in
11946 	* "[position() = 1]"; thus - obviously - a position-range,
11947 	* like it "[position() < 5]", is also not detected.
11948 	* Maybe we could rewrite the AST to ease the optimization.
11949 	*/
11950 
11951         if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11952 	    *maxPos = (int) floatval;
11953             if (floatval == (double) *maxPos)
11954                 return(1);
11955         }
11956     }
11957     return(0);
11958 }
11959 
11960 static int
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first,xmlNodePtr * last,int toBool)11961 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11962                            xmlXPathStepOpPtr op,
11963 			   xmlNodePtr * first, xmlNodePtr * last,
11964 			   int toBool)
11965 {
11966 
11967 #define XP_TEST_HIT \
11968     if (hasAxisRange != 0) { \
11969 	if (++pos == maxPos) { \
11970 	    if (addNode(seq, cur) < 0) \
11971 	        ctxt->error = XPATH_MEMORY_ERROR; \
11972 	    goto axis_range_end; } \
11973     } else { \
11974 	if (addNode(seq, cur) < 0) \
11975 	    ctxt->error = XPATH_MEMORY_ERROR; \
11976 	if (breakOnFirstHit) goto first_hit; }
11977 
11978 #define XP_TEST_HIT_NS \
11979     if (hasAxisRange != 0) { \
11980 	if (++pos == maxPos) { \
11981 	    hasNsNodes = 1; \
11982 	    if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11983 	        ctxt->error = XPATH_MEMORY_ERROR; \
11984 	goto axis_range_end; } \
11985     } else { \
11986 	hasNsNodes = 1; \
11987 	if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11988 	    ctxt->error = XPATH_MEMORY_ERROR; \
11989 	if (breakOnFirstHit) goto first_hit; }
11990 
11991     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11992     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11993     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11994     const xmlChar *prefix = op->value4;
11995     const xmlChar *name = op->value5;
11996     const xmlChar *URI = NULL;
11997 
11998 #ifdef DEBUG_STEP
11999     int nbMatches = 0, prevMatches = 0;
12000 #endif
12001     int total = 0, hasNsNodes = 0;
12002     /* The popped object holding the context nodes */
12003     xmlXPathObjectPtr obj;
12004     /* The set of context nodes for the node tests */
12005     xmlNodeSetPtr contextSeq;
12006     int contextIdx;
12007     xmlNodePtr contextNode;
12008     /* The final resulting node set wrt to all context nodes */
12009     xmlNodeSetPtr outSeq;
12010     /*
12011     * The temporary resulting node set wrt 1 context node.
12012     * Used to feed predicate evaluation.
12013     */
12014     xmlNodeSetPtr seq;
12015     xmlNodePtr cur;
12016     /* First predicate operator */
12017     xmlXPathStepOpPtr predOp;
12018     int maxPos; /* The requested position() (when a "[n]" predicate) */
12019     int hasPredicateRange, hasAxisRange, pos;
12020     int breakOnFirstHit;
12021 
12022     xmlXPathTraversalFunction next = NULL;
12023     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12024     xmlXPathNodeSetMergeFunction mergeAndClear;
12025     xmlNodePtr oldContextNode;
12026     xmlXPathContextPtr xpctxt = ctxt->context;
12027 
12028 
12029     CHECK_TYPE0(XPATH_NODESET);
12030     obj = valuePop(ctxt);
12031     /*
12032     * Setup namespaces.
12033     */
12034     if (prefix != NULL) {
12035         URI = xmlXPathNsLookup(xpctxt, prefix);
12036         if (URI == NULL) {
12037 	    xmlXPathReleaseObject(xpctxt, obj);
12038             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12039 	}
12040     }
12041     /*
12042     * Setup axis.
12043     *
12044     * MAYBE FUTURE TODO: merging optimizations:
12045     * - If the nodes to be traversed wrt to the initial nodes and
12046     *   the current axis cannot overlap, then we could avoid searching
12047     *   for duplicates during the merge.
12048     *   But the question is how/when to evaluate if they cannot overlap.
12049     *   Example: if we know that for two initial nodes, the one is
12050     *   not in the ancestor-or-self axis of the other, then we could safely
12051     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12052     *   the descendant-or-self axis.
12053     */
12054     mergeAndClear = xmlXPathNodeSetMergeAndClear;
12055     switch (axis) {
12056         case AXIS_ANCESTOR:
12057             first = NULL;
12058             next = xmlXPathNextAncestor;
12059             break;
12060         case AXIS_ANCESTOR_OR_SELF:
12061             first = NULL;
12062             next = xmlXPathNextAncestorOrSelf;
12063             break;
12064         case AXIS_ATTRIBUTE:
12065             first = NULL;
12066 	    last = NULL;
12067             next = xmlXPathNextAttribute;
12068 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12069             break;
12070         case AXIS_CHILD:
12071 	    last = NULL;
12072 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12073 		(type == NODE_TYPE_NODE))
12074 	    {
12075 		/*
12076 		* Optimization if an element node type is 'element'.
12077 		*/
12078 		next = xmlXPathNextChildElement;
12079 	    } else
12080 		next = xmlXPathNextChild;
12081 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12082             break;
12083         case AXIS_DESCENDANT:
12084 	    last = NULL;
12085             next = xmlXPathNextDescendant;
12086             break;
12087         case AXIS_DESCENDANT_OR_SELF:
12088 	    last = NULL;
12089             next = xmlXPathNextDescendantOrSelf;
12090             break;
12091         case AXIS_FOLLOWING:
12092 	    last = NULL;
12093             next = xmlXPathNextFollowing;
12094             break;
12095         case AXIS_FOLLOWING_SIBLING:
12096 	    last = NULL;
12097             next = xmlXPathNextFollowingSibling;
12098             break;
12099         case AXIS_NAMESPACE:
12100             first = NULL;
12101 	    last = NULL;
12102             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12103 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12104             break;
12105         case AXIS_PARENT:
12106             first = NULL;
12107             next = xmlXPathNextParent;
12108             break;
12109         case AXIS_PRECEDING:
12110             first = NULL;
12111             next = xmlXPathNextPrecedingInternal;
12112             break;
12113         case AXIS_PRECEDING_SIBLING:
12114             first = NULL;
12115             next = xmlXPathNextPrecedingSibling;
12116             break;
12117         case AXIS_SELF:
12118             first = NULL;
12119 	    last = NULL;
12120             next = xmlXPathNextSelf;
12121 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12122             break;
12123     }
12124 
12125 #ifdef DEBUG_STEP
12126     xmlXPathDebugDumpStepAxis(op,
12127 	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12128 #endif
12129 
12130     if (next == NULL) {
12131 	xmlXPathReleaseObject(xpctxt, obj);
12132         return(0);
12133     }
12134     contextSeq = obj->nodesetval;
12135     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12136 	xmlXPathReleaseObject(xpctxt, obj);
12137         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12138         return(0);
12139     }
12140     /*
12141     * Predicate optimization ---------------------------------------------
12142     * If this step has a last predicate, which contains a position(),
12143     * then we'll optimize (although not exactly "position()", but only
12144     * the  short-hand form, i.e., "[n]".
12145     *
12146     * Example - expression "/foo[parent::bar][1]":
12147     *
12148     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12149     *   ROOT                               -- op->ch1
12150     *   PREDICATE                          -- op->ch2 (predOp)
12151     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12152     *       SORT
12153     *         COLLECT  'parent' 'name' 'node' bar
12154     *           NODE
12155     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12156     *
12157     */
12158     maxPos = 0;
12159     predOp = NULL;
12160     hasPredicateRange = 0;
12161     hasAxisRange = 0;
12162     if (op->ch2 != -1) {
12163 	/*
12164 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
12165 	*/
12166 	predOp = &ctxt->comp->steps[op->ch2];
12167 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12168 	    if (predOp->ch1 != -1) {
12169 		/*
12170 		* Use the next inner predicate operator.
12171 		*/
12172 		predOp = &ctxt->comp->steps[predOp->ch1];
12173 		hasPredicateRange = 1;
12174 	    } else {
12175 		/*
12176 		* There's no other predicate than the [n] predicate.
12177 		*/
12178 		predOp = NULL;
12179 		hasAxisRange = 1;
12180 	    }
12181 	}
12182     }
12183     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12184     /*
12185     * Axis traversal -----------------------------------------------------
12186     */
12187     /*
12188      * 2.3 Node Tests
12189      *  - For the attribute axis, the principal node type is attribute.
12190      *  - For the namespace axis, the principal node type is namespace.
12191      *  - For other axes, the principal node type is element.
12192      *
12193      * A node test * is true for any node of the
12194      * principal node type. For example, child::* will
12195      * select all element children of the context node
12196      */
12197     oldContextNode = xpctxt->node;
12198     addNode = xmlXPathNodeSetAddUnique;
12199     outSeq = NULL;
12200     seq = NULL;
12201     contextNode = NULL;
12202     contextIdx = 0;
12203 
12204 
12205     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12206            (ctxt->error == XPATH_EXPRESSION_OK)) {
12207 	xpctxt->node = contextSeq->nodeTab[contextIdx++];
12208 
12209 	if (seq == NULL) {
12210 	    seq = xmlXPathNodeSetCreate(NULL);
12211 	    if (seq == NULL) {
12212                 /* TODO: Propagate memory error. */
12213 		total = 0;
12214 		goto error;
12215 	    }
12216 	}
12217 	/*
12218 	* Traverse the axis and test the nodes.
12219 	*/
12220 	pos = 0;
12221 	cur = NULL;
12222 	hasNsNodes = 0;
12223         do {
12224             if (OP_LIMIT_EXCEEDED(ctxt, 1))
12225                 goto error;
12226 
12227             cur = next(ctxt, cur);
12228             if (cur == NULL)
12229                 break;
12230 
12231 	    /*
12232 	    * QUESTION TODO: What does the "first" and "last" stuff do?
12233 	    */
12234             if ((first != NULL) && (*first != NULL)) {
12235 		if (*first == cur)
12236 		    break;
12237 		if (((total % 256) == 0) &&
12238 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12239 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12240 #else
12241 		    (xmlXPathCmpNodes(*first, cur) >= 0))
12242 #endif
12243 		{
12244 		    break;
12245 		}
12246 	    }
12247 	    if ((last != NULL) && (*last != NULL)) {
12248 		if (*last == cur)
12249 		    break;
12250 		if (((total % 256) == 0) &&
12251 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12252 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12253 #else
12254 		    (xmlXPathCmpNodes(cur, *last) >= 0))
12255 #endif
12256 		{
12257 		    break;
12258 		}
12259 	    }
12260 
12261             total++;
12262 
12263 #ifdef DEBUG_STEP
12264             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12265 #endif
12266 
12267 	    switch (test) {
12268                 case NODE_TEST_NONE:
12269 		    total = 0;
12270                     STRANGE
12271 		    goto error;
12272                 case NODE_TEST_TYPE:
12273 		    if (type == NODE_TYPE_NODE) {
12274 			switch (cur->type) {
12275 			    case XML_DOCUMENT_NODE:
12276 			    case XML_HTML_DOCUMENT_NODE:
12277 			    case XML_ELEMENT_NODE:
12278 			    case XML_ATTRIBUTE_NODE:
12279 			    case XML_PI_NODE:
12280 			    case XML_COMMENT_NODE:
12281 			    case XML_CDATA_SECTION_NODE:
12282 			    case XML_TEXT_NODE:
12283 				XP_TEST_HIT
12284 				break;
12285 			    case XML_NAMESPACE_DECL: {
12286 				if (axis == AXIS_NAMESPACE) {
12287 				    XP_TEST_HIT_NS
12288 				} else {
12289 	                            hasNsNodes = 1;
12290 				    XP_TEST_HIT
12291 				}
12292 				break;
12293                             }
12294 			    default:
12295 				break;
12296 			}
12297 		    } else if (cur->type == (xmlElementType) type) {
12298 			if (cur->type == XML_NAMESPACE_DECL)
12299 			    XP_TEST_HIT_NS
12300 			else
12301 			    XP_TEST_HIT
12302 		    } else if ((type == NODE_TYPE_TEXT) &&
12303 			 (cur->type == XML_CDATA_SECTION_NODE))
12304 		    {
12305 			XP_TEST_HIT
12306 		    }
12307 		    break;
12308                 case NODE_TEST_PI:
12309                     if ((cur->type == XML_PI_NODE) &&
12310                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12311 		    {
12312 			XP_TEST_HIT
12313                     }
12314                     break;
12315                 case NODE_TEST_ALL:
12316                     if (axis == AXIS_ATTRIBUTE) {
12317                         if (cur->type == XML_ATTRIBUTE_NODE)
12318 			{
12319                             if (prefix == NULL)
12320 			    {
12321 				XP_TEST_HIT
12322                             } else if ((cur->ns != NULL) &&
12323 				(xmlStrEqual(URI, cur->ns->href)))
12324 			    {
12325 				XP_TEST_HIT
12326                             }
12327                         }
12328                     } else if (axis == AXIS_NAMESPACE) {
12329                         if (cur->type == XML_NAMESPACE_DECL)
12330 			{
12331 			    XP_TEST_HIT_NS
12332                         }
12333                     } else {
12334                         if (cur->type == XML_ELEMENT_NODE) {
12335                             if (prefix == NULL)
12336 			    {
12337 				XP_TEST_HIT
12338 
12339                             } else if ((cur->ns != NULL) &&
12340 				(xmlStrEqual(URI, cur->ns->href)))
12341 			    {
12342 				XP_TEST_HIT
12343                             }
12344                         }
12345                     }
12346                     break;
12347                 case NODE_TEST_NS:{
12348                         TODO;
12349                         break;
12350                     }
12351                 case NODE_TEST_NAME:
12352                     if (axis == AXIS_ATTRIBUTE) {
12353                         if (cur->type != XML_ATTRIBUTE_NODE)
12354 			    break;
12355 		    } else if (axis == AXIS_NAMESPACE) {
12356                         if (cur->type != XML_NAMESPACE_DECL)
12357 			    break;
12358 		    } else {
12359 		        if (cur->type != XML_ELEMENT_NODE)
12360 			    break;
12361 		    }
12362                     switch (cur->type) {
12363                         case XML_ELEMENT_NODE:
12364                             if (xmlStrEqual(name, cur->name)) {
12365                                 if (prefix == NULL) {
12366                                     if (cur->ns == NULL)
12367 				    {
12368 					XP_TEST_HIT
12369                                     }
12370                                 } else {
12371                                     if ((cur->ns != NULL) &&
12372                                         (xmlStrEqual(URI, cur->ns->href)))
12373 				    {
12374 					XP_TEST_HIT
12375                                     }
12376                                 }
12377                             }
12378                             break;
12379                         case XML_ATTRIBUTE_NODE:{
12380                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12381 
12382                                 if (xmlStrEqual(name, attr->name)) {
12383                                     if (prefix == NULL) {
12384                                         if ((attr->ns == NULL) ||
12385                                             (attr->ns->prefix == NULL))
12386 					{
12387 					    XP_TEST_HIT
12388                                         }
12389                                     } else {
12390                                         if ((attr->ns != NULL) &&
12391                                             (xmlStrEqual(URI,
12392 					      attr->ns->href)))
12393 					{
12394 					    XP_TEST_HIT
12395                                         }
12396                                     }
12397                                 }
12398                                 break;
12399                             }
12400                         case XML_NAMESPACE_DECL:
12401                             if (cur->type == XML_NAMESPACE_DECL) {
12402                                 xmlNsPtr ns = (xmlNsPtr) cur;
12403 
12404                                 if ((ns->prefix != NULL) && (name != NULL)
12405                                     && (xmlStrEqual(ns->prefix, name)))
12406 				{
12407 				    XP_TEST_HIT_NS
12408                                 }
12409                             }
12410                             break;
12411                         default:
12412                             break;
12413                     }
12414                     break;
12415 	    } /* switch(test) */
12416         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12417 
12418 	goto apply_predicates;
12419 
12420 axis_range_end: /* ----------------------------------------------------- */
12421 	/*
12422 	* We have a "/foo[n]", and position() = n was reached.
12423 	* Note that we can have as well "/foo/::parent::foo[1]", so
12424 	* a duplicate-aware merge is still needed.
12425 	* Merge with the result.
12426 	*/
12427 	if (outSeq == NULL) {
12428 	    outSeq = seq;
12429 	    seq = NULL;
12430 	} else
12431             /* TODO: Check memory error. */
12432 	    outSeq = mergeAndClear(outSeq, seq);
12433 	/*
12434 	* Break if only a true/false result was requested.
12435 	*/
12436 	if (toBool)
12437 	    break;
12438 	continue;
12439 
12440 first_hit: /* ---------------------------------------------------------- */
12441 	/*
12442 	* Break if only a true/false result was requested and
12443 	* no predicates existed and a node test succeeded.
12444 	*/
12445 	if (outSeq == NULL) {
12446 	    outSeq = seq;
12447 	    seq = NULL;
12448 	} else
12449             /* TODO: Check memory error. */
12450 	    outSeq = mergeAndClear(outSeq, seq);
12451 	break;
12452 
12453 #ifdef DEBUG_STEP
12454 	if (seq != NULL)
12455 	    nbMatches += seq->nodeNr;
12456 #endif
12457 
12458 apply_predicates: /* --------------------------------------------------- */
12459         if (ctxt->error != XPATH_EXPRESSION_OK)
12460 	    goto error;
12461 
12462         /*
12463 	* Apply predicates.
12464 	*/
12465         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12466 	    /*
12467 	    * E.g. when we have a "/foo[some expression][n]".
12468 	    */
12469 	    /*
12470 	    * QUESTION TODO: The old predicate evaluation took into
12471 	    *  account location-sets.
12472 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12473 	    *  Do we expect such a set here?
12474 	    *  All what I learned now from the evaluation semantics
12475 	    *  does not indicate that a location-set will be processed
12476 	    *  here, so this looks OK.
12477 	    */
12478 	    /*
12479 	    * Iterate over all predicates, starting with the outermost
12480 	    * predicate.
12481 	    * TODO: Problem: we cannot execute the inner predicates first
12482 	    *  since we cannot go back *up* the operator tree!
12483 	    *  Options we have:
12484 	    *  1) Use of recursive functions (like is it currently done
12485 	    *     via xmlXPathCompOpEval())
12486 	    *  2) Add a predicate evaluation information stack to the
12487 	    *     context struct
12488 	    *  3) Change the way the operators are linked; we need a
12489 	    *     "parent" field on xmlXPathStepOp
12490 	    *
12491 	    * For the moment, I'll try to solve this with a recursive
12492 	    * function: xmlXPathCompOpEvalPredicate().
12493 	    */
12494 	    if (hasPredicateRange != 0)
12495 		xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12496 					    hasNsNodes);
12497 	    else
12498 		xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12499 					    hasNsNodes);
12500 
12501 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12502 		total = 0;
12503 		goto error;
12504 	    }
12505         }
12506 
12507         if (seq->nodeNr > 0) {
12508 	    /*
12509 	    * Add to result set.
12510 	    */
12511 	    if (outSeq == NULL) {
12512 		outSeq = seq;
12513 		seq = NULL;
12514 	    } else {
12515                 /* TODO: Check memory error. */
12516 		outSeq = mergeAndClear(outSeq, seq);
12517 	    }
12518 
12519             if (toBool)
12520                 break;
12521 	}
12522     }
12523 
12524 error:
12525     if ((obj->boolval) && (obj->user != NULL)) {
12526 	/*
12527 	* QUESTION TODO: What does this do and why?
12528 	* TODO: Do we have to do this also for the "error"
12529 	* cleanup further down?
12530 	*/
12531 	ctxt->value->boolval = 1;
12532 	ctxt->value->user = obj->user;
12533 	obj->user = NULL;
12534 	obj->boolval = 0;
12535     }
12536     xmlXPathReleaseObject(xpctxt, obj);
12537 
12538     /*
12539     * Ensure we return at least an empty set.
12540     */
12541     if (outSeq == NULL) {
12542 	if ((seq != NULL) && (seq->nodeNr == 0))
12543 	    outSeq = seq;
12544 	else
12545             /* TODO: Check memory error. */
12546 	    outSeq = xmlXPathNodeSetCreate(NULL);
12547     }
12548     if ((seq != NULL) && (seq != outSeq)) {
12549 	 xmlXPathFreeNodeSet(seq);
12550     }
12551     /*
12552     * Hand over the result. Better to push the set also in
12553     * case of errors.
12554     */
12555     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12556     /*
12557     * Reset the context node.
12558     */
12559     xpctxt->node = oldContextNode;
12560     /*
12561     * When traversing the namespace axis in "toBool" mode, it's
12562     * possible that tmpNsList wasn't freed.
12563     */
12564     if (xpctxt->tmpNsList != NULL) {
12565         xmlFree(xpctxt->tmpNsList);
12566         xpctxt->tmpNsList = NULL;
12567     }
12568 
12569 #ifdef DEBUG_STEP
12570     xmlGenericError(xmlGenericErrorContext,
12571 	"\nExamined %d nodes, found %d nodes at that step\n",
12572 	total, nbMatches);
12573 #endif
12574 
12575     return(total);
12576 }
12577 
12578 static int
12579 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12580 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12581 
12582 /**
12583  * xmlXPathCompOpEvalFirst:
12584  * @ctxt:  the XPath parser context with the compiled expression
12585  * @op:  an XPath compiled operation
12586  * @first:  the first elem found so far
12587  *
12588  * Evaluate the Precompiled XPath operation searching only the first
12589  * element in document order
12590  *
12591  * Returns the number of examined objects.
12592  */
12593 static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12594 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12595                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12596 {
12597     int total = 0, cur;
12598     xmlXPathCompExprPtr comp;
12599     xmlXPathObjectPtr arg1, arg2;
12600 
12601     CHECK_ERROR0;
12602     if (OP_LIMIT_EXCEEDED(ctxt, 1))
12603         return(0);
12604     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12605         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12606     ctxt->context->depth += 1;
12607     comp = ctxt->comp;
12608     switch (op->op) {
12609         case XPATH_OP_END:
12610             break;
12611         case XPATH_OP_UNION:
12612             total =
12613                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12614                                         first);
12615 	    CHECK_ERROR0;
12616             if ((ctxt->value != NULL)
12617                 && (ctxt->value->type == XPATH_NODESET)
12618                 && (ctxt->value->nodesetval != NULL)
12619                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12620                 /*
12621                  * limit tree traversing to first node in the result
12622                  */
12623 		/*
12624 		* OPTIMIZE TODO: This implicitly sorts
12625 		*  the result, even if not needed. E.g. if the argument
12626 		*  of the count() function, no sorting is needed.
12627 		* OPTIMIZE TODO: How do we know if the node-list wasn't
12628 		*  already sorted?
12629 		*/
12630 		if (ctxt->value->nodesetval->nodeNr > 1)
12631 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12632                 *first = ctxt->value->nodesetval->nodeTab[0];
12633             }
12634             cur =
12635                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12636                                         first);
12637 	    CHECK_ERROR0;
12638 
12639             arg2 = valuePop(ctxt);
12640             arg1 = valuePop(ctxt);
12641             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12642                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12643 	        xmlXPathReleaseObject(ctxt->context, arg1);
12644 	        xmlXPathReleaseObject(ctxt->context, arg2);
12645                 XP_ERROR0(XPATH_INVALID_TYPE);
12646             }
12647             if ((ctxt->context->opLimit != 0) &&
12648                 (((arg1->nodesetval != NULL) &&
12649                   (xmlXPathCheckOpLimit(ctxt,
12650                                         arg1->nodesetval->nodeNr) < 0)) ||
12651                  ((arg2->nodesetval != NULL) &&
12652                   (xmlXPathCheckOpLimit(ctxt,
12653                                         arg2->nodesetval->nodeNr) < 0)))) {
12654 	        xmlXPathReleaseObject(ctxt->context, arg1);
12655 	        xmlXPathReleaseObject(ctxt->context, arg2);
12656                 break;
12657             }
12658 
12659             /* TODO: Check memory error. */
12660             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12661                                                     arg2->nodesetval);
12662             valuePush(ctxt, arg1);
12663 	    xmlXPathReleaseObject(ctxt->context, arg2);
12664             /* optimizer */
12665 	    if (total > cur)
12666 		xmlXPathCompSwap(op);
12667             total += cur;
12668             break;
12669         case XPATH_OP_ROOT:
12670             xmlXPathRoot(ctxt);
12671             break;
12672         case XPATH_OP_NODE:
12673             if (op->ch1 != -1)
12674                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12675 	    CHECK_ERROR0;
12676             if (op->ch2 != -1)
12677                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12678 	    CHECK_ERROR0;
12679 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12680 		ctxt->context->node));
12681             break;
12682         case XPATH_OP_COLLECT:{
12683                 if (op->ch1 == -1)
12684                     break;
12685 
12686                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12687 		CHECK_ERROR0;
12688 
12689                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12690                 break;
12691             }
12692         case XPATH_OP_VALUE:
12693             valuePush(ctxt,
12694                       xmlXPathCacheObjectCopy(ctxt->context,
12695 			(xmlXPathObjectPtr) op->value4));
12696             break;
12697         case XPATH_OP_SORT:
12698             if (op->ch1 != -1)
12699                 total +=
12700                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12701                                             first);
12702 	    CHECK_ERROR0;
12703             if ((ctxt->value != NULL)
12704                 && (ctxt->value->type == XPATH_NODESET)
12705                 && (ctxt->value->nodesetval != NULL)
12706 		&& (ctxt->value->nodesetval->nodeNr > 1))
12707                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12708             break;
12709 #ifdef XP_OPTIMIZED_FILTER_FIRST
12710 	case XPATH_OP_FILTER:
12711                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12712             break;
12713 #endif
12714         default:
12715             total += xmlXPathCompOpEval(ctxt, op);
12716             break;
12717     }
12718 
12719     ctxt->context->depth -= 1;
12720     return(total);
12721 }
12722 
12723 /**
12724  * xmlXPathCompOpEvalLast:
12725  * @ctxt:  the XPath parser context with the compiled expression
12726  * @op:  an XPath compiled operation
12727  * @last:  the last elem found so far
12728  *
12729  * Evaluate the Precompiled XPath operation searching only the last
12730  * element in document order
12731  *
12732  * Returns the number of nodes traversed
12733  */
12734 static int
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * last)12735 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12736                        xmlNodePtr * last)
12737 {
12738     int total = 0, cur;
12739     xmlXPathCompExprPtr comp;
12740     xmlXPathObjectPtr arg1, arg2;
12741 
12742     CHECK_ERROR0;
12743     if (OP_LIMIT_EXCEEDED(ctxt, 1))
12744         return(0);
12745     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12746         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12747     ctxt->context->depth += 1;
12748     comp = ctxt->comp;
12749     switch (op->op) {
12750         case XPATH_OP_END:
12751             break;
12752         case XPATH_OP_UNION:
12753             total =
12754                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12755 	    CHECK_ERROR0;
12756             if ((ctxt->value != NULL)
12757                 && (ctxt->value->type == XPATH_NODESET)
12758                 && (ctxt->value->nodesetval != NULL)
12759                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12760                 /*
12761                  * limit tree traversing to first node in the result
12762                  */
12763 		if (ctxt->value->nodesetval->nodeNr > 1)
12764 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12765                 *last =
12766                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12767                                                      nodesetval->nodeNr -
12768                                                      1];
12769             }
12770             cur =
12771                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12772 	    CHECK_ERROR0;
12773             if ((ctxt->value != NULL)
12774                 && (ctxt->value->type == XPATH_NODESET)
12775                 && (ctxt->value->nodesetval != NULL)
12776                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12777             }
12778 
12779             arg2 = valuePop(ctxt);
12780             arg1 = valuePop(ctxt);
12781             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12782                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12783 	        xmlXPathReleaseObject(ctxt->context, arg1);
12784 	        xmlXPathReleaseObject(ctxt->context, arg2);
12785                 XP_ERROR0(XPATH_INVALID_TYPE);
12786             }
12787             if ((ctxt->context->opLimit != 0) &&
12788                 (((arg1->nodesetval != NULL) &&
12789                   (xmlXPathCheckOpLimit(ctxt,
12790                                         arg1->nodesetval->nodeNr) < 0)) ||
12791                  ((arg2->nodesetval != NULL) &&
12792                   (xmlXPathCheckOpLimit(ctxt,
12793                                         arg2->nodesetval->nodeNr) < 0)))) {
12794 	        xmlXPathReleaseObject(ctxt->context, arg1);
12795 	        xmlXPathReleaseObject(ctxt->context, arg2);
12796                 break;
12797             }
12798 
12799             /* TODO: Check memory error. */
12800             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12801                                                     arg2->nodesetval);
12802             valuePush(ctxt, arg1);
12803 	    xmlXPathReleaseObject(ctxt->context, arg2);
12804             /* optimizer */
12805 	    if (total > cur)
12806 		xmlXPathCompSwap(op);
12807             total += cur;
12808             break;
12809         case XPATH_OP_ROOT:
12810             xmlXPathRoot(ctxt);
12811             break;
12812         case XPATH_OP_NODE:
12813             if (op->ch1 != -1)
12814                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12815 	    CHECK_ERROR0;
12816             if (op->ch2 != -1)
12817                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12818 	    CHECK_ERROR0;
12819 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12820 		ctxt->context->node));
12821             break;
12822         case XPATH_OP_COLLECT:{
12823                 if (op->ch1 == -1)
12824                     break;
12825 
12826                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12827 		CHECK_ERROR0;
12828 
12829                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12830                 break;
12831             }
12832         case XPATH_OP_VALUE:
12833             valuePush(ctxt,
12834                       xmlXPathCacheObjectCopy(ctxt->context,
12835 			(xmlXPathObjectPtr) op->value4));
12836             break;
12837         case XPATH_OP_SORT:
12838             if (op->ch1 != -1)
12839                 total +=
12840                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12841                                            last);
12842 	    CHECK_ERROR0;
12843             if ((ctxt->value != NULL)
12844                 && (ctxt->value->type == XPATH_NODESET)
12845                 && (ctxt->value->nodesetval != NULL)
12846 		&& (ctxt->value->nodesetval->nodeNr > 1))
12847                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12848             break;
12849         default:
12850             total += xmlXPathCompOpEval(ctxt, op);
12851             break;
12852     }
12853 
12854     ctxt->context->depth -= 1;
12855     return (total);
12856 }
12857 
12858 #ifdef XP_OPTIMIZED_FILTER_FIRST
12859 static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12860 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12861 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
12862 {
12863     int total = 0;
12864     xmlXPathCompExprPtr comp;
12865     xmlNodeSetPtr set;
12866 
12867     CHECK_ERROR0;
12868     comp = ctxt->comp;
12869     /*
12870     * Optimization for ()[last()] selection i.e. the last elem
12871     */
12872     if ((op->ch1 != -1) && (op->ch2 != -1) &&
12873 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12874 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12875 	int f = comp->steps[op->ch2].ch1;
12876 
12877 	if ((f != -1) &&
12878 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12879 	    (comp->steps[f].value5 == NULL) &&
12880 	    (comp->steps[f].value == 0) &&
12881 	    (comp->steps[f].value4 != NULL) &&
12882 	    (xmlStrEqual
12883 	    (comp->steps[f].value4, BAD_CAST "last"))) {
12884 	    xmlNodePtr last = NULL;
12885 
12886 	    total +=
12887 		xmlXPathCompOpEvalLast(ctxt,
12888 		    &comp->steps[op->ch1],
12889 		    &last);
12890 	    CHECK_ERROR0;
12891 	    /*
12892 	    * The nodeset should be in document order,
12893 	    * Keep only the last value
12894 	    */
12895 	    if ((ctxt->value != NULL) &&
12896 		(ctxt->value->type == XPATH_NODESET) &&
12897 		(ctxt->value->nodesetval != NULL) &&
12898 		(ctxt->value->nodesetval->nodeTab != NULL) &&
12899 		(ctxt->value->nodesetval->nodeNr > 1)) {
12900                 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12901 		*first = *(ctxt->value->nodesetval->nodeTab);
12902 	    }
12903 	    return (total);
12904 	}
12905     }
12906 
12907     if (op->ch1 != -1)
12908 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12909     CHECK_ERROR0;
12910     if (op->ch2 == -1)
12911 	return (total);
12912     if (ctxt->value == NULL)
12913 	return (total);
12914 
12915 #ifdef LIBXML_XPTR_LOCS_ENABLED
12916     /*
12917     * Hum are we filtering the result of an XPointer expression
12918     */
12919     if (ctxt->value->type == XPATH_LOCATIONSET) {
12920         xmlLocationSetPtr locset = ctxt->value->user;
12921 
12922         if (locset != NULL) {
12923             xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12924             if (locset->locNr > 0)
12925                 *first = (xmlNodePtr) locset->locTab[0]->user;
12926         }
12927 
12928 	return (total);
12929     }
12930 #endif /* LIBXML_XPTR_LOCS_ENABLED */
12931 
12932     CHECK_TYPE0(XPATH_NODESET);
12933     set = ctxt->value->nodesetval;
12934     if (set != NULL) {
12935         xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12936         if (set->nodeNr > 0)
12937             *first = set->nodeTab[0];
12938     }
12939 
12940     return (total);
12941 }
12942 #endif /* XP_OPTIMIZED_FILTER_FIRST */
12943 
12944 /**
12945  * xmlXPathCompOpEval:
12946  * @ctxt:  the XPath parser context with the compiled expression
12947  * @op:  an XPath compiled operation
12948  *
12949  * Evaluate the Precompiled XPath operation
12950  * Returns the number of nodes traversed
12951  */
12952 static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op)12953 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12954 {
12955     int total = 0;
12956     int equal, ret;
12957     xmlXPathCompExprPtr comp;
12958     xmlXPathObjectPtr arg1, arg2;
12959 
12960     CHECK_ERROR0;
12961     if (OP_LIMIT_EXCEEDED(ctxt, 1))
12962         return(0);
12963     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12964         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12965     ctxt->context->depth += 1;
12966     comp = ctxt->comp;
12967     switch (op->op) {
12968         case XPATH_OP_END:
12969             break;
12970         case XPATH_OP_AND:
12971             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12972 	    CHECK_ERROR0;
12973             xmlXPathBooleanFunction(ctxt, 1);
12974             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12975                 break;
12976             arg2 = valuePop(ctxt);
12977             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12978 	    if (ctxt->error) {
12979 		xmlXPathFreeObject(arg2);
12980 		break;
12981 	    }
12982             xmlXPathBooleanFunction(ctxt, 1);
12983             if (ctxt->value != NULL)
12984                 ctxt->value->boolval &= arg2->boolval;
12985 	    xmlXPathReleaseObject(ctxt->context, arg2);
12986             break;
12987         case XPATH_OP_OR:
12988             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12989 	    CHECK_ERROR0;
12990             xmlXPathBooleanFunction(ctxt, 1);
12991             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12992                 break;
12993             arg2 = valuePop(ctxt);
12994             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12995 	    if (ctxt->error) {
12996 		xmlXPathFreeObject(arg2);
12997 		break;
12998 	    }
12999             xmlXPathBooleanFunction(ctxt, 1);
13000             if (ctxt->value != NULL)
13001                 ctxt->value->boolval |= arg2->boolval;
13002 	    xmlXPathReleaseObject(ctxt->context, arg2);
13003             break;
13004         case XPATH_OP_EQUAL:
13005             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13006 	    CHECK_ERROR0;
13007             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13008 	    CHECK_ERROR0;
13009 	    if (op->value)
13010 		equal = xmlXPathEqualValues(ctxt);
13011 	    else
13012 		equal = xmlXPathNotEqualValues(ctxt);
13013 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13014             break;
13015         case XPATH_OP_CMP:
13016             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13017 	    CHECK_ERROR0;
13018             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13019 	    CHECK_ERROR0;
13020             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13021 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13022             break;
13023         case XPATH_OP_PLUS:
13024             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13025 	    CHECK_ERROR0;
13026             if (op->ch2 != -1) {
13027                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13028 	    }
13029 	    CHECK_ERROR0;
13030             if (op->value == 0)
13031                 xmlXPathSubValues(ctxt);
13032             else if (op->value == 1)
13033                 xmlXPathAddValues(ctxt);
13034             else if (op->value == 2)
13035                 xmlXPathValueFlipSign(ctxt);
13036             else if (op->value == 3) {
13037                 CAST_TO_NUMBER;
13038                 CHECK_TYPE0(XPATH_NUMBER);
13039             }
13040             break;
13041         case XPATH_OP_MULT:
13042             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13043 	    CHECK_ERROR0;
13044             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13045 	    CHECK_ERROR0;
13046             if (op->value == 0)
13047                 xmlXPathMultValues(ctxt);
13048             else if (op->value == 1)
13049                 xmlXPathDivValues(ctxt);
13050             else if (op->value == 2)
13051                 xmlXPathModValues(ctxt);
13052             break;
13053         case XPATH_OP_UNION:
13054             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13055 	    CHECK_ERROR0;
13056             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13057 	    CHECK_ERROR0;
13058 
13059             arg2 = valuePop(ctxt);
13060             arg1 = valuePop(ctxt);
13061             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13062                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13063 	        xmlXPathReleaseObject(ctxt->context, arg1);
13064 	        xmlXPathReleaseObject(ctxt->context, arg2);
13065                 XP_ERROR0(XPATH_INVALID_TYPE);
13066             }
13067             if ((ctxt->context->opLimit != 0) &&
13068                 (((arg1->nodesetval != NULL) &&
13069                   (xmlXPathCheckOpLimit(ctxt,
13070                                         arg1->nodesetval->nodeNr) < 0)) ||
13071                  ((arg2->nodesetval != NULL) &&
13072                   (xmlXPathCheckOpLimit(ctxt,
13073                                         arg2->nodesetval->nodeNr) < 0)))) {
13074 	        xmlXPathReleaseObject(ctxt->context, arg1);
13075 	        xmlXPathReleaseObject(ctxt->context, arg2);
13076                 break;
13077             }
13078 
13079 	    if ((arg1->nodesetval == NULL) ||
13080 		((arg2->nodesetval != NULL) &&
13081 		 (arg2->nodesetval->nodeNr != 0)))
13082 	    {
13083                 /* TODO: Check memory error. */
13084 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13085 							arg2->nodesetval);
13086 	    }
13087 
13088             valuePush(ctxt, arg1);
13089 	    xmlXPathReleaseObject(ctxt->context, arg2);
13090             break;
13091         case XPATH_OP_ROOT:
13092             xmlXPathRoot(ctxt);
13093             break;
13094         case XPATH_OP_NODE:
13095             if (op->ch1 != -1)
13096                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13097 	    CHECK_ERROR0;
13098             if (op->ch2 != -1)
13099                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13100 	    CHECK_ERROR0;
13101 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13102 		ctxt->context->node));
13103             break;
13104         case XPATH_OP_COLLECT:{
13105                 if (op->ch1 == -1)
13106                     break;
13107 
13108                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13109 		CHECK_ERROR0;
13110 
13111                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13112                 break;
13113             }
13114         case XPATH_OP_VALUE:
13115             valuePush(ctxt,
13116                       xmlXPathCacheObjectCopy(ctxt->context,
13117 			(xmlXPathObjectPtr) op->value4));
13118             break;
13119         case XPATH_OP_VARIABLE:{
13120 		xmlXPathObjectPtr val;
13121 
13122                 if (op->ch1 != -1)
13123                     total +=
13124                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13125                 if (op->value5 == NULL) {
13126 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13127 		    if (val == NULL)
13128 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13129                     valuePush(ctxt, val);
13130 		} else {
13131                     const xmlChar *URI;
13132 
13133                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13134                     if (URI == NULL) {
13135                         xmlGenericError(xmlGenericErrorContext,
13136             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13137                                     (char *) op->value4, (char *)op->value5);
13138                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13139                         break;
13140                     }
13141 		    val = xmlXPathVariableLookupNS(ctxt->context,
13142                                                        op->value4, URI);
13143 		    if (val == NULL)
13144 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13145                     valuePush(ctxt, val);
13146                 }
13147                 break;
13148             }
13149         case XPATH_OP_FUNCTION:{
13150                 xmlXPathFunction func;
13151                 const xmlChar *oldFunc, *oldFuncURI;
13152 		int i;
13153                 int frame;
13154 
13155                 frame = xmlXPathSetFrame(ctxt);
13156                 if (op->ch1 != -1) {
13157                     total +=
13158                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13159                     if (ctxt->error != XPATH_EXPRESSION_OK) {
13160                         xmlXPathPopFrame(ctxt, frame);
13161                         break;
13162                     }
13163                 }
13164 		if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13165 		    xmlGenericError(xmlGenericErrorContext,
13166 			    "xmlXPathCompOpEval: parameter error\n");
13167 		    ctxt->error = XPATH_INVALID_OPERAND;
13168                     xmlXPathPopFrame(ctxt, frame);
13169 		    break;
13170 		}
13171 		for (i = 0; i < op->value; i++) {
13172 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13173 			xmlGenericError(xmlGenericErrorContext,
13174 				"xmlXPathCompOpEval: parameter error\n");
13175 			ctxt->error = XPATH_INVALID_OPERAND;
13176                         xmlXPathPopFrame(ctxt, frame);
13177 			break;
13178 		    }
13179                 }
13180                 if (op->cache != NULL)
13181                     func = op->cache;
13182                 else {
13183                     const xmlChar *URI = NULL;
13184 
13185                     if (op->value5 == NULL)
13186                         func =
13187                             xmlXPathFunctionLookup(ctxt->context,
13188                                                    op->value4);
13189                     else {
13190                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
13191                         if (URI == NULL) {
13192                             xmlGenericError(xmlGenericErrorContext,
13193             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13194                                     (char *)op->value4, (char *)op->value5);
13195                             xmlXPathPopFrame(ctxt, frame);
13196                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13197                             break;
13198                         }
13199                         func = xmlXPathFunctionLookupNS(ctxt->context,
13200                                                         op->value4, URI);
13201                     }
13202                     if (func == NULL) {
13203                         xmlGenericError(xmlGenericErrorContext,
13204                                 "xmlXPathCompOpEval: function %s not found\n",
13205                                         (char *)op->value4);
13206                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13207                     }
13208                     op->cache = func;
13209                     op->cacheURI = (void *) URI;
13210                 }
13211                 oldFunc = ctxt->context->function;
13212                 oldFuncURI = ctxt->context->functionURI;
13213                 ctxt->context->function = op->value4;
13214                 ctxt->context->functionURI = op->cacheURI;
13215                 func(ctxt, op->value);
13216                 ctxt->context->function = oldFunc;
13217                 ctxt->context->functionURI = oldFuncURI;
13218                 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13219                     (ctxt->valueNr != ctxt->valueFrame + 1))
13220                     XP_ERROR0(XPATH_STACK_ERROR);
13221                 xmlXPathPopFrame(ctxt, frame);
13222                 break;
13223             }
13224         case XPATH_OP_ARG:
13225             if (op->ch1 != -1) {
13226                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13227 	        CHECK_ERROR0;
13228             }
13229             if (op->ch2 != -1) {
13230                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13231 	        CHECK_ERROR0;
13232 	    }
13233             break;
13234         case XPATH_OP_PREDICATE:
13235         case XPATH_OP_FILTER:{
13236                 xmlNodeSetPtr set;
13237 
13238                 /*
13239                  * Optimization for ()[1] selection i.e. the first elem
13240                  */
13241                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13242 #ifdef XP_OPTIMIZED_FILTER_FIRST
13243 		    /*
13244 		    * FILTER TODO: Can we assume that the inner processing
13245 		    *  will result in an ordered list if we have an
13246 		    *  XPATH_OP_FILTER?
13247 		    *  What about an additional field or flag on
13248 		    *  xmlXPathObject like @sorted ? This way we wouldn't need
13249 		    *  to assume anything, so it would be more robust and
13250 		    *  easier to optimize.
13251 		    */
13252                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13253 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13254 #else
13255 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13256 #endif
13257                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13258                     xmlXPathObjectPtr val;
13259 
13260                     val = comp->steps[op->ch2].value4;
13261                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13262                         (val->floatval == 1.0)) {
13263                         xmlNodePtr first = NULL;
13264 
13265                         total +=
13266                             xmlXPathCompOpEvalFirst(ctxt,
13267                                                     &comp->steps[op->ch1],
13268                                                     &first);
13269 			CHECK_ERROR0;
13270                         /*
13271                          * The nodeset should be in document order,
13272                          * Keep only the first value
13273                          */
13274                         if ((ctxt->value != NULL) &&
13275                             (ctxt->value->type == XPATH_NODESET) &&
13276                             (ctxt->value->nodesetval != NULL) &&
13277                             (ctxt->value->nodesetval->nodeNr > 1))
13278                             xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13279                                                         1, 1);
13280                         break;
13281                     }
13282                 }
13283                 /*
13284                  * Optimization for ()[last()] selection i.e. the last elem
13285                  */
13286                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13287                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13288                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13289                     int f = comp->steps[op->ch2].ch1;
13290 
13291                     if ((f != -1) &&
13292                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13293                         (comp->steps[f].value5 == NULL) &&
13294                         (comp->steps[f].value == 0) &&
13295                         (comp->steps[f].value4 != NULL) &&
13296                         (xmlStrEqual
13297                          (comp->steps[f].value4, BAD_CAST "last"))) {
13298                         xmlNodePtr last = NULL;
13299 
13300                         total +=
13301                             xmlXPathCompOpEvalLast(ctxt,
13302                                                    &comp->steps[op->ch1],
13303                                                    &last);
13304 			CHECK_ERROR0;
13305                         /*
13306                          * The nodeset should be in document order,
13307                          * Keep only the last value
13308                          */
13309                         if ((ctxt->value != NULL) &&
13310                             (ctxt->value->type == XPATH_NODESET) &&
13311                             (ctxt->value->nodesetval != NULL) &&
13312                             (ctxt->value->nodesetval->nodeTab != NULL) &&
13313                             (ctxt->value->nodesetval->nodeNr > 1))
13314                             xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13315                         break;
13316                     }
13317                 }
13318 		/*
13319 		* Process inner predicates first.
13320 		* Example "index[parent::book][1]":
13321 		* ...
13322 		*   PREDICATE   <-- we are here "[1]"
13323 		*     PREDICATE <-- process "[parent::book]" first
13324 		*       SORT
13325 		*         COLLECT  'parent' 'name' 'node' book
13326 		*           NODE
13327 		*     ELEM Object is a number : 1
13328 		*/
13329                 if (op->ch1 != -1)
13330                     total +=
13331                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13332 		CHECK_ERROR0;
13333                 if (op->ch2 == -1)
13334                     break;
13335                 if (ctxt->value == NULL)
13336                     break;
13337 
13338 #ifdef LIBXML_XPTR_LOCS_ENABLED
13339                 /*
13340                  * Hum are we filtering the result of an XPointer expression
13341                  */
13342                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13343                     xmlLocationSetPtr locset = ctxt->value->user;
13344                     xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13345                                               1, locset->locNr);
13346                     break;
13347                 }
13348 #endif /* LIBXML_XPTR_LOCS_ENABLED */
13349 
13350                 CHECK_TYPE0(XPATH_NODESET);
13351                 set = ctxt->value->nodesetval;
13352                 if (set != NULL)
13353                     xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13354                                           1, set->nodeNr, 1);
13355                 break;
13356             }
13357         case XPATH_OP_SORT:
13358             if (op->ch1 != -1)
13359                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13360 	    CHECK_ERROR0;
13361             if ((ctxt->value != NULL) &&
13362                 (ctxt->value->type == XPATH_NODESET) &&
13363                 (ctxt->value->nodesetval != NULL) &&
13364 		(ctxt->value->nodesetval->nodeNr > 1))
13365 	    {
13366                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13367 	    }
13368             break;
13369 #ifdef LIBXML_XPTR_LOCS_ENABLED
13370         case XPATH_OP_RANGETO:{
13371                 xmlXPathObjectPtr range;
13372                 xmlXPathObjectPtr res, obj;
13373                 xmlXPathObjectPtr tmp;
13374                 xmlLocationSetPtr newlocset = NULL;
13375 		    xmlLocationSetPtr oldlocset;
13376                 xmlNodeSetPtr oldset;
13377                 xmlNodePtr oldnode = ctxt->context->node;
13378                 int oldcs = ctxt->context->contextSize;
13379                 int oldpp = ctxt->context->proximityPosition;
13380                 int i, j;
13381 
13382                 if (op->ch1 != -1) {
13383                     total +=
13384                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13385                     CHECK_ERROR0;
13386                 }
13387                 if (ctxt->value == NULL) {
13388                     XP_ERROR0(XPATH_INVALID_OPERAND);
13389                 }
13390                 if (op->ch2 == -1)
13391                     break;
13392 
13393                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13394                     /*
13395                      * Extract the old locset, and then evaluate the result of the
13396                      * expression for all the element in the locset. use it to grow
13397                      * up a new locset.
13398                      */
13399                     CHECK_TYPE0(XPATH_LOCATIONSET);
13400 
13401                     if ((ctxt->value->user == NULL) ||
13402                         (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13403                         break;
13404 
13405                     obj = valuePop(ctxt);
13406                     oldlocset = obj->user;
13407 
13408                     newlocset = xmlXPtrLocationSetCreate(NULL);
13409 
13410                     for (i = 0; i < oldlocset->locNr; i++) {
13411                         /*
13412                          * Run the evaluation with a node list made of a
13413                          * single item in the nodelocset.
13414                          */
13415                         ctxt->context->node = oldlocset->locTab[i]->user;
13416                         ctxt->context->contextSize = oldlocset->locNr;
13417                         ctxt->context->proximityPosition = i + 1;
13418 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13419 			    ctxt->context->node);
13420                         valuePush(ctxt, tmp);
13421 
13422                         if (op->ch2 != -1)
13423                             total +=
13424                                 xmlXPathCompOpEval(ctxt,
13425                                                    &comp->steps[op->ch2]);
13426 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13427                             xmlXPtrFreeLocationSet(newlocset);
13428                             goto rangeto_error;
13429 			}
13430 
13431                         res = valuePop(ctxt);
13432 			if (res->type == XPATH_LOCATIONSET) {
13433 			    xmlLocationSetPtr rloc =
13434 			        (xmlLocationSetPtr)res->user;
13435 			    for (j=0; j<rloc->locNr; j++) {
13436 			        range = xmlXPtrNewRange(
13437 				  oldlocset->locTab[i]->user,
13438 				  oldlocset->locTab[i]->index,
13439 				  rloc->locTab[j]->user2,
13440 				  rloc->locTab[j]->index2);
13441 				if (range != NULL) {
13442 				    xmlXPtrLocationSetAdd(newlocset, range);
13443 				}
13444 			    }
13445 			} else {
13446 			    range = xmlXPtrNewRangeNodeObject(
13447 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
13448                             if (range != NULL) {
13449                                 xmlXPtrLocationSetAdd(newlocset,range);
13450 			    }
13451                         }
13452 
13453                         /*
13454                          * Cleanup
13455                          */
13456                         if (res != NULL) {
13457 			    xmlXPathReleaseObject(ctxt->context, res);
13458 			}
13459                         if (ctxt->value == tmp) {
13460                             res = valuePop(ctxt);
13461 			    xmlXPathReleaseObject(ctxt->context, res);
13462                         }
13463                     }
13464 		} else {	/* Not a location set */
13465                     CHECK_TYPE0(XPATH_NODESET);
13466                     obj = valuePop(ctxt);
13467                     oldset = obj->nodesetval;
13468 
13469                     newlocset = xmlXPtrLocationSetCreate(NULL);
13470 
13471                     if (oldset != NULL) {
13472                         for (i = 0; i < oldset->nodeNr; i++) {
13473                             /*
13474                              * Run the evaluation with a node list made of a single item
13475                              * in the nodeset.
13476                              */
13477                             ctxt->context->node = oldset->nodeTab[i];
13478 			    /*
13479 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
13480 			    */
13481 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13482 				ctxt->context->node);
13483                             valuePush(ctxt, tmp);
13484 
13485                             if (op->ch2 != -1)
13486                                 total +=
13487                                     xmlXPathCompOpEval(ctxt,
13488                                                    &comp->steps[op->ch2]);
13489 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
13490                                 xmlXPtrFreeLocationSet(newlocset);
13491                                 goto rangeto_error;
13492 			    }
13493 
13494                             res = valuePop(ctxt);
13495                             range =
13496                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13497                                                       res);
13498                             if (range != NULL) {
13499                                 xmlXPtrLocationSetAdd(newlocset, range);
13500                             }
13501 
13502                             /*
13503                              * Cleanup
13504                              */
13505                             if (res != NULL) {
13506 				xmlXPathReleaseObject(ctxt->context, res);
13507 			    }
13508                             if (ctxt->value == tmp) {
13509                                 res = valuePop(ctxt);
13510 				xmlXPathReleaseObject(ctxt->context, res);
13511                             }
13512                         }
13513                     }
13514                 }
13515 
13516                 /*
13517                  * The result is used as the new evaluation set.
13518                  */
13519                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13520 rangeto_error:
13521 		xmlXPathReleaseObject(ctxt->context, obj);
13522                 ctxt->context->node = oldnode;
13523                 ctxt->context->contextSize = oldcs;
13524                 ctxt->context->proximityPosition = oldpp;
13525                 break;
13526             }
13527 #endif /* LIBXML_XPTR_LOCS_ENABLED */
13528         default:
13529             xmlGenericError(xmlGenericErrorContext,
13530                             "XPath: unknown precompiled operation %d\n", op->op);
13531             ctxt->error = XPATH_INVALID_OPERAND;
13532             break;
13533     }
13534 
13535     ctxt->context->depth -= 1;
13536     return (total);
13537 }
13538 
13539 /**
13540  * xmlXPathCompOpEvalToBoolean:
13541  * @ctxt:  the XPath parser context
13542  *
13543  * Evaluates if the expression evaluates to true.
13544  *
13545  * Returns 1 if true, 0 if false and -1 on API or internal errors.
13546  */
13547 static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int isPredicate)13548 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13549 			    xmlXPathStepOpPtr op,
13550 			    int isPredicate)
13551 {
13552     xmlXPathObjectPtr resObj = NULL;
13553 
13554 start:
13555     if (OP_LIMIT_EXCEEDED(ctxt, 1))
13556         return(0);
13557     /* comp = ctxt->comp; */
13558     switch (op->op) {
13559         case XPATH_OP_END:
13560             return (0);
13561 	case XPATH_OP_VALUE:
13562 	    resObj = (xmlXPathObjectPtr) op->value4;
13563 	    if (isPredicate)
13564 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13565 	    return(xmlXPathCastToBoolean(resObj));
13566 	case XPATH_OP_SORT:
13567 	    /*
13568 	    * We don't need sorting for boolean results. Skip this one.
13569 	    */
13570             if (op->ch1 != -1) {
13571 		op = &ctxt->comp->steps[op->ch1];
13572 		goto start;
13573 	    }
13574 	    return(0);
13575 	case XPATH_OP_COLLECT:
13576 	    if (op->ch1 == -1)
13577 		return(0);
13578 
13579             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13580 	    if (ctxt->error != XPATH_EXPRESSION_OK)
13581 		return(-1);
13582 
13583             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13584 	    if (ctxt->error != XPATH_EXPRESSION_OK)
13585 		return(-1);
13586 
13587 	    resObj = valuePop(ctxt);
13588 	    if (resObj == NULL)
13589 		return(-1);
13590 	    break;
13591 	default:
13592 	    /*
13593 	    * Fallback to call xmlXPathCompOpEval().
13594 	    */
13595 	    xmlXPathCompOpEval(ctxt, op);
13596 	    if (ctxt->error != XPATH_EXPRESSION_OK)
13597 		return(-1);
13598 
13599 	    resObj = valuePop(ctxt);
13600 	    if (resObj == NULL)
13601 		return(-1);
13602 	    break;
13603     }
13604 
13605     if (resObj) {
13606 	int res;
13607 
13608 	if (resObj->type == XPATH_BOOLEAN) {
13609 	    res = resObj->boolval;
13610 	} else if (isPredicate) {
13611 	    /*
13612 	    * For predicates a result of type "number" is handled
13613 	    * differently:
13614 	    * SPEC XPath 1.0:
13615 	    * "If the result is a number, the result will be converted
13616 	    *  to true if the number is equal to the context position
13617 	    *  and will be converted to false otherwise;"
13618 	    */
13619 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13620 	} else {
13621 	    res = xmlXPathCastToBoolean(resObj);
13622 	}
13623 	xmlXPathReleaseObject(ctxt->context, resObj);
13624 	return(res);
13625     }
13626 
13627     return(0);
13628 }
13629 
13630 #ifdef XPATH_STREAMING
13631 /**
13632  * xmlXPathRunStreamEval:
13633  * @ctxt:  the XPath parser context with the compiled expression
13634  *
13635  * Evaluate the Precompiled Streamable XPath expression in the given context.
13636  */
13637 static int
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt,xmlPatternPtr comp,xmlXPathObjectPtr * resultSeq,int toBool)13638 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13639 		      xmlXPathObjectPtr *resultSeq, int toBool)
13640 {
13641     int max_depth, min_depth;
13642     int from_root;
13643     int ret, depth;
13644     int eval_all_nodes;
13645     xmlNodePtr cur = NULL, limit = NULL;
13646     xmlStreamCtxtPtr patstream = NULL;
13647 
13648     int nb_nodes = 0;
13649 
13650     if ((ctxt == NULL) || (comp == NULL))
13651         return(-1);
13652     max_depth = xmlPatternMaxDepth(comp);
13653     if (max_depth == -1)
13654         return(-1);
13655     if (max_depth == -2)
13656         max_depth = 10000;
13657     min_depth = xmlPatternMinDepth(comp);
13658     if (min_depth == -1)
13659         return(-1);
13660     from_root = xmlPatternFromRoot(comp);
13661     if (from_root < 0)
13662         return(-1);
13663 #if 0
13664     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13665 #endif
13666 
13667     if (! toBool) {
13668 	if (resultSeq == NULL)
13669 	    return(-1);
13670 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13671 	if (*resultSeq == NULL)
13672 	    return(-1);
13673     }
13674 
13675     /*
13676      * handle the special cases of "/" amd "." being matched
13677      */
13678     if (min_depth == 0) {
13679 	if (from_root) {
13680 	    /* Select "/" */
13681 	    if (toBool)
13682 		return(1);
13683             /* TODO: Check memory error. */
13684 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
13685 		                     (xmlNodePtr) ctxt->doc);
13686 	} else {
13687 	    /* Select "self::node()" */
13688 	    if (toBool)
13689 		return(1);
13690             /* TODO: Check memory error. */
13691 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13692 	}
13693     }
13694     if (max_depth == 0) {
13695 	return(0);
13696     }
13697 
13698     if (from_root) {
13699         cur = (xmlNodePtr)ctxt->doc;
13700     } else if (ctxt->node != NULL) {
13701         switch (ctxt->node->type) {
13702             case XML_ELEMENT_NODE:
13703             case XML_DOCUMENT_NODE:
13704             case XML_DOCUMENT_FRAG_NODE:
13705             case XML_HTML_DOCUMENT_NODE:
13706 	        cur = ctxt->node;
13707 		break;
13708             case XML_ATTRIBUTE_NODE:
13709             case XML_TEXT_NODE:
13710             case XML_CDATA_SECTION_NODE:
13711             case XML_ENTITY_REF_NODE:
13712             case XML_ENTITY_NODE:
13713             case XML_PI_NODE:
13714             case XML_COMMENT_NODE:
13715             case XML_NOTATION_NODE:
13716             case XML_DTD_NODE:
13717             case XML_DOCUMENT_TYPE_NODE:
13718             case XML_ELEMENT_DECL:
13719             case XML_ATTRIBUTE_DECL:
13720             case XML_ENTITY_DECL:
13721             case XML_NAMESPACE_DECL:
13722             case XML_XINCLUDE_START:
13723             case XML_XINCLUDE_END:
13724 		break;
13725 	}
13726 	limit = cur;
13727     }
13728     if (cur == NULL) {
13729         return(0);
13730     }
13731 
13732     patstream = xmlPatternGetStreamCtxt(comp);
13733     if (patstream == NULL) {
13734 	/*
13735 	* QUESTION TODO: Is this an error?
13736 	*/
13737 	return(0);
13738     }
13739 
13740     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13741 
13742     if (from_root) {
13743 	ret = xmlStreamPush(patstream, NULL, NULL);
13744 	if (ret < 0) {
13745 	} else if (ret == 1) {
13746 	    if (toBool)
13747 		goto return_1;
13748             /* TODO: Check memory error. */
13749 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13750 	}
13751     }
13752     depth = 0;
13753     goto scan_children;
13754 next_node:
13755     do {
13756         if (ctxt->opLimit != 0) {
13757             if (ctxt->opCount >= ctxt->opLimit) {
13758                 xmlGenericError(xmlGenericErrorContext,
13759                         "XPath operation limit exceeded\n");
13760                 xmlFreeStreamCtxt(patstream);
13761                 return(-1);
13762             }
13763             ctxt->opCount++;
13764         }
13765 
13766         nb_nodes++;
13767 
13768 	switch (cur->type) {
13769 	    case XML_ELEMENT_NODE:
13770 	    case XML_TEXT_NODE:
13771 	    case XML_CDATA_SECTION_NODE:
13772 	    case XML_COMMENT_NODE:
13773 	    case XML_PI_NODE:
13774 		if (cur->type == XML_ELEMENT_NODE) {
13775 		    ret = xmlStreamPush(patstream, cur->name,
13776 				(cur->ns ? cur->ns->href : NULL));
13777 		} else if (eval_all_nodes)
13778 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13779 		else
13780 		    break;
13781 
13782 		if (ret < 0) {
13783 		    /* NOP. */
13784 		} else if (ret == 1) {
13785 		    if (toBool)
13786 			goto return_1;
13787 		    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13788 		        < 0) {
13789 			ctxt->lastError.domain = XML_FROM_XPATH;
13790 			ctxt->lastError.code = XML_ERR_NO_MEMORY;
13791 		    }
13792 		}
13793 		if ((cur->children == NULL) || (depth >= max_depth)) {
13794 		    ret = xmlStreamPop(patstream);
13795 		    while (cur->next != NULL) {
13796 			cur = cur->next;
13797 			if ((cur->type != XML_ENTITY_DECL) &&
13798 			    (cur->type != XML_DTD_NODE))
13799 			    goto next_node;
13800 		    }
13801 		}
13802 	    default:
13803 		break;
13804 	}
13805 
13806 scan_children:
13807 	if (cur->type == XML_NAMESPACE_DECL) break;
13808 	if ((cur->children != NULL) && (depth < max_depth)) {
13809 	    /*
13810 	     * Do not descend on entities declarations
13811 	     */
13812 	    if (cur->children->type != XML_ENTITY_DECL) {
13813 		cur = cur->children;
13814 		depth++;
13815 		/*
13816 		 * Skip DTDs
13817 		 */
13818 		if (cur->type != XML_DTD_NODE)
13819 		    continue;
13820 	    }
13821 	}
13822 
13823 	if (cur == limit)
13824 	    break;
13825 
13826 	while (cur->next != NULL) {
13827 	    cur = cur->next;
13828 	    if ((cur->type != XML_ENTITY_DECL) &&
13829 		(cur->type != XML_DTD_NODE))
13830 		goto next_node;
13831 	}
13832 
13833 	do {
13834 	    cur = cur->parent;
13835 	    depth--;
13836 	    if ((cur == NULL) || (cur == limit) ||
13837                 (cur->type == XML_DOCUMENT_NODE))
13838 	        goto done;
13839 	    if (cur->type == XML_ELEMENT_NODE) {
13840 		ret = xmlStreamPop(patstream);
13841 	    } else if ((eval_all_nodes) &&
13842 		((cur->type == XML_TEXT_NODE) ||
13843 		 (cur->type == XML_CDATA_SECTION_NODE) ||
13844 		 (cur->type == XML_COMMENT_NODE) ||
13845 		 (cur->type == XML_PI_NODE)))
13846 	    {
13847 		ret = xmlStreamPop(patstream);
13848 	    }
13849 	    if (cur->next != NULL) {
13850 		cur = cur->next;
13851 		break;
13852 	    }
13853 	} while (cur != NULL);
13854 
13855     } while ((cur != NULL) && (depth >= 0));
13856 
13857 done:
13858 
13859 #if 0
13860     printf("stream eval: checked %d nodes selected %d\n",
13861            nb_nodes, retObj->nodesetval->nodeNr);
13862 #endif
13863 
13864     if (patstream)
13865 	xmlFreeStreamCtxt(patstream);
13866     return(0);
13867 
13868 return_1:
13869     if (patstream)
13870 	xmlFreeStreamCtxt(patstream);
13871     return(1);
13872 }
13873 #endif /* XPATH_STREAMING */
13874 
13875 /**
13876  * xmlXPathRunEval:
13877  * @ctxt:  the XPath parser context with the compiled expression
13878  * @toBool:  evaluate to a boolean result
13879  *
13880  * Evaluate the Precompiled XPath expression in the given context.
13881  */
13882 static int
xmlXPathRunEval(xmlXPathParserContextPtr ctxt,int toBool)13883 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13884 {
13885     xmlXPathCompExprPtr comp;
13886     int oldDepth;
13887 
13888     if ((ctxt == NULL) || (ctxt->comp == NULL))
13889 	return(-1);
13890 
13891     if (ctxt->valueTab == NULL) {
13892 	/* Allocate the value stack */
13893 	ctxt->valueTab = (xmlXPathObjectPtr *)
13894 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13895 	if (ctxt->valueTab == NULL) {
13896 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13897 	    return(-1);
13898 	}
13899 	ctxt->valueNr = 0;
13900 	ctxt->valueMax = 10;
13901 	ctxt->value = NULL;
13902         ctxt->valueFrame = 0;
13903     }
13904 #ifdef XPATH_STREAMING
13905     if (ctxt->comp->stream) {
13906 	int res;
13907 
13908 	if (toBool) {
13909 	    /*
13910 	    * Evaluation to boolean result.
13911 	    */
13912 	    res = xmlXPathRunStreamEval(ctxt->context,
13913 		ctxt->comp->stream, NULL, 1);
13914 	    if (res != -1)
13915 		return(res);
13916 	} else {
13917 	    xmlXPathObjectPtr resObj = NULL;
13918 
13919 	    /*
13920 	    * Evaluation to a sequence.
13921 	    */
13922 	    res = xmlXPathRunStreamEval(ctxt->context,
13923 		ctxt->comp->stream, &resObj, 0);
13924 
13925 	    if ((res != -1) && (resObj != NULL)) {
13926 		valuePush(ctxt, resObj);
13927 		return(0);
13928 	    }
13929 	    if (resObj != NULL)
13930 		xmlXPathReleaseObject(ctxt->context, resObj);
13931 	}
13932 	/*
13933 	* QUESTION TODO: This falls back to normal XPath evaluation
13934 	* if res == -1. Is this intended?
13935 	*/
13936     }
13937 #endif
13938     comp = ctxt->comp;
13939     if (comp->last < 0) {
13940 	xmlGenericError(xmlGenericErrorContext,
13941 	    "xmlXPathRunEval: last is less than zero\n");
13942 	return(-1);
13943     }
13944     oldDepth = ctxt->context->depth;
13945     if (toBool)
13946 	return(xmlXPathCompOpEvalToBoolean(ctxt,
13947 	    &comp->steps[comp->last], 0));
13948     else
13949 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13950     ctxt->context->depth = oldDepth;
13951 
13952     return(0);
13953 }
13954 
13955 /************************************************************************
13956  *									*
13957  *			Public interfaces				*
13958  *									*
13959  ************************************************************************/
13960 
13961 /**
13962  * xmlXPathEvalPredicate:
13963  * @ctxt:  the XPath context
13964  * @res:  the Predicate Expression evaluation result
13965  *
13966  * Evaluate a predicate result for the current node.
13967  * A PredicateExpr is evaluated by evaluating the Expr and converting
13968  * the result to a boolean. If the result is a number, the result will
13969  * be converted to true if the number is equal to the position of the
13970  * context node in the context node list (as returned by the position
13971  * function) and will be converted to false otherwise; if the result
13972  * is not a number, then the result will be converted as if by a call
13973  * to the boolean function.
13974  *
13975  * Returns 1 if predicate is true, 0 otherwise
13976  */
13977 int
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt,xmlXPathObjectPtr res)13978 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13979     if ((ctxt == NULL) || (res == NULL)) return(0);
13980     switch (res->type) {
13981         case XPATH_BOOLEAN:
13982 	    return(res->boolval);
13983         case XPATH_NUMBER:
13984 	    return(res->floatval == ctxt->proximityPosition);
13985         case XPATH_NODESET:
13986         case XPATH_XSLT_TREE:
13987 	    if (res->nodesetval == NULL)
13988 		return(0);
13989 	    return(res->nodesetval->nodeNr != 0);
13990         case XPATH_STRING:
13991 	    return((res->stringval != NULL) &&
13992 	           (xmlStrlen(res->stringval) != 0));
13993         default:
13994 	    STRANGE
13995     }
13996     return(0);
13997 }
13998 
13999 /**
14000  * xmlXPathEvaluatePredicateResult:
14001  * @ctxt:  the XPath Parser context
14002  * @res:  the Predicate Expression evaluation result
14003  *
14004  * Evaluate a predicate result for the current node.
14005  * A PredicateExpr is evaluated by evaluating the Expr and converting
14006  * the result to a boolean. If the result is a number, the result will
14007  * be converted to true if the number is equal to the position of the
14008  * context node in the context node list (as returned by the position
14009  * function) and will be converted to false otherwise; if the result
14010  * is not a number, then the result will be converted as if by a call
14011  * to the boolean function.
14012  *
14013  * Returns 1 if predicate is true, 0 otherwise
14014  */
14015 int
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr res)14016 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14017                                 xmlXPathObjectPtr res) {
14018     if ((ctxt == NULL) || (res == NULL)) return(0);
14019     switch (res->type) {
14020         case XPATH_BOOLEAN:
14021 	    return(res->boolval);
14022         case XPATH_NUMBER:
14023 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14024 	    return((res->floatval == ctxt->context->proximityPosition) &&
14025 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14026 #else
14027 	    return(res->floatval == ctxt->context->proximityPosition);
14028 #endif
14029         case XPATH_NODESET:
14030         case XPATH_XSLT_TREE:
14031 	    if (res->nodesetval == NULL)
14032 		return(0);
14033 	    return(res->nodesetval->nodeNr != 0);
14034         case XPATH_STRING:
14035 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
14036 #ifdef LIBXML_XPTR_LOCS_ENABLED
14037 	case XPATH_LOCATIONSET:{
14038 	    xmlLocationSetPtr ptr = res->user;
14039 	    if (ptr == NULL)
14040 	        return(0);
14041 	    return (ptr->locNr != 0);
14042 	    }
14043 #endif
14044         default:
14045 	    STRANGE
14046     }
14047     return(0);
14048 }
14049 
14050 #ifdef XPATH_STREAMING
14051 /**
14052  * xmlXPathTryStreamCompile:
14053  * @ctxt: an XPath context
14054  * @str:  the XPath expression
14055  *
14056  * Try to compile the XPath expression as a streamable subset.
14057  *
14058  * Returns the compiled expression or NULL if failed to compile.
14059  */
14060 static xmlXPathCompExprPtr
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14061 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14062     /*
14063      * Optimization: use streaming patterns when the XPath expression can
14064      * be compiled to a stream lookup
14065      */
14066     xmlPatternPtr stream;
14067     xmlXPathCompExprPtr comp;
14068     xmlDictPtr dict = NULL;
14069     const xmlChar **namespaces = NULL;
14070     xmlNsPtr ns;
14071     int i, j;
14072 
14073     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14074         (!xmlStrchr(str, '@'))) {
14075 	const xmlChar *tmp;
14076 
14077 	/*
14078 	 * We don't try to handle expressions using the verbose axis
14079 	 * specifiers ("::"), just the simplified form at this point.
14080 	 * Additionally, if there is no list of namespaces available and
14081 	 *  there's a ":" in the expression, indicating a prefixed QName,
14082 	 *  then we won't try to compile either. xmlPatterncompile() needs
14083 	 *  to have a list of namespaces at compilation time in order to
14084 	 *  compile prefixed name tests.
14085 	 */
14086 	tmp = xmlStrchr(str, ':');
14087 	if ((tmp != NULL) &&
14088 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14089 	    return(NULL);
14090 
14091 	if (ctxt != NULL) {
14092 	    dict = ctxt->dict;
14093 	    if (ctxt->nsNr > 0) {
14094 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14095 		if (namespaces == NULL) {
14096 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14097 		    return(NULL);
14098 		}
14099 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14100 		    ns = ctxt->namespaces[j];
14101 		    namespaces[i++] = ns->href;
14102 		    namespaces[i++] = ns->prefix;
14103 		}
14104 		namespaces[i++] = NULL;
14105 		namespaces[i] = NULL;
14106 	    }
14107 	}
14108 
14109 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14110 	if (namespaces != NULL) {
14111 	    xmlFree((xmlChar **)namespaces);
14112 	}
14113 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14114 	    comp = xmlXPathNewCompExpr();
14115 	    if (comp == NULL) {
14116 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14117 		return(NULL);
14118 	    }
14119 	    comp->stream = stream;
14120 	    comp->dict = dict;
14121 	    if (comp->dict)
14122 		xmlDictReference(comp->dict);
14123 	    return(comp);
14124 	}
14125 	xmlFreePattern(stream);
14126     }
14127     return(NULL);
14128 }
14129 #endif /* XPATH_STREAMING */
14130 
14131 static void
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,xmlXPathStepOpPtr op)14132 xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14133                            xmlXPathStepOpPtr op)
14134 {
14135     xmlXPathCompExprPtr comp = pctxt->comp;
14136     xmlXPathContextPtr ctxt;
14137 
14138     /*
14139     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14140     * internal representation.
14141     */
14142 
14143     if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14144         (op->ch1 != -1) &&
14145         (op->ch2 == -1 /* no predicate */))
14146     {
14147         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14148 
14149         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14150             ((xmlXPathAxisVal) prevop->value ==
14151                 AXIS_DESCENDANT_OR_SELF) &&
14152             (prevop->ch2 == -1) &&
14153             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14154             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14155         {
14156             /*
14157             * This is a "descendant-or-self::node()" without predicates.
14158             * Try to eliminate it.
14159             */
14160 
14161             switch ((xmlXPathAxisVal) op->value) {
14162                 case AXIS_CHILD:
14163                 case AXIS_DESCENDANT:
14164                     /*
14165                     * Convert "descendant-or-self::node()/child::" or
14166                     * "descendant-or-self::node()/descendant::" to
14167                     * "descendant::"
14168                     */
14169                     op->ch1   = prevop->ch1;
14170                     op->value = AXIS_DESCENDANT;
14171                     break;
14172                 case AXIS_SELF:
14173                 case AXIS_DESCENDANT_OR_SELF:
14174                     /*
14175                     * Convert "descendant-or-self::node()/self::" or
14176                     * "descendant-or-self::node()/descendant-or-self::" to
14177                     * to "descendant-or-self::"
14178                     */
14179                     op->ch1   = prevop->ch1;
14180                     op->value = AXIS_DESCENDANT_OR_SELF;
14181                     break;
14182                 default:
14183                     break;
14184             }
14185 	}
14186     }
14187 
14188     /* OP_VALUE has invalid ch1. */
14189     if (op->op == XPATH_OP_VALUE)
14190         return;
14191 
14192     /* Recurse */
14193     ctxt = pctxt->context;
14194     if (ctxt != NULL) {
14195         if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14196             return;
14197         ctxt->depth += 1;
14198     }
14199     if (op->ch1 != -1)
14200         xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14201     if (op->ch2 != -1)
14202 	xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14203     if (ctxt != NULL)
14204         ctxt->depth -= 1;
14205 }
14206 
14207 /**
14208  * xmlXPathCtxtCompile:
14209  * @ctxt: an XPath context
14210  * @str:  the XPath expression
14211  *
14212  * Compile an XPath expression
14213  *
14214  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14215  *         the caller has to free the object.
14216  */
14217 xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14218 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14219     xmlXPathParserContextPtr pctxt;
14220     xmlXPathCompExprPtr comp;
14221     int oldDepth = 0;
14222 
14223 #ifdef XPATH_STREAMING
14224     comp = xmlXPathTryStreamCompile(ctxt, str);
14225     if (comp != NULL)
14226         return(comp);
14227 #endif
14228 
14229     xmlInitParser();
14230 
14231     pctxt = xmlXPathNewParserContext(str, ctxt);
14232     if (pctxt == NULL)
14233         return NULL;
14234     if (ctxt != NULL)
14235         oldDepth = ctxt->depth;
14236     xmlXPathCompileExpr(pctxt, 1);
14237     if (ctxt != NULL)
14238         ctxt->depth = oldDepth;
14239 
14240     if( pctxt->error != XPATH_EXPRESSION_OK )
14241     {
14242         xmlXPathFreeParserContext(pctxt);
14243         return(NULL);
14244     }
14245 
14246     if (*pctxt->cur != 0) {
14247 	/*
14248 	 * aleksey: in some cases this line prints *second* error message
14249 	 * (see bug #78858) and probably this should be fixed.
14250 	 * However, we are not sure that all error messages are printed
14251 	 * out in other places. It's not critical so we leave it as-is for now
14252 	 */
14253 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14254 	comp = NULL;
14255     } else {
14256 	comp = pctxt->comp;
14257 	if ((comp->nbStep > 1) && (comp->last >= 0)) {
14258             if (ctxt != NULL)
14259                 oldDepth = ctxt->depth;
14260 	    xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14261             if (ctxt != NULL)
14262                 ctxt->depth = oldDepth;
14263 	}
14264 	pctxt->comp = NULL;
14265     }
14266     xmlXPathFreeParserContext(pctxt);
14267 
14268     if (comp != NULL) {
14269 	comp->expr = xmlStrdup(str);
14270 #ifdef DEBUG_EVAL_COUNTS
14271 	comp->string = xmlStrdup(str);
14272 	comp->nb = 0;
14273 #endif
14274     }
14275     return(comp);
14276 }
14277 
14278 /**
14279  * xmlXPathCompile:
14280  * @str:  the XPath expression
14281  *
14282  * Compile an XPath expression
14283  *
14284  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14285  *         the caller has to free the object.
14286  */
14287 xmlXPathCompExprPtr
xmlXPathCompile(const xmlChar * str)14288 xmlXPathCompile(const xmlChar *str) {
14289     return(xmlXPathCtxtCompile(NULL, str));
14290 }
14291 
14292 /**
14293  * xmlXPathCompiledEvalInternal:
14294  * @comp:  the compiled XPath expression
14295  * @ctxt:  the XPath context
14296  * @resObj: the resulting XPath object or NULL
14297  * @toBool: 1 if only a boolean result is requested
14298  *
14299  * Evaluate the Precompiled XPath expression in the given context.
14300  * The caller has to free @resObj.
14301  *
14302  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14303  *         the caller has to free the object.
14304  */
14305 static int
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt,xmlXPathObjectPtr * resObjPtr,int toBool)14306 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14307 			     xmlXPathContextPtr ctxt,
14308 			     xmlXPathObjectPtr *resObjPtr,
14309 			     int toBool)
14310 {
14311     xmlXPathParserContextPtr pctxt;
14312     xmlXPathObjectPtr resObj;
14313 #ifndef LIBXML_THREAD_ENABLED
14314     static int reentance = 0;
14315 #endif
14316     int res;
14317 
14318     CHECK_CTXT_NEG(ctxt)
14319 
14320     if (comp == NULL)
14321 	return(-1);
14322     xmlInitParser();
14323 
14324 #ifndef LIBXML_THREAD_ENABLED
14325     reentance++;
14326     if (reentance > 1)
14327 	xmlXPathDisableOptimizer = 1;
14328 #endif
14329 
14330 #ifdef DEBUG_EVAL_COUNTS
14331     comp->nb++;
14332     if ((comp->string != NULL) && (comp->nb > 100)) {
14333 	fprintf(stderr, "100 x %s\n", comp->string);
14334 	comp->nb = 0;
14335     }
14336 #endif
14337     pctxt = xmlXPathCompParserContext(comp, ctxt);
14338     res = xmlXPathRunEval(pctxt, toBool);
14339 
14340     if (pctxt->error != XPATH_EXPRESSION_OK) {
14341         resObj = NULL;
14342     } else {
14343         resObj = valuePop(pctxt);
14344         if (resObj == NULL) {
14345             if (!toBool)
14346                 xmlGenericError(xmlGenericErrorContext,
14347                     "xmlXPathCompiledEval: No result on the stack.\n");
14348         } else if (pctxt->valueNr > 0) {
14349             xmlGenericError(xmlGenericErrorContext,
14350                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14351                 pctxt->valueNr);
14352         }
14353     }
14354 
14355     if (resObjPtr)
14356         *resObjPtr = resObj;
14357     else
14358         xmlXPathReleaseObject(ctxt, resObj);
14359 
14360     pctxt->comp = NULL;
14361     xmlXPathFreeParserContext(pctxt);
14362 #ifndef LIBXML_THREAD_ENABLED
14363     reentance--;
14364 #endif
14365 
14366     return(res);
14367 }
14368 
14369 /**
14370  * xmlXPathCompiledEval:
14371  * @comp:  the compiled XPath expression
14372  * @ctx:  the XPath context
14373  *
14374  * Evaluate the Precompiled XPath expression in the given context.
14375  *
14376  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14377  *         the caller has to free the object.
14378  */
14379 xmlXPathObjectPtr
xmlXPathCompiledEval(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctx)14380 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14381 {
14382     xmlXPathObjectPtr res = NULL;
14383 
14384     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14385     return(res);
14386 }
14387 
14388 /**
14389  * xmlXPathCompiledEvalToBoolean:
14390  * @comp:  the compiled XPath expression
14391  * @ctxt:  the XPath context
14392  *
14393  * Applies the XPath boolean() function on the result of the given
14394  * compiled expression.
14395  *
14396  * Returns 1 if the expression evaluated to true, 0 if to false and
14397  *         -1 in API and internal errors.
14398  */
14399 int
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)14400 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14401 			      xmlXPathContextPtr ctxt)
14402 {
14403     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14404 }
14405 
14406 /**
14407  * xmlXPathEvalExpr:
14408  * @ctxt:  the XPath Parser context
14409  *
14410  * Parse and evaluate an XPath expression in the given context,
14411  * then push the result on the context stack
14412  */
14413 void
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt)14414 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14415 #ifdef XPATH_STREAMING
14416     xmlXPathCompExprPtr comp;
14417 #endif
14418     int oldDepth = 0;
14419 
14420     if (ctxt == NULL) return;
14421 
14422 #ifdef XPATH_STREAMING
14423     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14424     if (comp != NULL) {
14425         if (ctxt->comp != NULL)
14426 	    xmlXPathFreeCompExpr(ctxt->comp);
14427         ctxt->comp = comp;
14428     } else
14429 #endif
14430     {
14431         if (ctxt->context != NULL)
14432             oldDepth = ctxt->context->depth;
14433 	xmlXPathCompileExpr(ctxt, 1);
14434         if (ctxt->context != NULL)
14435             ctxt->context->depth = oldDepth;
14436         CHECK_ERROR;
14437 
14438         /* Check for trailing characters. */
14439         if (*ctxt->cur != 0)
14440             XP_ERROR(XPATH_EXPR_ERROR);
14441 
14442 	if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14443             if (ctxt->context != NULL)
14444                 oldDepth = ctxt->context->depth;
14445 	    xmlXPathOptimizeExpression(ctxt,
14446 		&ctxt->comp->steps[ctxt->comp->last]);
14447             if (ctxt->context != NULL)
14448                 ctxt->context->depth = oldDepth;
14449         }
14450     }
14451 
14452     xmlXPathRunEval(ctxt, 0);
14453 }
14454 
14455 /**
14456  * xmlXPathEval:
14457  * @str:  the XPath expression
14458  * @ctx:  the XPath context
14459  *
14460  * Evaluate the XPath Location Path in the given context.
14461  *
14462  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14463  *         the caller has to free the object.
14464  */
14465 xmlXPathObjectPtr
xmlXPathEval(const xmlChar * str,xmlXPathContextPtr ctx)14466 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14467     xmlXPathParserContextPtr ctxt;
14468     xmlXPathObjectPtr res;
14469 
14470     CHECK_CTXT(ctx)
14471 
14472     xmlInitParser();
14473 
14474     ctxt = xmlXPathNewParserContext(str, ctx);
14475     if (ctxt == NULL)
14476         return NULL;
14477     xmlXPathEvalExpr(ctxt);
14478 
14479     if (ctxt->error != XPATH_EXPRESSION_OK) {
14480 	res = NULL;
14481     } else {
14482 	res = valuePop(ctxt);
14483         if (res == NULL) {
14484             xmlGenericError(xmlGenericErrorContext,
14485                 "xmlXPathCompiledEval: No result on the stack.\n");
14486         } else if (ctxt->valueNr > 0) {
14487             xmlGenericError(xmlGenericErrorContext,
14488                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14489                 ctxt->valueNr);
14490         }
14491     }
14492 
14493     xmlXPathFreeParserContext(ctxt);
14494     return(res);
14495 }
14496 
14497 /**
14498  * xmlXPathSetContextNode:
14499  * @node: the node to to use as the context node
14500  * @ctx:  the XPath context
14501  *
14502  * Sets 'node' as the context node. The node must be in the same
14503  * document as that associated with the context.
14504  *
14505  * Returns -1 in case of error or 0 if successful
14506  */
14507 int
xmlXPathSetContextNode(xmlNodePtr node,xmlXPathContextPtr ctx)14508 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14509     if ((node == NULL) || (ctx == NULL))
14510         return(-1);
14511 
14512     if (node->doc == ctx->doc) {
14513         ctx->node = node;
14514 	return(0);
14515     }
14516     return(-1);
14517 }
14518 
14519 /**
14520  * xmlXPathNodeEval:
14521  * @node: the node to to use as the context node
14522  * @str:  the XPath expression
14523  * @ctx:  the XPath context
14524  *
14525  * Evaluate the XPath Location Path in the given context. The node 'node'
14526  * is set as the context node. The context node is not restored.
14527  *
14528  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14529  *         the caller has to free the object.
14530  */
14531 xmlXPathObjectPtr
xmlXPathNodeEval(xmlNodePtr node,const xmlChar * str,xmlXPathContextPtr ctx)14532 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14533     if (str == NULL)
14534         return(NULL);
14535     if (xmlXPathSetContextNode(node, ctx) < 0)
14536         return(NULL);
14537     return(xmlXPathEval(str, ctx));
14538 }
14539 
14540 /**
14541  * xmlXPathEvalExpression:
14542  * @str:  the XPath expression
14543  * @ctxt:  the XPath context
14544  *
14545  * Alias for xmlXPathEval().
14546  *
14547  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14548  *         the caller has to free the object.
14549  */
14550 xmlXPathObjectPtr
xmlXPathEvalExpression(const xmlChar * str,xmlXPathContextPtr ctxt)14551 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14552     return(xmlXPathEval(str, ctxt));
14553 }
14554 
14555 /************************************************************************
14556  *									*
14557  *	Extra functions not pertaining to the XPath spec		*
14558  *									*
14559  ************************************************************************/
14560 /**
14561  * xmlXPathEscapeUriFunction:
14562  * @ctxt:  the XPath Parser context
14563  * @nargs:  the number of arguments
14564  *
14565  * Implement the escape-uri() XPath function
14566  *    string escape-uri(string $str, bool $escape-reserved)
14567  *
14568  * This function applies the URI escaping rules defined in section 2 of [RFC
14569  * 2396] to the string supplied as $uri-part, which typically represents all
14570  * or part of a URI. The effect of the function is to replace any special
14571  * character in the string by an escape sequence of the form %xx%yy...,
14572  * where xxyy... is the hexadecimal representation of the octets used to
14573  * represent the character in UTF-8.
14574  *
14575  * The set of characters that are escaped depends on the setting of the
14576  * boolean argument $escape-reserved.
14577  *
14578  * If $escape-reserved is true, all characters are escaped other than lower
14579  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14580  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14581  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14582  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14583  * A-F).
14584  *
14585  * If $escape-reserved is false, the behavior differs in that characters
14586  * referred to in [RFC 2396] as reserved characters are not escaped. These
14587  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14588  *
14589  * [RFC 2396] does not define whether escaped URIs should use lower case or
14590  * upper case for hexadecimal digits. To ensure that escaped URIs can be
14591  * compared using string comparison functions, this function must always use
14592  * the upper-case letters A-F.
14593  *
14594  * Generally, $escape-reserved should be set to true when escaping a string
14595  * that is to form a single part of a URI, and to false when escaping an
14596  * entire URI or URI reference.
14597  *
14598  * In the case of non-ascii characters, the string is encoded according to
14599  * utf-8 and then converted according to RFC 2396.
14600  *
14601  * Examples
14602  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14603  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14604  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14605  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14606  *
14607  */
14608 static void
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt,int nargs)14609 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14610     xmlXPathObjectPtr str;
14611     int escape_reserved;
14612     xmlBufPtr target;
14613     xmlChar *cptr;
14614     xmlChar escape[4];
14615 
14616     CHECK_ARITY(2);
14617 
14618     escape_reserved = xmlXPathPopBoolean(ctxt);
14619 
14620     CAST_TO_STRING;
14621     str = valuePop(ctxt);
14622 
14623     target = xmlBufCreate();
14624 
14625     escape[0] = '%';
14626     escape[3] = 0;
14627 
14628     if (target) {
14629 	for (cptr = str->stringval; *cptr; cptr++) {
14630 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
14631 		(*cptr >= 'a' && *cptr <= 'z') ||
14632 		(*cptr >= '0' && *cptr <= '9') ||
14633 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
14634 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
14635 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14636 		(*cptr == '%' &&
14637 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14638 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14639 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
14640 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14641 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14642 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14643 		(!escape_reserved &&
14644 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14645 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14646 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14647 		  *cptr == ','))) {
14648 		xmlBufAdd(target, cptr, 1);
14649 	    } else {
14650 		if ((*cptr >> 4) < 10)
14651 		    escape[1] = '0' + (*cptr >> 4);
14652 		else
14653 		    escape[1] = 'A' - 10 + (*cptr >> 4);
14654 		if ((*cptr & 0xF) < 10)
14655 		    escape[2] = '0' + (*cptr & 0xF);
14656 		else
14657 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
14658 
14659 		xmlBufAdd(target, &escape[0], 3);
14660 	    }
14661 	}
14662     }
14663     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14664 	xmlBufContent(target)));
14665     xmlBufFree(target);
14666     xmlXPathReleaseObject(ctxt->context, str);
14667 }
14668 
14669 /**
14670  * xmlXPathRegisterAllFunctions:
14671  * @ctxt:  the XPath context
14672  *
14673  * Registers all default XPath functions in this context
14674  */
14675 void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)14676 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14677 {
14678     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14679                          xmlXPathBooleanFunction);
14680     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14681                          xmlXPathCeilingFunction);
14682     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14683                          xmlXPathCountFunction);
14684     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14685                          xmlXPathConcatFunction);
14686     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14687                          xmlXPathContainsFunction);
14688     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14689                          xmlXPathIdFunction);
14690     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14691                          xmlXPathFalseFunction);
14692     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14693                          xmlXPathFloorFunction);
14694     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14695                          xmlXPathLastFunction);
14696     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14697                          xmlXPathLangFunction);
14698     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14699                          xmlXPathLocalNameFunction);
14700     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14701                          xmlXPathNotFunction);
14702     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14703                          xmlXPathNameFunction);
14704     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14705                          xmlXPathNamespaceURIFunction);
14706     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14707                          xmlXPathNormalizeFunction);
14708     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14709                          xmlXPathNumberFunction);
14710     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14711                          xmlXPathPositionFunction);
14712     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14713                          xmlXPathRoundFunction);
14714     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14715                          xmlXPathStringFunction);
14716     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14717                          xmlXPathStringLengthFunction);
14718     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14719                          xmlXPathStartsWithFunction);
14720     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14721                          xmlXPathSubstringFunction);
14722     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14723                          xmlXPathSubstringBeforeFunction);
14724     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14725                          xmlXPathSubstringAfterFunction);
14726     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14727                          xmlXPathSumFunction);
14728     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14729                          xmlXPathTrueFunction);
14730     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14731                          xmlXPathTranslateFunction);
14732 
14733     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14734 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14735                          xmlXPathEscapeUriFunction);
14736 }
14737 
14738 #endif /* LIBXML_XPATH_ENABLED */
14739