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 
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
31 #endif
32 #ifdef HAVE_MATH_H
33 #include <math.h>
34 #endif
35 #ifdef HAVE_FLOAT_H
36 #include <float.h>
37 #endif
38 #ifdef HAVE_CTYPE_H
39 #include <ctype.h>
40 #endif
41 #ifdef HAVE_SIGNAL_H
42 #include <signal.h>
43 #endif
44 
45 #include <libxml/xmlmemory.h>
46 #include <libxml/tree.h>
47 #include <libxml/valid.h>
48 #include <libxml/xpath.h>
49 #include <libxml/xpathInternals.h>
50 #include <libxml/parserInternals.h>
51 #include <libxml/hash.h>
52 #ifdef LIBXML_XPTR_ENABLED
53 #include <libxml/xpointer.h>
54 #endif
55 #ifdef LIBXML_DEBUG_ENABLED
56 #include <libxml/debugXML.h>
57 #endif
58 #include <libxml/xmlerror.h>
59 #include <libxml/threads.h>
60 #include <libxml/globals.h>
61 #ifdef LIBXML_PATTERN_ENABLED
62 #include <libxml/pattern.h>
63 #endif
64 
65 #include "buf.h"
66 
67 #ifdef LIBXML_PATTERN_ENABLED
68 #define XPATH_STREAMING
69 #endif
70 
71 #define TODO								\
72     xmlGenericError(xmlGenericErrorContext,				\
73 	    "Unimplemented block at %s:%d\n",				\
74             __FILE__, __LINE__);
75 
76 /**
77  * WITH_TIM_SORT:
78  *
79  * Use the Timsort algorithm provided in timsort.h to sort
80  * nodeset as this is a great improvement over the old Shell sort
81  * used in xmlXPathNodeSetSort()
82  */
83 #define WITH_TIM_SORT
84 
85 /*
86 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
87 * If defined, this will use xmlXPathCmpNodesExt() instead of
88 * xmlXPathCmpNodes(). The new function is optimized comparison of
89 * non-element nodes; actually it will speed up comparison only if
90 * xmlXPathOrderDocElems() was called in order to index the elements of
91 * a tree in document order; Libxslt does such an indexing, thus it will
92 * benefit from this optimization.
93 */
94 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
95 
96 /*
97 * XP_OPTIMIZED_FILTER_FIRST:
98 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
99 * in a way, that it stop evaluation at the first node.
100 */
101 #define XP_OPTIMIZED_FILTER_FIRST
102 
103 /*
104 * XP_DEBUG_OBJ_USAGE:
105 * Internal flag to enable tracking of how much XPath objects have been
106 * created.
107 */
108 /* #define XP_DEBUG_OBJ_USAGE */
109 
110 /*
111  * XPATH_MAX_STEPS:
112  * when compiling an XPath expression we arbitrary limit the maximum
113  * number of step operation in the compiled expression. 1000000 is
114  * an insanely large value which should never be reached under normal
115  * circumstances
116  */
117 #define XPATH_MAX_STEPS 1000000
118 
119 /*
120  * XPATH_MAX_STACK_DEPTH:
121  * when evaluating an XPath expression we arbitrary limit the maximum
122  * number of object allowed to be pushed on the stack. 1000000 is
123  * an insanely large value which should never be reached under normal
124  * circumstances
125  */
126 #define XPATH_MAX_STACK_DEPTH 1000000
127 
128 /*
129  * XPATH_MAX_NODESET_LENGTH:
130  * when evaluating an XPath expression nodesets are created and we
131  * arbitrary limit the maximum length of those node set. 10000000 is
132  * an insanely large value which should never be reached under normal
133  * circumstances, one would first need to construct an in memory tree
134  * with more than 10 millions nodes.
135  */
136 #define XPATH_MAX_NODESET_LENGTH 10000000
137 
138 /*
139  * TODO:
140  * There are a few spots where some tests are done which depend upon ascii
141  * data.  These should be enhanced for full UTF8 support (see particularly
142  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
143  */
144 
145 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
146 /**
147  * xmlXPathCmpNodesExt:
148  * @node1:  the first node
149  * @node2:  the second node
150  *
151  * Compare two nodes w.r.t document order.
152  * This one is optimized for handling of non-element nodes.
153  *
154  * Returns -2 in case of error 1 if first point < second point, 0 if
155  *         it's the same node, -1 otherwise
156  */
157 static int
xmlXPathCmpNodesExt(xmlNodePtr node1,xmlNodePtr node2)158 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
159     int depth1, depth2;
160     int misc = 0, precedence1 = 0, precedence2 = 0;
161     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
162     xmlNodePtr cur, root;
163     ptrdiff_t l1, l2;
164 
165     if ((node1 == NULL) || (node2 == NULL))
166 	return(-2);
167 
168     if (node1 == node2)
169 	return(0);
170 
171     /*
172      * a couple of optimizations which will avoid computations in most cases
173      */
174     switch (node1->type) {
175 	case XML_ELEMENT_NODE:
176 	    if (node2->type == XML_ELEMENT_NODE) {
177 		if ((0 > (ptrdiff_t) node1->content) &&
178 		    (0 > (ptrdiff_t) node2->content) &&
179 		    (node1->doc == node2->doc))
180 		{
181 		    l1 = -((ptrdiff_t) node1->content);
182 		    l2 = -((ptrdiff_t) node2->content);
183 		    if (l1 < l2)
184 			return(1);
185 		    if (l1 > l2)
186 			return(-1);
187 		} else
188 		    goto turtle_comparison;
189 	    }
190 	    break;
191 	case XML_ATTRIBUTE_NODE:
192 	    precedence1 = 1; /* element is owner */
193 	    miscNode1 = node1;
194 	    node1 = node1->parent;
195 	    misc = 1;
196 	    break;
197 	case XML_TEXT_NODE:
198 	case XML_CDATA_SECTION_NODE:
199 	case XML_COMMENT_NODE:
200 	case XML_PI_NODE: {
201 	    miscNode1 = node1;
202 	    /*
203 	    * Find nearest element node.
204 	    */
205 	    if (node1->prev != NULL) {
206 		do {
207 		    node1 = node1->prev;
208 		    if (node1->type == XML_ELEMENT_NODE) {
209 			precedence1 = 3; /* element in prev-sibl axis */
210 			break;
211 		    }
212 		    if (node1->prev == NULL) {
213 			precedence1 = 2; /* element is parent */
214 			/*
215 			* URGENT TODO: Are there any cases, where the
216 			* parent of such a node is not an element node?
217 			*/
218 			node1 = node1->parent;
219 			break;
220 		    }
221 		} while (1);
222 	    } else {
223 		precedence1 = 2; /* element is parent */
224 		node1 = node1->parent;
225 	    }
226 	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
227 		(0 <= (ptrdiff_t) node1->content)) {
228 		/*
229 		* Fallback for whatever case.
230 		*/
231 		node1 = miscNode1;
232 		precedence1 = 0;
233 	    } else
234 		misc = 1;
235 	}
236 	    break;
237 	case XML_NAMESPACE_DECL:
238 	    /*
239 	    * TODO: why do we return 1 for namespace nodes?
240 	    */
241 	    return(1);
242 	default:
243 	    break;
244     }
245     switch (node2->type) {
246 	case XML_ELEMENT_NODE:
247 	    break;
248 	case XML_ATTRIBUTE_NODE:
249 	    precedence2 = 1; /* element is owner */
250 	    miscNode2 = node2;
251 	    node2 = node2->parent;
252 	    misc = 1;
253 	    break;
254 	case XML_TEXT_NODE:
255 	case XML_CDATA_SECTION_NODE:
256 	case XML_COMMENT_NODE:
257 	case XML_PI_NODE: {
258 	    miscNode2 = node2;
259 	    if (node2->prev != NULL) {
260 		do {
261 		    node2 = node2->prev;
262 		    if (node2->type == XML_ELEMENT_NODE) {
263 			precedence2 = 3; /* element in prev-sibl axis */
264 			break;
265 		    }
266 		    if (node2->prev == NULL) {
267 			precedence2 = 2; /* element is parent */
268 			node2 = node2->parent;
269 			break;
270 		    }
271 		} while (1);
272 	    } else {
273 		precedence2 = 2; /* element is parent */
274 		node2 = node2->parent;
275 	    }
276 	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
277 		(0 <= (ptrdiff_t) node2->content))
278 	    {
279 		node2 = miscNode2;
280 		precedence2 = 0;
281 	    } else
282 		misc = 1;
283 	}
284 	    break;
285 	case XML_NAMESPACE_DECL:
286 	    return(1);
287 	default:
288 	    break;
289     }
290     if (misc) {
291 	if (node1 == node2) {
292 	    if (precedence1 == precedence2) {
293 		/*
294 		* The ugly case; but normally there aren't many
295 		* adjacent non-element nodes around.
296 		*/
297 		cur = miscNode2->prev;
298 		while (cur != NULL) {
299 		    if (cur == miscNode1)
300 			return(1);
301 		    if (cur->type == XML_ELEMENT_NODE)
302 			return(-1);
303 		    cur = cur->prev;
304 		}
305 		return (-1);
306 	    } else {
307 		/*
308 		* Evaluate based on higher precedence wrt to the element.
309 		* TODO: This assumes attributes are sorted before content.
310 		*   Is this 100% correct?
311 		*/
312 		if (precedence1 < precedence2)
313 		    return(1);
314 		else
315 		    return(-1);
316 	    }
317 	}
318 	/*
319 	* Special case: One of the helper-elements is contained by the other.
320 	* <foo>
321 	*   <node2>
322 	*     <node1>Text-1(precedence1 == 2)</node1>
323 	*   </node2>
324 	*   Text-6(precedence2 == 3)
325 	* </foo>
326 	*/
327 	if ((precedence2 == 3) && (precedence1 > 1)) {
328 	    cur = node1->parent;
329 	    while (cur) {
330 		if (cur == node2)
331 		    return(1);
332 		cur = cur->parent;
333 	    }
334 	}
335 	if ((precedence1 == 3) && (precedence2 > 1)) {
336 	    cur = node2->parent;
337 	    while (cur) {
338 		if (cur == node1)
339 		    return(-1);
340 		cur = cur->parent;
341 	    }
342 	}
343     }
344 
345     /*
346      * Speedup using document order if availble.
347      */
348     if ((node1->type == XML_ELEMENT_NODE) &&
349 	(node2->type == XML_ELEMENT_NODE) &&
350 	(0 > (ptrdiff_t) node1->content) &&
351 	(0 > (ptrdiff_t) node2->content) &&
352 	(node1->doc == node2->doc)) {
353 
354 	l1 = -((ptrdiff_t) node1->content);
355 	l2 = -((ptrdiff_t) node2->content);
356 	if (l1 < l2)
357 	    return(1);
358 	if (l1 > l2)
359 	    return(-1);
360     }
361 
362 turtle_comparison:
363 
364     if (node1 == node2->prev)
365 	return(1);
366     if (node1 == node2->next)
367 	return(-1);
368     /*
369      * compute depth to root
370      */
371     for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
372 	if (cur->parent == node1)
373 	    return(1);
374 	depth2++;
375     }
376     root = cur;
377     for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
378 	if (cur->parent == node2)
379 	    return(-1);
380 	depth1++;
381     }
382     /*
383      * Distinct document (or distinct entities :-( ) case.
384      */
385     if (root != cur) {
386 	return(-2);
387     }
388     /*
389      * get the nearest common ancestor.
390      */
391     while (depth1 > depth2) {
392 	depth1--;
393 	node1 = node1->parent;
394     }
395     while (depth2 > depth1) {
396 	depth2--;
397 	node2 = node2->parent;
398     }
399     while (node1->parent != node2->parent) {
400 	node1 = node1->parent;
401 	node2 = node2->parent;
402 	/* should not happen but just in case ... */
403 	if ((node1 == NULL) || (node2 == NULL))
404 	    return(-2);
405     }
406     /*
407      * Find who's first.
408      */
409     if (node1 == node2->prev)
410 	return(1);
411     if (node1 == node2->next)
412 	return(-1);
413     /*
414      * Speedup using document order if availble.
415      */
416     if ((node1->type == XML_ELEMENT_NODE) &&
417 	(node2->type == XML_ELEMENT_NODE) &&
418 	(0 > (ptrdiff_t) node1->content) &&
419 	(0 > (ptrdiff_t) node2->content) &&
420 	(node1->doc == node2->doc)) {
421 
422 	l1 = -((ptrdiff_t) node1->content);
423 	l2 = -((ptrdiff_t) node2->content);
424 	if (l1 < l2)
425 	    return(1);
426 	if (l1 > l2)
427 	    return(-1);
428     }
429 
430     for (cur = node1->next;cur != NULL;cur = cur->next)
431 	if (cur == node2)
432 	    return(1);
433     return(-1); /* assume there is no sibling list corruption */
434 }
435 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
436 
437 /*
438  * Wrapper for the Timsort argorithm from timsort.h
439  */
440 #ifdef WITH_TIM_SORT
441 #define SORT_NAME libxml_domnode
442 #define SORT_TYPE xmlNodePtr
443 /**
444  * wrap_cmp:
445  * @x: a node
446  * @y: another node
447  *
448  * Comparison function for the Timsort implementation
449  *
450  * Returns -2 in case of error -1 if first point < second point, 0 if
451  *         it's the same node, +1 otherwise
452  */
453 static
454 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
455 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
wrap_cmp(xmlNodePtr x,xmlNodePtr y)456     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
457     {
458         int res = xmlXPathCmpNodesExt(x, y);
459         return res == -2 ? res : -res;
460     }
461 #else
wrap_cmp(xmlNodePtr x,xmlNodePtr y)462     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
463     {
464         int res = xmlXPathCmpNodes(x, y);
465         return res == -2 ? res : -res;
466     }
467 #endif
468 #define SORT_CMP(x, y)  (wrap_cmp(x, y))
469 #include "timsort.h"
470 #endif /* WITH_TIM_SORT */
471 
472 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
473 
474 /************************************************************************
475  *									*
476  *			Floating point stuff				*
477  *									*
478  ************************************************************************/
479 
480 #ifndef INFINITY
481 #define INFINITY (DBL_MAX * DBL_MAX)
482 #endif
483 
484 #ifndef NAN
485 #define NAN (INFINITY / INFINITY)
486 #endif
487 
488 double xmlXPathNAN;
489 double xmlXPathPINF;
490 double xmlXPathNINF;
491 
492 /**
493  * xmlXPathInit:
494  *
495  * Initialize the XPath environment
496  */
497 void
xmlXPathInit(void)498 xmlXPathInit(void) {
499     xmlXPathNAN = NAN;
500     xmlXPathPINF = INFINITY;
501     xmlXPathNINF = -INFINITY;
502 }
503 
504 /**
505  * xmlXPathIsNaN:
506  * @val:  a double value
507  *
508  * Returns 1 if the value is a NaN, 0 otherwise
509  */
510 int
xmlXPathIsNaN(double val)511 xmlXPathIsNaN(double val) {
512 #ifdef isnan
513     return isnan(val);
514 #else
515     return !(val == val);
516 #endif
517 }
518 
519 /**
520  * xmlXPathIsInf:
521  * @val:  a double value
522  *
523  * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
524  */
525 int
xmlXPathIsInf(double val)526 xmlXPathIsInf(double val) {
527 #ifdef isinf
528     return isinf(val) ? (val > 0 ? 1 : -1) : 0;
529 #else
530     if (val >= INFINITY)
531         return 1;
532     if (val <= -INFINITY)
533         return -1;
534     return 0;
535 #endif
536 }
537 
538 #endif /* SCHEMAS or XPATH */
539 
540 #ifdef LIBXML_XPATH_ENABLED
541 
542 /*
543  * TODO: when compatibility allows remove all "fake node libxslt" strings
544  *       the test should just be name[0] = ' '
545  */
546 #ifdef DEBUG_XPATH_EXPRESSION
547 #define DEBUG_STEP
548 #define DEBUG_EXPR
549 #define DEBUG_EVAL_COUNTS
550 #endif
551 
552 static xmlNs xmlXPathXMLNamespaceStruct = {
553     NULL,
554     XML_NAMESPACE_DECL,
555     XML_XML_NAMESPACE,
556     BAD_CAST "xml",
557     NULL,
558     NULL
559 };
560 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
561 #ifndef LIBXML_THREAD_ENABLED
562 /*
563  * Optimizer is disabled only when threaded apps are detected while
564  * the library ain't compiled for thread safety.
565  */
566 static int xmlXPathDisableOptimizer = 0;
567 #endif
568 
569 /************************************************************************
570  *									*
571  *			Error handling routines				*
572  *									*
573  ************************************************************************/
574 
575 /**
576  * XP_ERRORNULL:
577  * @X:  the error code
578  *
579  * Macro to raise an XPath error and return NULL.
580  */
581 #define XP_ERRORNULL(X)							\
582     { xmlXPathErr(ctxt, X); return(NULL); }
583 
584 /*
585  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
586  */
587 static const char *xmlXPathErrorMessages[] = {
588     "Ok\n",
589     "Number encoding\n",
590     "Unfinished literal\n",
591     "Start of literal\n",
592     "Expected $ for variable reference\n",
593     "Undefined variable\n",
594     "Invalid predicate\n",
595     "Invalid expression\n",
596     "Missing closing curly brace\n",
597     "Unregistered function\n",
598     "Invalid operand\n",
599     "Invalid type\n",
600     "Invalid number of arguments\n",
601     "Invalid context size\n",
602     "Invalid context position\n",
603     "Memory allocation error\n",
604     "Syntax error\n",
605     "Resource error\n",
606     "Sub resource error\n",
607     "Undefined namespace prefix\n",
608     "Encoding error\n",
609     "Char out of XML range\n",
610     "Invalid or incomplete context\n",
611     "Stack usage error\n",
612     "Forbidden variable\n",
613     "?? Unknown error ??\n"	/* Must be last in the list! */
614 };
615 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
616 		   sizeof(xmlXPathErrorMessages[0])) - 1)
617 /**
618  * xmlXPathErrMemory:
619  * @ctxt:  an XPath context
620  * @extra:  extra informations
621  *
622  * Handle a redefinition of attribute error
623  */
624 static void
xmlXPathErrMemory(xmlXPathContextPtr ctxt,const char * extra)625 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
626 {
627     if (ctxt != NULL) {
628         if (extra) {
629             xmlChar buf[200];
630 
631             xmlStrPrintf(buf, 200,
632                          "Memory allocation failed : %s\n",
633                          extra);
634             ctxt->lastError.message = (char *) xmlStrdup(buf);
635         } else {
636             ctxt->lastError.message = (char *)
637 	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
638         }
639         ctxt->lastError.domain = XML_FROM_XPATH;
640         ctxt->lastError.code = XML_ERR_NO_MEMORY;
641 	if (ctxt->error != NULL)
642 	    ctxt->error(ctxt->userData, &ctxt->lastError);
643     } else {
644         if (extra)
645             __xmlRaiseError(NULL, NULL, NULL,
646                             NULL, NULL, XML_FROM_XPATH,
647                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
648                             extra, NULL, NULL, 0, 0,
649                             "Memory allocation failed : %s\n", extra);
650         else
651             __xmlRaiseError(NULL, NULL, NULL,
652                             NULL, NULL, XML_FROM_XPATH,
653                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
654                             NULL, NULL, NULL, 0, 0,
655                             "Memory allocation failed\n");
656     }
657 }
658 
659 /**
660  * xmlXPathPErrMemory:
661  * @ctxt:  an XPath parser context
662  * @extra:  extra informations
663  *
664  * Handle a redefinition of attribute error
665  */
666 static void
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt,const char * extra)667 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
668 {
669     if (ctxt == NULL)
670 	xmlXPathErrMemory(NULL, extra);
671     else {
672 	ctxt->error = XPATH_MEMORY_ERROR;
673 	xmlXPathErrMemory(ctxt->context, extra);
674     }
675 }
676 
677 /**
678  * xmlXPathErr:
679  * @ctxt:  a XPath parser context
680  * @error:  the error code
681  *
682  * Handle an XPath error
683  */
684 void
xmlXPathErr(xmlXPathParserContextPtr ctxt,int error)685 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
686 {
687     if ((error < 0) || (error > MAXERRNO))
688 	error = MAXERRNO;
689     if (ctxt == NULL) {
690 	__xmlRaiseError(NULL, NULL, NULL,
691 			NULL, NULL, XML_FROM_XPATH,
692 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
693 			XML_ERR_ERROR, NULL, 0,
694 			NULL, NULL, NULL, 0, 0,
695 			"%s", xmlXPathErrorMessages[error]);
696 	return;
697     }
698     ctxt->error = error;
699     if (ctxt->context == NULL) {
700 	__xmlRaiseError(NULL, NULL, NULL,
701 			NULL, NULL, XML_FROM_XPATH,
702 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
703 			XML_ERR_ERROR, NULL, 0,
704 			(const char *) ctxt->base, NULL, NULL,
705 			ctxt->cur - ctxt->base, 0,
706 			"%s", xmlXPathErrorMessages[error]);
707 	return;
708     }
709 
710     /* cleanup current last error */
711     xmlResetError(&ctxt->context->lastError);
712 
713     ctxt->context->lastError.domain = XML_FROM_XPATH;
714     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
715                            XPATH_EXPRESSION_OK;
716     ctxt->context->lastError.level = XML_ERR_ERROR;
717     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
718     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
719     ctxt->context->lastError.node = ctxt->context->debugNode;
720     if (ctxt->context->error != NULL) {
721 	ctxt->context->error(ctxt->context->userData,
722 	                     &ctxt->context->lastError);
723     } else {
724 	__xmlRaiseError(NULL, NULL, NULL,
725 			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
726 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
727 			XML_ERR_ERROR, NULL, 0,
728 			(const char *) ctxt->base, NULL, NULL,
729 			ctxt->cur - ctxt->base, 0,
730 			"%s", xmlXPathErrorMessages[error]);
731     }
732 
733 }
734 
735 /**
736  * xmlXPatherror:
737  * @ctxt:  the XPath Parser context
738  * @file:  the file name
739  * @line:  the line number
740  * @no:  the error number
741  *
742  * Formats an error message.
743  */
744 void
xmlXPatherror(xmlXPathParserContextPtr ctxt,const char * file ATTRIBUTE_UNUSED,int line ATTRIBUTE_UNUSED,int no)745 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
746               int line ATTRIBUTE_UNUSED, int no) {
747     xmlXPathErr(ctxt, no);
748 }
749 
750 /************************************************************************
751  *									*
752  *			Utilities					*
753  *									*
754  ************************************************************************/
755 
756 /**
757  * xsltPointerList:
758  *
759  * Pointer-list for various purposes.
760  */
761 typedef struct _xmlPointerList xmlPointerList;
762 typedef xmlPointerList *xmlPointerListPtr;
763 struct _xmlPointerList {
764     void **items;
765     int number;
766     int size;
767 };
768 /*
769 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
770 * and here, we should make the functions public.
771 */
772 static int
xmlPointerListAddSize(xmlPointerListPtr list,void * item,int initialSize)773 xmlPointerListAddSize(xmlPointerListPtr list,
774 		       void *item,
775 		       int initialSize)
776 {
777     if (list->items == NULL) {
778 	if (initialSize <= 0)
779 	    initialSize = 1;
780 	list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
781 	if (list->items == NULL) {
782 	    xmlXPathErrMemory(NULL,
783 		"xmlPointerListCreate: allocating item\n");
784 	    return(-1);
785 	}
786 	list->number = 0;
787 	list->size = initialSize;
788     } else if (list->size <= list->number) {
789         if (list->size > 50000000) {
790 	    xmlXPathErrMemory(NULL,
791 		"xmlPointerListAddSize: re-allocating item\n");
792             return(-1);
793         }
794 	list->size *= 2;
795 	list->items = (void **) xmlRealloc(list->items,
796 	    list->size * sizeof(void *));
797 	if (list->items == NULL) {
798 	    xmlXPathErrMemory(NULL,
799 		"xmlPointerListAddSize: re-allocating item\n");
800 	    list->size = 0;
801 	    return(-1);
802 	}
803     }
804     list->items[list->number++] = item;
805     return(0);
806 }
807 
808 /**
809  * xsltPointerListCreate:
810  *
811  * Creates an xsltPointerList structure.
812  *
813  * Returns a xsltPointerList structure or NULL in case of an error.
814  */
815 static xmlPointerListPtr
xmlPointerListCreate(int initialSize)816 xmlPointerListCreate(int initialSize)
817 {
818     xmlPointerListPtr ret;
819 
820     ret = xmlMalloc(sizeof(xmlPointerList));
821     if (ret == NULL) {
822 	xmlXPathErrMemory(NULL,
823 	    "xmlPointerListCreate: allocating item\n");
824 	return (NULL);
825     }
826     memset(ret, 0, sizeof(xmlPointerList));
827     if (initialSize > 0) {
828 	xmlPointerListAddSize(ret, NULL, initialSize);
829 	ret->number = 0;
830     }
831     return (ret);
832 }
833 
834 /**
835  * xsltPointerListFree:
836  *
837  * Frees the xsltPointerList structure. This does not free
838  * the content of the list.
839  */
840 static void
xmlPointerListFree(xmlPointerListPtr list)841 xmlPointerListFree(xmlPointerListPtr list)
842 {
843     if (list == NULL)
844 	return;
845     if (list->items != NULL)
846 	xmlFree(list->items);
847     xmlFree(list);
848 }
849 
850 /************************************************************************
851  *									*
852  *			Parser Types					*
853  *									*
854  ************************************************************************/
855 
856 /*
857  * Types are private:
858  */
859 
860 typedef enum {
861     XPATH_OP_END=0,
862     XPATH_OP_AND,
863     XPATH_OP_OR,
864     XPATH_OP_EQUAL,
865     XPATH_OP_CMP,
866     XPATH_OP_PLUS,
867     XPATH_OP_MULT,
868     XPATH_OP_UNION,
869     XPATH_OP_ROOT,
870     XPATH_OP_NODE,
871     XPATH_OP_COLLECT,
872     XPATH_OP_VALUE, /* 11 */
873     XPATH_OP_VARIABLE,
874     XPATH_OP_FUNCTION,
875     XPATH_OP_ARG,
876     XPATH_OP_PREDICATE,
877     XPATH_OP_FILTER, /* 16 */
878     XPATH_OP_SORT /* 17 */
879 #ifdef LIBXML_XPTR_ENABLED
880     ,XPATH_OP_RANGETO
881 #endif
882 } xmlXPathOp;
883 
884 typedef enum {
885     AXIS_ANCESTOR = 1,
886     AXIS_ANCESTOR_OR_SELF,
887     AXIS_ATTRIBUTE,
888     AXIS_CHILD,
889     AXIS_DESCENDANT,
890     AXIS_DESCENDANT_OR_SELF,
891     AXIS_FOLLOWING,
892     AXIS_FOLLOWING_SIBLING,
893     AXIS_NAMESPACE,
894     AXIS_PARENT,
895     AXIS_PRECEDING,
896     AXIS_PRECEDING_SIBLING,
897     AXIS_SELF
898 } xmlXPathAxisVal;
899 
900 typedef enum {
901     NODE_TEST_NONE = 0,
902     NODE_TEST_TYPE = 1,
903     NODE_TEST_PI = 2,
904     NODE_TEST_ALL = 3,
905     NODE_TEST_NS = 4,
906     NODE_TEST_NAME = 5
907 } xmlXPathTestVal;
908 
909 typedef enum {
910     NODE_TYPE_NODE = 0,
911     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
912     NODE_TYPE_TEXT = XML_TEXT_NODE,
913     NODE_TYPE_PI = XML_PI_NODE
914 } xmlXPathTypeVal;
915 
916 typedef struct _xmlXPathStepOp xmlXPathStepOp;
917 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
918 struct _xmlXPathStepOp {
919     xmlXPathOp op;		/* The identifier of the operation */
920     int ch1;			/* First child */
921     int ch2;			/* Second child */
922     int value;
923     int value2;
924     int value3;
925     void *value4;
926     void *value5;
927     xmlXPathFunction cache;
928     void *cacheURI;
929 };
930 
931 struct _xmlXPathCompExpr {
932     int nbStep;			/* Number of steps in this expression */
933     int maxStep;		/* Maximum number of steps allocated */
934     xmlXPathStepOp *steps;	/* ops for computation of this expression */
935     int last;			/* index of last step in expression */
936     xmlChar *expr;		/* the expression being computed */
937     xmlDictPtr dict;		/* the dictionary to use if any */
938 #ifdef DEBUG_EVAL_COUNTS
939     int nb;
940     xmlChar *string;
941 #endif
942 #ifdef XPATH_STREAMING
943     xmlPatternPtr stream;
944 #endif
945 };
946 
947 /************************************************************************
948  *									*
949  *			Forward declarations				*
950  *									*
951  ************************************************************************/
952 static void
953 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
954 static void
955 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
956 static int
957 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
958                         xmlXPathStepOpPtr op, xmlNodePtr *first);
959 static int
960 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
961 			    xmlXPathStepOpPtr op,
962 			    int isPredicate);
963 static void
964 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
965 
966 /************************************************************************
967  *									*
968  *			Parser Type functions				*
969  *									*
970  ************************************************************************/
971 
972 /**
973  * xmlXPathNewCompExpr:
974  *
975  * Create a new Xpath component
976  *
977  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
978  */
979 static xmlXPathCompExprPtr
xmlXPathNewCompExpr(void)980 xmlXPathNewCompExpr(void) {
981     xmlXPathCompExprPtr cur;
982 
983     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
984     if (cur == NULL) {
985         xmlXPathErrMemory(NULL, "allocating component\n");
986 	return(NULL);
987     }
988     memset(cur, 0, sizeof(xmlXPathCompExpr));
989     cur->maxStep = 10;
990     cur->nbStep = 0;
991     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
992 	                                   sizeof(xmlXPathStepOp));
993     if (cur->steps == NULL) {
994         xmlXPathErrMemory(NULL, "allocating steps\n");
995 	xmlFree(cur);
996 	return(NULL);
997     }
998     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
999     cur->last = -1;
1000 #ifdef DEBUG_EVAL_COUNTS
1001     cur->nb = 0;
1002 #endif
1003     return(cur);
1004 }
1005 
1006 /**
1007  * xmlXPathFreeCompExpr:
1008  * @comp:  an XPATH comp
1009  *
1010  * Free up the memory allocated by @comp
1011  */
1012 void
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)1013 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1014 {
1015     xmlXPathStepOpPtr op;
1016     int i;
1017 
1018     if (comp == NULL)
1019         return;
1020     if (comp->dict == NULL) {
1021 	for (i = 0; i < comp->nbStep; i++) {
1022 	    op = &comp->steps[i];
1023 	    if (op->value4 != NULL) {
1024 		if (op->op == XPATH_OP_VALUE)
1025 		    xmlXPathFreeObject(op->value4);
1026 		else
1027 		    xmlFree(op->value4);
1028 	    }
1029 	    if (op->value5 != NULL)
1030 		xmlFree(op->value5);
1031 	}
1032     } else {
1033 	for (i = 0; i < comp->nbStep; i++) {
1034 	    op = &comp->steps[i];
1035 	    if (op->value4 != NULL) {
1036 		if (op->op == XPATH_OP_VALUE)
1037 		    xmlXPathFreeObject(op->value4);
1038 	    }
1039 	}
1040         xmlDictFree(comp->dict);
1041     }
1042     if (comp->steps != NULL) {
1043         xmlFree(comp->steps);
1044     }
1045 #ifdef DEBUG_EVAL_COUNTS
1046     if (comp->string != NULL) {
1047         xmlFree(comp->string);
1048     }
1049 #endif
1050 #ifdef XPATH_STREAMING
1051     if (comp->stream != NULL) {
1052         xmlFreePatternList(comp->stream);
1053     }
1054 #endif
1055     if (comp->expr != NULL) {
1056         xmlFree(comp->expr);
1057     }
1058 
1059     xmlFree(comp);
1060 }
1061 
1062 /**
1063  * xmlXPathCompExprAdd:
1064  * @comp:  the compiled expression
1065  * @ch1: first child index
1066  * @ch2: second child index
1067  * @op:  an op
1068  * @value:  the first int value
1069  * @value2:  the second int value
1070  * @value3:  the third int value
1071  * @value4:  the first string value
1072  * @value5:  the second string value
1073  *
1074  * Add a step to an XPath Compiled Expression
1075  *
1076  * Returns -1 in case of failure, the index otherwise
1077  */
1078 static int
xmlXPathCompExprAdd(xmlXPathCompExprPtr comp,int ch1,int ch2,xmlXPathOp op,int value,int value2,int value3,void * value4,void * value5)1079 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
1080    xmlXPathOp op, int value,
1081    int value2, int value3, void *value4, void *value5) {
1082     if (comp->nbStep >= comp->maxStep) {
1083 	xmlXPathStepOp *real;
1084 
1085         if (comp->maxStep >= XPATH_MAX_STEPS) {
1086 	    xmlXPathErrMemory(NULL, "adding step\n");
1087 	    return(-1);
1088         }
1089 	comp->maxStep *= 2;
1090 	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1091 		                      comp->maxStep * sizeof(xmlXPathStepOp));
1092 	if (real == NULL) {
1093 	    comp->maxStep /= 2;
1094 	    xmlXPathErrMemory(NULL, "adding step\n");
1095 	    return(-1);
1096 	}
1097 	comp->steps = real;
1098     }
1099     comp->last = comp->nbStep;
1100     comp->steps[comp->nbStep].ch1 = ch1;
1101     comp->steps[comp->nbStep].ch2 = ch2;
1102     comp->steps[comp->nbStep].op = op;
1103     comp->steps[comp->nbStep].value = value;
1104     comp->steps[comp->nbStep].value2 = value2;
1105     comp->steps[comp->nbStep].value3 = value3;
1106     if ((comp->dict != NULL) &&
1107         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1108 	 (op == XPATH_OP_COLLECT))) {
1109         if (value4 != NULL) {
1110 	    comp->steps[comp->nbStep].value4 = (xmlChar *)
1111 	        (void *)xmlDictLookup(comp->dict, value4, -1);
1112 	    xmlFree(value4);
1113 	} else
1114 	    comp->steps[comp->nbStep].value4 = NULL;
1115         if (value5 != NULL) {
1116 	    comp->steps[comp->nbStep].value5 = (xmlChar *)
1117 	        (void *)xmlDictLookup(comp->dict, value5, -1);
1118 	    xmlFree(value5);
1119 	} else
1120 	    comp->steps[comp->nbStep].value5 = NULL;
1121     } else {
1122 	comp->steps[comp->nbStep].value4 = value4;
1123 	comp->steps[comp->nbStep].value5 = value5;
1124     }
1125     comp->steps[comp->nbStep].cache = NULL;
1126     return(comp->nbStep++);
1127 }
1128 
1129 /**
1130  * xmlXPathCompSwap:
1131  * @comp:  the compiled expression
1132  * @op: operation index
1133  *
1134  * Swaps 2 operations in the compiled expression
1135  */
1136 static void
xmlXPathCompSwap(xmlXPathStepOpPtr op)1137 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1138     int tmp;
1139 
1140 #ifndef LIBXML_THREAD_ENABLED
1141     /*
1142      * Since this manipulates possibly shared variables, this is
1143      * disabled if one detects that the library is used in a multithreaded
1144      * application
1145      */
1146     if (xmlXPathDisableOptimizer)
1147 	return;
1148 #endif
1149 
1150     tmp = op->ch1;
1151     op->ch1 = op->ch2;
1152     op->ch2 = tmp;
1153 }
1154 
1155 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
1156     xmlXPathCompExprAdd(ctxt->comp, (op1), (op2),			\
1157 	                (op), (val), (val2), (val3), (val4), (val5))
1158 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
1159     xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1,		\
1160 	                (op), (val), (val2), (val3), (val4), (val5))
1161 
1162 #define PUSH_LEAVE_EXPR(op, val, val2)					\
1163 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1164 
1165 #define PUSH_UNARY_EXPR(op, ch, val, val2)				\
1166 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1167 
1168 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
1169 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op),			\
1170 			(val), (val2), 0 ,NULL ,NULL)
1171 
1172 /************************************************************************
1173  *									*
1174  *		XPath object cache structures				*
1175  *									*
1176  ************************************************************************/
1177 
1178 /* #define XP_DEFAULT_CACHE_ON */
1179 
1180 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1181 
1182 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1183 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1184 struct _xmlXPathContextCache {
1185     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1186     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1187     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1188     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1189     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1190     int maxNodeset;
1191     int maxString;
1192     int maxBoolean;
1193     int maxNumber;
1194     int maxMisc;
1195 #ifdef XP_DEBUG_OBJ_USAGE
1196     int dbgCachedAll;
1197     int dbgCachedNodeset;
1198     int dbgCachedString;
1199     int dbgCachedBool;
1200     int dbgCachedNumber;
1201     int dbgCachedPoint;
1202     int dbgCachedRange;
1203     int dbgCachedLocset;
1204     int dbgCachedUsers;
1205     int dbgCachedXSLTTree;
1206     int dbgCachedUndefined;
1207 
1208 
1209     int dbgReusedAll;
1210     int dbgReusedNodeset;
1211     int dbgReusedString;
1212     int dbgReusedBool;
1213     int dbgReusedNumber;
1214     int dbgReusedPoint;
1215     int dbgReusedRange;
1216     int dbgReusedLocset;
1217     int dbgReusedUsers;
1218     int dbgReusedXSLTTree;
1219     int dbgReusedUndefined;
1220 
1221 #endif
1222 };
1223 
1224 /************************************************************************
1225  *									*
1226  *		Debugging related functions				*
1227  *									*
1228  ************************************************************************/
1229 
1230 #define STRANGE							\
1231     xmlGenericError(xmlGenericErrorContext,				\
1232 	    "Internal error at %s:%d\n",				\
1233             __FILE__, __LINE__);
1234 
1235 #ifdef LIBXML_DEBUG_ENABLED
1236 static void
xmlXPathDebugDumpNode(FILE * output,xmlNodePtr cur,int depth)1237 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1238     int i;
1239     char shift[100];
1240 
1241     for (i = 0;((i < depth) && (i < 25));i++)
1242         shift[2 * i] = shift[2 * i + 1] = ' ';
1243     shift[2 * i] = shift[2 * i + 1] = 0;
1244     if (cur == NULL) {
1245 	fprintf(output, "%s", shift);
1246 	fprintf(output, "Node is NULL !\n");
1247 	return;
1248 
1249     }
1250 
1251     if ((cur->type == XML_DOCUMENT_NODE) ||
1252 	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
1253 	fprintf(output, "%s", shift);
1254 	fprintf(output, " /\n");
1255     } else if (cur->type == XML_ATTRIBUTE_NODE)
1256 	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1257     else
1258 	xmlDebugDumpOneNode(output, cur, depth);
1259 }
1260 static void
xmlXPathDebugDumpNodeList(FILE * output,xmlNodePtr cur,int depth)1261 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1262     xmlNodePtr tmp;
1263     int i;
1264     char shift[100];
1265 
1266     for (i = 0;((i < depth) && (i < 25));i++)
1267         shift[2 * i] = shift[2 * i + 1] = ' ';
1268     shift[2 * i] = shift[2 * i + 1] = 0;
1269     if (cur == NULL) {
1270 	fprintf(output, "%s", shift);
1271 	fprintf(output, "Node is NULL !\n");
1272 	return;
1273 
1274     }
1275 
1276     while (cur != NULL) {
1277 	tmp = cur;
1278 	cur = cur->next;
1279 	xmlDebugDumpOneNode(output, tmp, depth);
1280     }
1281 }
1282 
1283 static void
xmlXPathDebugDumpNodeSet(FILE * output,xmlNodeSetPtr cur,int depth)1284 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1285     int i;
1286     char shift[100];
1287 
1288     for (i = 0;((i < depth) && (i < 25));i++)
1289         shift[2 * i] = shift[2 * i + 1] = ' ';
1290     shift[2 * i] = shift[2 * i + 1] = 0;
1291 
1292     if (cur == NULL) {
1293 	fprintf(output, "%s", shift);
1294 	fprintf(output, "NodeSet is NULL !\n");
1295 	return;
1296 
1297     }
1298 
1299     if (cur != NULL) {
1300 	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1301 	for (i = 0;i < cur->nodeNr;i++) {
1302 	    fprintf(output, "%s", shift);
1303 	    fprintf(output, "%d", i + 1);
1304 	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1305 	}
1306     }
1307 }
1308 
1309 static void
xmlXPathDebugDumpValueTree(FILE * output,xmlNodeSetPtr cur,int depth)1310 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1311     int i;
1312     char shift[100];
1313 
1314     for (i = 0;((i < depth) && (i < 25));i++)
1315         shift[2 * i] = shift[2 * i + 1] = ' ';
1316     shift[2 * i] = shift[2 * i + 1] = 0;
1317 
1318     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1319 	fprintf(output, "%s", shift);
1320 	fprintf(output, "Value Tree is NULL !\n");
1321 	return;
1322 
1323     }
1324 
1325     fprintf(output, "%s", shift);
1326     fprintf(output, "%d", i + 1);
1327     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1328 }
1329 #if defined(LIBXML_XPTR_ENABLED)
1330 static void
xmlXPathDebugDumpLocationSet(FILE * output,xmlLocationSetPtr cur,int depth)1331 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1332     int i;
1333     char shift[100];
1334 
1335     for (i = 0;((i < depth) && (i < 25));i++)
1336         shift[2 * i] = shift[2 * i + 1] = ' ';
1337     shift[2 * i] = shift[2 * i + 1] = 0;
1338 
1339     if (cur == NULL) {
1340 	fprintf(output, "%s", shift);
1341 	fprintf(output, "LocationSet is NULL !\n");
1342 	return;
1343 
1344     }
1345 
1346     for (i = 0;i < cur->locNr;i++) {
1347 	fprintf(output, "%s", shift);
1348         fprintf(output, "%d : ", i + 1);
1349 	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1350     }
1351 }
1352 #endif /* LIBXML_XPTR_ENABLED */
1353 
1354 /**
1355  * xmlXPathDebugDumpObject:
1356  * @output:  the FILE * to dump the output
1357  * @cur:  the object to inspect
1358  * @depth:  indentation level
1359  *
1360  * Dump the content of the object for debugging purposes
1361  */
1362 void
xmlXPathDebugDumpObject(FILE * output,xmlXPathObjectPtr cur,int depth)1363 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1364     int i;
1365     char shift[100];
1366 
1367     if (output == NULL) return;
1368 
1369     for (i = 0;((i < depth) && (i < 25));i++)
1370         shift[2 * i] = shift[2 * i + 1] = ' ';
1371     shift[2 * i] = shift[2 * i + 1] = 0;
1372 
1373 
1374     fprintf(output, "%s", shift);
1375 
1376     if (cur == NULL) {
1377         fprintf(output, "Object is empty (NULL)\n");
1378 	return;
1379     }
1380     switch(cur->type) {
1381         case XPATH_UNDEFINED:
1382 	    fprintf(output, "Object is uninitialized\n");
1383 	    break;
1384         case XPATH_NODESET:
1385 	    fprintf(output, "Object is a Node Set :\n");
1386 	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1387 	    break;
1388 	case XPATH_XSLT_TREE:
1389 	    fprintf(output, "Object is an XSLT value tree :\n");
1390 	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1391 	    break;
1392         case XPATH_BOOLEAN:
1393 	    fprintf(output, "Object is a Boolean : ");
1394 	    if (cur->boolval) fprintf(output, "true\n");
1395 	    else fprintf(output, "false\n");
1396 	    break;
1397         case XPATH_NUMBER:
1398 	    switch (xmlXPathIsInf(cur->floatval)) {
1399 	    case 1:
1400 		fprintf(output, "Object is a number : Infinity\n");
1401 		break;
1402 	    case -1:
1403 		fprintf(output, "Object is a number : -Infinity\n");
1404 		break;
1405 	    default:
1406 		if (xmlXPathIsNaN(cur->floatval)) {
1407 		    fprintf(output, "Object is a number : NaN\n");
1408 		} else if (cur->floatval == 0) {
1409                     /* Omit sign for negative zero. */
1410 		    fprintf(output, "Object is a number : 0\n");
1411 		} else {
1412 		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
1413 		}
1414 	    }
1415 	    break;
1416         case XPATH_STRING:
1417 	    fprintf(output, "Object is a string : ");
1418 	    xmlDebugDumpString(output, cur->stringval);
1419 	    fprintf(output, "\n");
1420 	    break;
1421 	case XPATH_POINT:
1422 	    fprintf(output, "Object is a point : index %d in node", cur->index);
1423 	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1424 	    fprintf(output, "\n");
1425 	    break;
1426 	case XPATH_RANGE:
1427 	    if ((cur->user2 == NULL) ||
1428 		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1429 		fprintf(output, "Object is a collapsed range :\n");
1430 		fprintf(output, "%s", shift);
1431 		if (cur->index >= 0)
1432 		    fprintf(output, "index %d in ", cur->index);
1433 		fprintf(output, "node\n");
1434 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1435 			              depth + 1);
1436 	    } else  {
1437 		fprintf(output, "Object is a range :\n");
1438 		fprintf(output, "%s", shift);
1439 		fprintf(output, "From ");
1440 		if (cur->index >= 0)
1441 		    fprintf(output, "index %d in ", cur->index);
1442 		fprintf(output, "node\n");
1443 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1444 			              depth + 1);
1445 		fprintf(output, "%s", shift);
1446 		fprintf(output, "To ");
1447 		if (cur->index2 >= 0)
1448 		    fprintf(output, "index %d in ", cur->index2);
1449 		fprintf(output, "node\n");
1450 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1451 			              depth + 1);
1452 		fprintf(output, "\n");
1453 	    }
1454 	    break;
1455 	case XPATH_LOCATIONSET:
1456 #if defined(LIBXML_XPTR_ENABLED)
1457 	    fprintf(output, "Object is a Location Set:\n");
1458 	    xmlXPathDebugDumpLocationSet(output,
1459 		    (xmlLocationSetPtr) cur->user, depth);
1460 #endif
1461 	    break;
1462 	case XPATH_USERS:
1463 	    fprintf(output, "Object is user defined\n");
1464 	    break;
1465     }
1466 }
1467 
1468 static void
xmlXPathDebugDumpStepOp(FILE * output,xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op,int depth)1469 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1470 	                     xmlXPathStepOpPtr op, int depth) {
1471     int i;
1472     char shift[100];
1473 
1474     for (i = 0;((i < depth) && (i < 25));i++)
1475         shift[2 * i] = shift[2 * i + 1] = ' ';
1476     shift[2 * i] = shift[2 * i + 1] = 0;
1477 
1478     fprintf(output, "%s", shift);
1479     if (op == NULL) {
1480 	fprintf(output, "Step is NULL\n");
1481 	return;
1482     }
1483     switch (op->op) {
1484         case XPATH_OP_END:
1485 	    fprintf(output, "END"); break;
1486         case XPATH_OP_AND:
1487 	    fprintf(output, "AND"); break;
1488         case XPATH_OP_OR:
1489 	    fprintf(output, "OR"); break;
1490         case XPATH_OP_EQUAL:
1491 	     if (op->value)
1492 		 fprintf(output, "EQUAL =");
1493 	     else
1494 		 fprintf(output, "EQUAL !=");
1495 	     break;
1496         case XPATH_OP_CMP:
1497 	     if (op->value)
1498 		 fprintf(output, "CMP <");
1499 	     else
1500 		 fprintf(output, "CMP >");
1501 	     if (!op->value2)
1502 		 fprintf(output, "=");
1503 	     break;
1504         case XPATH_OP_PLUS:
1505 	     if (op->value == 0)
1506 		 fprintf(output, "PLUS -");
1507 	     else if (op->value == 1)
1508 		 fprintf(output, "PLUS +");
1509 	     else if (op->value == 2)
1510 		 fprintf(output, "PLUS unary -");
1511 	     else if (op->value == 3)
1512 		 fprintf(output, "PLUS unary - -");
1513 	     break;
1514         case XPATH_OP_MULT:
1515 	     if (op->value == 0)
1516 		 fprintf(output, "MULT *");
1517 	     else if (op->value == 1)
1518 		 fprintf(output, "MULT div");
1519 	     else
1520 		 fprintf(output, "MULT mod");
1521 	     break;
1522         case XPATH_OP_UNION:
1523 	     fprintf(output, "UNION"); break;
1524         case XPATH_OP_ROOT:
1525 	     fprintf(output, "ROOT"); break;
1526         case XPATH_OP_NODE:
1527 	     fprintf(output, "NODE"); break;
1528         case XPATH_OP_SORT:
1529 	     fprintf(output, "SORT"); break;
1530         case XPATH_OP_COLLECT: {
1531 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1532 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1533 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1534 	    const xmlChar *prefix = op->value4;
1535 	    const xmlChar *name = op->value5;
1536 
1537 	    fprintf(output, "COLLECT ");
1538 	    switch (axis) {
1539 		case AXIS_ANCESTOR:
1540 		    fprintf(output, " 'ancestors' "); break;
1541 		case AXIS_ANCESTOR_OR_SELF:
1542 		    fprintf(output, " 'ancestors-or-self' "); break;
1543 		case AXIS_ATTRIBUTE:
1544 		    fprintf(output, " 'attributes' "); break;
1545 		case AXIS_CHILD:
1546 		    fprintf(output, " 'child' "); break;
1547 		case AXIS_DESCENDANT:
1548 		    fprintf(output, " 'descendant' "); break;
1549 		case AXIS_DESCENDANT_OR_SELF:
1550 		    fprintf(output, " 'descendant-or-self' "); break;
1551 		case AXIS_FOLLOWING:
1552 		    fprintf(output, " 'following' "); break;
1553 		case AXIS_FOLLOWING_SIBLING:
1554 		    fprintf(output, " 'following-siblings' "); break;
1555 		case AXIS_NAMESPACE:
1556 		    fprintf(output, " 'namespace' "); break;
1557 		case AXIS_PARENT:
1558 		    fprintf(output, " 'parent' "); break;
1559 		case AXIS_PRECEDING:
1560 		    fprintf(output, " 'preceding' "); break;
1561 		case AXIS_PRECEDING_SIBLING:
1562 		    fprintf(output, " 'preceding-sibling' "); break;
1563 		case AXIS_SELF:
1564 		    fprintf(output, " 'self' "); break;
1565 	    }
1566 	    switch (test) {
1567                 case NODE_TEST_NONE:
1568 		    fprintf(output, "'none' "); break;
1569                 case NODE_TEST_TYPE:
1570 		    fprintf(output, "'type' "); break;
1571                 case NODE_TEST_PI:
1572 		    fprintf(output, "'PI' "); break;
1573                 case NODE_TEST_ALL:
1574 		    fprintf(output, "'all' "); break;
1575                 case NODE_TEST_NS:
1576 		    fprintf(output, "'namespace' "); break;
1577                 case NODE_TEST_NAME:
1578 		    fprintf(output, "'name' "); break;
1579 	    }
1580 	    switch (type) {
1581                 case NODE_TYPE_NODE:
1582 		    fprintf(output, "'node' "); break;
1583                 case NODE_TYPE_COMMENT:
1584 		    fprintf(output, "'comment' "); break;
1585                 case NODE_TYPE_TEXT:
1586 		    fprintf(output, "'text' "); break;
1587                 case NODE_TYPE_PI:
1588 		    fprintf(output, "'PI' "); break;
1589 	    }
1590 	    if (prefix != NULL)
1591 		fprintf(output, "%s:", prefix);
1592 	    if (name != NULL)
1593 		fprintf(output, "%s", (const char *) name);
1594 	    break;
1595 
1596         }
1597 	case XPATH_OP_VALUE: {
1598 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1599 
1600 	    fprintf(output, "ELEM ");
1601 	    xmlXPathDebugDumpObject(output, object, 0);
1602 	    goto finish;
1603 	}
1604 	case XPATH_OP_VARIABLE: {
1605 	    const xmlChar *prefix = op->value5;
1606 	    const xmlChar *name = op->value4;
1607 
1608 	    if (prefix != NULL)
1609 		fprintf(output, "VARIABLE %s:%s", prefix, name);
1610 	    else
1611 		fprintf(output, "VARIABLE %s", name);
1612 	    break;
1613 	}
1614 	case XPATH_OP_FUNCTION: {
1615 	    int nbargs = op->value;
1616 	    const xmlChar *prefix = op->value5;
1617 	    const xmlChar *name = op->value4;
1618 
1619 	    if (prefix != NULL)
1620 		fprintf(output, "FUNCTION %s:%s(%d args)",
1621 			prefix, name, nbargs);
1622 	    else
1623 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1624 	    break;
1625 	}
1626         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1627         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1628         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1629 #ifdef LIBXML_XPTR_ENABLED
1630         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1631 #endif
1632 	default:
1633         fprintf(output, "UNKNOWN %d\n", op->op); return;
1634     }
1635     fprintf(output, "\n");
1636 finish:
1637     if (op->ch1 >= 0)
1638 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1639     if (op->ch2 >= 0)
1640 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1641 }
1642 
1643 /**
1644  * xmlXPathDebugDumpCompExpr:
1645  * @output:  the FILE * for the output
1646  * @comp:  the precompiled XPath expression
1647  * @depth:  the indentation level.
1648  *
1649  * Dumps the tree of the compiled XPath expression.
1650  */
1651 void
xmlXPathDebugDumpCompExpr(FILE * output,xmlXPathCompExprPtr comp,int depth)1652 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1653 	                  int depth) {
1654     int i;
1655     char shift[100];
1656 
1657     if ((output == NULL) || (comp == NULL)) return;
1658 
1659     for (i = 0;((i < depth) && (i < 25));i++)
1660         shift[2 * i] = shift[2 * i + 1] = ' ';
1661     shift[2 * i] = shift[2 * i + 1] = 0;
1662 
1663     fprintf(output, "%s", shift);
1664 
1665 #ifdef XPATH_STREAMING
1666     if (comp->stream) {
1667         fprintf(output, "Streaming Expression\n");
1668     } else
1669 #endif
1670     {
1671         fprintf(output, "Compiled Expression : %d elements\n",
1672                 comp->nbStep);
1673         i = comp->last;
1674         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1675     }
1676 }
1677 
1678 #ifdef XP_DEBUG_OBJ_USAGE
1679 
1680 /*
1681 * XPath object usage related debugging variables.
1682 */
1683 static int xmlXPathDebugObjCounterUndefined = 0;
1684 static int xmlXPathDebugObjCounterNodeset = 0;
1685 static int xmlXPathDebugObjCounterBool = 0;
1686 static int xmlXPathDebugObjCounterNumber = 0;
1687 static int xmlXPathDebugObjCounterString = 0;
1688 static int xmlXPathDebugObjCounterPoint = 0;
1689 static int xmlXPathDebugObjCounterRange = 0;
1690 static int xmlXPathDebugObjCounterLocset = 0;
1691 static int xmlXPathDebugObjCounterUsers = 0;
1692 static int xmlXPathDebugObjCounterXSLTTree = 0;
1693 static int xmlXPathDebugObjCounterAll = 0;
1694 
1695 static int xmlXPathDebugObjTotalUndefined = 0;
1696 static int xmlXPathDebugObjTotalNodeset = 0;
1697 static int xmlXPathDebugObjTotalBool = 0;
1698 static int xmlXPathDebugObjTotalNumber = 0;
1699 static int xmlXPathDebugObjTotalString = 0;
1700 static int xmlXPathDebugObjTotalPoint = 0;
1701 static int xmlXPathDebugObjTotalRange = 0;
1702 static int xmlXPathDebugObjTotalLocset = 0;
1703 static int xmlXPathDebugObjTotalUsers = 0;
1704 static int xmlXPathDebugObjTotalXSLTTree = 0;
1705 static int xmlXPathDebugObjTotalAll = 0;
1706 
1707 static int xmlXPathDebugObjMaxUndefined = 0;
1708 static int xmlXPathDebugObjMaxNodeset = 0;
1709 static int xmlXPathDebugObjMaxBool = 0;
1710 static int xmlXPathDebugObjMaxNumber = 0;
1711 static int xmlXPathDebugObjMaxString = 0;
1712 static int xmlXPathDebugObjMaxPoint = 0;
1713 static int xmlXPathDebugObjMaxRange = 0;
1714 static int xmlXPathDebugObjMaxLocset = 0;
1715 static int xmlXPathDebugObjMaxUsers = 0;
1716 static int xmlXPathDebugObjMaxXSLTTree = 0;
1717 static int xmlXPathDebugObjMaxAll = 0;
1718 
1719 /* REVISIT TODO: Make this static when committing */
1720 static void
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)1721 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1722 {
1723     if (ctxt != NULL) {
1724 	if (ctxt->cache != NULL) {
1725 	    xmlXPathContextCachePtr cache =
1726 		(xmlXPathContextCachePtr) ctxt->cache;
1727 
1728 	    cache->dbgCachedAll = 0;
1729 	    cache->dbgCachedNodeset = 0;
1730 	    cache->dbgCachedString = 0;
1731 	    cache->dbgCachedBool = 0;
1732 	    cache->dbgCachedNumber = 0;
1733 	    cache->dbgCachedPoint = 0;
1734 	    cache->dbgCachedRange = 0;
1735 	    cache->dbgCachedLocset = 0;
1736 	    cache->dbgCachedUsers = 0;
1737 	    cache->dbgCachedXSLTTree = 0;
1738 	    cache->dbgCachedUndefined = 0;
1739 
1740 	    cache->dbgReusedAll = 0;
1741 	    cache->dbgReusedNodeset = 0;
1742 	    cache->dbgReusedString = 0;
1743 	    cache->dbgReusedBool = 0;
1744 	    cache->dbgReusedNumber = 0;
1745 	    cache->dbgReusedPoint = 0;
1746 	    cache->dbgReusedRange = 0;
1747 	    cache->dbgReusedLocset = 0;
1748 	    cache->dbgReusedUsers = 0;
1749 	    cache->dbgReusedXSLTTree = 0;
1750 	    cache->dbgReusedUndefined = 0;
1751 	}
1752     }
1753 
1754     xmlXPathDebugObjCounterUndefined = 0;
1755     xmlXPathDebugObjCounterNodeset = 0;
1756     xmlXPathDebugObjCounterBool = 0;
1757     xmlXPathDebugObjCounterNumber = 0;
1758     xmlXPathDebugObjCounterString = 0;
1759     xmlXPathDebugObjCounterPoint = 0;
1760     xmlXPathDebugObjCounterRange = 0;
1761     xmlXPathDebugObjCounterLocset = 0;
1762     xmlXPathDebugObjCounterUsers = 0;
1763     xmlXPathDebugObjCounterXSLTTree = 0;
1764     xmlXPathDebugObjCounterAll = 0;
1765 
1766     xmlXPathDebugObjTotalUndefined = 0;
1767     xmlXPathDebugObjTotalNodeset = 0;
1768     xmlXPathDebugObjTotalBool = 0;
1769     xmlXPathDebugObjTotalNumber = 0;
1770     xmlXPathDebugObjTotalString = 0;
1771     xmlXPathDebugObjTotalPoint = 0;
1772     xmlXPathDebugObjTotalRange = 0;
1773     xmlXPathDebugObjTotalLocset = 0;
1774     xmlXPathDebugObjTotalUsers = 0;
1775     xmlXPathDebugObjTotalXSLTTree = 0;
1776     xmlXPathDebugObjTotalAll = 0;
1777 
1778     xmlXPathDebugObjMaxUndefined = 0;
1779     xmlXPathDebugObjMaxNodeset = 0;
1780     xmlXPathDebugObjMaxBool = 0;
1781     xmlXPathDebugObjMaxNumber = 0;
1782     xmlXPathDebugObjMaxString = 0;
1783     xmlXPathDebugObjMaxPoint = 0;
1784     xmlXPathDebugObjMaxRange = 0;
1785     xmlXPathDebugObjMaxLocset = 0;
1786     xmlXPathDebugObjMaxUsers = 0;
1787     xmlXPathDebugObjMaxXSLTTree = 0;
1788     xmlXPathDebugObjMaxAll = 0;
1789 
1790 }
1791 
1792 static void
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,xmlXPathObjectType objType)1793 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1794 			      xmlXPathObjectType objType)
1795 {
1796     int isCached = 0;
1797 
1798     if (ctxt != NULL) {
1799 	if (ctxt->cache != NULL) {
1800 	    xmlXPathContextCachePtr cache =
1801 		(xmlXPathContextCachePtr) ctxt->cache;
1802 
1803 	    isCached = 1;
1804 
1805 	    cache->dbgReusedAll++;
1806 	    switch (objType) {
1807 		case XPATH_UNDEFINED:
1808 		    cache->dbgReusedUndefined++;
1809 		    break;
1810 		case XPATH_NODESET:
1811 		    cache->dbgReusedNodeset++;
1812 		    break;
1813 		case XPATH_BOOLEAN:
1814 		    cache->dbgReusedBool++;
1815 		    break;
1816 		case XPATH_NUMBER:
1817 		    cache->dbgReusedNumber++;
1818 		    break;
1819 		case XPATH_STRING:
1820 		    cache->dbgReusedString++;
1821 		    break;
1822 		case XPATH_POINT:
1823 		    cache->dbgReusedPoint++;
1824 		    break;
1825 		case XPATH_RANGE:
1826 		    cache->dbgReusedRange++;
1827 		    break;
1828 		case XPATH_LOCATIONSET:
1829 		    cache->dbgReusedLocset++;
1830 		    break;
1831 		case XPATH_USERS:
1832 		    cache->dbgReusedUsers++;
1833 		    break;
1834 		case XPATH_XSLT_TREE:
1835 		    cache->dbgReusedXSLTTree++;
1836 		    break;
1837 		default:
1838 		    break;
1839 	    }
1840 	}
1841     }
1842 
1843     switch (objType) {
1844 	case XPATH_UNDEFINED:
1845 	    if (! isCached)
1846 		xmlXPathDebugObjTotalUndefined++;
1847 	    xmlXPathDebugObjCounterUndefined++;
1848 	    if (xmlXPathDebugObjCounterUndefined >
1849 		xmlXPathDebugObjMaxUndefined)
1850 		xmlXPathDebugObjMaxUndefined =
1851 		    xmlXPathDebugObjCounterUndefined;
1852 	    break;
1853 	case XPATH_NODESET:
1854 	    if (! isCached)
1855 		xmlXPathDebugObjTotalNodeset++;
1856 	    xmlXPathDebugObjCounterNodeset++;
1857 	    if (xmlXPathDebugObjCounterNodeset >
1858 		xmlXPathDebugObjMaxNodeset)
1859 		xmlXPathDebugObjMaxNodeset =
1860 		    xmlXPathDebugObjCounterNodeset;
1861 	    break;
1862 	case XPATH_BOOLEAN:
1863 	    if (! isCached)
1864 		xmlXPathDebugObjTotalBool++;
1865 	    xmlXPathDebugObjCounterBool++;
1866 	    if (xmlXPathDebugObjCounterBool >
1867 		xmlXPathDebugObjMaxBool)
1868 		xmlXPathDebugObjMaxBool =
1869 		    xmlXPathDebugObjCounterBool;
1870 	    break;
1871 	case XPATH_NUMBER:
1872 	    if (! isCached)
1873 		xmlXPathDebugObjTotalNumber++;
1874 	    xmlXPathDebugObjCounterNumber++;
1875 	    if (xmlXPathDebugObjCounterNumber >
1876 		xmlXPathDebugObjMaxNumber)
1877 		xmlXPathDebugObjMaxNumber =
1878 		    xmlXPathDebugObjCounterNumber;
1879 	    break;
1880 	case XPATH_STRING:
1881 	    if (! isCached)
1882 		xmlXPathDebugObjTotalString++;
1883 	    xmlXPathDebugObjCounterString++;
1884 	    if (xmlXPathDebugObjCounterString >
1885 		xmlXPathDebugObjMaxString)
1886 		xmlXPathDebugObjMaxString =
1887 		    xmlXPathDebugObjCounterString;
1888 	    break;
1889 	case XPATH_POINT:
1890 	    if (! isCached)
1891 		xmlXPathDebugObjTotalPoint++;
1892 	    xmlXPathDebugObjCounterPoint++;
1893 	    if (xmlXPathDebugObjCounterPoint >
1894 		xmlXPathDebugObjMaxPoint)
1895 		xmlXPathDebugObjMaxPoint =
1896 		    xmlXPathDebugObjCounterPoint;
1897 	    break;
1898 	case XPATH_RANGE:
1899 	    if (! isCached)
1900 		xmlXPathDebugObjTotalRange++;
1901 	    xmlXPathDebugObjCounterRange++;
1902 	    if (xmlXPathDebugObjCounterRange >
1903 		xmlXPathDebugObjMaxRange)
1904 		xmlXPathDebugObjMaxRange =
1905 		    xmlXPathDebugObjCounterRange;
1906 	    break;
1907 	case XPATH_LOCATIONSET:
1908 	    if (! isCached)
1909 		xmlXPathDebugObjTotalLocset++;
1910 	    xmlXPathDebugObjCounterLocset++;
1911 	    if (xmlXPathDebugObjCounterLocset >
1912 		xmlXPathDebugObjMaxLocset)
1913 		xmlXPathDebugObjMaxLocset =
1914 		    xmlXPathDebugObjCounterLocset;
1915 	    break;
1916 	case XPATH_USERS:
1917 	    if (! isCached)
1918 		xmlXPathDebugObjTotalUsers++;
1919 	    xmlXPathDebugObjCounterUsers++;
1920 	    if (xmlXPathDebugObjCounterUsers >
1921 		xmlXPathDebugObjMaxUsers)
1922 		xmlXPathDebugObjMaxUsers =
1923 		    xmlXPathDebugObjCounterUsers;
1924 	    break;
1925 	case XPATH_XSLT_TREE:
1926 	    if (! isCached)
1927 		xmlXPathDebugObjTotalXSLTTree++;
1928 	    xmlXPathDebugObjCounterXSLTTree++;
1929 	    if (xmlXPathDebugObjCounterXSLTTree >
1930 		xmlXPathDebugObjMaxXSLTTree)
1931 		xmlXPathDebugObjMaxXSLTTree =
1932 		    xmlXPathDebugObjCounterXSLTTree;
1933 	    break;
1934 	default:
1935 	    break;
1936     }
1937     if (! isCached)
1938 	xmlXPathDebugObjTotalAll++;
1939     xmlXPathDebugObjCounterAll++;
1940     if (xmlXPathDebugObjCounterAll >
1941 	xmlXPathDebugObjMaxAll)
1942 	xmlXPathDebugObjMaxAll =
1943 	    xmlXPathDebugObjCounterAll;
1944 }
1945 
1946 static void
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,xmlXPathObjectType objType)1947 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1948 			      xmlXPathObjectType objType)
1949 {
1950     int isCached = 0;
1951 
1952     if (ctxt != NULL) {
1953 	if (ctxt->cache != NULL) {
1954 	    xmlXPathContextCachePtr cache =
1955 		(xmlXPathContextCachePtr) ctxt->cache;
1956 
1957 	    isCached = 1;
1958 
1959 	    cache->dbgCachedAll++;
1960 	    switch (objType) {
1961 		case XPATH_UNDEFINED:
1962 		    cache->dbgCachedUndefined++;
1963 		    break;
1964 		case XPATH_NODESET:
1965 		    cache->dbgCachedNodeset++;
1966 		    break;
1967 		case XPATH_BOOLEAN:
1968 		    cache->dbgCachedBool++;
1969 		    break;
1970 		case XPATH_NUMBER:
1971 		    cache->dbgCachedNumber++;
1972 		    break;
1973 		case XPATH_STRING:
1974 		    cache->dbgCachedString++;
1975 		    break;
1976 		case XPATH_POINT:
1977 		    cache->dbgCachedPoint++;
1978 		    break;
1979 		case XPATH_RANGE:
1980 		    cache->dbgCachedRange++;
1981 		    break;
1982 		case XPATH_LOCATIONSET:
1983 		    cache->dbgCachedLocset++;
1984 		    break;
1985 		case XPATH_USERS:
1986 		    cache->dbgCachedUsers++;
1987 		    break;
1988 		case XPATH_XSLT_TREE:
1989 		    cache->dbgCachedXSLTTree++;
1990 		    break;
1991 		default:
1992 		    break;
1993 	    }
1994 
1995 	}
1996     }
1997     switch (objType) {
1998 	case XPATH_UNDEFINED:
1999 	    xmlXPathDebugObjCounterUndefined--;
2000 	    break;
2001 	case XPATH_NODESET:
2002 	    xmlXPathDebugObjCounterNodeset--;
2003 	    break;
2004 	case XPATH_BOOLEAN:
2005 	    xmlXPathDebugObjCounterBool--;
2006 	    break;
2007 	case XPATH_NUMBER:
2008 	    xmlXPathDebugObjCounterNumber--;
2009 	    break;
2010 	case XPATH_STRING:
2011 	    xmlXPathDebugObjCounterString--;
2012 	    break;
2013 	case XPATH_POINT:
2014 	    xmlXPathDebugObjCounterPoint--;
2015 	    break;
2016 	case XPATH_RANGE:
2017 	    xmlXPathDebugObjCounterRange--;
2018 	    break;
2019 	case XPATH_LOCATIONSET:
2020 	    xmlXPathDebugObjCounterLocset--;
2021 	    break;
2022 	case XPATH_USERS:
2023 	    xmlXPathDebugObjCounterUsers--;
2024 	    break;
2025 	case XPATH_XSLT_TREE:
2026 	    xmlXPathDebugObjCounterXSLTTree--;
2027 	    break;
2028 	default:
2029 	    break;
2030     }
2031     xmlXPathDebugObjCounterAll--;
2032 }
2033 
2034 /* REVISIT TODO: Make this static when committing */
2035 static void
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)2036 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2037 {
2038     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2039 	reqXSLTTree, reqUndefined;
2040     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2041 	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2042     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2043 	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2044     int leftObjs = xmlXPathDebugObjCounterAll;
2045 
2046     reqAll = xmlXPathDebugObjTotalAll;
2047     reqNodeset = xmlXPathDebugObjTotalNodeset;
2048     reqString = xmlXPathDebugObjTotalString;
2049     reqBool = xmlXPathDebugObjTotalBool;
2050     reqNumber = xmlXPathDebugObjTotalNumber;
2051     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2052     reqUndefined = xmlXPathDebugObjTotalUndefined;
2053 
2054     printf("# XPath object usage:\n");
2055 
2056     if (ctxt != NULL) {
2057 	if (ctxt->cache != NULL) {
2058 	    xmlXPathContextCachePtr cache =
2059 		(xmlXPathContextCachePtr) ctxt->cache;
2060 
2061 	    reAll = cache->dbgReusedAll;
2062 	    reqAll += reAll;
2063 	    reNodeset = cache->dbgReusedNodeset;
2064 	    reqNodeset += reNodeset;
2065 	    reString = cache->dbgReusedString;
2066 	    reqString += reString;
2067 	    reBool = cache->dbgReusedBool;
2068 	    reqBool += reBool;
2069 	    reNumber = cache->dbgReusedNumber;
2070 	    reqNumber += reNumber;
2071 	    reXSLTTree = cache->dbgReusedXSLTTree;
2072 	    reqXSLTTree += reXSLTTree;
2073 	    reUndefined = cache->dbgReusedUndefined;
2074 	    reqUndefined += reUndefined;
2075 
2076 	    caAll = cache->dbgCachedAll;
2077 	    caBool = cache->dbgCachedBool;
2078 	    caNodeset = cache->dbgCachedNodeset;
2079 	    caString = cache->dbgCachedString;
2080 	    caNumber = cache->dbgCachedNumber;
2081 	    caXSLTTree = cache->dbgCachedXSLTTree;
2082 	    caUndefined = cache->dbgCachedUndefined;
2083 
2084 	    if (cache->nodesetObjs)
2085 		leftObjs -= cache->nodesetObjs->number;
2086 	    if (cache->stringObjs)
2087 		leftObjs -= cache->stringObjs->number;
2088 	    if (cache->booleanObjs)
2089 		leftObjs -= cache->booleanObjs->number;
2090 	    if (cache->numberObjs)
2091 		leftObjs -= cache->numberObjs->number;
2092 	    if (cache->miscObjs)
2093 		leftObjs -= cache->miscObjs->number;
2094 	}
2095     }
2096 
2097     printf("# all\n");
2098     printf("#   total  : %d\n", reqAll);
2099     printf("#   left  : %d\n", leftObjs);
2100     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2101     printf("#   reused : %d\n", reAll);
2102     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2103 
2104     printf("# node-sets\n");
2105     printf("#   total  : %d\n", reqNodeset);
2106     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2107     printf("#   reused : %d\n", reNodeset);
2108     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2109 
2110     printf("# strings\n");
2111     printf("#   total  : %d\n", reqString);
2112     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2113     printf("#   reused : %d\n", reString);
2114     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2115 
2116     printf("# booleans\n");
2117     printf("#   total  : %d\n", reqBool);
2118     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2119     printf("#   reused : %d\n", reBool);
2120     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2121 
2122     printf("# numbers\n");
2123     printf("#   total  : %d\n", reqNumber);
2124     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2125     printf("#   reused : %d\n", reNumber);
2126     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2127 
2128     printf("# XSLT result tree fragments\n");
2129     printf("#   total  : %d\n", reqXSLTTree);
2130     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2131     printf("#   reused : %d\n", reXSLTTree);
2132     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2133 
2134     printf("# undefined\n");
2135     printf("#   total  : %d\n", reqUndefined);
2136     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2137     printf("#   reused : %d\n", reUndefined);
2138     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2139 
2140 }
2141 
2142 #endif /* XP_DEBUG_OBJ_USAGE */
2143 
2144 #endif /* LIBXML_DEBUG_ENABLED */
2145 
2146 /************************************************************************
2147  *									*
2148  *			XPath object caching				*
2149  *									*
2150  ************************************************************************/
2151 
2152 /**
2153  * xmlXPathNewCache:
2154  *
2155  * Create a new object cache
2156  *
2157  * Returns the xmlXPathCache just allocated.
2158  */
2159 static xmlXPathContextCachePtr
xmlXPathNewCache(void)2160 xmlXPathNewCache(void)
2161 {
2162     xmlXPathContextCachePtr ret;
2163 
2164     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2165     if (ret == NULL) {
2166         xmlXPathErrMemory(NULL, "creating object cache\n");
2167 	return(NULL);
2168     }
2169     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2170     ret->maxNodeset = 100;
2171     ret->maxString = 100;
2172     ret->maxBoolean = 100;
2173     ret->maxNumber = 100;
2174     ret->maxMisc = 100;
2175     return(ret);
2176 }
2177 
2178 static void
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)2179 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2180 {
2181     int i;
2182     xmlXPathObjectPtr obj;
2183 
2184     if (list == NULL)
2185 	return;
2186 
2187     for (i = 0; i < list->number; i++) {
2188 	obj = list->items[i];
2189 	/*
2190 	* Note that it is already assured that we don't need to
2191 	* look out for namespace nodes in the node-set.
2192 	*/
2193 	if (obj->nodesetval != NULL) {
2194 	    if (obj->nodesetval->nodeTab != NULL)
2195 		xmlFree(obj->nodesetval->nodeTab);
2196 	    xmlFree(obj->nodesetval);
2197 	}
2198 	xmlFree(obj);
2199 #ifdef XP_DEBUG_OBJ_USAGE
2200 	xmlXPathDebugObjCounterAll--;
2201 #endif
2202     }
2203     xmlPointerListFree(list);
2204 }
2205 
2206 static void
xmlXPathFreeCache(xmlXPathContextCachePtr cache)2207 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2208 {
2209     if (cache == NULL)
2210 	return;
2211     if (cache->nodesetObjs)
2212 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2213     if (cache->stringObjs)
2214 	xmlXPathCacheFreeObjectList(cache->stringObjs);
2215     if (cache->booleanObjs)
2216 	xmlXPathCacheFreeObjectList(cache->booleanObjs);
2217     if (cache->numberObjs)
2218 	xmlXPathCacheFreeObjectList(cache->numberObjs);
2219     if (cache->miscObjs)
2220 	xmlXPathCacheFreeObjectList(cache->miscObjs);
2221     xmlFree(cache);
2222 }
2223 
2224 /**
2225  * xmlXPathContextSetCache:
2226  *
2227  * @ctxt:  the XPath context
2228  * @active: enables/disables (creates/frees) the cache
2229  * @value: a value with semantics dependant on @options
2230  * @options: options (currently only the value 0 is used)
2231  *
2232  * Creates/frees an object cache on the XPath context.
2233  * If activates XPath objects (xmlXPathObject) will be cached internally
2234  * to be reused.
2235  * @options:
2236  *   0: This will set the XPath object caching:
2237  *      @value:
2238  *        This will set the maximum number of XPath objects
2239  *        to be cached per slot
2240  *        There are 5 slots for: node-set, string, number, boolean, and
2241  *        misc objects. Use <0 for the default number (100).
2242  *   Other values for @options have currently no effect.
2243  *
2244  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2245  */
2246 int
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,int active,int value,int options)2247 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2248 			int active,
2249 			int value,
2250 			int options)
2251 {
2252     if (ctxt == NULL)
2253 	return(-1);
2254     if (active) {
2255 	xmlXPathContextCachePtr cache;
2256 
2257 	if (ctxt->cache == NULL) {
2258 	    ctxt->cache = xmlXPathNewCache();
2259 	    if (ctxt->cache == NULL)
2260 		return(-1);
2261 	}
2262 	cache = (xmlXPathContextCachePtr) ctxt->cache;
2263 	if (options == 0) {
2264 	    if (value < 0)
2265 		value = 100;
2266 	    cache->maxNodeset = value;
2267 	    cache->maxString = value;
2268 	    cache->maxNumber = value;
2269 	    cache->maxBoolean = value;
2270 	    cache->maxMisc = value;
2271 	}
2272     } else if (ctxt->cache != NULL) {
2273 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2274 	ctxt->cache = NULL;
2275     }
2276     return(0);
2277 }
2278 
2279 /**
2280  * xmlXPathCacheWrapNodeSet:
2281  * @ctxt: the XPath context
2282  * @val:  the NodePtr value
2283  *
2284  * This is the cached version of xmlXPathWrapNodeSet().
2285  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2286  *
2287  * Returns the created or reused object.
2288  */
2289 static xmlXPathObjectPtr
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt,xmlNodeSetPtr val)2290 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2291 {
2292     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2293 	xmlXPathContextCachePtr cache =
2294 	    (xmlXPathContextCachePtr) ctxt->cache;
2295 
2296 	if ((cache->miscObjs != NULL) &&
2297 	    (cache->miscObjs->number != 0))
2298 	{
2299 	    xmlXPathObjectPtr ret;
2300 
2301 	    ret = (xmlXPathObjectPtr)
2302 		cache->miscObjs->items[--cache->miscObjs->number];
2303 	    ret->type = XPATH_NODESET;
2304 	    ret->nodesetval = val;
2305 #ifdef XP_DEBUG_OBJ_USAGE
2306 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2307 #endif
2308 	    return(ret);
2309 	}
2310     }
2311 
2312     return(xmlXPathWrapNodeSet(val));
2313 
2314 }
2315 
2316 /**
2317  * xmlXPathCacheWrapString:
2318  * @ctxt: the XPath context
2319  * @val:  the xmlChar * value
2320  *
2321  * This is the cached version of xmlXPathWrapString().
2322  * Wraps the @val string into an XPath object.
2323  *
2324  * Returns the created or reused object.
2325  */
2326 static xmlXPathObjectPtr
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt,xmlChar * val)2327 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2328 {
2329     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2330 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2331 
2332 	if ((cache->stringObjs != NULL) &&
2333 	    (cache->stringObjs->number != 0))
2334 	{
2335 
2336 	    xmlXPathObjectPtr ret;
2337 
2338 	    ret = (xmlXPathObjectPtr)
2339 		cache->stringObjs->items[--cache->stringObjs->number];
2340 	    ret->type = XPATH_STRING;
2341 	    ret->stringval = val;
2342 #ifdef XP_DEBUG_OBJ_USAGE
2343 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2344 #endif
2345 	    return(ret);
2346 	} else if ((cache->miscObjs != NULL) &&
2347 	    (cache->miscObjs->number != 0))
2348 	{
2349 	    xmlXPathObjectPtr ret;
2350 	    /*
2351 	    * Fallback to misc-cache.
2352 	    */
2353 	    ret = (xmlXPathObjectPtr)
2354 		cache->miscObjs->items[--cache->miscObjs->number];
2355 
2356 	    ret->type = XPATH_STRING;
2357 	    ret->stringval = val;
2358 #ifdef XP_DEBUG_OBJ_USAGE
2359 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2360 #endif
2361 	    return(ret);
2362 	}
2363     }
2364     return(xmlXPathWrapString(val));
2365 }
2366 
2367 /**
2368  * xmlXPathCacheNewNodeSet:
2369  * @ctxt: the XPath context
2370  * @val:  the NodePtr value
2371  *
2372  * This is the cached version of xmlXPathNewNodeSet().
2373  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2374  * it with the single Node @val
2375  *
2376  * Returns the created or reused object.
2377  */
2378 static xmlXPathObjectPtr
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt,xmlNodePtr val)2379 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2380 {
2381     if ((ctxt != NULL) && (ctxt->cache)) {
2382 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2383 
2384 	if ((cache->nodesetObjs != NULL) &&
2385 	    (cache->nodesetObjs->number != 0))
2386 	{
2387 	    xmlXPathObjectPtr ret;
2388 	    /*
2389 	    * Use the nodset-cache.
2390 	    */
2391 	    ret = (xmlXPathObjectPtr)
2392 		cache->nodesetObjs->items[--cache->nodesetObjs->number];
2393 	    ret->type = XPATH_NODESET;
2394 	    ret->boolval = 0;
2395 	    if (val) {
2396 		if ((ret->nodesetval->nodeMax == 0) ||
2397 		    (val->type == XML_NAMESPACE_DECL))
2398 		{
2399 		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2400 		} else {
2401 		    ret->nodesetval->nodeTab[0] = val;
2402 		    ret->nodesetval->nodeNr = 1;
2403 		}
2404 	    }
2405 #ifdef XP_DEBUG_OBJ_USAGE
2406 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2407 #endif
2408 	    return(ret);
2409 	} else if ((cache->miscObjs != NULL) &&
2410 	    (cache->miscObjs->number != 0))
2411 	{
2412 	    xmlXPathObjectPtr ret;
2413 	    /*
2414 	    * Fallback to misc-cache.
2415 	    */
2416 
2417 	    ret = (xmlXPathObjectPtr)
2418 		cache->miscObjs->items[--cache->miscObjs->number];
2419 
2420 	    ret->type = XPATH_NODESET;
2421 	    ret->boolval = 0;
2422 	    ret->nodesetval = xmlXPathNodeSetCreate(val);
2423 	    if (ret->nodesetval == NULL) {
2424 		ctxt->lastError.domain = XML_FROM_XPATH;
2425 		ctxt->lastError.code = XML_ERR_NO_MEMORY;
2426 		return(NULL);
2427 	    }
2428 #ifdef XP_DEBUG_OBJ_USAGE
2429 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2430 #endif
2431 	    return(ret);
2432 	}
2433     }
2434     return(xmlXPathNewNodeSet(val));
2435 }
2436 
2437 /**
2438  * xmlXPathCacheNewCString:
2439  * @ctxt: the XPath context
2440  * @val:  the char * value
2441  *
2442  * This is the cached version of xmlXPathNewCString().
2443  * Acquire an xmlXPathObjectPtr of type string and of value @val
2444  *
2445  * Returns the created or reused object.
2446  */
2447 static xmlXPathObjectPtr
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt,const char * val)2448 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2449 {
2450     if ((ctxt != NULL) && (ctxt->cache)) {
2451 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2452 
2453 	if ((cache->stringObjs != NULL) &&
2454 	    (cache->stringObjs->number != 0))
2455 	{
2456 	    xmlXPathObjectPtr ret;
2457 
2458 	    ret = (xmlXPathObjectPtr)
2459 		cache->stringObjs->items[--cache->stringObjs->number];
2460 
2461 	    ret->type = XPATH_STRING;
2462 	    ret->stringval = xmlStrdup(BAD_CAST val);
2463 #ifdef XP_DEBUG_OBJ_USAGE
2464 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2465 #endif
2466 	    return(ret);
2467 	} else if ((cache->miscObjs != NULL) &&
2468 	    (cache->miscObjs->number != 0))
2469 	{
2470 	    xmlXPathObjectPtr ret;
2471 
2472 	    ret = (xmlXPathObjectPtr)
2473 		cache->miscObjs->items[--cache->miscObjs->number];
2474 
2475 	    ret->type = XPATH_STRING;
2476 	    ret->stringval = xmlStrdup(BAD_CAST val);
2477 #ifdef XP_DEBUG_OBJ_USAGE
2478 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2479 #endif
2480 	    return(ret);
2481 	}
2482     }
2483     return(xmlXPathNewCString(val));
2484 }
2485 
2486 /**
2487  * xmlXPathCacheNewString:
2488  * @ctxt: the XPath context
2489  * @val:  the xmlChar * value
2490  *
2491  * This is the cached version of xmlXPathNewString().
2492  * Acquire an xmlXPathObjectPtr of type string and of value @val
2493  *
2494  * Returns the created or reused object.
2495  */
2496 static xmlXPathObjectPtr
xmlXPathCacheNewString(xmlXPathContextPtr ctxt,const xmlChar * val)2497 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2498 {
2499     if ((ctxt != NULL) && (ctxt->cache)) {
2500 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2501 
2502 	if ((cache->stringObjs != NULL) &&
2503 	    (cache->stringObjs->number != 0))
2504 	{
2505 	    xmlXPathObjectPtr ret;
2506 
2507 	    ret = (xmlXPathObjectPtr)
2508 		cache->stringObjs->items[--cache->stringObjs->number];
2509 	    ret->type = XPATH_STRING;
2510 	    if (val != NULL)
2511 		ret->stringval = xmlStrdup(val);
2512 	    else
2513 		ret->stringval = xmlStrdup((const xmlChar *)"");
2514 #ifdef XP_DEBUG_OBJ_USAGE
2515 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2516 #endif
2517 	    return(ret);
2518 	} else if ((cache->miscObjs != NULL) &&
2519 	    (cache->miscObjs->number != 0))
2520 	{
2521 	    xmlXPathObjectPtr ret;
2522 
2523 	    ret = (xmlXPathObjectPtr)
2524 		cache->miscObjs->items[--cache->miscObjs->number];
2525 
2526 	    ret->type = XPATH_STRING;
2527 	    if (val != NULL)
2528 		ret->stringval = xmlStrdup(val);
2529 	    else
2530 		ret->stringval = xmlStrdup((const xmlChar *)"");
2531 #ifdef XP_DEBUG_OBJ_USAGE
2532 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2533 #endif
2534 	    return(ret);
2535 	}
2536     }
2537     return(xmlXPathNewString(val));
2538 }
2539 
2540 /**
2541  * xmlXPathCacheNewBoolean:
2542  * @ctxt: the XPath context
2543  * @val:  the boolean value
2544  *
2545  * This is the cached version of xmlXPathNewBoolean().
2546  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2547  *
2548  * Returns the created or reused object.
2549  */
2550 static xmlXPathObjectPtr
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt,int val)2551 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2552 {
2553     if ((ctxt != NULL) && (ctxt->cache)) {
2554 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2555 
2556 	if ((cache->booleanObjs != NULL) &&
2557 	    (cache->booleanObjs->number != 0))
2558 	{
2559 	    xmlXPathObjectPtr ret;
2560 
2561 	    ret = (xmlXPathObjectPtr)
2562 		cache->booleanObjs->items[--cache->booleanObjs->number];
2563 	    ret->type = XPATH_BOOLEAN;
2564 	    ret->boolval = (val != 0);
2565 #ifdef XP_DEBUG_OBJ_USAGE
2566 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2567 #endif
2568 	    return(ret);
2569 	} else if ((cache->miscObjs != NULL) &&
2570 	    (cache->miscObjs->number != 0))
2571 	{
2572 	    xmlXPathObjectPtr ret;
2573 
2574 	    ret = (xmlXPathObjectPtr)
2575 		cache->miscObjs->items[--cache->miscObjs->number];
2576 
2577 	    ret->type = XPATH_BOOLEAN;
2578 	    ret->boolval = (val != 0);
2579 #ifdef XP_DEBUG_OBJ_USAGE
2580 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2581 #endif
2582 	    return(ret);
2583 	}
2584     }
2585     return(xmlXPathNewBoolean(val));
2586 }
2587 
2588 /**
2589  * xmlXPathCacheNewFloat:
2590  * @ctxt: the XPath context
2591  * @val:  the double value
2592  *
2593  * This is the cached version of xmlXPathNewFloat().
2594  * Acquires an xmlXPathObjectPtr of type double and of value @val
2595  *
2596  * Returns the created or reused object.
2597  */
2598 static xmlXPathObjectPtr
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt,double val)2599 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2600 {
2601      if ((ctxt != NULL) && (ctxt->cache)) {
2602 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2603 
2604 	if ((cache->numberObjs != NULL) &&
2605 	    (cache->numberObjs->number != 0))
2606 	{
2607 	    xmlXPathObjectPtr ret;
2608 
2609 	    ret = (xmlXPathObjectPtr)
2610 		cache->numberObjs->items[--cache->numberObjs->number];
2611 	    ret->type = XPATH_NUMBER;
2612 	    ret->floatval = val;
2613 #ifdef XP_DEBUG_OBJ_USAGE
2614 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2615 #endif
2616 	    return(ret);
2617 	} else if ((cache->miscObjs != NULL) &&
2618 	    (cache->miscObjs->number != 0))
2619 	{
2620 	    xmlXPathObjectPtr ret;
2621 
2622 	    ret = (xmlXPathObjectPtr)
2623 		cache->miscObjs->items[--cache->miscObjs->number];
2624 
2625 	    ret->type = XPATH_NUMBER;
2626 	    ret->floatval = val;
2627 #ifdef XP_DEBUG_OBJ_USAGE
2628 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2629 #endif
2630 	    return(ret);
2631 	}
2632     }
2633     return(xmlXPathNewFloat(val));
2634 }
2635 
2636 /**
2637  * xmlXPathCacheConvertString:
2638  * @ctxt: the XPath context
2639  * @val:  an XPath object
2640  *
2641  * This is the cached version of xmlXPathConvertString().
2642  * Converts an existing object to its string() equivalent
2643  *
2644  * Returns a created or reused object, the old one is freed (cached)
2645  *         (or the operation is done directly on @val)
2646  */
2647 
2648 static xmlXPathObjectPtr
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2649 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2650     xmlChar *res = NULL;
2651 
2652     if (val == NULL)
2653 	return(xmlXPathCacheNewCString(ctxt, ""));
2654 
2655     switch (val->type) {
2656     case XPATH_UNDEFINED:
2657 #ifdef DEBUG_EXPR
2658 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2659 #endif
2660 	break;
2661     case XPATH_NODESET:
2662     case XPATH_XSLT_TREE:
2663 	res = xmlXPathCastNodeSetToString(val->nodesetval);
2664 	break;
2665     case XPATH_STRING:
2666 	return(val);
2667     case XPATH_BOOLEAN:
2668 	res = xmlXPathCastBooleanToString(val->boolval);
2669 	break;
2670     case XPATH_NUMBER:
2671 	res = xmlXPathCastNumberToString(val->floatval);
2672 	break;
2673     case XPATH_USERS:
2674     case XPATH_POINT:
2675     case XPATH_RANGE:
2676     case XPATH_LOCATIONSET:
2677 	TODO;
2678 	break;
2679     }
2680     xmlXPathReleaseObject(ctxt, val);
2681     if (res == NULL)
2682 	return(xmlXPathCacheNewCString(ctxt, ""));
2683     return(xmlXPathCacheWrapString(ctxt, res));
2684 }
2685 
2686 /**
2687  * xmlXPathCacheObjectCopy:
2688  * @ctxt: the XPath context
2689  * @val:  the original object
2690  *
2691  * This is the cached version of xmlXPathObjectCopy().
2692  * Acquire a copy of a given object
2693  *
2694  * Returns a created or reused created object.
2695  */
2696 static xmlXPathObjectPtr
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2697 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2698 {
2699     if (val == NULL)
2700 	return(NULL);
2701 
2702     if (XP_HAS_CACHE(ctxt)) {
2703 	switch (val->type) {
2704 	    case XPATH_NODESET:
2705 		return(xmlXPathCacheWrapNodeSet(ctxt,
2706 		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2707 	    case XPATH_STRING:
2708 		return(xmlXPathCacheNewString(ctxt, val->stringval));
2709 	    case XPATH_BOOLEAN:
2710 		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2711 	    case XPATH_NUMBER:
2712 		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2713 	    default:
2714 		break;
2715 	}
2716     }
2717     return(xmlXPathObjectCopy(val));
2718 }
2719 
2720 /**
2721  * xmlXPathCacheConvertBoolean:
2722  * @ctxt: the XPath context
2723  * @val:  an XPath object
2724  *
2725  * This is the cached version of xmlXPathConvertBoolean().
2726  * Converts an existing object to its boolean() equivalent
2727  *
2728  * Returns a created or reused object, the old one is freed (or the operation
2729  *         is done directly on @val)
2730  */
2731 static xmlXPathObjectPtr
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2732 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2733     xmlXPathObjectPtr ret;
2734 
2735     if (val == NULL)
2736 	return(xmlXPathCacheNewBoolean(ctxt, 0));
2737     if (val->type == XPATH_BOOLEAN)
2738 	return(val);
2739     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2740     xmlXPathReleaseObject(ctxt, val);
2741     return(ret);
2742 }
2743 
2744 /**
2745  * xmlXPathCacheConvertNumber:
2746  * @ctxt: the XPath context
2747  * @val:  an XPath object
2748  *
2749  * This is the cached version of xmlXPathConvertNumber().
2750  * Converts an existing object to its number() equivalent
2751  *
2752  * Returns a created or reused object, the old one is freed (or the operation
2753  *         is done directly on @val)
2754  */
2755 static xmlXPathObjectPtr
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2756 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2757     xmlXPathObjectPtr ret;
2758 
2759     if (val == NULL)
2760 	return(xmlXPathCacheNewFloat(ctxt, 0.0));
2761     if (val->type == XPATH_NUMBER)
2762 	return(val);
2763     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2764     xmlXPathReleaseObject(ctxt, val);
2765     return(ret);
2766 }
2767 
2768 /************************************************************************
2769  *									*
2770  *		Parser stacks related functions and macros		*
2771  *									*
2772  ************************************************************************/
2773 
2774 /**
2775  * xmlXPathSetFrame:
2776  * @ctxt: an XPath parser context
2777  *
2778  * Set the callee evaluation frame
2779  *
2780  * Returns the previous frame value to be restored once done
2781  */
2782 static int
xmlXPathSetFrame(xmlXPathParserContextPtr ctxt)2783 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2784     int ret;
2785 
2786     if (ctxt == NULL)
2787         return(0);
2788     ret = ctxt->valueFrame;
2789     ctxt->valueFrame = ctxt->valueNr;
2790     return(ret);
2791 }
2792 
2793 /**
2794  * xmlXPathPopFrame:
2795  * @ctxt: an XPath parser context
2796  * @frame: the previous frame value
2797  *
2798  * Remove the callee evaluation frame
2799  */
2800 static void
xmlXPathPopFrame(xmlXPathParserContextPtr ctxt,int frame)2801 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2802     if (ctxt == NULL)
2803         return;
2804     if (ctxt->valueNr < ctxt->valueFrame) {
2805         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2806     }
2807     ctxt->valueFrame = frame;
2808 }
2809 
2810 /**
2811  * valuePop:
2812  * @ctxt: an XPath evaluation context
2813  *
2814  * Pops the top XPath object from the value stack
2815  *
2816  * Returns the XPath object just removed
2817  */
2818 xmlXPathObjectPtr
valuePop(xmlXPathParserContextPtr ctxt)2819 valuePop(xmlXPathParserContextPtr ctxt)
2820 {
2821     xmlXPathObjectPtr ret;
2822 
2823     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2824         return (NULL);
2825 
2826     if (ctxt->valueNr <= ctxt->valueFrame) {
2827         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2828         return (NULL);
2829     }
2830 
2831     ctxt->valueNr--;
2832     if (ctxt->valueNr > 0)
2833         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2834     else
2835         ctxt->value = NULL;
2836     ret = ctxt->valueTab[ctxt->valueNr];
2837     ctxt->valueTab[ctxt->valueNr] = NULL;
2838     return (ret);
2839 }
2840 /**
2841  * valuePush:
2842  * @ctxt:  an XPath evaluation context
2843  * @value:  the XPath object
2844  *
2845  * Pushes a new XPath object on top of the value stack
2846  *
2847  * returns the number of items on the value stack
2848  */
2849 int
valuePush(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr value)2850 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2851 {
2852     if ((ctxt == NULL) || (value == NULL)) return(-1);
2853     if (ctxt->valueNr >= ctxt->valueMax) {
2854         xmlXPathObjectPtr *tmp;
2855 
2856         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2857             xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2858             ctxt->error = XPATH_MEMORY_ERROR;
2859             return (0);
2860         }
2861         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2862                                              2 * ctxt->valueMax *
2863                                              sizeof(ctxt->valueTab[0]));
2864         if (tmp == NULL) {
2865             xmlXPathErrMemory(NULL, "pushing value\n");
2866             ctxt->error = XPATH_MEMORY_ERROR;
2867             return (0);
2868         }
2869         ctxt->valueMax *= 2;
2870 	ctxt->valueTab = tmp;
2871     }
2872     ctxt->valueTab[ctxt->valueNr] = value;
2873     ctxt->value = value;
2874     return (ctxt->valueNr++);
2875 }
2876 
2877 /**
2878  * xmlXPathPopBoolean:
2879  * @ctxt:  an XPath parser context
2880  *
2881  * Pops a boolean from the stack, handling conversion if needed.
2882  * Check error with #xmlXPathCheckError.
2883  *
2884  * Returns the boolean
2885  */
2886 int
xmlXPathPopBoolean(xmlXPathParserContextPtr ctxt)2887 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2888     xmlXPathObjectPtr obj;
2889     int ret;
2890 
2891     obj = valuePop(ctxt);
2892     if (obj == NULL) {
2893 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2894 	return(0);
2895     }
2896     if (obj->type != XPATH_BOOLEAN)
2897 	ret = xmlXPathCastToBoolean(obj);
2898     else
2899         ret = obj->boolval;
2900     xmlXPathReleaseObject(ctxt->context, obj);
2901     return(ret);
2902 }
2903 
2904 /**
2905  * xmlXPathPopNumber:
2906  * @ctxt:  an XPath parser context
2907  *
2908  * Pops a number from the stack, handling conversion if needed.
2909  * Check error with #xmlXPathCheckError.
2910  *
2911  * Returns the number
2912  */
2913 double
xmlXPathPopNumber(xmlXPathParserContextPtr ctxt)2914 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2915     xmlXPathObjectPtr obj;
2916     double ret;
2917 
2918     obj = valuePop(ctxt);
2919     if (obj == NULL) {
2920 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2921 	return(0);
2922     }
2923     if (obj->type != XPATH_NUMBER)
2924 	ret = xmlXPathCastToNumber(obj);
2925     else
2926         ret = obj->floatval;
2927     xmlXPathReleaseObject(ctxt->context, obj);
2928     return(ret);
2929 }
2930 
2931 /**
2932  * xmlXPathPopString:
2933  * @ctxt:  an XPath parser context
2934  *
2935  * Pops a string from the stack, handling conversion if needed.
2936  * Check error with #xmlXPathCheckError.
2937  *
2938  * Returns the string
2939  */
2940 xmlChar *
xmlXPathPopString(xmlXPathParserContextPtr ctxt)2941 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2942     xmlXPathObjectPtr obj;
2943     xmlChar * ret;
2944 
2945     obj = valuePop(ctxt);
2946     if (obj == NULL) {
2947 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2948 	return(NULL);
2949     }
2950     ret = xmlXPathCastToString(obj);	/* this does required strdup */
2951     /* TODO: needs refactoring somewhere else */
2952     if (obj->stringval == ret)
2953 	obj->stringval = NULL;
2954     xmlXPathReleaseObject(ctxt->context, obj);
2955     return(ret);
2956 }
2957 
2958 /**
2959  * xmlXPathPopNodeSet:
2960  * @ctxt:  an XPath parser context
2961  *
2962  * Pops a node-set from the stack, handling conversion if needed.
2963  * Check error with #xmlXPathCheckError.
2964  *
2965  * Returns the node-set
2966  */
2967 xmlNodeSetPtr
xmlXPathPopNodeSet(xmlXPathParserContextPtr ctxt)2968 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2969     xmlXPathObjectPtr obj;
2970     xmlNodeSetPtr ret;
2971 
2972     if (ctxt == NULL) return(NULL);
2973     if (ctxt->value == NULL) {
2974 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2975 	return(NULL);
2976     }
2977     if (!xmlXPathStackIsNodeSet(ctxt)) {
2978 	xmlXPathSetTypeError(ctxt);
2979 	return(NULL);
2980     }
2981     obj = valuePop(ctxt);
2982     ret = obj->nodesetval;
2983 #if 0
2984     /* to fix memory leak of not clearing obj->user */
2985     if (obj->boolval && obj->user != NULL)
2986         xmlFreeNodeList((xmlNodePtr) obj->user);
2987 #endif
2988     obj->nodesetval = NULL;
2989     xmlXPathReleaseObject(ctxt->context, obj);
2990     return(ret);
2991 }
2992 
2993 /**
2994  * xmlXPathPopExternal:
2995  * @ctxt:  an XPath parser context
2996  *
2997  * Pops an external object from the stack, handling conversion if needed.
2998  * Check error with #xmlXPathCheckError.
2999  *
3000  * Returns the object
3001  */
3002 void *
xmlXPathPopExternal(xmlXPathParserContextPtr ctxt)3003 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3004     xmlXPathObjectPtr obj;
3005     void * ret;
3006 
3007     if ((ctxt == NULL) || (ctxt->value == NULL)) {
3008 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3009 	return(NULL);
3010     }
3011     if (ctxt->value->type != XPATH_USERS) {
3012 	xmlXPathSetTypeError(ctxt);
3013 	return(NULL);
3014     }
3015     obj = valuePop(ctxt);
3016     ret = obj->user;
3017     obj->user = NULL;
3018     xmlXPathReleaseObject(ctxt->context, obj);
3019     return(ret);
3020 }
3021 
3022 /*
3023  * Macros for accessing the content. Those should be used only by the parser,
3024  * and not exported.
3025  *
3026  * Dirty macros, i.e. one need to make assumption on the context to use them
3027  *
3028  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3029  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3030  *           in ISO-Latin or UTF-8.
3031  *           This should be used internally by the parser
3032  *           only to compare to ASCII values otherwise it would break when
3033  *           running with UTF-8 encoding.
3034  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3035  *           to compare on ASCII based substring.
3036  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3037  *           strings within the parser.
3038  *   CURRENT Returns the current char value, with the full decoding of
3039  *           UTF-8 if we are using this mode. It returns an int.
3040  *   NEXT    Skip to the next character, this does the proper decoding
3041  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3042  *           It returns the pointer to the current xmlChar.
3043  */
3044 
3045 #define CUR (*ctxt->cur)
3046 #define SKIP(val) ctxt->cur += (val)
3047 #define NXT(val) ctxt->cur[(val)]
3048 #define CUR_PTR ctxt->cur
3049 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3050 
3051 #define COPY_BUF(l,b,i,v)                                              \
3052     if (l == 1) b[i++] = (xmlChar) v;                                  \
3053     else i += xmlCopyChar(l,&b[i],v)
3054 
3055 #define NEXTL(l)  ctxt->cur += l
3056 
3057 #define SKIP_BLANKS							\
3058     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3059 
3060 #define CURRENT (*ctxt->cur)
3061 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3062 
3063 
3064 #ifndef DBL_DIG
3065 #define DBL_DIG 16
3066 #endif
3067 #ifndef DBL_EPSILON
3068 #define DBL_EPSILON 1E-9
3069 #endif
3070 
3071 #define UPPER_DOUBLE 1E9
3072 #define LOWER_DOUBLE 1E-5
3073 #define	LOWER_DOUBLE_EXP 5
3074 
3075 #define INTEGER_DIGITS DBL_DIG
3076 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3077 #define EXPONENT_DIGITS (3 + 2)
3078 
3079 /**
3080  * xmlXPathFormatNumber:
3081  * @number:     number to format
3082  * @buffer:     output buffer
3083  * @buffersize: size of output buffer
3084  *
3085  * Convert the number into a string representation.
3086  */
3087 static void
xmlXPathFormatNumber(double number,char buffer[],int buffersize)3088 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3089 {
3090     switch (xmlXPathIsInf(number)) {
3091     case 1:
3092 	if (buffersize > (int)sizeof("Infinity"))
3093 	    snprintf(buffer, buffersize, "Infinity");
3094 	break;
3095     case -1:
3096 	if (buffersize > (int)sizeof("-Infinity"))
3097 	    snprintf(buffer, buffersize, "-Infinity");
3098 	break;
3099     default:
3100 	if (xmlXPathIsNaN(number)) {
3101 	    if (buffersize > (int)sizeof("NaN"))
3102 		snprintf(buffer, buffersize, "NaN");
3103 	} else if (number == 0) {
3104             /* Omit sign for negative zero. */
3105 	    snprintf(buffer, buffersize, "0");
3106 	} else if ((number > INT_MIN) && (number < INT_MAX) &&
3107                    (number == (int) number)) {
3108 	    char work[30];
3109 	    char *ptr, *cur;
3110 	    int value = (int) number;
3111 
3112             ptr = &buffer[0];
3113 	    if (value == 0) {
3114 		*ptr++ = '0';
3115 	    } else {
3116 		snprintf(work, 29, "%d", value);
3117 		cur = &work[0];
3118 		while ((*cur) && (ptr - buffer < buffersize)) {
3119 		    *ptr++ = *cur++;
3120 		}
3121 	    }
3122 	    if (ptr - buffer < buffersize) {
3123 		*ptr = 0;
3124 	    } else if (buffersize > 0) {
3125 		ptr--;
3126 		*ptr = 0;
3127 	    }
3128 	} else {
3129 	    /*
3130 	      For the dimension of work,
3131 	          DBL_DIG is number of significant digits
3132 		  EXPONENT is only needed for "scientific notation"
3133 	          3 is sign, decimal point, and terminating zero
3134 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3135 	      Note that this dimension is slightly (a few characters)
3136 	      larger than actually necessary.
3137 	    */
3138 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3139 	    int integer_place, fraction_place;
3140 	    char *ptr;
3141 	    char *after_fraction;
3142 	    double absolute_value;
3143 	    int size;
3144 
3145 	    absolute_value = fabs(number);
3146 
3147 	    /*
3148 	     * First choose format - scientific or regular floating point.
3149 	     * In either case, result is in work, and after_fraction points
3150 	     * just past the fractional part.
3151 	    */
3152 	    if ( ((absolute_value > UPPER_DOUBLE) ||
3153 		  (absolute_value < LOWER_DOUBLE)) &&
3154 		 (absolute_value != 0.0) ) {
3155 		/* Use scientific notation */
3156 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3157 		fraction_place = DBL_DIG - 1;
3158 		size = snprintf(work, sizeof(work),"%*.*e",
3159 			 integer_place, fraction_place, number);
3160 		while ((size > 0) && (work[size] != 'e')) size--;
3161 
3162 	    }
3163 	    else {
3164 		/* Use regular notation */
3165 		if (absolute_value > 0.0) {
3166 		    integer_place = (int)log10(absolute_value);
3167 		    if (integer_place > 0)
3168 		        fraction_place = DBL_DIG - integer_place - 1;
3169 		    else
3170 		        fraction_place = DBL_DIG - integer_place;
3171 		} else {
3172 		    fraction_place = 1;
3173 		}
3174 		size = snprintf(work, sizeof(work), "%0.*f",
3175 				fraction_place, number);
3176 	    }
3177 
3178 	    /* Remove leading spaces sometimes inserted by snprintf */
3179 	    while (work[0] == ' ') {
3180 	        for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3181 		size--;
3182 	    }
3183 
3184 	    /* Remove fractional trailing zeroes */
3185 	    after_fraction = work + size;
3186 	    ptr = after_fraction;
3187 	    while (*(--ptr) == '0')
3188 		;
3189 	    if (*ptr != '.')
3190 	        ptr++;
3191 	    while ((*ptr++ = *after_fraction++) != 0);
3192 
3193 	    /* Finally copy result back to caller */
3194 	    size = strlen(work) + 1;
3195 	    if (size > buffersize) {
3196 		work[buffersize - 1] = 0;
3197 		size = buffersize;
3198 	    }
3199 	    memmove(buffer, work, size);
3200 	}
3201 	break;
3202     }
3203 }
3204 
3205 
3206 /************************************************************************
3207  *									*
3208  *			Routines to handle NodeSets			*
3209  *									*
3210  ************************************************************************/
3211 
3212 /**
3213  * xmlXPathOrderDocElems:
3214  * @doc:  an input document
3215  *
3216  * Call this routine to speed up XPath computation on static documents.
3217  * This stamps all the element nodes with the document order
3218  * Like for line information, the order is kept in the element->content
3219  * field, the value stored is actually - the node number (starting at -1)
3220  * to be able to differentiate from line numbers.
3221  *
3222  * Returns the number of elements found in the document or -1 in case
3223  *    of error.
3224  */
3225 long
xmlXPathOrderDocElems(xmlDocPtr doc)3226 xmlXPathOrderDocElems(xmlDocPtr doc) {
3227     ptrdiff_t count = 0;
3228     xmlNodePtr cur;
3229 
3230     if (doc == NULL)
3231 	return(-1);
3232     cur = doc->children;
3233     while (cur != NULL) {
3234 	if (cur->type == XML_ELEMENT_NODE) {
3235 	    cur->content = (void *) (-(++count));
3236 	    if (cur->children != NULL) {
3237 		cur = cur->children;
3238 		continue;
3239 	    }
3240 	}
3241 	if (cur->next != NULL) {
3242 	    cur = cur->next;
3243 	    continue;
3244 	}
3245 	do {
3246 	    cur = cur->parent;
3247 	    if (cur == NULL)
3248 		break;
3249 	    if (cur == (xmlNodePtr) doc) {
3250 		cur = NULL;
3251 		break;
3252 	    }
3253 	    if (cur->next != NULL) {
3254 		cur = cur->next;
3255 		break;
3256 	    }
3257 	} while (cur != NULL);
3258     }
3259     return((long) count);
3260 }
3261 
3262 /**
3263  * xmlXPathCmpNodes:
3264  * @node1:  the first node
3265  * @node2:  the second node
3266  *
3267  * Compare two nodes w.r.t document order
3268  *
3269  * Returns -2 in case of error 1 if first point < second point, 0 if
3270  *         it's the same node, -1 otherwise
3271  */
3272 int
xmlXPathCmpNodes(xmlNodePtr node1,xmlNodePtr node2)3273 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3274     int depth1, depth2;
3275     int attr1 = 0, attr2 = 0;
3276     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3277     xmlNodePtr cur, root;
3278 
3279     if ((node1 == NULL) || (node2 == NULL))
3280 	return(-2);
3281     /*
3282      * a couple of optimizations which will avoid computations in most cases
3283      */
3284     if (node1 == node2)		/* trivial case */
3285 	return(0);
3286     if (node1->type == XML_ATTRIBUTE_NODE) {
3287 	attr1 = 1;
3288 	attrNode1 = node1;
3289 	node1 = node1->parent;
3290     }
3291     if (node2->type == XML_ATTRIBUTE_NODE) {
3292 	attr2 = 1;
3293 	attrNode2 = node2;
3294 	node2 = node2->parent;
3295     }
3296     if (node1 == node2) {
3297 	if (attr1 == attr2) {
3298 	    /* not required, but we keep attributes in order */
3299 	    if (attr1 != 0) {
3300 	        cur = attrNode2->prev;
3301 		while (cur != NULL) {
3302 		    if (cur == attrNode1)
3303 		        return (1);
3304 		    cur = cur->prev;
3305 		}
3306 		return (-1);
3307 	    }
3308 	    return(0);
3309 	}
3310 	if (attr2 == 1)
3311 	    return(1);
3312 	return(-1);
3313     }
3314     if ((node1->type == XML_NAMESPACE_DECL) ||
3315         (node2->type == XML_NAMESPACE_DECL))
3316 	return(1);
3317     if (node1 == node2->prev)
3318 	return(1);
3319     if (node1 == node2->next)
3320 	return(-1);
3321 
3322     /*
3323      * Speedup using document order if availble.
3324      */
3325     if ((node1->type == XML_ELEMENT_NODE) &&
3326 	(node2->type == XML_ELEMENT_NODE) &&
3327 	(0 > (ptrdiff_t) node1->content) &&
3328 	(0 > (ptrdiff_t) node2->content) &&
3329 	(node1->doc == node2->doc)) {
3330 	ptrdiff_t l1, l2;
3331 
3332 	l1 = -((ptrdiff_t) node1->content);
3333 	l2 = -((ptrdiff_t) node2->content);
3334 	if (l1 < l2)
3335 	    return(1);
3336 	if (l1 > l2)
3337 	    return(-1);
3338     }
3339 
3340     /*
3341      * compute depth to root
3342      */
3343     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3344 	if (cur->parent == node1)
3345 	    return(1);
3346 	depth2++;
3347     }
3348     root = cur;
3349     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3350 	if (cur->parent == node2)
3351 	    return(-1);
3352 	depth1++;
3353     }
3354     /*
3355      * Distinct document (or distinct entities :-( ) case.
3356      */
3357     if (root != cur) {
3358 	return(-2);
3359     }
3360     /*
3361      * get the nearest common ancestor.
3362      */
3363     while (depth1 > depth2) {
3364 	depth1--;
3365 	node1 = node1->parent;
3366     }
3367     while (depth2 > depth1) {
3368 	depth2--;
3369 	node2 = node2->parent;
3370     }
3371     while (node1->parent != node2->parent) {
3372 	node1 = node1->parent;
3373 	node2 = node2->parent;
3374 	/* should not happen but just in case ... */
3375 	if ((node1 == NULL) || (node2 == NULL))
3376 	    return(-2);
3377     }
3378     /*
3379      * Find who's first.
3380      */
3381     if (node1 == node2->prev)
3382 	return(1);
3383     if (node1 == node2->next)
3384 	return(-1);
3385     /*
3386      * Speedup using document order if availble.
3387      */
3388     if ((node1->type == XML_ELEMENT_NODE) &&
3389 	(node2->type == XML_ELEMENT_NODE) &&
3390 	(0 > (ptrdiff_t) node1->content) &&
3391 	(0 > (ptrdiff_t) node2->content) &&
3392 	(node1->doc == node2->doc)) {
3393 	ptrdiff_t l1, l2;
3394 
3395 	l1 = -((ptrdiff_t) node1->content);
3396 	l2 = -((ptrdiff_t) node2->content);
3397 	if (l1 < l2)
3398 	    return(1);
3399 	if (l1 > l2)
3400 	    return(-1);
3401     }
3402 
3403     for (cur = node1->next;cur != NULL;cur = cur->next)
3404 	if (cur == node2)
3405 	    return(1);
3406     return(-1); /* assume there is no sibling list corruption */
3407 }
3408 
3409 /**
3410  * xmlXPathNodeSetSort:
3411  * @set:  the node set
3412  *
3413  * Sort the node set in document order
3414  */
3415 void
xmlXPathNodeSetSort(xmlNodeSetPtr set)3416 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3417 #ifndef WITH_TIM_SORT
3418     int i, j, incr, len;
3419     xmlNodePtr tmp;
3420 #endif
3421 
3422     if (set == NULL)
3423 	return;
3424 
3425 #ifndef WITH_TIM_SORT
3426     /*
3427      * Use the old Shell's sort implementation to sort the node-set
3428      * Timsort ought to be quite faster
3429      */
3430     len = set->nodeNr;
3431     for (incr = len / 2; incr > 0; incr /= 2) {
3432 	for (i = incr; i < len; i++) {
3433 	    j = i - incr;
3434 	    while (j >= 0) {
3435 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3436 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
3437 			set->nodeTab[j + incr]) == -1)
3438 #else
3439 		if (xmlXPathCmpNodes(set->nodeTab[j],
3440 			set->nodeTab[j + incr]) == -1)
3441 #endif
3442 		{
3443 		    tmp = set->nodeTab[j];
3444 		    set->nodeTab[j] = set->nodeTab[j + incr];
3445 		    set->nodeTab[j + incr] = tmp;
3446 		    j -= incr;
3447 		} else
3448 		    break;
3449 	    }
3450 	}
3451     }
3452 #else /* WITH_TIM_SORT */
3453     libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3454 #endif /* WITH_TIM_SORT */
3455 }
3456 
3457 #define XML_NODESET_DEFAULT	10
3458 /**
3459  * xmlXPathNodeSetDupNs:
3460  * @node:  the parent node of the namespace XPath node
3461  * @ns:  the libxml namespace declaration node.
3462  *
3463  * Namespace node in libxml don't match the XPath semantic. In a node set
3464  * the namespace nodes are duplicated and the next pointer is set to the
3465  * parent node in the XPath semantic.
3466  *
3467  * Returns the newly created object.
3468  */
3469 static xmlNodePtr
xmlXPathNodeSetDupNs(xmlNodePtr node,xmlNsPtr ns)3470 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3471     xmlNsPtr cur;
3472 
3473     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3474 	return(NULL);
3475     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3476 	return((xmlNodePtr) ns);
3477 
3478     /*
3479      * Allocate a new Namespace and fill the fields.
3480      */
3481     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3482     if (cur == NULL) {
3483         xmlXPathErrMemory(NULL, "duplicating namespace\n");
3484 	return(NULL);
3485     }
3486     memset(cur, 0, sizeof(xmlNs));
3487     cur->type = XML_NAMESPACE_DECL;
3488     if (ns->href != NULL)
3489 	cur->href = xmlStrdup(ns->href);
3490     if (ns->prefix != NULL)
3491 	cur->prefix = xmlStrdup(ns->prefix);
3492     cur->next = (xmlNsPtr) node;
3493     return((xmlNodePtr) cur);
3494 }
3495 
3496 /**
3497  * xmlXPathNodeSetFreeNs:
3498  * @ns:  the XPath namespace node found in a nodeset.
3499  *
3500  * Namespace nodes in libxml don't match the XPath semantic. In a node set
3501  * the namespace nodes are duplicated and the next pointer is set to the
3502  * parent node in the XPath semantic. Check if such a node needs to be freed
3503  */
3504 void
xmlXPathNodeSetFreeNs(xmlNsPtr ns)3505 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3506     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3507 	return;
3508 
3509     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3510 	if (ns->href != NULL)
3511 	    xmlFree((xmlChar *)ns->href);
3512 	if (ns->prefix != NULL)
3513 	    xmlFree((xmlChar *)ns->prefix);
3514 	xmlFree(ns);
3515     }
3516 }
3517 
3518 /**
3519  * xmlXPathNodeSetCreate:
3520  * @val:  an initial xmlNodePtr, or NULL
3521  *
3522  * Create a new xmlNodeSetPtr of type double and of value @val
3523  *
3524  * Returns the newly created object.
3525  */
3526 xmlNodeSetPtr
xmlXPathNodeSetCreate(xmlNodePtr val)3527 xmlXPathNodeSetCreate(xmlNodePtr val) {
3528     xmlNodeSetPtr ret;
3529 
3530     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3531     if (ret == NULL) {
3532         xmlXPathErrMemory(NULL, "creating nodeset\n");
3533 	return(NULL);
3534     }
3535     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3536     if (val != NULL) {
3537         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3538 					     sizeof(xmlNodePtr));
3539 	if (ret->nodeTab == NULL) {
3540 	    xmlXPathErrMemory(NULL, "creating nodeset\n");
3541 	    xmlFree(ret);
3542 	    return(NULL);
3543 	}
3544 	memset(ret->nodeTab, 0 ,
3545 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3546         ret->nodeMax = XML_NODESET_DEFAULT;
3547 	if (val->type == XML_NAMESPACE_DECL) {
3548 	    xmlNsPtr ns = (xmlNsPtr) val;
3549 
3550 	    ret->nodeTab[ret->nodeNr++] =
3551 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3552 	} else
3553 	    ret->nodeTab[ret->nodeNr++] = val;
3554     }
3555     return(ret);
3556 }
3557 
3558 /**
3559  * xmlXPathNodeSetCreateSize:
3560  * @size:  the initial size of the set
3561  *
3562  * Create a new xmlNodeSetPtr of type double and of value @val
3563  *
3564  * Returns the newly created object.
3565  */
3566 static xmlNodeSetPtr
xmlXPathNodeSetCreateSize(int size)3567 xmlXPathNodeSetCreateSize(int size) {
3568     xmlNodeSetPtr ret;
3569 
3570     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3571     if (ret == NULL) {
3572         xmlXPathErrMemory(NULL, "creating nodeset\n");
3573 	return(NULL);
3574     }
3575     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3576     if (size < XML_NODESET_DEFAULT)
3577 	size = XML_NODESET_DEFAULT;
3578     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3579     if (ret->nodeTab == NULL) {
3580 	xmlXPathErrMemory(NULL, "creating nodeset\n");
3581 	xmlFree(ret);
3582 	return(NULL);
3583     }
3584     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3585     ret->nodeMax = size;
3586     return(ret);
3587 }
3588 
3589 /**
3590  * xmlXPathNodeSetContains:
3591  * @cur:  the node-set
3592  * @val:  the node
3593  *
3594  * checks whether @cur contains @val
3595  *
3596  * Returns true (1) if @cur contains @val, false (0) otherwise
3597  */
3598 int
xmlXPathNodeSetContains(xmlNodeSetPtr cur,xmlNodePtr val)3599 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3600     int i;
3601 
3602     if ((cur == NULL) || (val == NULL)) return(0);
3603     if (val->type == XML_NAMESPACE_DECL) {
3604 	for (i = 0; i < cur->nodeNr; i++) {
3605 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3606 		xmlNsPtr ns1, ns2;
3607 
3608 		ns1 = (xmlNsPtr) val;
3609 		ns2 = (xmlNsPtr) cur->nodeTab[i];
3610 		if (ns1 == ns2)
3611 		    return(1);
3612 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3613 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
3614 		    return(1);
3615 	    }
3616 	}
3617     } else {
3618 	for (i = 0; i < cur->nodeNr; i++) {
3619 	    if (cur->nodeTab[i] == val)
3620 		return(1);
3621 	}
3622     }
3623     return(0);
3624 }
3625 
3626 /**
3627  * xmlXPathNodeSetAddNs:
3628  * @cur:  the initial node set
3629  * @node:  the hosting node
3630  * @ns:  a the namespace node
3631  *
3632  * add a new namespace node to an existing NodeSet
3633  *
3634  * Returns 0 in case of success and -1 in case of error
3635  */
3636 int
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur,xmlNodePtr node,xmlNsPtr ns)3637 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3638     int i;
3639 
3640 
3641     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3642         (ns->type != XML_NAMESPACE_DECL) ||
3643 	(node->type != XML_ELEMENT_NODE))
3644 	return(-1);
3645 
3646     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3647     /*
3648      * prevent duplicates
3649      */
3650     for (i = 0;i < cur->nodeNr;i++) {
3651         if ((cur->nodeTab[i] != NULL) &&
3652 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3653 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3654 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3655 	    return(0);
3656     }
3657 
3658     /*
3659      * grow the nodeTab if needed
3660      */
3661     if (cur->nodeMax == 0) {
3662         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3663 					     sizeof(xmlNodePtr));
3664 	if (cur->nodeTab == NULL) {
3665 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3666 	    return(-1);
3667 	}
3668 	memset(cur->nodeTab, 0 ,
3669 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3670         cur->nodeMax = XML_NODESET_DEFAULT;
3671     } else if (cur->nodeNr == cur->nodeMax) {
3672         xmlNodePtr *temp;
3673 
3674         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3675             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3676             return(-1);
3677         }
3678 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3679 				      sizeof(xmlNodePtr));
3680 	if (temp == NULL) {
3681 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3682 	    return(-1);
3683 	}
3684         cur->nodeMax *= 2;
3685 	cur->nodeTab = temp;
3686     }
3687     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3688     return(0);
3689 }
3690 
3691 /**
3692  * xmlXPathNodeSetAdd:
3693  * @cur:  the initial node set
3694  * @val:  a new xmlNodePtr
3695  *
3696  * add a new xmlNodePtr to an existing NodeSet
3697  *
3698  * Returns 0 in case of success, and -1 in case of error
3699  */
3700 int
xmlXPathNodeSetAdd(xmlNodeSetPtr cur,xmlNodePtr val)3701 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3702     int i;
3703 
3704     if ((cur == NULL) || (val == NULL)) return(-1);
3705 
3706     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3707     /*
3708      * prevent duplicates
3709      */
3710     for (i = 0;i < cur->nodeNr;i++)
3711         if (cur->nodeTab[i] == val) return(0);
3712 
3713     /*
3714      * grow the nodeTab if needed
3715      */
3716     if (cur->nodeMax == 0) {
3717         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3718 					     sizeof(xmlNodePtr));
3719 	if (cur->nodeTab == NULL) {
3720 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3721 	    return(-1);
3722 	}
3723 	memset(cur->nodeTab, 0 ,
3724 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3725         cur->nodeMax = XML_NODESET_DEFAULT;
3726     } else if (cur->nodeNr == cur->nodeMax) {
3727         xmlNodePtr *temp;
3728 
3729         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3730             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3731             return(-1);
3732         }
3733 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3734 				      sizeof(xmlNodePtr));
3735 	if (temp == NULL) {
3736 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3737 	    return(-1);
3738 	}
3739         cur->nodeMax *= 2;
3740 	cur->nodeTab = temp;
3741     }
3742     if (val->type == XML_NAMESPACE_DECL) {
3743 	xmlNsPtr ns = (xmlNsPtr) val;
3744 
3745 	cur->nodeTab[cur->nodeNr++] =
3746 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3747     } else
3748 	cur->nodeTab[cur->nodeNr++] = val;
3749     return(0);
3750 }
3751 
3752 /**
3753  * xmlXPathNodeSetAddUnique:
3754  * @cur:  the initial node set
3755  * @val:  a new xmlNodePtr
3756  *
3757  * add a new xmlNodePtr to an existing NodeSet, optimized version
3758  * when we are sure the node is not already in the set.
3759  *
3760  * Returns 0 in case of success and -1 in case of failure
3761  */
3762 int
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur,xmlNodePtr val)3763 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3764     if ((cur == NULL) || (val == NULL)) return(-1);
3765 
3766     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3767     /*
3768      * grow the nodeTab if needed
3769      */
3770     if (cur->nodeMax == 0) {
3771         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3772 					     sizeof(xmlNodePtr));
3773 	if (cur->nodeTab == NULL) {
3774 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3775 	    return(-1);
3776 	}
3777 	memset(cur->nodeTab, 0 ,
3778 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3779         cur->nodeMax = XML_NODESET_DEFAULT;
3780     } else if (cur->nodeNr == cur->nodeMax) {
3781         xmlNodePtr *temp;
3782 
3783         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3784             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3785             return(-1);
3786         }
3787 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3788 				      sizeof(xmlNodePtr));
3789 	if (temp == NULL) {
3790 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3791 	    return(-1);
3792 	}
3793 	cur->nodeTab = temp;
3794         cur->nodeMax *= 2;
3795     }
3796     if (val->type == XML_NAMESPACE_DECL) {
3797 	xmlNsPtr ns = (xmlNsPtr) val;
3798 
3799 	cur->nodeTab[cur->nodeNr++] =
3800 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3801     } else
3802 	cur->nodeTab[cur->nodeNr++] = val;
3803     return(0);
3804 }
3805 
3806 /**
3807  * xmlXPathNodeSetMerge:
3808  * @val1:  the first NodeSet or NULL
3809  * @val2:  the second NodeSet
3810  *
3811  * Merges two nodesets, all nodes from @val2 are added to @val1
3812  * if @val1 is NULL, a new set is created and copied from @val2
3813  *
3814  * Returns @val1 once extended or NULL in case of error.
3815  */
3816 xmlNodeSetPtr
xmlXPathNodeSetMerge(xmlNodeSetPtr val1,xmlNodeSetPtr val2)3817 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3818     int i, j, initNr, skip;
3819     xmlNodePtr n1, n2;
3820 
3821     if (val2 == NULL) return(val1);
3822     if (val1 == NULL) {
3823 	val1 = xmlXPathNodeSetCreate(NULL);
3824     if (val1 == NULL)
3825         return (NULL);
3826 #if 0
3827 	/*
3828 	* TODO: The optimization won't work in every case, since
3829 	*  those nasty namespace nodes need to be added with
3830 	*  xmlXPathNodeSetDupNs() to the set; thus a pure
3831 	*  memcpy is not possible.
3832 	*  If there was a flag on the nodesetval, indicating that
3833 	*  some temporary nodes are in, that would be helpfull.
3834 	*/
3835 	/*
3836 	* Optimization: Create an equally sized node-set
3837 	* and memcpy the content.
3838 	*/
3839 	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3840 	if (val1 == NULL)
3841 	    return(NULL);
3842 	if (val2->nodeNr != 0) {
3843 	    if (val2->nodeNr == 1)
3844 		*(val1->nodeTab) = *(val2->nodeTab);
3845 	    else {
3846 		memcpy(val1->nodeTab, val2->nodeTab,
3847 		    val2->nodeNr * sizeof(xmlNodePtr));
3848 	    }
3849 	    val1->nodeNr = val2->nodeNr;
3850 	}
3851 	return(val1);
3852 #endif
3853     }
3854 
3855     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3856     initNr = val1->nodeNr;
3857 
3858     for (i = 0;i < val2->nodeNr;i++) {
3859 	n2 = val2->nodeTab[i];
3860 	/*
3861 	 * check against duplicates
3862 	 */
3863 	skip = 0;
3864 	for (j = 0; j < initNr; j++) {
3865 	    n1 = val1->nodeTab[j];
3866 	    if (n1 == n2) {
3867 		skip = 1;
3868 		break;
3869 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3870 		       (n2->type == XML_NAMESPACE_DECL)) {
3871 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3872 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3873 			((xmlNsPtr) n2)->prefix)))
3874 		{
3875 		    skip = 1;
3876 		    break;
3877 		}
3878 	    }
3879 	}
3880 	if (skip)
3881 	    continue;
3882 
3883 	/*
3884 	 * grow the nodeTab if needed
3885 	 */
3886 	if (val1->nodeMax == 0) {
3887 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3888 						    sizeof(xmlNodePtr));
3889 	    if (val1->nodeTab == NULL) {
3890 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3891 		return(NULL);
3892 	    }
3893 	    memset(val1->nodeTab, 0 ,
3894 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3895 	    val1->nodeMax = XML_NODESET_DEFAULT;
3896 	} else if (val1->nodeNr == val1->nodeMax) {
3897 	    xmlNodePtr *temp;
3898 
3899             if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3900                 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3901                 return(NULL);
3902             }
3903 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3904 					     sizeof(xmlNodePtr));
3905 	    if (temp == NULL) {
3906 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3907 		return(NULL);
3908 	    }
3909 	    val1->nodeTab = temp;
3910 	    val1->nodeMax *= 2;
3911 	}
3912 	if (n2->type == XML_NAMESPACE_DECL) {
3913 	    xmlNsPtr ns = (xmlNsPtr) n2;
3914 
3915 	    val1->nodeTab[val1->nodeNr++] =
3916 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3917 	} else
3918 	    val1->nodeTab[val1->nodeNr++] = n2;
3919     }
3920 
3921     return(val1);
3922 }
3923 
3924 
3925 /**
3926  * xmlXPathNodeSetMergeAndClear:
3927  * @set1:  the first NodeSet or NULL
3928  * @set2:  the second NodeSet
3929  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3930  *
3931  * Merges two nodesets, all nodes from @set2 are added to @set1
3932  * if @set1 is NULL, a new set is created and copied from @set2.
3933  * Checks for duplicate nodes. Clears set2.
3934  *
3935  * Returns @set1 once extended or NULL in case of error.
3936  */
3937 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1,xmlNodeSetPtr set2,int hasNullEntries)3938 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3939 			     int hasNullEntries)
3940 {
3941     if ((set1 == NULL) && (hasNullEntries == 0)) {
3942 	/*
3943 	* Note that doing a memcpy of the list, namespace nodes are
3944 	* just assigned to set1, since set2 is cleared anyway.
3945 	*/
3946 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3947 	if (set1 == NULL)
3948 	    return(NULL);
3949 	if (set2->nodeNr != 0) {
3950 	    memcpy(set1->nodeTab, set2->nodeTab,
3951 		set2->nodeNr * sizeof(xmlNodePtr));
3952 	    set1->nodeNr = set2->nodeNr;
3953 	}
3954     } else {
3955 	int i, j, initNbSet1;
3956 	xmlNodePtr n1, n2;
3957 
3958 	if (set1 == NULL)
3959             set1 = xmlXPathNodeSetCreate(NULL);
3960         if (set1 == NULL)
3961             return (NULL);
3962 
3963 	initNbSet1 = set1->nodeNr;
3964 	for (i = 0;i < set2->nodeNr;i++) {
3965 	    n2 = set2->nodeTab[i];
3966 	    /*
3967 	    * Skip NULLed entries.
3968 	    */
3969 	    if (n2 == NULL)
3970 		continue;
3971 	    /*
3972 	    * Skip duplicates.
3973 	    */
3974 	    for (j = 0; j < initNbSet1; j++) {
3975 		n1 = set1->nodeTab[j];
3976 		if (n1 == n2) {
3977 		    goto skip_node;
3978 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
3979 		    (n2->type == XML_NAMESPACE_DECL))
3980 		{
3981 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3982 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
3983 			((xmlNsPtr) n2)->prefix)))
3984 		    {
3985 			/*
3986 			* Free the namespace node.
3987 			*/
3988 			set2->nodeTab[i] = NULL;
3989 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3990 			goto skip_node;
3991 		    }
3992 		}
3993 	    }
3994 	    /*
3995 	    * grow the nodeTab if needed
3996 	    */
3997 	    if (set1->nodeMax == 0) {
3998 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3999 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4000 		if (set1->nodeTab == NULL) {
4001 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4002 		    return(NULL);
4003 		}
4004 		memset(set1->nodeTab, 0,
4005 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4006 		set1->nodeMax = XML_NODESET_DEFAULT;
4007 	    } else if (set1->nodeNr >= set1->nodeMax) {
4008 		xmlNodePtr *temp;
4009 
4010                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4011                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4012                     return(NULL);
4013                 }
4014 		temp = (xmlNodePtr *) xmlRealloc(
4015 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4016 		if (temp == NULL) {
4017 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4018 		    return(NULL);
4019 		}
4020 		set1->nodeTab = temp;
4021 		set1->nodeMax *= 2;
4022 	    }
4023 	    set1->nodeTab[set1->nodeNr++] = n2;
4024 skip_node:
4025 	    {}
4026 	}
4027     }
4028     set2->nodeNr = 0;
4029     return(set1);
4030 }
4031 
4032 /**
4033  * xmlXPathNodeSetMergeAndClearNoDupls:
4034  * @set1:  the first NodeSet or NULL
4035  * @set2:  the second NodeSet
4036  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4037  *
4038  * Merges two nodesets, all nodes from @set2 are added to @set1
4039  * if @set1 is NULL, a new set is created and copied from @set2.
4040  * Doesn't chack for duplicate nodes. Clears set2.
4041  *
4042  * Returns @set1 once extended or NULL in case of error.
4043  */
4044 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1,xmlNodeSetPtr set2,int hasNullEntries)4045 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4046 				    int hasNullEntries)
4047 {
4048     if (set2 == NULL)
4049 	return(set1);
4050     if ((set1 == NULL) && (hasNullEntries == 0)) {
4051 	/*
4052 	* Note that doing a memcpy of the list, namespace nodes are
4053 	* just assigned to set1, since set2 is cleared anyway.
4054 	*/
4055 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4056 	if (set1 == NULL)
4057 	    return(NULL);
4058 	if (set2->nodeNr != 0) {
4059 	    memcpy(set1->nodeTab, set2->nodeTab,
4060 		set2->nodeNr * sizeof(xmlNodePtr));
4061 	    set1->nodeNr = set2->nodeNr;
4062 	}
4063     } else {
4064 	int i;
4065 	xmlNodePtr n2;
4066 
4067 	if (set1 == NULL)
4068 	    set1 = xmlXPathNodeSetCreate(NULL);
4069         if (set1 == NULL)
4070             return (NULL);
4071 
4072 	for (i = 0;i < set2->nodeNr;i++) {
4073 	    n2 = set2->nodeTab[i];
4074 	    /*
4075 	    * Skip NULLed entries.
4076 	    */
4077 	    if (n2 == NULL)
4078 		continue;
4079 	    if (set1->nodeMax == 0) {
4080 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4081 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4082 		if (set1->nodeTab == NULL) {
4083 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4084 		    return(NULL);
4085 		}
4086 		memset(set1->nodeTab, 0,
4087 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4088 		set1->nodeMax = XML_NODESET_DEFAULT;
4089 	    } else if (set1->nodeNr >= set1->nodeMax) {
4090 		xmlNodePtr *temp;
4091 
4092                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4093                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4094                     return(NULL);
4095                 }
4096 		temp = (xmlNodePtr *) xmlRealloc(
4097 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4098 		if (temp == NULL) {
4099 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4100 		    return(NULL);
4101 		}
4102 		set1->nodeTab = temp;
4103 		set1->nodeMax *= 2;
4104 	    }
4105 	    set1->nodeTab[set1->nodeNr++] = n2;
4106 	}
4107     }
4108     set2->nodeNr = 0;
4109     return(set1);
4110 }
4111 
4112 /**
4113  * xmlXPathNodeSetDel:
4114  * @cur:  the initial node set
4115  * @val:  an xmlNodePtr
4116  *
4117  * Removes an xmlNodePtr from an existing NodeSet
4118  */
4119 void
xmlXPathNodeSetDel(xmlNodeSetPtr cur,xmlNodePtr val)4120 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4121     int i;
4122 
4123     if (cur == NULL) return;
4124     if (val == NULL) return;
4125 
4126     /*
4127      * find node in nodeTab
4128      */
4129     for (i = 0;i < cur->nodeNr;i++)
4130         if (cur->nodeTab[i] == val) break;
4131 
4132     if (i >= cur->nodeNr) {	/* not found */
4133 #ifdef DEBUG
4134         xmlGenericError(xmlGenericErrorContext,
4135 	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4136 		val->name);
4137 #endif
4138         return;
4139     }
4140     if ((cur->nodeTab[i] != NULL) &&
4141 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4142 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4143     cur->nodeNr--;
4144     for (;i < cur->nodeNr;i++)
4145         cur->nodeTab[i] = cur->nodeTab[i + 1];
4146     cur->nodeTab[cur->nodeNr] = NULL;
4147 }
4148 
4149 /**
4150  * xmlXPathNodeSetRemove:
4151  * @cur:  the initial node set
4152  * @val:  the index to remove
4153  *
4154  * Removes an entry from an existing NodeSet list.
4155  */
4156 void
xmlXPathNodeSetRemove(xmlNodeSetPtr cur,int val)4157 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4158     if (cur == NULL) return;
4159     if (val >= cur->nodeNr) return;
4160     if ((cur->nodeTab[val] != NULL) &&
4161 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4162 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4163     cur->nodeNr--;
4164     for (;val < cur->nodeNr;val++)
4165         cur->nodeTab[val] = cur->nodeTab[val + 1];
4166     cur->nodeTab[cur->nodeNr] = NULL;
4167 }
4168 
4169 /**
4170  * xmlXPathFreeNodeSet:
4171  * @obj:  the xmlNodeSetPtr to free
4172  *
4173  * Free the NodeSet compound (not the actual nodes !).
4174  */
4175 void
xmlXPathFreeNodeSet(xmlNodeSetPtr obj)4176 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4177     if (obj == NULL) return;
4178     if (obj->nodeTab != NULL) {
4179 	int i;
4180 
4181 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
4182 	for (i = 0;i < obj->nodeNr;i++)
4183 	    if ((obj->nodeTab[i] != NULL) &&
4184 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4185 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4186 	xmlFree(obj->nodeTab);
4187     }
4188     xmlFree(obj);
4189 }
4190 
4191 /**
4192  * xmlXPathNodeSetClearFromPos:
4193  * @set: the node set to be cleared
4194  * @pos: the start position to clear from
4195  *
4196  * Clears the list from temporary XPath objects (e.g. namespace nodes
4197  * are feed) starting with the entry at @pos, but does *not* free the list
4198  * itself. Sets the length of the list to @pos.
4199  */
4200 static void
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set,int pos,int hasNsNodes)4201 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4202 {
4203     if ((set == NULL) || (pos >= set->nodeNr))
4204 	return;
4205     else if ((hasNsNodes)) {
4206 	int i;
4207 	xmlNodePtr node;
4208 
4209 	for (i = pos; i < set->nodeNr; i++) {
4210 	    node = set->nodeTab[i];
4211 	    if ((node != NULL) &&
4212 		(node->type == XML_NAMESPACE_DECL))
4213 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4214 	}
4215     }
4216     set->nodeNr = pos;
4217 }
4218 
4219 /**
4220  * xmlXPathNodeSetClear:
4221  * @set:  the node set to clear
4222  *
4223  * Clears the list from all temporary XPath objects (e.g. namespace nodes
4224  * are feed), but does *not* free the list itself. Sets the length of the
4225  * list to 0.
4226  */
4227 static void
xmlXPathNodeSetClear(xmlNodeSetPtr set,int hasNsNodes)4228 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4229 {
4230     xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4231 }
4232 
4233 /**
4234  * xmlXPathNodeSetKeepLast:
4235  * @set: the node set to be cleared
4236  *
4237  * Move the last node to the first position and clear temporary XPath objects
4238  * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4239  * to 1.
4240  */
4241 static void
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)4242 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4243 {
4244     int i;
4245     xmlNodePtr node;
4246 
4247     if ((set == NULL) || (set->nodeNr <= 1))
4248 	return;
4249     for (i = 0; i < set->nodeNr - 1; i++) {
4250         node = set->nodeTab[i];
4251         if ((node != NULL) &&
4252             (node->type == XML_NAMESPACE_DECL))
4253             xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4254     }
4255     set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4256     set->nodeNr = 1;
4257 }
4258 
4259 /**
4260  * xmlXPathFreeValueTree:
4261  * @obj:  the xmlNodeSetPtr to free
4262  *
4263  * Free the NodeSet compound and the actual tree, this is different
4264  * from xmlXPathFreeNodeSet()
4265  */
4266 static void
xmlXPathFreeValueTree(xmlNodeSetPtr obj)4267 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4268     int i;
4269 
4270     if (obj == NULL) return;
4271 
4272     if (obj->nodeTab != NULL) {
4273 	for (i = 0;i < obj->nodeNr;i++) {
4274 	    if (obj->nodeTab[i] != NULL) {
4275 		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4276 		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4277 		} else {
4278 		    xmlFreeNodeList(obj->nodeTab[i]);
4279 		}
4280 	    }
4281 	}
4282 	xmlFree(obj->nodeTab);
4283     }
4284     xmlFree(obj);
4285 }
4286 
4287 #if defined(DEBUG) || defined(DEBUG_STEP)
4288 /**
4289  * xmlGenericErrorContextNodeSet:
4290  * @output:  a FILE * for the output
4291  * @obj:  the xmlNodeSetPtr to display
4292  *
4293  * Quick display of a NodeSet
4294  */
4295 void
xmlGenericErrorContextNodeSet(FILE * output,xmlNodeSetPtr obj)4296 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4297     int i;
4298 
4299     if (output == NULL) output = xmlGenericErrorContext;
4300     if (obj == NULL)  {
4301         fprintf(output, "NodeSet == NULL !\n");
4302 	return;
4303     }
4304     if (obj->nodeNr == 0) {
4305         fprintf(output, "NodeSet is empty\n");
4306 	return;
4307     }
4308     if (obj->nodeTab == NULL) {
4309 	fprintf(output, " nodeTab == NULL !\n");
4310 	return;
4311     }
4312     for (i = 0; i < obj->nodeNr; i++) {
4313         if (obj->nodeTab[i] == NULL) {
4314 	    fprintf(output, " NULL !\n");
4315 	    return;
4316         }
4317 	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4318 	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4319 	    fprintf(output, " /");
4320 	else if (obj->nodeTab[i]->name == NULL)
4321 	    fprintf(output, " noname!");
4322 	else fprintf(output, " %s", obj->nodeTab[i]->name);
4323     }
4324     fprintf(output, "\n");
4325 }
4326 #endif
4327 
4328 /**
4329  * xmlXPathNewNodeSet:
4330  * @val:  the NodePtr value
4331  *
4332  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4333  * it with the single Node @val
4334  *
4335  * Returns the newly created object.
4336  */
4337 xmlXPathObjectPtr
xmlXPathNewNodeSet(xmlNodePtr val)4338 xmlXPathNewNodeSet(xmlNodePtr val) {
4339     xmlXPathObjectPtr ret;
4340 
4341     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4342     if (ret == NULL) {
4343         xmlXPathErrMemory(NULL, "creating nodeset\n");
4344 	return(NULL);
4345     }
4346     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4347     ret->type = XPATH_NODESET;
4348     ret->boolval = 0;
4349     ret->nodesetval = xmlXPathNodeSetCreate(val);
4350     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4351 #ifdef XP_DEBUG_OBJ_USAGE
4352     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4353 #endif
4354     return(ret);
4355 }
4356 
4357 /**
4358  * xmlXPathNewValueTree:
4359  * @val:  the NodePtr value
4360  *
4361  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4362  * it with the tree root @val
4363  *
4364  * Returns the newly created object.
4365  */
4366 xmlXPathObjectPtr
xmlXPathNewValueTree(xmlNodePtr val)4367 xmlXPathNewValueTree(xmlNodePtr val) {
4368     xmlXPathObjectPtr ret;
4369 
4370     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4371     if (ret == NULL) {
4372         xmlXPathErrMemory(NULL, "creating result value tree\n");
4373 	return(NULL);
4374     }
4375     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4376     ret->type = XPATH_XSLT_TREE;
4377     ret->boolval = 0;
4378     ret->user = (void *) val;
4379     ret->nodesetval = xmlXPathNodeSetCreate(val);
4380 #ifdef XP_DEBUG_OBJ_USAGE
4381     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4382 #endif
4383     return(ret);
4384 }
4385 
4386 /**
4387  * xmlXPathNewNodeSetList:
4388  * @val:  an existing NodeSet
4389  *
4390  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4391  * it with the Nodeset @val
4392  *
4393  * Returns the newly created object.
4394  */
4395 xmlXPathObjectPtr
xmlXPathNewNodeSetList(xmlNodeSetPtr val)4396 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4397 {
4398     xmlXPathObjectPtr ret;
4399     int i;
4400 
4401     if (val == NULL)
4402         ret = NULL;
4403     else if (val->nodeTab == NULL)
4404         ret = xmlXPathNewNodeSet(NULL);
4405     else {
4406         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4407         if (ret) {
4408             for (i = 1; i < val->nodeNr; ++i) {
4409                 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4410 		    < 0) break;
4411 	    }
4412 	}
4413     }
4414 
4415     return (ret);
4416 }
4417 
4418 /**
4419  * xmlXPathWrapNodeSet:
4420  * @val:  the NodePtr value
4421  *
4422  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4423  *
4424  * Returns the newly created object.
4425  */
4426 xmlXPathObjectPtr
xmlXPathWrapNodeSet(xmlNodeSetPtr val)4427 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4428     xmlXPathObjectPtr ret;
4429 
4430     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4431     if (ret == NULL) {
4432         xmlXPathErrMemory(NULL, "creating node set object\n");
4433 	return(NULL);
4434     }
4435     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4436     ret->type = XPATH_NODESET;
4437     ret->nodesetval = val;
4438 #ifdef XP_DEBUG_OBJ_USAGE
4439     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4440 #endif
4441     return(ret);
4442 }
4443 
4444 /**
4445  * xmlXPathFreeNodeSetList:
4446  * @obj:  an existing NodeSetList object
4447  *
4448  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4449  * the list contrary to xmlXPathFreeObject().
4450  */
4451 void
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj)4452 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4453     if (obj == NULL) return;
4454 #ifdef XP_DEBUG_OBJ_USAGE
4455     xmlXPathDebugObjUsageReleased(NULL, obj->type);
4456 #endif
4457     xmlFree(obj);
4458 }
4459 
4460 /**
4461  * xmlXPathDifference:
4462  * @nodes1:  a node-set
4463  * @nodes2:  a node-set
4464  *
4465  * Implements the EXSLT - Sets difference() function:
4466  *    node-set set:difference (node-set, node-set)
4467  *
4468  * Returns the difference between the two node sets, or nodes1 if
4469  *         nodes2 is empty
4470  */
4471 xmlNodeSetPtr
xmlXPathDifference(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4472 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4473     xmlNodeSetPtr ret;
4474     int i, l1;
4475     xmlNodePtr cur;
4476 
4477     if (xmlXPathNodeSetIsEmpty(nodes2))
4478 	return(nodes1);
4479 
4480     ret = xmlXPathNodeSetCreate(NULL);
4481     if (xmlXPathNodeSetIsEmpty(nodes1))
4482 	return(ret);
4483 
4484     l1 = xmlXPathNodeSetGetLength(nodes1);
4485 
4486     for (i = 0; i < l1; i++) {
4487 	cur = xmlXPathNodeSetItem(nodes1, i);
4488 	if (!xmlXPathNodeSetContains(nodes2, cur)) {
4489 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4490 	        break;
4491 	}
4492     }
4493     return(ret);
4494 }
4495 
4496 /**
4497  * xmlXPathIntersection:
4498  * @nodes1:  a node-set
4499  * @nodes2:  a node-set
4500  *
4501  * Implements the EXSLT - Sets intersection() function:
4502  *    node-set set:intersection (node-set, node-set)
4503  *
4504  * Returns a node set comprising the nodes that are within both the
4505  *         node sets passed as arguments
4506  */
4507 xmlNodeSetPtr
xmlXPathIntersection(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4508 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4509     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4510     int i, l1;
4511     xmlNodePtr cur;
4512 
4513     if (ret == NULL)
4514         return(ret);
4515     if (xmlXPathNodeSetIsEmpty(nodes1))
4516 	return(ret);
4517     if (xmlXPathNodeSetIsEmpty(nodes2))
4518 	return(ret);
4519 
4520     l1 = xmlXPathNodeSetGetLength(nodes1);
4521 
4522     for (i = 0; i < l1; i++) {
4523 	cur = xmlXPathNodeSetItem(nodes1, i);
4524 	if (xmlXPathNodeSetContains(nodes2, cur)) {
4525 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4526 	        break;
4527 	}
4528     }
4529     return(ret);
4530 }
4531 
4532 /**
4533  * xmlXPathDistinctSorted:
4534  * @nodes:  a node-set, sorted by document order
4535  *
4536  * Implements the EXSLT - Sets distinct() function:
4537  *    node-set set:distinct (node-set)
4538  *
4539  * Returns a subset of the nodes contained in @nodes, or @nodes if
4540  *         it is empty
4541  */
4542 xmlNodeSetPtr
xmlXPathDistinctSorted(xmlNodeSetPtr nodes)4543 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4544     xmlNodeSetPtr ret;
4545     xmlHashTablePtr hash;
4546     int i, l;
4547     xmlChar * strval;
4548     xmlNodePtr cur;
4549 
4550     if (xmlXPathNodeSetIsEmpty(nodes))
4551 	return(nodes);
4552 
4553     ret = xmlXPathNodeSetCreate(NULL);
4554     if (ret == NULL)
4555         return(ret);
4556     l = xmlXPathNodeSetGetLength(nodes);
4557     hash = xmlHashCreate (l);
4558     for (i = 0; i < l; i++) {
4559 	cur = xmlXPathNodeSetItem(nodes, i);
4560 	strval = xmlXPathCastNodeToString(cur);
4561 	if (xmlHashLookup(hash, strval) == NULL) {
4562 	    xmlHashAddEntry(hash, strval, strval);
4563 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4564 	        break;
4565 	} else {
4566 	    xmlFree(strval);
4567 	}
4568     }
4569     xmlHashFree(hash, xmlHashDefaultDeallocator);
4570     return(ret);
4571 }
4572 
4573 /**
4574  * xmlXPathDistinct:
4575  * @nodes:  a node-set
4576  *
4577  * Implements the EXSLT - Sets distinct() function:
4578  *    node-set set:distinct (node-set)
4579  * @nodes is sorted by document order, then #exslSetsDistinctSorted
4580  * is called with the sorted node-set
4581  *
4582  * Returns a subset of the nodes contained in @nodes, or @nodes if
4583  *         it is empty
4584  */
4585 xmlNodeSetPtr
xmlXPathDistinct(xmlNodeSetPtr nodes)4586 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4587     if (xmlXPathNodeSetIsEmpty(nodes))
4588 	return(nodes);
4589 
4590     xmlXPathNodeSetSort(nodes);
4591     return(xmlXPathDistinctSorted(nodes));
4592 }
4593 
4594 /**
4595  * xmlXPathHasSameNodes:
4596  * @nodes1:  a node-set
4597  * @nodes2:  a node-set
4598  *
4599  * Implements the EXSLT - Sets has-same-nodes function:
4600  *    boolean set:has-same-node(node-set, node-set)
4601  *
4602  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4603  *         otherwise
4604  */
4605 int
xmlXPathHasSameNodes(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4606 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4607     int i, l;
4608     xmlNodePtr cur;
4609 
4610     if (xmlXPathNodeSetIsEmpty(nodes1) ||
4611 	xmlXPathNodeSetIsEmpty(nodes2))
4612 	return(0);
4613 
4614     l = xmlXPathNodeSetGetLength(nodes1);
4615     for (i = 0; i < l; i++) {
4616 	cur = xmlXPathNodeSetItem(nodes1, i);
4617 	if (xmlXPathNodeSetContains(nodes2, cur))
4618 	    return(1);
4619     }
4620     return(0);
4621 }
4622 
4623 /**
4624  * xmlXPathNodeLeadingSorted:
4625  * @nodes: a node-set, sorted by document order
4626  * @node: a node
4627  *
4628  * Implements the EXSLT - Sets leading() function:
4629  *    node-set set:leading (node-set, node-set)
4630  *
4631  * Returns the nodes in @nodes that precede @node in document order,
4632  *         @nodes if @node is NULL or an empty node-set if @nodes
4633  *         doesn't contain @node
4634  */
4635 xmlNodeSetPtr
xmlXPathNodeLeadingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4636 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4637     int i, l;
4638     xmlNodePtr cur;
4639     xmlNodeSetPtr ret;
4640 
4641     if (node == NULL)
4642 	return(nodes);
4643 
4644     ret = xmlXPathNodeSetCreate(NULL);
4645     if (ret == NULL)
4646         return(ret);
4647     if (xmlXPathNodeSetIsEmpty(nodes) ||
4648 	(!xmlXPathNodeSetContains(nodes, node)))
4649 	return(ret);
4650 
4651     l = xmlXPathNodeSetGetLength(nodes);
4652     for (i = 0; i < l; i++) {
4653 	cur = xmlXPathNodeSetItem(nodes, i);
4654 	if (cur == node)
4655 	    break;
4656 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4657 	    break;
4658     }
4659     return(ret);
4660 }
4661 
4662 /**
4663  * xmlXPathNodeLeading:
4664  * @nodes:  a node-set
4665  * @node:  a node
4666  *
4667  * Implements the EXSLT - Sets leading() function:
4668  *    node-set set:leading (node-set, node-set)
4669  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4670  * is called.
4671  *
4672  * Returns the nodes in @nodes that precede @node in document order,
4673  *         @nodes if @node is NULL or an empty node-set if @nodes
4674  *         doesn't contain @node
4675  */
4676 xmlNodeSetPtr
xmlXPathNodeLeading(xmlNodeSetPtr nodes,xmlNodePtr node)4677 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4678     xmlXPathNodeSetSort(nodes);
4679     return(xmlXPathNodeLeadingSorted(nodes, node));
4680 }
4681 
4682 /**
4683  * xmlXPathLeadingSorted:
4684  * @nodes1:  a node-set, sorted by document order
4685  * @nodes2:  a node-set, sorted by document order
4686  *
4687  * Implements the EXSLT - Sets leading() function:
4688  *    node-set set:leading (node-set, node-set)
4689  *
4690  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4691  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4692  *         an empty node-set if @nodes1 doesn't contain @nodes2
4693  */
4694 xmlNodeSetPtr
xmlXPathLeadingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4695 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4696     if (xmlXPathNodeSetIsEmpty(nodes2))
4697 	return(nodes1);
4698     return(xmlXPathNodeLeadingSorted(nodes1,
4699 				     xmlXPathNodeSetItem(nodes2, 1)));
4700 }
4701 
4702 /**
4703  * xmlXPathLeading:
4704  * @nodes1:  a node-set
4705  * @nodes2:  a node-set
4706  *
4707  * Implements the EXSLT - Sets leading() function:
4708  *    node-set set:leading (node-set, node-set)
4709  * @nodes1 and @nodes2 are sorted by document order, then
4710  * #exslSetsLeadingSorted is called.
4711  *
4712  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4713  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4714  *         an empty node-set if @nodes1 doesn't contain @nodes2
4715  */
4716 xmlNodeSetPtr
xmlXPathLeading(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4717 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4718     if (xmlXPathNodeSetIsEmpty(nodes2))
4719 	return(nodes1);
4720     if (xmlXPathNodeSetIsEmpty(nodes1))
4721 	return(xmlXPathNodeSetCreate(NULL));
4722     xmlXPathNodeSetSort(nodes1);
4723     xmlXPathNodeSetSort(nodes2);
4724     return(xmlXPathNodeLeadingSorted(nodes1,
4725 				     xmlXPathNodeSetItem(nodes2, 1)));
4726 }
4727 
4728 /**
4729  * xmlXPathNodeTrailingSorted:
4730  * @nodes: a node-set, sorted by document order
4731  * @node: a node
4732  *
4733  * Implements the EXSLT - Sets trailing() function:
4734  *    node-set set:trailing (node-set, node-set)
4735  *
4736  * Returns the nodes in @nodes that follow @node in document order,
4737  *         @nodes if @node is NULL or an empty node-set if @nodes
4738  *         doesn't contain @node
4739  */
4740 xmlNodeSetPtr
xmlXPathNodeTrailingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4741 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4742     int i, l;
4743     xmlNodePtr cur;
4744     xmlNodeSetPtr ret;
4745 
4746     if (node == NULL)
4747 	return(nodes);
4748 
4749     ret = xmlXPathNodeSetCreate(NULL);
4750     if (ret == NULL)
4751         return(ret);
4752     if (xmlXPathNodeSetIsEmpty(nodes) ||
4753 	(!xmlXPathNodeSetContains(nodes, node)))
4754 	return(ret);
4755 
4756     l = xmlXPathNodeSetGetLength(nodes);
4757     for (i = l - 1; i >= 0; i--) {
4758 	cur = xmlXPathNodeSetItem(nodes, i);
4759 	if (cur == node)
4760 	    break;
4761 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4762 	    break;
4763     }
4764     xmlXPathNodeSetSort(ret);	/* bug 413451 */
4765     return(ret);
4766 }
4767 
4768 /**
4769  * xmlXPathNodeTrailing:
4770  * @nodes:  a node-set
4771  * @node:  a node
4772  *
4773  * Implements the EXSLT - Sets trailing() function:
4774  *    node-set set:trailing (node-set, node-set)
4775  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4776  * is called.
4777  *
4778  * Returns the nodes in @nodes that follow @node in document order,
4779  *         @nodes if @node is NULL or an empty node-set if @nodes
4780  *         doesn't contain @node
4781  */
4782 xmlNodeSetPtr
xmlXPathNodeTrailing(xmlNodeSetPtr nodes,xmlNodePtr node)4783 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4784     xmlXPathNodeSetSort(nodes);
4785     return(xmlXPathNodeTrailingSorted(nodes, node));
4786 }
4787 
4788 /**
4789  * xmlXPathTrailingSorted:
4790  * @nodes1:  a node-set, sorted by document order
4791  * @nodes2:  a node-set, sorted by document order
4792  *
4793  * Implements the EXSLT - Sets trailing() function:
4794  *    node-set set:trailing (node-set, node-set)
4795  *
4796  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4797  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4798  *         an empty node-set if @nodes1 doesn't contain @nodes2
4799  */
4800 xmlNodeSetPtr
xmlXPathTrailingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4801 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4802     if (xmlXPathNodeSetIsEmpty(nodes2))
4803 	return(nodes1);
4804     return(xmlXPathNodeTrailingSorted(nodes1,
4805 				      xmlXPathNodeSetItem(nodes2, 0)));
4806 }
4807 
4808 /**
4809  * xmlXPathTrailing:
4810  * @nodes1:  a node-set
4811  * @nodes2:  a node-set
4812  *
4813  * Implements the EXSLT - Sets trailing() function:
4814  *    node-set set:trailing (node-set, node-set)
4815  * @nodes1 and @nodes2 are sorted by document order, then
4816  * #xmlXPathTrailingSorted is called.
4817  *
4818  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4819  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4820  *         an empty node-set if @nodes1 doesn't contain @nodes2
4821  */
4822 xmlNodeSetPtr
xmlXPathTrailing(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4823 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4824     if (xmlXPathNodeSetIsEmpty(nodes2))
4825 	return(nodes1);
4826     if (xmlXPathNodeSetIsEmpty(nodes1))
4827 	return(xmlXPathNodeSetCreate(NULL));
4828     xmlXPathNodeSetSort(nodes1);
4829     xmlXPathNodeSetSort(nodes2);
4830     return(xmlXPathNodeTrailingSorted(nodes1,
4831 				      xmlXPathNodeSetItem(nodes2, 0)));
4832 }
4833 
4834 /************************************************************************
4835  *									*
4836  *		Routines to handle extra functions			*
4837  *									*
4838  ************************************************************************/
4839 
4840 /**
4841  * xmlXPathRegisterFunc:
4842  * @ctxt:  the XPath context
4843  * @name:  the function name
4844  * @f:  the function implementation or NULL
4845  *
4846  * Register a new function. If @f is NULL it unregisters the function
4847  *
4848  * Returns 0 in case of success, -1 in case of error
4849  */
4850 int
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathFunction f)4851 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4852 		     xmlXPathFunction f) {
4853     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4854 }
4855 
4856 /**
4857  * xmlXPathRegisterFuncNS:
4858  * @ctxt:  the XPath context
4859  * @name:  the function name
4860  * @ns_uri:  the function namespace URI
4861  * @f:  the function implementation or NULL
4862  *
4863  * Register a new function. If @f is NULL it unregisters the function
4864  *
4865  * Returns 0 in case of success, -1 in case of error
4866  */
4867 int
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathFunction f)4868 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4869 		       const xmlChar *ns_uri, xmlXPathFunction f) {
4870     if (ctxt == NULL)
4871 	return(-1);
4872     if (name == NULL)
4873 	return(-1);
4874 
4875     if (ctxt->funcHash == NULL)
4876 	ctxt->funcHash = xmlHashCreate(0);
4877     if (ctxt->funcHash == NULL)
4878 	return(-1);
4879     if (f == NULL)
4880         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4881 XML_IGNORE_PEDANTIC_WARNINGS
4882     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4883 XML_POP_WARNINGS
4884 }
4885 
4886 /**
4887  * xmlXPathRegisterFuncLookup:
4888  * @ctxt:  the XPath context
4889  * @f:  the lookup function
4890  * @funcCtxt:  the lookup data
4891  *
4892  * Registers an external mechanism to do function lookup.
4893  */
4894 void
xmlXPathRegisterFuncLookup(xmlXPathContextPtr ctxt,xmlXPathFuncLookupFunc f,void * funcCtxt)4895 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4896 			    xmlXPathFuncLookupFunc f,
4897 			    void *funcCtxt) {
4898     if (ctxt == NULL)
4899 	return;
4900     ctxt->funcLookupFunc = f;
4901     ctxt->funcLookupData = funcCtxt;
4902 }
4903 
4904 /**
4905  * xmlXPathFunctionLookup:
4906  * @ctxt:  the XPath context
4907  * @name:  the function name
4908  *
4909  * Search in the Function array of the context for the given
4910  * function.
4911  *
4912  * Returns the xmlXPathFunction or NULL if not found
4913  */
4914 xmlXPathFunction
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt,const xmlChar * name)4915 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4916     if (ctxt == NULL)
4917 	return (NULL);
4918 
4919     if (ctxt->funcLookupFunc != NULL) {
4920 	xmlXPathFunction ret;
4921 	xmlXPathFuncLookupFunc f;
4922 
4923 	f = ctxt->funcLookupFunc;
4924 	ret = f(ctxt->funcLookupData, name, NULL);
4925 	if (ret != NULL)
4926 	    return(ret);
4927     }
4928     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4929 }
4930 
4931 /**
4932  * xmlXPathFunctionLookupNS:
4933  * @ctxt:  the XPath context
4934  * @name:  the function name
4935  * @ns_uri:  the function namespace URI
4936  *
4937  * Search in the Function array of the context for the given
4938  * function.
4939  *
4940  * Returns the xmlXPathFunction or NULL if not found
4941  */
4942 xmlXPathFunction
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4943 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4944 			 const xmlChar *ns_uri) {
4945     xmlXPathFunction ret;
4946 
4947     if (ctxt == NULL)
4948 	return(NULL);
4949     if (name == NULL)
4950 	return(NULL);
4951 
4952     if (ctxt->funcLookupFunc != NULL) {
4953 	xmlXPathFuncLookupFunc f;
4954 
4955 	f = ctxt->funcLookupFunc;
4956 	ret = f(ctxt->funcLookupData, name, ns_uri);
4957 	if (ret != NULL)
4958 	    return(ret);
4959     }
4960 
4961     if (ctxt->funcHash == NULL)
4962 	return(NULL);
4963 
4964 XML_IGNORE_PEDANTIC_WARNINGS
4965     ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4966 XML_POP_WARNINGS
4967     return(ret);
4968 }
4969 
4970 /**
4971  * xmlXPathRegisteredFuncsCleanup:
4972  * @ctxt:  the XPath context
4973  *
4974  * Cleanup the XPath context data associated to registered functions
4975  */
4976 void
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt)4977 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4978     if (ctxt == NULL)
4979 	return;
4980 
4981     xmlHashFree(ctxt->funcHash, NULL);
4982     ctxt->funcHash = NULL;
4983 }
4984 
4985 /************************************************************************
4986  *									*
4987  *			Routines to handle Variables			*
4988  *									*
4989  ************************************************************************/
4990 
4991 /**
4992  * xmlXPathRegisterVariable:
4993  * @ctxt:  the XPath context
4994  * @name:  the variable name
4995  * @value:  the variable value or NULL
4996  *
4997  * Register a new variable value. If @value is NULL it unregisters
4998  * the variable
4999  *
5000  * Returns 0 in case of success, -1 in case of error
5001  */
5002 int
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathObjectPtr value)5003 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
5004 			 xmlXPathObjectPtr value) {
5005     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
5006 }
5007 
5008 /**
5009  * xmlXPathRegisterVariableNS:
5010  * @ctxt:  the XPath context
5011  * @name:  the variable name
5012  * @ns_uri:  the variable namespace URI
5013  * @value:  the variable value or NULL
5014  *
5015  * Register a new variable value. If @value is NULL it unregisters
5016  * the variable
5017  *
5018  * Returns 0 in case of success, -1 in case of error
5019  */
5020 int
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathObjectPtr value)5021 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5022 			   const xmlChar *ns_uri,
5023 			   xmlXPathObjectPtr value) {
5024     if (ctxt == NULL)
5025 	return(-1);
5026     if (name == NULL)
5027 	return(-1);
5028 
5029     if (ctxt->varHash == NULL)
5030 	ctxt->varHash = xmlHashCreate(0);
5031     if (ctxt->varHash == NULL)
5032 	return(-1);
5033     if (value == NULL)
5034         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5035 	                           xmlXPathFreeObjectEntry));
5036     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5037 			       (void *) value, xmlXPathFreeObjectEntry));
5038 }
5039 
5040 /**
5041  * xmlXPathRegisterVariableLookup:
5042  * @ctxt:  the XPath context
5043  * @f:  the lookup function
5044  * @data:  the lookup data
5045  *
5046  * register an external mechanism to do variable lookup
5047  */
5048 void
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,xmlXPathVariableLookupFunc f,void * data)5049 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5050 	 xmlXPathVariableLookupFunc f, void *data) {
5051     if (ctxt == NULL)
5052 	return;
5053     ctxt->varLookupFunc = f;
5054     ctxt->varLookupData = data;
5055 }
5056 
5057 /**
5058  * xmlXPathVariableLookup:
5059  * @ctxt:  the XPath context
5060  * @name:  the variable name
5061  *
5062  * Search in the Variable array of the context for the given
5063  * variable value.
5064  *
5065  * Returns a copy of the value or NULL if not found
5066  */
5067 xmlXPathObjectPtr
xmlXPathVariableLookup(xmlXPathContextPtr ctxt,const xmlChar * name)5068 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5069     if (ctxt == NULL)
5070 	return(NULL);
5071 
5072     if (ctxt->varLookupFunc != NULL) {
5073 	xmlXPathObjectPtr ret;
5074 
5075 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5076 	        (ctxt->varLookupData, name, NULL);
5077 	return(ret);
5078     }
5079     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5080 }
5081 
5082 /**
5083  * xmlXPathVariableLookupNS:
5084  * @ctxt:  the XPath context
5085  * @name:  the variable name
5086  * @ns_uri:  the variable namespace URI
5087  *
5088  * Search in the Variable array of the context for the given
5089  * variable value.
5090  *
5091  * Returns the a copy of the value or NULL if not found
5092  */
5093 xmlXPathObjectPtr
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)5094 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5095 			 const xmlChar *ns_uri) {
5096     if (ctxt == NULL)
5097 	return(NULL);
5098 
5099     if (ctxt->varLookupFunc != NULL) {
5100 	xmlXPathObjectPtr ret;
5101 
5102 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5103 	        (ctxt->varLookupData, name, ns_uri);
5104 	if (ret != NULL) return(ret);
5105     }
5106 
5107     if (ctxt->varHash == NULL)
5108 	return(NULL);
5109     if (name == NULL)
5110 	return(NULL);
5111 
5112     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5113 		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5114 }
5115 
5116 /**
5117  * xmlXPathRegisteredVariablesCleanup:
5118  * @ctxt:  the XPath context
5119  *
5120  * Cleanup the XPath context data associated to registered variables
5121  */
5122 void
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt)5123 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5124     if (ctxt == NULL)
5125 	return;
5126 
5127     xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5128     ctxt->varHash = NULL;
5129 }
5130 
5131 /**
5132  * xmlXPathRegisterNs:
5133  * @ctxt:  the XPath context
5134  * @prefix:  the namespace prefix cannot be NULL or empty string
5135  * @ns_uri:  the namespace name
5136  *
5137  * Register a new namespace. If @ns_uri is NULL it unregisters
5138  * the namespace
5139  *
5140  * Returns 0 in case of success, -1 in case of error
5141  */
5142 int
xmlXPathRegisterNs(xmlXPathContextPtr ctxt,const xmlChar * prefix,const xmlChar * ns_uri)5143 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5144 			   const xmlChar *ns_uri) {
5145     if (ctxt == NULL)
5146 	return(-1);
5147     if (prefix == NULL)
5148 	return(-1);
5149     if (prefix[0] == 0)
5150 	return(-1);
5151 
5152     if (ctxt->nsHash == NULL)
5153 	ctxt->nsHash = xmlHashCreate(10);
5154     if (ctxt->nsHash == NULL)
5155 	return(-1);
5156     if (ns_uri == NULL)
5157         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5158 	                          xmlHashDefaultDeallocator));
5159     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5160 			      xmlHashDefaultDeallocator));
5161 }
5162 
5163 /**
5164  * xmlXPathNsLookup:
5165  * @ctxt:  the XPath context
5166  * @prefix:  the namespace prefix value
5167  *
5168  * Search in the namespace declaration array of the context for the given
5169  * namespace name associated to the given prefix
5170  *
5171  * Returns the value or NULL if not found
5172  */
5173 const xmlChar *
xmlXPathNsLookup(xmlXPathContextPtr ctxt,const xmlChar * prefix)5174 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5175     if (ctxt == NULL)
5176 	return(NULL);
5177     if (prefix == NULL)
5178 	return(NULL);
5179 
5180 #ifdef XML_XML_NAMESPACE
5181     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5182 	return(XML_XML_NAMESPACE);
5183 #endif
5184 
5185     if (ctxt->namespaces != NULL) {
5186 	int i;
5187 
5188 	for (i = 0;i < ctxt->nsNr;i++) {
5189 	    if ((ctxt->namespaces[i] != NULL) &&
5190 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5191 		return(ctxt->namespaces[i]->href);
5192 	}
5193     }
5194 
5195     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5196 }
5197 
5198 /**
5199  * xmlXPathRegisteredNsCleanup:
5200  * @ctxt:  the XPath context
5201  *
5202  * Cleanup the XPath context data associated to registered variables
5203  */
5204 void
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt)5205 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5206     if (ctxt == NULL)
5207 	return;
5208 
5209     xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5210     ctxt->nsHash = NULL;
5211 }
5212 
5213 /************************************************************************
5214  *									*
5215  *			Routines to handle Values			*
5216  *									*
5217  ************************************************************************/
5218 
5219 /* Allocations are terrible, one needs to optimize all this !!! */
5220 
5221 /**
5222  * xmlXPathNewFloat:
5223  * @val:  the double value
5224  *
5225  * Create a new xmlXPathObjectPtr of type double and of value @val
5226  *
5227  * Returns the newly created object.
5228  */
5229 xmlXPathObjectPtr
xmlXPathNewFloat(double val)5230 xmlXPathNewFloat(double val) {
5231     xmlXPathObjectPtr ret;
5232 
5233     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5234     if (ret == NULL) {
5235         xmlXPathErrMemory(NULL, "creating float object\n");
5236 	return(NULL);
5237     }
5238     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5239     ret->type = XPATH_NUMBER;
5240     ret->floatval = val;
5241 #ifdef XP_DEBUG_OBJ_USAGE
5242     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5243 #endif
5244     return(ret);
5245 }
5246 
5247 /**
5248  * xmlXPathNewBoolean:
5249  * @val:  the boolean value
5250  *
5251  * Create a new xmlXPathObjectPtr of type boolean and of value @val
5252  *
5253  * Returns the newly created object.
5254  */
5255 xmlXPathObjectPtr
xmlXPathNewBoolean(int val)5256 xmlXPathNewBoolean(int val) {
5257     xmlXPathObjectPtr ret;
5258 
5259     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5260     if (ret == NULL) {
5261         xmlXPathErrMemory(NULL, "creating boolean object\n");
5262 	return(NULL);
5263     }
5264     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5265     ret->type = XPATH_BOOLEAN;
5266     ret->boolval = (val != 0);
5267 #ifdef XP_DEBUG_OBJ_USAGE
5268     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5269 #endif
5270     return(ret);
5271 }
5272 
5273 /**
5274  * xmlXPathNewString:
5275  * @val:  the xmlChar * value
5276  *
5277  * Create a new xmlXPathObjectPtr of type string and of value @val
5278  *
5279  * Returns the newly created object.
5280  */
5281 xmlXPathObjectPtr
xmlXPathNewString(const xmlChar * val)5282 xmlXPathNewString(const xmlChar *val) {
5283     xmlXPathObjectPtr ret;
5284 
5285     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5286     if (ret == NULL) {
5287         xmlXPathErrMemory(NULL, "creating string object\n");
5288 	return(NULL);
5289     }
5290     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5291     ret->type = XPATH_STRING;
5292     if (val != NULL)
5293 	ret->stringval = xmlStrdup(val);
5294     else
5295 	ret->stringval = xmlStrdup((const xmlChar *)"");
5296 #ifdef XP_DEBUG_OBJ_USAGE
5297     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5298 #endif
5299     return(ret);
5300 }
5301 
5302 /**
5303  * xmlXPathWrapString:
5304  * @val:  the xmlChar * value
5305  *
5306  * Wraps the @val string into an XPath object.
5307  *
5308  * Returns the newly created object.
5309  */
5310 xmlXPathObjectPtr
xmlXPathWrapString(xmlChar * val)5311 xmlXPathWrapString (xmlChar *val) {
5312     xmlXPathObjectPtr ret;
5313 
5314     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5315     if (ret == NULL) {
5316         xmlXPathErrMemory(NULL, "creating string object\n");
5317 	return(NULL);
5318     }
5319     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5320     ret->type = XPATH_STRING;
5321     ret->stringval = val;
5322 #ifdef XP_DEBUG_OBJ_USAGE
5323     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5324 #endif
5325     return(ret);
5326 }
5327 
5328 /**
5329  * xmlXPathNewCString:
5330  * @val:  the char * value
5331  *
5332  * Create a new xmlXPathObjectPtr of type string and of value @val
5333  *
5334  * Returns the newly created object.
5335  */
5336 xmlXPathObjectPtr
xmlXPathNewCString(const char * val)5337 xmlXPathNewCString(const char *val) {
5338     xmlXPathObjectPtr ret;
5339 
5340     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5341     if (ret == NULL) {
5342         xmlXPathErrMemory(NULL, "creating string object\n");
5343 	return(NULL);
5344     }
5345     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5346     ret->type = XPATH_STRING;
5347     ret->stringval = xmlStrdup(BAD_CAST val);
5348 #ifdef XP_DEBUG_OBJ_USAGE
5349     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5350 #endif
5351     return(ret);
5352 }
5353 
5354 /**
5355  * xmlXPathWrapCString:
5356  * @val:  the char * value
5357  *
5358  * Wraps a string into an XPath object.
5359  *
5360  * Returns the newly created object.
5361  */
5362 xmlXPathObjectPtr
xmlXPathWrapCString(char * val)5363 xmlXPathWrapCString (char * val) {
5364     return(xmlXPathWrapString((xmlChar *)(val)));
5365 }
5366 
5367 /**
5368  * xmlXPathWrapExternal:
5369  * @val:  the user data
5370  *
5371  * Wraps the @val data into an XPath object.
5372  *
5373  * Returns the newly created object.
5374  */
5375 xmlXPathObjectPtr
xmlXPathWrapExternal(void * val)5376 xmlXPathWrapExternal (void *val) {
5377     xmlXPathObjectPtr ret;
5378 
5379     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5380     if (ret == NULL) {
5381         xmlXPathErrMemory(NULL, "creating user object\n");
5382 	return(NULL);
5383     }
5384     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5385     ret->type = XPATH_USERS;
5386     ret->user = val;
5387 #ifdef XP_DEBUG_OBJ_USAGE
5388     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5389 #endif
5390     return(ret);
5391 }
5392 
5393 /**
5394  * xmlXPathObjectCopy:
5395  * @val:  the original object
5396  *
5397  * allocate a new copy of a given object
5398  *
5399  * Returns the newly created object.
5400  */
5401 xmlXPathObjectPtr
xmlXPathObjectCopy(xmlXPathObjectPtr val)5402 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5403     xmlXPathObjectPtr ret;
5404 
5405     if (val == NULL)
5406 	return(NULL);
5407 
5408     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5409     if (ret == NULL) {
5410         xmlXPathErrMemory(NULL, "copying object\n");
5411 	return(NULL);
5412     }
5413     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5414 #ifdef XP_DEBUG_OBJ_USAGE
5415     xmlXPathDebugObjUsageRequested(NULL, val->type);
5416 #endif
5417     switch (val->type) {
5418 	case XPATH_BOOLEAN:
5419 	case XPATH_NUMBER:
5420 	case XPATH_POINT:
5421 	case XPATH_RANGE:
5422 	    break;
5423 	case XPATH_STRING:
5424 	    ret->stringval = xmlStrdup(val->stringval);
5425 	    break;
5426 	case XPATH_XSLT_TREE:
5427 #if 0
5428 /*
5429   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5430   this previous handling is no longer correct, and can cause some serious
5431   problems (ref. bug 145547)
5432 */
5433 	    if ((val->nodesetval != NULL) &&
5434 		(val->nodesetval->nodeTab != NULL)) {
5435 		xmlNodePtr cur, tmp;
5436 		xmlDocPtr top;
5437 
5438 		ret->boolval = 1;
5439 		top =  xmlNewDoc(NULL);
5440 		top->name = (char *)
5441 		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
5442 		ret->user = top;
5443 		if (top != NULL) {
5444 		    top->doc = top;
5445 		    cur = val->nodesetval->nodeTab[0]->children;
5446 		    while (cur != NULL) {
5447 			tmp = xmlDocCopyNode(cur, top, 1);
5448 			xmlAddChild((xmlNodePtr) top, tmp);
5449 			cur = cur->next;
5450 		    }
5451 		}
5452 
5453 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5454 	    } else
5455 		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5456 	    /* Deallocate the copied tree value */
5457 	    break;
5458 #endif
5459 	case XPATH_NODESET:
5460 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5461 	    /* Do not deallocate the copied tree value */
5462 	    ret->boolval = 0;
5463 	    break;
5464 	case XPATH_LOCATIONSET:
5465 #ifdef LIBXML_XPTR_ENABLED
5466 	{
5467 	    xmlLocationSetPtr loc = val->user;
5468 	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5469 	    break;
5470 	}
5471 #endif
5472         case XPATH_USERS:
5473 	    ret->user = val->user;
5474 	    break;
5475         case XPATH_UNDEFINED:
5476 	    xmlGenericError(xmlGenericErrorContext,
5477 		    "xmlXPathObjectCopy: unsupported type %d\n",
5478 		    val->type);
5479 	    break;
5480     }
5481     return(ret);
5482 }
5483 
5484 /**
5485  * xmlXPathFreeObject:
5486  * @obj:  the object to free
5487  *
5488  * Free up an xmlXPathObjectPtr object.
5489  */
5490 void
xmlXPathFreeObject(xmlXPathObjectPtr obj)5491 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5492     if (obj == NULL) return;
5493     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5494 	if (obj->boolval) {
5495 #if 0
5496 	    if (obj->user != NULL) {
5497                 xmlXPathFreeNodeSet(obj->nodesetval);
5498 		xmlFreeNodeList((xmlNodePtr) obj->user);
5499 	    } else
5500 #endif
5501 	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5502 	    if (obj->nodesetval != NULL)
5503 		xmlXPathFreeValueTree(obj->nodesetval);
5504 	} else {
5505 	    if (obj->nodesetval != NULL)
5506 		xmlXPathFreeNodeSet(obj->nodesetval);
5507 	}
5508 #ifdef LIBXML_XPTR_ENABLED
5509     } else if (obj->type == XPATH_LOCATIONSET) {
5510 	if (obj->user != NULL)
5511 	    xmlXPtrFreeLocationSet(obj->user);
5512 #endif
5513     } else if (obj->type == XPATH_STRING) {
5514 	if (obj->stringval != NULL)
5515 	    xmlFree(obj->stringval);
5516     }
5517 #ifdef XP_DEBUG_OBJ_USAGE
5518     xmlXPathDebugObjUsageReleased(NULL, obj->type);
5519 #endif
5520     xmlFree(obj);
5521 }
5522 
5523 static void
xmlXPathFreeObjectEntry(void * obj,const xmlChar * name ATTRIBUTE_UNUSED)5524 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5525     xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5526 }
5527 
5528 /**
5529  * xmlXPathReleaseObject:
5530  * @obj:  the xmlXPathObjectPtr to free or to cache
5531  *
5532  * Depending on the state of the cache this frees the given
5533  * XPath object or stores it in the cache.
5534  */
5535 static void
xmlXPathReleaseObject(xmlXPathContextPtr ctxt,xmlXPathObjectPtr obj)5536 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5537 {
5538 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5539 	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5540     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5541 
5542 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5543 
5544     if (obj == NULL)
5545 	return;
5546     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5547 	 xmlXPathFreeObject(obj);
5548     } else {
5549 	xmlXPathContextCachePtr cache =
5550 	    (xmlXPathContextCachePtr) ctxt->cache;
5551 
5552 	switch (obj->type) {
5553 	    case XPATH_NODESET:
5554 	    case XPATH_XSLT_TREE:
5555 		if (obj->nodesetval != NULL) {
5556 		    if (obj->boolval) {
5557 			/*
5558 			* It looks like the @boolval is used for
5559 			* evaluation if this an XSLT Result Tree Fragment.
5560 			* TODO: Check if this assumption is correct.
5561 			*/
5562 			obj->type = XPATH_XSLT_TREE; /* just for debugging */
5563 			xmlXPathFreeValueTree(obj->nodesetval);
5564 			obj->nodesetval = NULL;
5565 		    } else if ((obj->nodesetval->nodeMax <= 40) &&
5566 			(XP_CACHE_WANTS(cache->nodesetObjs,
5567 					cache->maxNodeset)))
5568 		    {
5569 			XP_CACHE_ADD(cache->nodesetObjs, obj);
5570 			goto obj_cached;
5571 		    } else {
5572 			xmlXPathFreeNodeSet(obj->nodesetval);
5573 			obj->nodesetval = NULL;
5574 		    }
5575 		}
5576 		break;
5577 	    case XPATH_STRING:
5578 		if (obj->stringval != NULL)
5579 		    xmlFree(obj->stringval);
5580 
5581 		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5582 		    XP_CACHE_ADD(cache->stringObjs, obj);
5583 		    goto obj_cached;
5584 		}
5585 		break;
5586 	    case XPATH_BOOLEAN:
5587 		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5588 		    XP_CACHE_ADD(cache->booleanObjs, obj);
5589 		    goto obj_cached;
5590 		}
5591 		break;
5592 	    case XPATH_NUMBER:
5593 		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5594 		    XP_CACHE_ADD(cache->numberObjs, obj);
5595 		    goto obj_cached;
5596 		}
5597 		break;
5598 #ifdef LIBXML_XPTR_ENABLED
5599 	    case XPATH_LOCATIONSET:
5600 		if (obj->user != NULL) {
5601 		    xmlXPtrFreeLocationSet(obj->user);
5602 		}
5603 		goto free_obj;
5604 #endif
5605 	    default:
5606 		goto free_obj;
5607 	}
5608 
5609 	/*
5610 	* Fallback to adding to the misc-objects slot.
5611 	*/
5612 	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5613 	    XP_CACHE_ADD(cache->miscObjs, obj);
5614 	} else
5615 	    goto free_obj;
5616 
5617 obj_cached:
5618 
5619 #ifdef XP_DEBUG_OBJ_USAGE
5620 	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5621 #endif
5622 
5623 	if (obj->nodesetval != NULL) {
5624 	    xmlNodeSetPtr tmpset = obj->nodesetval;
5625 
5626 	    /*
5627 	    * TODO: Due to those nasty ns-nodes, we need to traverse
5628 	    *  the list and free the ns-nodes.
5629 	    * URGENT TODO: Check if it's actually slowing things down.
5630 	    *  Maybe we shouldn't try to preserve the list.
5631 	    */
5632 	    if (tmpset->nodeNr > 1) {
5633 		int i;
5634 		xmlNodePtr node;
5635 
5636 		for (i = 0; i < tmpset->nodeNr; i++) {
5637 		    node = tmpset->nodeTab[i];
5638 		    if ((node != NULL) &&
5639 			(node->type == XML_NAMESPACE_DECL))
5640 		    {
5641 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5642 		    }
5643 		}
5644 	    } else if (tmpset->nodeNr == 1) {
5645 		if ((tmpset->nodeTab[0] != NULL) &&
5646 		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5647 		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5648 	    }
5649 	    tmpset->nodeNr = 0;
5650 	    memset(obj, 0, sizeof(xmlXPathObject));
5651 	    obj->nodesetval = tmpset;
5652 	} else
5653 	    memset(obj, 0, sizeof(xmlXPathObject));
5654 
5655 	return;
5656 
5657 free_obj:
5658 	/*
5659 	* Cache is full; free the object.
5660 	*/
5661 	if (obj->nodesetval != NULL)
5662 	    xmlXPathFreeNodeSet(obj->nodesetval);
5663 #ifdef XP_DEBUG_OBJ_USAGE
5664 	xmlXPathDebugObjUsageReleased(NULL, obj->type);
5665 #endif
5666 	xmlFree(obj);
5667     }
5668     return;
5669 }
5670 
5671 
5672 /************************************************************************
5673  *									*
5674  *			Type Casting Routines				*
5675  *									*
5676  ************************************************************************/
5677 
5678 /**
5679  * xmlXPathCastBooleanToString:
5680  * @val:  a boolean
5681  *
5682  * Converts a boolean to its string value.
5683  *
5684  * Returns a newly allocated string.
5685  */
5686 xmlChar *
xmlXPathCastBooleanToString(int val)5687 xmlXPathCastBooleanToString (int val) {
5688     xmlChar *ret;
5689     if (val)
5690 	ret = xmlStrdup((const xmlChar *) "true");
5691     else
5692 	ret = xmlStrdup((const xmlChar *) "false");
5693     return(ret);
5694 }
5695 
5696 /**
5697  * xmlXPathCastNumberToString:
5698  * @val:  a number
5699  *
5700  * Converts a number to its string value.
5701  *
5702  * Returns a newly allocated string.
5703  */
5704 xmlChar *
xmlXPathCastNumberToString(double val)5705 xmlXPathCastNumberToString (double val) {
5706     xmlChar *ret;
5707     switch (xmlXPathIsInf(val)) {
5708     case 1:
5709 	ret = xmlStrdup((const xmlChar *) "Infinity");
5710 	break;
5711     case -1:
5712 	ret = xmlStrdup((const xmlChar *) "-Infinity");
5713 	break;
5714     default:
5715 	if (xmlXPathIsNaN(val)) {
5716 	    ret = xmlStrdup((const xmlChar *) "NaN");
5717 	} else if (val == 0) {
5718             /* Omit sign for negative zero. */
5719 	    ret = xmlStrdup((const xmlChar *) "0");
5720 	} else {
5721 	    /* could be improved */
5722 	    char buf[100];
5723 	    xmlXPathFormatNumber(val, buf, 99);
5724 	    buf[99] = 0;
5725 	    ret = xmlStrdup((const xmlChar *) buf);
5726 	}
5727     }
5728     return(ret);
5729 }
5730 
5731 /**
5732  * xmlXPathCastNodeToString:
5733  * @node:  a node
5734  *
5735  * Converts a node to its string value.
5736  *
5737  * Returns a newly allocated string.
5738  */
5739 xmlChar *
xmlXPathCastNodeToString(xmlNodePtr node)5740 xmlXPathCastNodeToString (xmlNodePtr node) {
5741 xmlChar *ret;
5742     if ((ret = xmlNodeGetContent(node)) == NULL)
5743 	ret = xmlStrdup((const xmlChar *) "");
5744     return(ret);
5745 }
5746 
5747 /**
5748  * xmlXPathCastNodeSetToString:
5749  * @ns:  a node-set
5750  *
5751  * Converts a node-set to its string value.
5752  *
5753  * Returns a newly allocated string.
5754  */
5755 xmlChar *
xmlXPathCastNodeSetToString(xmlNodeSetPtr ns)5756 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5757     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5758 	return(xmlStrdup((const xmlChar *) ""));
5759 
5760     if (ns->nodeNr > 1)
5761 	xmlXPathNodeSetSort(ns);
5762     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5763 }
5764 
5765 /**
5766  * xmlXPathCastToString:
5767  * @val:  an XPath object
5768  *
5769  * Converts an existing object to its string() equivalent
5770  *
5771  * Returns the allocated string value of the object, NULL in case of error.
5772  *         It's up to the caller to free the string memory with xmlFree().
5773  */
5774 xmlChar *
xmlXPathCastToString(xmlXPathObjectPtr val)5775 xmlXPathCastToString(xmlXPathObjectPtr val) {
5776     xmlChar *ret = NULL;
5777 
5778     if (val == NULL)
5779 	return(xmlStrdup((const xmlChar *) ""));
5780     switch (val->type) {
5781 	case XPATH_UNDEFINED:
5782 #ifdef DEBUG_EXPR
5783 	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5784 #endif
5785 	    ret = xmlStrdup((const xmlChar *) "");
5786 	    break;
5787         case XPATH_NODESET:
5788         case XPATH_XSLT_TREE:
5789 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
5790 	    break;
5791 	case XPATH_STRING:
5792 	    return(xmlStrdup(val->stringval));
5793         case XPATH_BOOLEAN:
5794 	    ret = xmlXPathCastBooleanToString(val->boolval);
5795 	    break;
5796 	case XPATH_NUMBER: {
5797 	    ret = xmlXPathCastNumberToString(val->floatval);
5798 	    break;
5799 	}
5800 	case XPATH_USERS:
5801 	case XPATH_POINT:
5802 	case XPATH_RANGE:
5803 	case XPATH_LOCATIONSET:
5804 	    TODO
5805 	    ret = xmlStrdup((const xmlChar *) "");
5806 	    break;
5807     }
5808     return(ret);
5809 }
5810 
5811 /**
5812  * xmlXPathConvertString:
5813  * @val:  an XPath object
5814  *
5815  * Converts an existing object to its string() equivalent
5816  *
5817  * Returns the new object, the old one is freed (or the operation
5818  *         is done directly on @val)
5819  */
5820 xmlXPathObjectPtr
xmlXPathConvertString(xmlXPathObjectPtr val)5821 xmlXPathConvertString(xmlXPathObjectPtr val) {
5822     xmlChar *res = NULL;
5823 
5824     if (val == NULL)
5825 	return(xmlXPathNewCString(""));
5826 
5827     switch (val->type) {
5828     case XPATH_UNDEFINED:
5829 #ifdef DEBUG_EXPR
5830 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5831 #endif
5832 	break;
5833     case XPATH_NODESET:
5834     case XPATH_XSLT_TREE:
5835 	res = xmlXPathCastNodeSetToString(val->nodesetval);
5836 	break;
5837     case XPATH_STRING:
5838 	return(val);
5839     case XPATH_BOOLEAN:
5840 	res = xmlXPathCastBooleanToString(val->boolval);
5841 	break;
5842     case XPATH_NUMBER:
5843 	res = xmlXPathCastNumberToString(val->floatval);
5844 	break;
5845     case XPATH_USERS:
5846     case XPATH_POINT:
5847     case XPATH_RANGE:
5848     case XPATH_LOCATIONSET:
5849 	TODO;
5850 	break;
5851     }
5852     xmlXPathFreeObject(val);
5853     if (res == NULL)
5854 	return(xmlXPathNewCString(""));
5855     return(xmlXPathWrapString(res));
5856 }
5857 
5858 /**
5859  * xmlXPathCastBooleanToNumber:
5860  * @val:  a boolean
5861  *
5862  * Converts a boolean to its number value
5863  *
5864  * Returns the number value
5865  */
5866 double
xmlXPathCastBooleanToNumber(int val)5867 xmlXPathCastBooleanToNumber(int val) {
5868     if (val)
5869 	return(1.0);
5870     return(0.0);
5871 }
5872 
5873 /**
5874  * xmlXPathCastStringToNumber:
5875  * @val:  a string
5876  *
5877  * Converts a string to its number value
5878  *
5879  * Returns the number value
5880  */
5881 double
xmlXPathCastStringToNumber(const xmlChar * val)5882 xmlXPathCastStringToNumber(const xmlChar * val) {
5883     return(xmlXPathStringEvalNumber(val));
5884 }
5885 
5886 /**
5887  * xmlXPathCastNodeToNumber:
5888  * @node:  a node
5889  *
5890  * Converts a node to its number value
5891  *
5892  * Returns the number value
5893  */
5894 double
xmlXPathCastNodeToNumber(xmlNodePtr node)5895 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5896     xmlChar *strval;
5897     double ret;
5898 
5899     if (node == NULL)
5900 	return(NAN);
5901     strval = xmlXPathCastNodeToString(node);
5902     if (strval == NULL)
5903 	return(NAN);
5904     ret = xmlXPathCastStringToNumber(strval);
5905     xmlFree(strval);
5906 
5907     return(ret);
5908 }
5909 
5910 /**
5911  * xmlXPathCastNodeSetToNumber:
5912  * @ns:  a node-set
5913  *
5914  * Converts a node-set to its number value
5915  *
5916  * Returns the number value
5917  */
5918 double
xmlXPathCastNodeSetToNumber(xmlNodeSetPtr ns)5919 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5920     xmlChar *str;
5921     double ret;
5922 
5923     if (ns == NULL)
5924 	return(NAN);
5925     str = xmlXPathCastNodeSetToString(ns);
5926     ret = xmlXPathCastStringToNumber(str);
5927     xmlFree(str);
5928     return(ret);
5929 }
5930 
5931 /**
5932  * xmlXPathCastToNumber:
5933  * @val:  an XPath object
5934  *
5935  * Converts an XPath object to its number value
5936  *
5937  * Returns the number value
5938  */
5939 double
xmlXPathCastToNumber(xmlXPathObjectPtr val)5940 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5941     double ret = 0.0;
5942 
5943     if (val == NULL)
5944 	return(NAN);
5945     switch (val->type) {
5946     case XPATH_UNDEFINED:
5947 #ifdef DEGUB_EXPR
5948 	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5949 #endif
5950 	ret = NAN;
5951 	break;
5952     case XPATH_NODESET:
5953     case XPATH_XSLT_TREE:
5954 	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5955 	break;
5956     case XPATH_STRING:
5957 	ret = xmlXPathCastStringToNumber(val->stringval);
5958 	break;
5959     case XPATH_NUMBER:
5960 	ret = val->floatval;
5961 	break;
5962     case XPATH_BOOLEAN:
5963 	ret = xmlXPathCastBooleanToNumber(val->boolval);
5964 	break;
5965     case XPATH_USERS:
5966     case XPATH_POINT:
5967     case XPATH_RANGE:
5968     case XPATH_LOCATIONSET:
5969 	TODO;
5970 	ret = NAN;
5971 	break;
5972     }
5973     return(ret);
5974 }
5975 
5976 /**
5977  * xmlXPathConvertNumber:
5978  * @val:  an XPath object
5979  *
5980  * Converts an existing object to its number() equivalent
5981  *
5982  * Returns the new object, the old one is freed (or the operation
5983  *         is done directly on @val)
5984  */
5985 xmlXPathObjectPtr
xmlXPathConvertNumber(xmlXPathObjectPtr val)5986 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5987     xmlXPathObjectPtr ret;
5988 
5989     if (val == NULL)
5990 	return(xmlXPathNewFloat(0.0));
5991     if (val->type == XPATH_NUMBER)
5992 	return(val);
5993     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5994     xmlXPathFreeObject(val);
5995     return(ret);
5996 }
5997 
5998 /**
5999  * xmlXPathCastNumberToBoolean:
6000  * @val:  a number
6001  *
6002  * Converts a number to its boolean value
6003  *
6004  * Returns the boolean value
6005  */
6006 int
xmlXPathCastNumberToBoolean(double val)6007 xmlXPathCastNumberToBoolean (double val) {
6008      if (xmlXPathIsNaN(val) || (val == 0.0))
6009 	 return(0);
6010      return(1);
6011 }
6012 
6013 /**
6014  * xmlXPathCastStringToBoolean:
6015  * @val:  a string
6016  *
6017  * Converts a string to its boolean value
6018  *
6019  * Returns the boolean value
6020  */
6021 int
xmlXPathCastStringToBoolean(const xmlChar * val)6022 xmlXPathCastStringToBoolean (const xmlChar *val) {
6023     if ((val == NULL) || (xmlStrlen(val) == 0))
6024 	return(0);
6025     return(1);
6026 }
6027 
6028 /**
6029  * xmlXPathCastNodeSetToBoolean:
6030  * @ns:  a node-set
6031  *
6032  * Converts a node-set to its boolean value
6033  *
6034  * Returns the boolean value
6035  */
6036 int
xmlXPathCastNodeSetToBoolean(xmlNodeSetPtr ns)6037 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6038     if ((ns == NULL) || (ns->nodeNr == 0))
6039 	return(0);
6040     return(1);
6041 }
6042 
6043 /**
6044  * xmlXPathCastToBoolean:
6045  * @val:  an XPath object
6046  *
6047  * Converts an XPath object to its boolean value
6048  *
6049  * Returns the boolean value
6050  */
6051 int
xmlXPathCastToBoolean(xmlXPathObjectPtr val)6052 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6053     int ret = 0;
6054 
6055     if (val == NULL)
6056 	return(0);
6057     switch (val->type) {
6058     case XPATH_UNDEFINED:
6059 #ifdef DEBUG_EXPR
6060 	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6061 #endif
6062 	ret = 0;
6063 	break;
6064     case XPATH_NODESET:
6065     case XPATH_XSLT_TREE:
6066 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6067 	break;
6068     case XPATH_STRING:
6069 	ret = xmlXPathCastStringToBoolean(val->stringval);
6070 	break;
6071     case XPATH_NUMBER:
6072 	ret = xmlXPathCastNumberToBoolean(val->floatval);
6073 	break;
6074     case XPATH_BOOLEAN:
6075 	ret = val->boolval;
6076 	break;
6077     case XPATH_USERS:
6078     case XPATH_POINT:
6079     case XPATH_RANGE:
6080     case XPATH_LOCATIONSET:
6081 	TODO;
6082 	ret = 0;
6083 	break;
6084     }
6085     return(ret);
6086 }
6087 
6088 
6089 /**
6090  * xmlXPathConvertBoolean:
6091  * @val:  an XPath object
6092  *
6093  * Converts an existing object to its boolean() equivalent
6094  *
6095  * Returns the new object, the old one is freed (or the operation
6096  *         is done directly on @val)
6097  */
6098 xmlXPathObjectPtr
xmlXPathConvertBoolean(xmlXPathObjectPtr val)6099 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6100     xmlXPathObjectPtr ret;
6101 
6102     if (val == NULL)
6103 	return(xmlXPathNewBoolean(0));
6104     if (val->type == XPATH_BOOLEAN)
6105 	return(val);
6106     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6107     xmlXPathFreeObject(val);
6108     return(ret);
6109 }
6110 
6111 /************************************************************************
6112  *									*
6113  *		Routines to handle XPath contexts			*
6114  *									*
6115  ************************************************************************/
6116 
6117 /**
6118  * xmlXPathNewContext:
6119  * @doc:  the XML document
6120  *
6121  * Create a new xmlXPathContext
6122  *
6123  * Returns the xmlXPathContext just allocated. The caller will need to free it.
6124  */
6125 xmlXPathContextPtr
xmlXPathNewContext(xmlDocPtr doc)6126 xmlXPathNewContext(xmlDocPtr doc) {
6127     xmlXPathContextPtr ret;
6128 
6129     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6130     if (ret == NULL) {
6131         xmlXPathErrMemory(NULL, "creating context\n");
6132 	return(NULL);
6133     }
6134     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6135     ret->doc = doc;
6136     ret->node = NULL;
6137 
6138     ret->varHash = NULL;
6139 
6140     ret->nb_types = 0;
6141     ret->max_types = 0;
6142     ret->types = NULL;
6143 
6144     ret->funcHash = xmlHashCreate(0);
6145 
6146     ret->nb_axis = 0;
6147     ret->max_axis = 0;
6148     ret->axis = NULL;
6149 
6150     ret->nsHash = NULL;
6151     ret->user = NULL;
6152 
6153     ret->contextSize = -1;
6154     ret->proximityPosition = -1;
6155 
6156 #ifdef XP_DEFAULT_CACHE_ON
6157     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6158 	xmlXPathFreeContext(ret);
6159 	return(NULL);
6160     }
6161 #endif
6162 
6163     xmlXPathRegisterAllFunctions(ret);
6164 
6165     return(ret);
6166 }
6167 
6168 /**
6169  * xmlXPathFreeContext:
6170  * @ctxt:  the context to free
6171  *
6172  * Free up an xmlXPathContext
6173  */
6174 void
xmlXPathFreeContext(xmlXPathContextPtr ctxt)6175 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6176     if (ctxt == NULL) return;
6177 
6178     if (ctxt->cache != NULL)
6179 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6180     xmlXPathRegisteredNsCleanup(ctxt);
6181     xmlXPathRegisteredFuncsCleanup(ctxt);
6182     xmlXPathRegisteredVariablesCleanup(ctxt);
6183     xmlResetError(&ctxt->lastError);
6184     xmlFree(ctxt);
6185 }
6186 
6187 /************************************************************************
6188  *									*
6189  *		Routines to handle XPath parser contexts		*
6190  *									*
6191  ************************************************************************/
6192 
6193 #define CHECK_CTXT(ctxt)						\
6194     if (ctxt == NULL) {						\
6195 	__xmlRaiseError(NULL, NULL, NULL,				\
6196 		NULL, NULL, XML_FROM_XPATH,				\
6197 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6198 		__FILE__, __LINE__,					\
6199 		NULL, NULL, NULL, 0, 0,					\
6200 		"NULL context pointer\n");				\
6201 	return(NULL);							\
6202     }									\
6203 
6204 #define CHECK_CTXT_NEG(ctxt)						\
6205     if (ctxt == NULL) {						\
6206 	__xmlRaiseError(NULL, NULL, NULL,				\
6207 		NULL, NULL, XML_FROM_XPATH,				\
6208 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6209 		__FILE__, __LINE__,					\
6210 		NULL, NULL, NULL, 0, 0,					\
6211 		"NULL context pointer\n");				\
6212 	return(-1);							\
6213     }									\
6214 
6215 
6216 #define CHECK_CONTEXT(ctxt)						\
6217     if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
6218         (ctxt->doc->children == NULL)) {				\
6219 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
6220 	return(NULL);							\
6221     }
6222 
6223 
6224 /**
6225  * xmlXPathNewParserContext:
6226  * @str:  the XPath expression
6227  * @ctxt:  the XPath context
6228  *
6229  * Create a new xmlXPathParserContext
6230  *
6231  * Returns the xmlXPathParserContext just allocated.
6232  */
6233 xmlXPathParserContextPtr
xmlXPathNewParserContext(const xmlChar * str,xmlXPathContextPtr ctxt)6234 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6235     xmlXPathParserContextPtr ret;
6236 
6237     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6238     if (ret == NULL) {
6239         xmlXPathErrMemory(ctxt, "creating parser context\n");
6240 	return(NULL);
6241     }
6242     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6243     ret->cur = ret->base = str;
6244     ret->context = ctxt;
6245 
6246     ret->comp = xmlXPathNewCompExpr();
6247     if (ret->comp == NULL) {
6248 	xmlFree(ret->valueTab);
6249 	xmlFree(ret);
6250 	return(NULL);
6251     }
6252     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6253         ret->comp->dict = ctxt->dict;
6254 	xmlDictReference(ret->comp->dict);
6255     }
6256 
6257     return(ret);
6258 }
6259 
6260 /**
6261  * xmlXPathCompParserContext:
6262  * @comp:  the XPath compiled expression
6263  * @ctxt:  the XPath context
6264  *
6265  * Create a new xmlXPathParserContext when processing a compiled expression
6266  *
6267  * Returns the xmlXPathParserContext just allocated.
6268  */
6269 static xmlXPathParserContextPtr
xmlXPathCompParserContext(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)6270 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6271     xmlXPathParserContextPtr ret;
6272 
6273     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6274     if (ret == NULL) {
6275         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6276 	return(NULL);
6277     }
6278     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6279 
6280     /* Allocate the value stack */
6281     ret->valueTab = (xmlXPathObjectPtr *)
6282                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6283     if (ret->valueTab == NULL) {
6284 	xmlFree(ret);
6285 	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6286 	return(NULL);
6287     }
6288     ret->valueNr = 0;
6289     ret->valueMax = 10;
6290     ret->value = NULL;
6291     ret->valueFrame = 0;
6292 
6293     ret->context = ctxt;
6294     ret->comp = comp;
6295 
6296     return(ret);
6297 }
6298 
6299 /**
6300  * xmlXPathFreeParserContext:
6301  * @ctxt:  the context to free
6302  *
6303  * Free up an xmlXPathParserContext
6304  */
6305 void
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt)6306 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6307     int i;
6308 
6309     if (ctxt->valueTab != NULL) {
6310         for (i = 0; i < ctxt->valueNr; i++) {
6311             if (ctxt->context)
6312                 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6313             else
6314                 xmlXPathFreeObject(ctxt->valueTab[i]);
6315         }
6316         xmlFree(ctxt->valueTab);
6317     }
6318     if (ctxt->comp != NULL) {
6319 #ifdef XPATH_STREAMING
6320 	if (ctxt->comp->stream != NULL) {
6321 	    xmlFreePatternList(ctxt->comp->stream);
6322 	    ctxt->comp->stream = NULL;
6323 	}
6324 #endif
6325 	xmlXPathFreeCompExpr(ctxt->comp);
6326     }
6327     xmlFree(ctxt);
6328 }
6329 
6330 /************************************************************************
6331  *									*
6332  *		The implicit core function library			*
6333  *									*
6334  ************************************************************************/
6335 
6336 /**
6337  * xmlXPathNodeValHash:
6338  * @node:  a node pointer
6339  *
6340  * Function computing the beginning of the string value of the node,
6341  * used to speed up comparisons
6342  *
6343  * Returns an int usable as a hash
6344  */
6345 static unsigned int
xmlXPathNodeValHash(xmlNodePtr node)6346 xmlXPathNodeValHash(xmlNodePtr node) {
6347     int len = 2;
6348     const xmlChar * string = NULL;
6349     xmlNodePtr tmp = NULL;
6350     unsigned int ret = 0;
6351 
6352     if (node == NULL)
6353 	return(0);
6354 
6355     if (node->type == XML_DOCUMENT_NODE) {
6356 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
6357 	if (tmp == NULL)
6358 	    node = node->children;
6359 	else
6360 	    node = tmp;
6361 
6362 	if (node == NULL)
6363 	    return(0);
6364     }
6365 
6366     switch (node->type) {
6367 	case XML_COMMENT_NODE:
6368 	case XML_PI_NODE:
6369 	case XML_CDATA_SECTION_NODE:
6370 	case XML_TEXT_NODE:
6371 	    string = node->content;
6372 	    if (string == NULL)
6373 		return(0);
6374 	    if (string[0] == 0)
6375 		return(0);
6376 	    return(((unsigned int) string[0]) +
6377 		   (((unsigned int) string[1]) << 8));
6378 	case XML_NAMESPACE_DECL:
6379 	    string = ((xmlNsPtr)node)->href;
6380 	    if (string == NULL)
6381 		return(0);
6382 	    if (string[0] == 0)
6383 		return(0);
6384 	    return(((unsigned int) string[0]) +
6385 		   (((unsigned int) string[1]) << 8));
6386 	case XML_ATTRIBUTE_NODE:
6387 	    tmp = ((xmlAttrPtr) node)->children;
6388 	    break;
6389 	case XML_ELEMENT_NODE:
6390 	    tmp = node->children;
6391 	    break;
6392 	default:
6393 	    return(0);
6394     }
6395     while (tmp != NULL) {
6396 	switch (tmp->type) {
6397 	    case XML_CDATA_SECTION_NODE:
6398 	    case XML_TEXT_NODE:
6399 		string = tmp->content;
6400 		break;
6401 	    default:
6402                 string = NULL;
6403 		break;
6404 	}
6405 	if ((string != NULL) && (string[0] != 0)) {
6406 	    if (len == 1) {
6407 		return(ret + (((unsigned int) string[0]) << 8));
6408 	    }
6409 	    if (string[1] == 0) {
6410 		len = 1;
6411 		ret = (unsigned int) string[0];
6412 	    } else {
6413 		return(((unsigned int) string[0]) +
6414 		       (((unsigned int) string[1]) << 8));
6415 	    }
6416 	}
6417 	/*
6418 	 * Skip to next node
6419 	 */
6420 	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6421 	    if (tmp->children->type != XML_ENTITY_DECL) {
6422 		tmp = tmp->children;
6423 		continue;
6424 	    }
6425 	}
6426 	if (tmp == node)
6427 	    break;
6428 
6429 	if (tmp->next != NULL) {
6430 	    tmp = tmp->next;
6431 	    continue;
6432 	}
6433 
6434 	do {
6435 	    tmp = tmp->parent;
6436 	    if (tmp == NULL)
6437 		break;
6438 	    if (tmp == node) {
6439 		tmp = NULL;
6440 		break;
6441 	    }
6442 	    if (tmp->next != NULL) {
6443 		tmp = tmp->next;
6444 		break;
6445 	    }
6446 	} while (tmp != NULL);
6447     }
6448     return(ret);
6449 }
6450 
6451 /**
6452  * xmlXPathStringHash:
6453  * @string:  a string
6454  *
6455  * Function computing the beginning of the string value of the node,
6456  * used to speed up comparisons
6457  *
6458  * Returns an int usable as a hash
6459  */
6460 static unsigned int
xmlXPathStringHash(const xmlChar * string)6461 xmlXPathStringHash(const xmlChar * string) {
6462     if (string == NULL)
6463 	return((unsigned int) 0);
6464     if (string[0] == 0)
6465 	return(0);
6466     return(((unsigned int) string[0]) +
6467 	   (((unsigned int) string[1]) << 8));
6468 }
6469 
6470 /**
6471  * xmlXPathCompareNodeSetFloat:
6472  * @ctxt:  the XPath Parser context
6473  * @inf:  less than (1) or greater than (0)
6474  * @strict:  is the comparison strict
6475  * @arg:  the node set
6476  * @f:  the value
6477  *
6478  * Implement the compare operation between a nodeset and a number
6479  *     @ns < @val    (1, 1, ...
6480  *     @ns <= @val   (1, 0, ...
6481  *     @ns > @val    (0, 1, ...
6482  *     @ns >= @val   (0, 0, ...
6483  *
6484  * If one object to be compared is a node-set and the other is a number,
6485  * then the comparison will be true if and only if there is a node in the
6486  * node-set such that the result of performing the comparison on the number
6487  * to be compared and on the result of converting the string-value of that
6488  * node to a number using the number function is true.
6489  *
6490  * Returns 0 or 1 depending on the results of the test.
6491  */
6492 static int
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr f)6493 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6494 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6495     int i, ret = 0;
6496     xmlNodeSetPtr ns;
6497     xmlChar *str2;
6498 
6499     if ((f == NULL) || (arg == NULL) ||
6500 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6501 	xmlXPathReleaseObject(ctxt->context, arg);
6502 	xmlXPathReleaseObject(ctxt->context, f);
6503         return(0);
6504     }
6505     ns = arg->nodesetval;
6506     if (ns != NULL) {
6507 	for (i = 0;i < ns->nodeNr;i++) {
6508 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6509 	     if (str2 != NULL) {
6510 		 valuePush(ctxt,
6511 			   xmlXPathCacheNewString(ctxt->context, str2));
6512 		 xmlFree(str2);
6513 		 xmlXPathNumberFunction(ctxt, 1);
6514 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6515 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6516 		 if (ret)
6517 		     break;
6518 	     }
6519 	}
6520     }
6521     xmlXPathReleaseObject(ctxt->context, arg);
6522     xmlXPathReleaseObject(ctxt->context, f);
6523     return(ret);
6524 }
6525 
6526 /**
6527  * xmlXPathCompareNodeSetString:
6528  * @ctxt:  the XPath Parser context
6529  * @inf:  less than (1) or greater than (0)
6530  * @strict:  is the comparison strict
6531  * @arg:  the node set
6532  * @s:  the value
6533  *
6534  * Implement the compare operation between a nodeset and a string
6535  *     @ns < @val    (1, 1, ...
6536  *     @ns <= @val   (1, 0, ...
6537  *     @ns > @val    (0, 1, ...
6538  *     @ns >= @val   (0, 0, ...
6539  *
6540  * If one object to be compared is a node-set and the other is a string,
6541  * then the comparison will be true if and only if there is a node in
6542  * the node-set such that the result of performing the comparison on the
6543  * string-value of the node and the other string is true.
6544  *
6545  * Returns 0 or 1 depending on the results of the test.
6546  */
6547 static int
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr s)6548 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6549 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6550     int i, ret = 0;
6551     xmlNodeSetPtr ns;
6552     xmlChar *str2;
6553 
6554     if ((s == NULL) || (arg == NULL) ||
6555 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6556 	xmlXPathReleaseObject(ctxt->context, arg);
6557 	xmlXPathReleaseObject(ctxt->context, s);
6558         return(0);
6559     }
6560     ns = arg->nodesetval;
6561     if (ns != NULL) {
6562 	for (i = 0;i < ns->nodeNr;i++) {
6563 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6564 	     if (str2 != NULL) {
6565 		 valuePush(ctxt,
6566 			   xmlXPathCacheNewString(ctxt->context, str2));
6567 		 xmlFree(str2);
6568 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6569 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6570 		 if (ret)
6571 		     break;
6572 	     }
6573 	}
6574     }
6575     xmlXPathReleaseObject(ctxt->context, arg);
6576     xmlXPathReleaseObject(ctxt->context, s);
6577     return(ret);
6578 }
6579 
6580 /**
6581  * xmlXPathCompareNodeSets:
6582  * @inf:  less than (1) or greater than (0)
6583  * @strict:  is the comparison strict
6584  * @arg1:  the first node set object
6585  * @arg2:  the second node set object
6586  *
6587  * Implement the compare operation on nodesets:
6588  *
6589  * If both objects to be compared are node-sets, then the comparison
6590  * will be true if and only if there is a node in the first node-set
6591  * and a node in the second node-set such that the result of performing
6592  * the comparison on the string-values of the two nodes is true.
6593  * ....
6594  * When neither object to be compared is a node-set and the operator
6595  * is <=, <, >= or >, then the objects are compared by converting both
6596  * objects to numbers and comparing the numbers according to IEEE 754.
6597  * ....
6598  * The number function converts its argument to a number as follows:
6599  *  - a string that consists of optional whitespace followed by an
6600  *    optional minus sign followed by a Number followed by whitespace
6601  *    is converted to the IEEE 754 number that is nearest (according
6602  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6603  *    represented by the string; any other string is converted to NaN
6604  *
6605  * Conclusion all nodes need to be converted first to their string value
6606  * and then the comparison must be done when possible
6607  */
6608 static int
xmlXPathCompareNodeSets(int inf,int strict,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6609 xmlXPathCompareNodeSets(int inf, int strict,
6610 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6611     int i, j, init = 0;
6612     double val1;
6613     double *values2;
6614     int ret = 0;
6615     xmlNodeSetPtr ns1;
6616     xmlNodeSetPtr ns2;
6617 
6618     if ((arg1 == NULL) ||
6619 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6620 	xmlXPathFreeObject(arg2);
6621         return(0);
6622     }
6623     if ((arg2 == NULL) ||
6624 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6625 	xmlXPathFreeObject(arg1);
6626 	xmlXPathFreeObject(arg2);
6627         return(0);
6628     }
6629 
6630     ns1 = arg1->nodesetval;
6631     ns2 = arg2->nodesetval;
6632 
6633     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6634 	xmlXPathFreeObject(arg1);
6635 	xmlXPathFreeObject(arg2);
6636 	return(0);
6637     }
6638     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6639 	xmlXPathFreeObject(arg1);
6640 	xmlXPathFreeObject(arg2);
6641 	return(0);
6642     }
6643 
6644     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6645     if (values2 == NULL) {
6646         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6647 	xmlXPathFreeObject(arg1);
6648 	xmlXPathFreeObject(arg2);
6649 	return(0);
6650     }
6651     for (i = 0;i < ns1->nodeNr;i++) {
6652 	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6653 	if (xmlXPathIsNaN(val1))
6654 	    continue;
6655 	for (j = 0;j < ns2->nodeNr;j++) {
6656 	    if (init == 0) {
6657 		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6658 	    }
6659 	    if (xmlXPathIsNaN(values2[j]))
6660 		continue;
6661 	    if (inf && strict)
6662 		ret = (val1 < values2[j]);
6663 	    else if (inf && !strict)
6664 		ret = (val1 <= values2[j]);
6665 	    else if (!inf && strict)
6666 		ret = (val1 > values2[j]);
6667 	    else if (!inf && !strict)
6668 		ret = (val1 >= values2[j]);
6669 	    if (ret)
6670 		break;
6671 	}
6672 	if (ret)
6673 	    break;
6674 	init = 1;
6675     }
6676     xmlFree(values2);
6677     xmlXPathFreeObject(arg1);
6678     xmlXPathFreeObject(arg2);
6679     return(ret);
6680 }
6681 
6682 /**
6683  * xmlXPathCompareNodeSetValue:
6684  * @ctxt:  the XPath Parser context
6685  * @inf:  less than (1) or greater than (0)
6686  * @strict:  is the comparison strict
6687  * @arg:  the node set
6688  * @val:  the value
6689  *
6690  * Implement the compare operation between a nodeset and a value
6691  *     @ns < @val    (1, 1, ...
6692  *     @ns <= @val   (1, 0, ...
6693  *     @ns > @val    (0, 1, ...
6694  *     @ns >= @val   (0, 0, ...
6695  *
6696  * If one object to be compared is a node-set and the other is a boolean,
6697  * then the comparison will be true if and only if the result of performing
6698  * the comparison on the boolean and on the result of converting
6699  * the node-set to a boolean using the boolean function is true.
6700  *
6701  * Returns 0 or 1 depending on the results of the test.
6702  */
6703 static int
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr val)6704 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6705 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6706     if ((val == NULL) || (arg == NULL) ||
6707 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6708         return(0);
6709 
6710     switch(val->type) {
6711         case XPATH_NUMBER:
6712 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6713         case XPATH_NODESET:
6714         case XPATH_XSLT_TREE:
6715 	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6716         case XPATH_STRING:
6717 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6718         case XPATH_BOOLEAN:
6719 	    valuePush(ctxt, arg);
6720 	    xmlXPathBooleanFunction(ctxt, 1);
6721 	    valuePush(ctxt, val);
6722 	    return(xmlXPathCompareValues(ctxt, inf, strict));
6723 	default:
6724             xmlGenericError(xmlGenericErrorContext,
6725                     "xmlXPathCompareNodeSetValue: Can't compare node set "
6726                     "and object of type %d\n",
6727                     val->type);
6728             xmlXPathReleaseObject(ctxt->context, arg);
6729             xmlXPathReleaseObject(ctxt->context, val);
6730             XP_ERROR0(XPATH_INVALID_TYPE);
6731     }
6732     return(0);
6733 }
6734 
6735 /**
6736  * xmlXPathEqualNodeSetString:
6737  * @arg:  the nodeset object argument
6738  * @str:  the string to compare to.
6739  * @neq:  flag to show whether for '=' (0) or '!=' (1)
6740  *
6741  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6742  * If one object to be compared is a node-set and the other is a string,
6743  * then the comparison will be true if and only if there is a node in
6744  * the node-set such that the result of performing the comparison on the
6745  * string-value of the node and the other string is true.
6746  *
6747  * Returns 0 or 1 depending on the results of the test.
6748  */
6749 static int
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg,const xmlChar * str,int neq)6750 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6751 {
6752     int i;
6753     xmlNodeSetPtr ns;
6754     xmlChar *str2;
6755     unsigned int hash;
6756 
6757     if ((str == NULL) || (arg == NULL) ||
6758         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6759         return (0);
6760     ns = arg->nodesetval;
6761     /*
6762      * A NULL nodeset compared with a string is always false
6763      * (since there is no node equal, and no node not equal)
6764      */
6765     if ((ns == NULL) || (ns->nodeNr <= 0) )
6766         return (0);
6767     hash = xmlXPathStringHash(str);
6768     for (i = 0; i < ns->nodeNr; i++) {
6769         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6770             str2 = xmlNodeGetContent(ns->nodeTab[i]);
6771             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6772                 xmlFree(str2);
6773 		if (neq)
6774 		    continue;
6775                 return (1);
6776 	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6777 		if (neq)
6778 		    continue;
6779                 return (1);
6780             } else if (neq) {
6781 		if (str2 != NULL)
6782 		    xmlFree(str2);
6783 		return (1);
6784 	    }
6785             if (str2 != NULL)
6786                 xmlFree(str2);
6787         } else if (neq)
6788 	    return (1);
6789     }
6790     return (0);
6791 }
6792 
6793 /**
6794  * xmlXPathEqualNodeSetFloat:
6795  * @arg:  the nodeset object argument
6796  * @f:  the float to compare to
6797  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6798  *
6799  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6800  * If one object to be compared is a node-set and the other is a number,
6801  * then the comparison will be true if and only if there is a node in
6802  * the node-set such that the result of performing the comparison on the
6803  * number to be compared and on the result of converting the string-value
6804  * of that node to a number using the number function is true.
6805  *
6806  * Returns 0 or 1 depending on the results of the test.
6807  */
6808 static int
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,double f,int neq)6809 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6810     xmlXPathObjectPtr arg, double f, int neq) {
6811   int i, ret=0;
6812   xmlNodeSetPtr ns;
6813   xmlChar *str2;
6814   xmlXPathObjectPtr val;
6815   double v;
6816 
6817     if ((arg == NULL) ||
6818 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6819         return(0);
6820 
6821     ns = arg->nodesetval;
6822     if (ns != NULL) {
6823 	for (i=0;i<ns->nodeNr;i++) {
6824 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6825 	    if (str2 != NULL) {
6826 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6827 		xmlFree(str2);
6828 		xmlXPathNumberFunction(ctxt, 1);
6829 		val = valuePop(ctxt);
6830 		v = val->floatval;
6831 		xmlXPathReleaseObject(ctxt->context, val);
6832 		if (!xmlXPathIsNaN(v)) {
6833 		    if ((!neq) && (v==f)) {
6834 			ret = 1;
6835 			break;
6836 		    } else if ((neq) && (v!=f)) {
6837 			ret = 1;
6838 			break;
6839 		    }
6840 		} else {	/* NaN is unequal to any value */
6841 		    if (neq)
6842 			ret = 1;
6843 		}
6844 	    }
6845 	}
6846     }
6847 
6848     return(ret);
6849 }
6850 
6851 
6852 /**
6853  * xmlXPathEqualNodeSets:
6854  * @arg1:  first nodeset object argument
6855  * @arg2:  second nodeset object argument
6856  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6857  *
6858  * Implement the equal / not equal operation on XPath nodesets:
6859  * @arg1 == @arg2  or  @arg1 != @arg2
6860  * If both objects to be compared are node-sets, then the comparison
6861  * will be true if and only if there is a node in the first node-set and
6862  * a node in the second node-set such that the result of performing the
6863  * comparison on the string-values of the two nodes is true.
6864  *
6865  * (needless to say, this is a costly operation)
6866  *
6867  * Returns 0 or 1 depending on the results of the test.
6868  */
6869 static int
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2,int neq)6870 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6871     int i, j;
6872     unsigned int *hashs1;
6873     unsigned int *hashs2;
6874     xmlChar **values1;
6875     xmlChar **values2;
6876     int ret = 0;
6877     xmlNodeSetPtr ns1;
6878     xmlNodeSetPtr ns2;
6879 
6880     if ((arg1 == NULL) ||
6881 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6882         return(0);
6883     if ((arg2 == NULL) ||
6884 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6885         return(0);
6886 
6887     ns1 = arg1->nodesetval;
6888     ns2 = arg2->nodesetval;
6889 
6890     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6891 	return(0);
6892     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6893 	return(0);
6894 
6895     /*
6896      * for equal, check if there is a node pertaining to both sets
6897      */
6898     if (neq == 0)
6899 	for (i = 0;i < ns1->nodeNr;i++)
6900 	    for (j = 0;j < ns2->nodeNr;j++)
6901 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
6902 		    return(1);
6903 
6904     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6905     if (values1 == NULL) {
6906         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6907 	return(0);
6908     }
6909     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6910     if (hashs1 == NULL) {
6911         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6912 	xmlFree(values1);
6913 	return(0);
6914     }
6915     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6916     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6917     if (values2 == NULL) {
6918         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6919 	xmlFree(hashs1);
6920 	xmlFree(values1);
6921 	return(0);
6922     }
6923     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6924     if (hashs2 == NULL) {
6925         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6926 	xmlFree(hashs1);
6927 	xmlFree(values1);
6928 	xmlFree(values2);
6929 	return(0);
6930     }
6931     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6932     for (i = 0;i < ns1->nodeNr;i++) {
6933 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6934 	for (j = 0;j < ns2->nodeNr;j++) {
6935 	    if (i == 0)
6936 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6937 	    if (hashs1[i] != hashs2[j]) {
6938 		if (neq) {
6939 		    ret = 1;
6940 		    break;
6941 		}
6942 	    }
6943 	    else {
6944 		if (values1[i] == NULL)
6945 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6946 		if (values2[j] == NULL)
6947 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6948 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6949 		if (ret)
6950 		    break;
6951 	    }
6952 	}
6953 	if (ret)
6954 	    break;
6955     }
6956     for (i = 0;i < ns1->nodeNr;i++)
6957 	if (values1[i] != NULL)
6958 	    xmlFree(values1[i]);
6959     for (j = 0;j < ns2->nodeNr;j++)
6960 	if (values2[j] != NULL)
6961 	    xmlFree(values2[j]);
6962     xmlFree(values1);
6963     xmlFree(values2);
6964     xmlFree(hashs1);
6965     xmlFree(hashs2);
6966     return(ret);
6967 }
6968 
6969 static int
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6970 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6971   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6972     int ret = 0;
6973     /*
6974      *At this point we are assured neither arg1 nor arg2
6975      *is a nodeset, so we can just pick the appropriate routine.
6976      */
6977     switch (arg1->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 	    switch (arg2->type) {
6986 	        case XPATH_UNDEFINED:
6987 #ifdef DEBUG_EXPR
6988 		    xmlGenericError(xmlGenericErrorContext,
6989 			    "Equal: undefined\n");
6990 #endif
6991 		    break;
6992 		case XPATH_BOOLEAN:
6993 #ifdef DEBUG_EXPR
6994 		    xmlGenericError(xmlGenericErrorContext,
6995 			    "Equal: %d boolean %d \n",
6996 			    arg1->boolval, arg2->boolval);
6997 #endif
6998 		    ret = (arg1->boolval == arg2->boolval);
6999 		    break;
7000 		case XPATH_NUMBER:
7001 		    ret = (arg1->boolval ==
7002 			   xmlXPathCastNumberToBoolean(arg2->floatval));
7003 		    break;
7004 		case XPATH_STRING:
7005 		    if ((arg2->stringval == NULL) ||
7006 			(arg2->stringval[0] == 0)) ret = 0;
7007 		    else
7008 			ret = 1;
7009 		    ret = (arg1->boolval == ret);
7010 		    break;
7011 		case XPATH_USERS:
7012 		case XPATH_POINT:
7013 		case XPATH_RANGE:
7014 		case XPATH_LOCATIONSET:
7015 		    TODO
7016 		    break;
7017 		case XPATH_NODESET:
7018 		case XPATH_XSLT_TREE:
7019 		    break;
7020 	    }
7021 	    break;
7022         case XPATH_NUMBER:
7023 	    switch (arg2->type) {
7024 	        case XPATH_UNDEFINED:
7025 #ifdef DEBUG_EXPR
7026 		    xmlGenericError(xmlGenericErrorContext,
7027 			    "Equal: undefined\n");
7028 #endif
7029 		    break;
7030 		case XPATH_BOOLEAN:
7031 		    ret = (arg2->boolval==
7032 			   xmlXPathCastNumberToBoolean(arg1->floatval));
7033 		    break;
7034 		case XPATH_STRING:
7035 		    valuePush(ctxt, arg2);
7036 		    xmlXPathNumberFunction(ctxt, 1);
7037 		    arg2 = valuePop(ctxt);
7038                     /* Falls through. */
7039 		case XPATH_NUMBER:
7040 		    /* Hand check NaN and Infinity equalities */
7041 		    if (xmlXPathIsNaN(arg1->floatval) ||
7042 			    xmlXPathIsNaN(arg2->floatval)) {
7043 		        ret = 0;
7044 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7045 		        if (xmlXPathIsInf(arg2->floatval) == 1)
7046 			    ret = 1;
7047 			else
7048 			    ret = 0;
7049 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7050 			if (xmlXPathIsInf(arg2->floatval) == -1)
7051 			    ret = 1;
7052 			else
7053 			    ret = 0;
7054 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7055 			if (xmlXPathIsInf(arg1->floatval) == 1)
7056 			    ret = 1;
7057 			else
7058 			    ret = 0;
7059 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7060 			if (xmlXPathIsInf(arg1->floatval) == -1)
7061 			    ret = 1;
7062 			else
7063 			    ret = 0;
7064 		    } else {
7065 		        ret = (arg1->floatval == arg2->floatval);
7066 		    }
7067 		    break;
7068 		case XPATH_USERS:
7069 		case XPATH_POINT:
7070 		case XPATH_RANGE:
7071 		case XPATH_LOCATIONSET:
7072 		    TODO
7073 		    break;
7074 		case XPATH_NODESET:
7075 		case XPATH_XSLT_TREE:
7076 		    break;
7077 	    }
7078 	    break;
7079         case XPATH_STRING:
7080 	    switch (arg2->type) {
7081 	        case XPATH_UNDEFINED:
7082 #ifdef DEBUG_EXPR
7083 		    xmlGenericError(xmlGenericErrorContext,
7084 			    "Equal: undefined\n");
7085 #endif
7086 		    break;
7087 		case XPATH_BOOLEAN:
7088 		    if ((arg1->stringval == NULL) ||
7089 			(arg1->stringval[0] == 0)) ret = 0;
7090 		    else
7091 			ret = 1;
7092 		    ret = (arg2->boolval == ret);
7093 		    break;
7094 		case XPATH_STRING:
7095 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7096 		    break;
7097 		case XPATH_NUMBER:
7098 		    valuePush(ctxt, arg1);
7099 		    xmlXPathNumberFunction(ctxt, 1);
7100 		    arg1 = valuePop(ctxt);
7101 		    /* Hand check NaN and Infinity equalities */
7102 		    if (xmlXPathIsNaN(arg1->floatval) ||
7103 			    xmlXPathIsNaN(arg2->floatval)) {
7104 		        ret = 0;
7105 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7106 			if (xmlXPathIsInf(arg2->floatval) == 1)
7107 			    ret = 1;
7108 			else
7109 			    ret = 0;
7110 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7111 			if (xmlXPathIsInf(arg2->floatval) == -1)
7112 			    ret = 1;
7113 			else
7114 			    ret = 0;
7115 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7116 			if (xmlXPathIsInf(arg1->floatval) == 1)
7117 			    ret = 1;
7118 			else
7119 			    ret = 0;
7120 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7121 			if (xmlXPathIsInf(arg1->floatval) == -1)
7122 			    ret = 1;
7123 			else
7124 			    ret = 0;
7125 		    } else {
7126 		        ret = (arg1->floatval == arg2->floatval);
7127 		    }
7128 		    break;
7129 		case XPATH_USERS:
7130 		case XPATH_POINT:
7131 		case XPATH_RANGE:
7132 		case XPATH_LOCATIONSET:
7133 		    TODO
7134 		    break;
7135 		case XPATH_NODESET:
7136 		case XPATH_XSLT_TREE:
7137 		    break;
7138 	    }
7139 	    break;
7140         case XPATH_USERS:
7141 	case XPATH_POINT:
7142 	case XPATH_RANGE:
7143 	case XPATH_LOCATIONSET:
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 	    case XPATH_POINT:
7227 	    case XPATH_RANGE:
7228 	    case XPATH_LOCATIONSET:
7229 		TODO
7230 		break;
7231 	}
7232 	xmlXPathReleaseObject(ctxt->context, arg1);
7233 	xmlXPathReleaseObject(ctxt->context, arg2);
7234 	return(ret);
7235     }
7236 
7237     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7238 }
7239 
7240 /**
7241  * xmlXPathNotEqualValues:
7242  * @ctxt:  the XPath Parser context
7243  *
7244  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7245  *
7246  * Returns 0 or 1 depending on the results of the test.
7247  */
7248 int
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt)7249 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7250     xmlXPathObjectPtr arg1, arg2, argtmp;
7251     int ret = 0;
7252 
7253     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7254     arg2 = valuePop(ctxt);
7255     arg1 = valuePop(ctxt);
7256     if ((arg1 == NULL) || (arg2 == NULL)) {
7257 	if (arg1 != NULL)
7258 	    xmlXPathReleaseObject(ctxt->context, arg1);
7259 	else
7260 	    xmlXPathReleaseObject(ctxt->context, arg2);
7261 	XP_ERROR0(XPATH_INVALID_OPERAND);
7262     }
7263 
7264     if (arg1 == arg2) {
7265 #ifdef DEBUG_EXPR
7266         xmlGenericError(xmlGenericErrorContext,
7267 		"NotEqual: by pointer\n");
7268 #endif
7269 	xmlXPathReleaseObject(ctxt->context, arg1);
7270         return(0);
7271     }
7272 
7273     /*
7274      *If either argument is a nodeset, it's a 'special case'
7275      */
7276     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7277       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7278 	/*
7279 	 *Hack it to assure arg1 is the nodeset
7280 	 */
7281 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7282 		argtmp = arg2;
7283 		arg2 = arg1;
7284 		arg1 = argtmp;
7285 	}
7286 	switch (arg2->type) {
7287 	    case XPATH_UNDEFINED:
7288 #ifdef DEBUG_EXPR
7289 		xmlGenericError(xmlGenericErrorContext,
7290 			"NotEqual: undefined\n");
7291 #endif
7292 		break;
7293 	    case XPATH_NODESET:
7294 	    case XPATH_XSLT_TREE:
7295 		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7296 		break;
7297 	    case XPATH_BOOLEAN:
7298 		if ((arg1->nodesetval == NULL) ||
7299 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7300 		else
7301 		    ret = 1;
7302 		ret = (ret != arg2->boolval);
7303 		break;
7304 	    case XPATH_NUMBER:
7305 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7306 		break;
7307 	    case XPATH_STRING:
7308 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7309 		break;
7310 	    case XPATH_USERS:
7311 	    case XPATH_POINT:
7312 	    case XPATH_RANGE:
7313 	    case XPATH_LOCATIONSET:
7314 		TODO
7315 		break;
7316 	}
7317 	xmlXPathReleaseObject(ctxt->context, arg1);
7318 	xmlXPathReleaseObject(ctxt->context, arg2);
7319 	return(ret);
7320     }
7321 
7322     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7323 }
7324 
7325 /**
7326  * xmlXPathCompareValues:
7327  * @ctxt:  the XPath Parser context
7328  * @inf:  less than (1) or greater than (0)
7329  * @strict:  is the comparison strict
7330  *
7331  * Implement the compare operation on XPath objects:
7332  *     @arg1 < @arg2    (1, 1, ...
7333  *     @arg1 <= @arg2   (1, 0, ...
7334  *     @arg1 > @arg2    (0, 1, ...
7335  *     @arg1 >= @arg2   (0, 0, ...
7336  *
7337  * When neither object to be compared is a node-set and the operator is
7338  * <=, <, >=, >, then the objects are compared by converted both objects
7339  * to numbers and comparing the numbers according to IEEE 754. The <
7340  * comparison will be true if and only if the first number is less than the
7341  * second number. The <= comparison will be true if and only if the first
7342  * number is less than or equal to the second number. The > comparison
7343  * will be true if and only if the first number is greater than the second
7344  * number. The >= comparison will be true if and only if the first number
7345  * is greater than or equal to the second number.
7346  *
7347  * Returns 1 if the comparison succeeded, 0 if it failed
7348  */
7349 int
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt,int inf,int strict)7350 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7351     int ret = 0, arg1i = 0, arg2i = 0;
7352     xmlXPathObjectPtr arg1, arg2;
7353 
7354     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7355     arg2 = valuePop(ctxt);
7356     arg1 = valuePop(ctxt);
7357     if ((arg1 == NULL) || (arg2 == NULL)) {
7358 	if (arg1 != NULL)
7359 	    xmlXPathReleaseObject(ctxt->context, arg1);
7360 	else
7361 	    xmlXPathReleaseObject(ctxt->context, arg2);
7362 	XP_ERROR0(XPATH_INVALID_OPERAND);
7363     }
7364 
7365     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7366       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7367 	/*
7368 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7369 	 * are not freed from within this routine; they will be freed from the
7370 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7371 	 */
7372 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7373 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7374 	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7375 	} else {
7376 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7377 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7378 			                          arg1, arg2);
7379 	    } else {
7380 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7381 			                          arg2, arg1);
7382 	    }
7383 	}
7384 	return(ret);
7385     }
7386 
7387     if (arg1->type != XPATH_NUMBER) {
7388 	valuePush(ctxt, arg1);
7389 	xmlXPathNumberFunction(ctxt, 1);
7390 	arg1 = valuePop(ctxt);
7391     }
7392     if (arg1->type != XPATH_NUMBER) {
7393 	xmlXPathFreeObject(arg1);
7394 	xmlXPathFreeObject(arg2);
7395 	XP_ERROR0(XPATH_INVALID_OPERAND);
7396     }
7397     if (arg2->type != XPATH_NUMBER) {
7398 	valuePush(ctxt, arg2);
7399 	xmlXPathNumberFunction(ctxt, 1);
7400 	arg2 = valuePop(ctxt);
7401     }
7402     if (arg2->type != XPATH_NUMBER) {
7403 	xmlXPathReleaseObject(ctxt->context, arg1);
7404 	xmlXPathReleaseObject(ctxt->context, arg2);
7405 	XP_ERROR0(XPATH_INVALID_OPERAND);
7406     }
7407     /*
7408      * Add tests for infinity and nan
7409      * => feedback on 3.4 for Inf and NaN
7410      */
7411     /* Hand check NaN and Infinity comparisons */
7412     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7413 	ret=0;
7414     } else {
7415 	arg1i=xmlXPathIsInf(arg1->floatval);
7416 	arg2i=xmlXPathIsInf(arg2->floatval);
7417 	if (inf && strict) {
7418 	    if ((arg1i == -1 && arg2i != -1) ||
7419 		(arg2i == 1 && arg1i != 1)) {
7420 		ret = 1;
7421 	    } else if (arg1i == 0 && arg2i == 0) {
7422 		ret = (arg1->floatval < arg2->floatval);
7423 	    } else {
7424 		ret = 0;
7425 	    }
7426 	}
7427 	else if (inf && !strict) {
7428 	    if (arg1i == -1 || arg2i == 1) {
7429 		ret = 1;
7430 	    } else if (arg1i == 0 && arg2i == 0) {
7431 		ret = (arg1->floatval <= arg2->floatval);
7432 	    } else {
7433 		ret = 0;
7434 	    }
7435 	}
7436 	else if (!inf && strict) {
7437 	    if ((arg1i == 1 && arg2i != 1) ||
7438 		(arg2i == -1 && arg1i != -1)) {
7439 		ret = 1;
7440 	    } else if (arg1i == 0 && arg2i == 0) {
7441 		ret = (arg1->floatval > arg2->floatval);
7442 	    } else {
7443 		ret = 0;
7444 	    }
7445 	}
7446 	else if (!inf && !strict) {
7447 	    if (arg1i == 1 || arg2i == -1) {
7448 		ret = 1;
7449 	    } else if (arg1i == 0 && arg2i == 0) {
7450 		ret = (arg1->floatval >= arg2->floatval);
7451 	    } else {
7452 		ret = 0;
7453 	    }
7454 	}
7455     }
7456     xmlXPathReleaseObject(ctxt->context, arg1);
7457     xmlXPathReleaseObject(ctxt->context, arg2);
7458     return(ret);
7459 }
7460 
7461 /**
7462  * xmlXPathValueFlipSign:
7463  * @ctxt:  the XPath Parser context
7464  *
7465  * Implement the unary - operation on an XPath object
7466  * The numeric operators convert their operands to numbers as if
7467  * by calling the number function.
7468  */
7469 void
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt)7470 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7471     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7472     CAST_TO_NUMBER;
7473     CHECK_TYPE(XPATH_NUMBER);
7474     ctxt->value->floatval = -ctxt->value->floatval;
7475 }
7476 
7477 /**
7478  * xmlXPathAddValues:
7479  * @ctxt:  the XPath Parser context
7480  *
7481  * Implement the add operation on XPath objects:
7482  * The numeric operators convert their operands to numbers as if
7483  * by calling the number function.
7484  */
7485 void
xmlXPathAddValues(xmlXPathParserContextPtr ctxt)7486 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7487     xmlXPathObjectPtr arg;
7488     double val;
7489 
7490     arg = valuePop(ctxt);
7491     if (arg == NULL)
7492 	XP_ERROR(XPATH_INVALID_OPERAND);
7493     val = xmlXPathCastToNumber(arg);
7494     xmlXPathReleaseObject(ctxt->context, arg);
7495     CAST_TO_NUMBER;
7496     CHECK_TYPE(XPATH_NUMBER);
7497     ctxt->value->floatval += val;
7498 }
7499 
7500 /**
7501  * xmlXPathSubValues:
7502  * @ctxt:  the XPath Parser context
7503  *
7504  * Implement the subtraction operation on XPath objects:
7505  * The numeric operators convert their operands to numbers as if
7506  * by calling the number function.
7507  */
7508 void
xmlXPathSubValues(xmlXPathParserContextPtr ctxt)7509 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7510     xmlXPathObjectPtr arg;
7511     double val;
7512 
7513     arg = valuePop(ctxt);
7514     if (arg == NULL)
7515 	XP_ERROR(XPATH_INVALID_OPERAND);
7516     val = xmlXPathCastToNumber(arg);
7517     xmlXPathReleaseObject(ctxt->context, arg);
7518     CAST_TO_NUMBER;
7519     CHECK_TYPE(XPATH_NUMBER);
7520     ctxt->value->floatval -= val;
7521 }
7522 
7523 /**
7524  * xmlXPathMultValues:
7525  * @ctxt:  the XPath Parser context
7526  *
7527  * Implement the multiply operation on XPath objects:
7528  * The numeric operators convert their operands to numbers as if
7529  * by calling the number function.
7530  */
7531 void
xmlXPathMultValues(xmlXPathParserContextPtr ctxt)7532 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7533     xmlXPathObjectPtr arg;
7534     double val;
7535 
7536     arg = valuePop(ctxt);
7537     if (arg == NULL)
7538 	XP_ERROR(XPATH_INVALID_OPERAND);
7539     val = xmlXPathCastToNumber(arg);
7540     xmlXPathReleaseObject(ctxt->context, arg);
7541     CAST_TO_NUMBER;
7542     CHECK_TYPE(XPATH_NUMBER);
7543     ctxt->value->floatval *= val;
7544 }
7545 
7546 /**
7547  * xmlXPathDivValues:
7548  * @ctxt:  the XPath Parser context
7549  *
7550  * Implement the div operation on XPath objects @arg1 / @arg2:
7551  * The numeric operators convert their operands to numbers as if
7552  * by calling the number function.
7553  */
7554 void
xmlXPathDivValues(xmlXPathParserContextPtr ctxt)7555 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7556     xmlXPathObjectPtr arg;
7557     double val;
7558 
7559     arg = valuePop(ctxt);
7560     if (arg == NULL)
7561 	XP_ERROR(XPATH_INVALID_OPERAND);
7562     val = xmlXPathCastToNumber(arg);
7563     xmlXPathReleaseObject(ctxt->context, arg);
7564     CAST_TO_NUMBER;
7565     CHECK_TYPE(XPATH_NUMBER);
7566     ctxt->value->floatval /= val;
7567 }
7568 
7569 /**
7570  * xmlXPathModValues:
7571  * @ctxt:  the XPath Parser context
7572  *
7573  * Implement the mod operation on XPath objects: @arg1 / @arg2
7574  * The numeric operators convert their operands to numbers as if
7575  * by calling the number function.
7576  */
7577 void
xmlXPathModValues(xmlXPathParserContextPtr ctxt)7578 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7579     xmlXPathObjectPtr arg;
7580     double arg1, arg2;
7581 
7582     arg = valuePop(ctxt);
7583     if (arg == NULL)
7584 	XP_ERROR(XPATH_INVALID_OPERAND);
7585     arg2 = xmlXPathCastToNumber(arg);
7586     xmlXPathReleaseObject(ctxt->context, arg);
7587     CAST_TO_NUMBER;
7588     CHECK_TYPE(XPATH_NUMBER);
7589     arg1 = ctxt->value->floatval;
7590     if (arg2 == 0)
7591 	ctxt->value->floatval = NAN;
7592     else {
7593 	ctxt->value->floatval = fmod(arg1, arg2);
7594     }
7595 }
7596 
7597 /************************************************************************
7598  *									*
7599  *		The traversal functions					*
7600  *									*
7601  ************************************************************************/
7602 
7603 /*
7604  * A traversal function enumerates nodes along an axis.
7605  * Initially it must be called with NULL, and it indicates
7606  * termination on the axis by returning NULL.
7607  */
7608 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7609                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7610 
7611 /*
7612  * xmlXPathTraversalFunctionExt:
7613  * A traversal function enumerates nodes along an axis.
7614  * Initially it must be called with NULL, and it indicates
7615  * termination on the axis by returning NULL.
7616  * The context node of the traversal is specified via @contextNode.
7617  */
7618 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7619                     (xmlNodePtr cur, xmlNodePtr contextNode);
7620 
7621 /*
7622  * xmlXPathNodeSetMergeFunction:
7623  * Used for merging node sets in xmlXPathCollectAndTest().
7624  */
7625 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7626 		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
7627 
7628 
7629 /**
7630  * xmlXPathNextSelf:
7631  * @ctxt:  the XPath Parser context
7632  * @cur:  the current node in the traversal
7633  *
7634  * Traversal function for the "self" direction
7635  * The self axis contains just the context node itself
7636  *
7637  * Returns the next element following that axis
7638  */
7639 xmlNodePtr
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7640 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7641     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7642     if (cur == NULL)
7643         return(ctxt->context->node);
7644     return(NULL);
7645 }
7646 
7647 /**
7648  * xmlXPathNextChild:
7649  * @ctxt:  the XPath Parser context
7650  * @cur:  the current node in the traversal
7651  *
7652  * Traversal function for the "child" direction
7653  * The child axis contains the children of the context node in document order.
7654  *
7655  * Returns the next element following that axis
7656  */
7657 xmlNodePtr
xmlXPathNextChild(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7658 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7659     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7660     if (cur == NULL) {
7661 	if (ctxt->context->node == NULL) return(NULL);
7662 	switch (ctxt->context->node->type) {
7663             case XML_ELEMENT_NODE:
7664             case XML_TEXT_NODE:
7665             case XML_CDATA_SECTION_NODE:
7666             case XML_ENTITY_REF_NODE:
7667             case XML_ENTITY_NODE:
7668             case XML_PI_NODE:
7669             case XML_COMMENT_NODE:
7670             case XML_NOTATION_NODE:
7671             case XML_DTD_NODE:
7672 		return(ctxt->context->node->children);
7673             case XML_DOCUMENT_NODE:
7674             case XML_DOCUMENT_TYPE_NODE:
7675             case XML_DOCUMENT_FRAG_NODE:
7676             case XML_HTML_DOCUMENT_NODE:
7677 #ifdef LIBXML_DOCB_ENABLED
7678 	    case XML_DOCB_DOCUMENT_NODE:
7679 #endif
7680 		return(((xmlDocPtr) ctxt->context->node)->children);
7681 	    case XML_ELEMENT_DECL:
7682 	    case XML_ATTRIBUTE_DECL:
7683 	    case XML_ENTITY_DECL:
7684             case XML_ATTRIBUTE_NODE:
7685 	    case XML_NAMESPACE_DECL:
7686 	    case XML_XINCLUDE_START:
7687 	    case XML_XINCLUDE_END:
7688 		return(NULL);
7689 	}
7690 	return(NULL);
7691     }
7692     if ((cur->type == XML_DOCUMENT_NODE) ||
7693         (cur->type == XML_HTML_DOCUMENT_NODE))
7694 	return(NULL);
7695     return(cur->next);
7696 }
7697 
7698 /**
7699  * xmlXPathNextChildElement:
7700  * @ctxt:  the XPath Parser context
7701  * @cur:  the current node in the traversal
7702  *
7703  * Traversal function for the "child" direction and nodes of type element.
7704  * The child axis contains the children of the context node in document order.
7705  *
7706  * Returns the next element following that axis
7707  */
7708 static xmlNodePtr
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7709 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7710     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7711     if (cur == NULL) {
7712 	cur = ctxt->context->node;
7713 	if (cur == NULL) return(NULL);
7714 	/*
7715 	* Get the first element child.
7716 	*/
7717 	switch (cur->type) {
7718             case XML_ELEMENT_NODE:
7719 	    case XML_DOCUMENT_FRAG_NODE:
7720 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7721             case XML_ENTITY_NODE:
7722 		cur = cur->children;
7723 		if (cur != NULL) {
7724 		    if (cur->type == XML_ELEMENT_NODE)
7725 			return(cur);
7726 		    do {
7727 			cur = cur->next;
7728 		    } while ((cur != NULL) &&
7729 			(cur->type != XML_ELEMENT_NODE));
7730 		    return(cur);
7731 		}
7732 		return(NULL);
7733             case XML_DOCUMENT_NODE:
7734             case XML_HTML_DOCUMENT_NODE:
7735 #ifdef LIBXML_DOCB_ENABLED
7736 	    case XML_DOCB_DOCUMENT_NODE:
7737 #endif
7738 		return(xmlDocGetRootElement((xmlDocPtr) cur));
7739 	    default:
7740 		return(NULL);
7741 	}
7742 	return(NULL);
7743     }
7744     /*
7745     * Get the next sibling element node.
7746     */
7747     switch (cur->type) {
7748 	case XML_ELEMENT_NODE:
7749 	case XML_TEXT_NODE:
7750 	case XML_ENTITY_REF_NODE:
7751 	case XML_ENTITY_NODE:
7752 	case XML_CDATA_SECTION_NODE:
7753 	case XML_PI_NODE:
7754 	case XML_COMMENT_NODE:
7755 	case XML_XINCLUDE_END:
7756 	    break;
7757 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7758 	default:
7759 	    return(NULL);
7760     }
7761     if (cur->next != NULL) {
7762 	if (cur->next->type == XML_ELEMENT_NODE)
7763 	    return(cur->next);
7764 	cur = cur->next;
7765 	do {
7766 	    cur = cur->next;
7767 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7768 	return(cur);
7769     }
7770     return(NULL);
7771 }
7772 
7773 #if 0
7774 /**
7775  * xmlXPathNextDescendantOrSelfElemParent:
7776  * @ctxt:  the XPath Parser context
7777  * @cur:  the current node in the traversal
7778  *
7779  * Traversal function for the "descendant-or-self" axis.
7780  * Additionally it returns only nodes which can be parents of
7781  * element nodes.
7782  *
7783  *
7784  * Returns the next element following that axis
7785  */
7786 static xmlNodePtr
7787 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7788 				       xmlNodePtr contextNode)
7789 {
7790     if (cur == NULL) {
7791 	if (contextNode == NULL)
7792 	    return(NULL);
7793 	switch (contextNode->type) {
7794 	    case XML_ELEMENT_NODE:
7795 	    case XML_XINCLUDE_START:
7796 	    case XML_DOCUMENT_FRAG_NODE:
7797 	    case XML_DOCUMENT_NODE:
7798 #ifdef LIBXML_DOCB_ENABLED
7799 	    case XML_DOCB_DOCUMENT_NODE:
7800 #endif
7801 	    case XML_HTML_DOCUMENT_NODE:
7802 		return(contextNode);
7803 	    default:
7804 		return(NULL);
7805 	}
7806 	return(NULL);
7807     } else {
7808 	xmlNodePtr start = cur;
7809 
7810 	while (cur != NULL) {
7811 	    switch (cur->type) {
7812 		case XML_ELEMENT_NODE:
7813 		/* TODO: OK to have XInclude here? */
7814 		case XML_XINCLUDE_START:
7815 		case XML_DOCUMENT_FRAG_NODE:
7816 		    if (cur != start)
7817 			return(cur);
7818 		    if (cur->children != NULL) {
7819 			cur = cur->children;
7820 			continue;
7821 		    }
7822 		    break;
7823 		/* Not sure if we need those here. */
7824 		case XML_DOCUMENT_NODE:
7825 #ifdef LIBXML_DOCB_ENABLED
7826 		case XML_DOCB_DOCUMENT_NODE:
7827 #endif
7828 		case XML_HTML_DOCUMENT_NODE:
7829 		    if (cur != start)
7830 			return(cur);
7831 		    return(xmlDocGetRootElement((xmlDocPtr) cur));
7832 		default:
7833 		    break;
7834 	    }
7835 
7836 next_sibling:
7837 	    if ((cur == NULL) || (cur == contextNode))
7838 		return(NULL);
7839 	    if (cur->next != NULL) {
7840 		cur = cur->next;
7841 	    } else {
7842 		cur = cur->parent;
7843 		goto next_sibling;
7844 	    }
7845 	}
7846     }
7847     return(NULL);
7848 }
7849 #endif
7850 
7851 /**
7852  * xmlXPathNextDescendant:
7853  * @ctxt:  the XPath Parser context
7854  * @cur:  the current node in the traversal
7855  *
7856  * Traversal function for the "descendant" direction
7857  * the descendant axis contains the descendants of the context node in document
7858  * order; a descendant is a child or a child of a child and so on.
7859  *
7860  * Returns the next element following that axis
7861  */
7862 xmlNodePtr
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7863 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7864     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7865     if (cur == NULL) {
7866 	if (ctxt->context->node == NULL)
7867 	    return(NULL);
7868 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7869 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7870 	    return(NULL);
7871 
7872         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7873 	    return(ctxt->context->doc->children);
7874         return(ctxt->context->node->children);
7875     }
7876 
7877     if (cur->type == XML_NAMESPACE_DECL)
7878         return(NULL);
7879     if (cur->children != NULL) {
7880 	/*
7881 	 * Do not descend on entities declarations
7882 	 */
7883 	if (cur->children->type != XML_ENTITY_DECL) {
7884 	    cur = cur->children;
7885 	    /*
7886 	     * Skip DTDs
7887 	     */
7888 	    if (cur->type != XML_DTD_NODE)
7889 		return(cur);
7890 	}
7891     }
7892 
7893     if (cur == ctxt->context->node) return(NULL);
7894 
7895     while (cur->next != NULL) {
7896 	cur = cur->next;
7897 	if ((cur->type != XML_ENTITY_DECL) &&
7898 	    (cur->type != XML_DTD_NODE))
7899 	    return(cur);
7900     }
7901 
7902     do {
7903         cur = cur->parent;
7904 	if (cur == NULL) break;
7905 	if (cur == ctxt->context->node) return(NULL);
7906 	if (cur->next != NULL) {
7907 	    cur = cur->next;
7908 	    return(cur);
7909 	}
7910     } while (cur != NULL);
7911     return(cur);
7912 }
7913 
7914 /**
7915  * xmlXPathNextDescendantOrSelf:
7916  * @ctxt:  the XPath Parser context
7917  * @cur:  the current node in the traversal
7918  *
7919  * Traversal function for the "descendant-or-self" direction
7920  * the descendant-or-self axis contains the context node and the descendants
7921  * of the context node in document order; thus the context node is the first
7922  * node on the axis, and the first child of the context node is the second node
7923  * on the axis
7924  *
7925  * Returns the next element following that axis
7926  */
7927 xmlNodePtr
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7928 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7929     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7930     if (cur == NULL)
7931         return(ctxt->context->node);
7932 
7933     if (ctxt->context->node == NULL)
7934         return(NULL);
7935     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7936         (ctxt->context->node->type == XML_NAMESPACE_DECL))
7937         return(NULL);
7938 
7939     return(xmlXPathNextDescendant(ctxt, cur));
7940 }
7941 
7942 /**
7943  * xmlXPathNextParent:
7944  * @ctxt:  the XPath Parser context
7945  * @cur:  the current node in the traversal
7946  *
7947  * Traversal function for the "parent" direction
7948  * The parent axis contains the parent of the context node, if there is one.
7949  *
7950  * Returns the next element following that axis
7951  */
7952 xmlNodePtr
xmlXPathNextParent(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7953 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7954     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7955     /*
7956      * the parent of an attribute or namespace node is the element
7957      * to which the attribute or namespace node is attached
7958      * Namespace handling !!!
7959      */
7960     if (cur == NULL) {
7961 	if (ctxt->context->node == NULL) return(NULL);
7962 	switch (ctxt->context->node->type) {
7963             case XML_ELEMENT_NODE:
7964             case XML_TEXT_NODE:
7965             case XML_CDATA_SECTION_NODE:
7966             case XML_ENTITY_REF_NODE:
7967             case XML_ENTITY_NODE:
7968             case XML_PI_NODE:
7969             case XML_COMMENT_NODE:
7970             case XML_NOTATION_NODE:
7971             case XML_DTD_NODE:
7972 	    case XML_ELEMENT_DECL:
7973 	    case XML_ATTRIBUTE_DECL:
7974 	    case XML_XINCLUDE_START:
7975 	    case XML_XINCLUDE_END:
7976 	    case XML_ENTITY_DECL:
7977 		if (ctxt->context->node->parent == NULL)
7978 		    return((xmlNodePtr) ctxt->context->doc);
7979 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7980 		    ((ctxt->context->node->parent->name[0] == ' ') ||
7981 		     (xmlStrEqual(ctxt->context->node->parent->name,
7982 				 BAD_CAST "fake node libxslt"))))
7983 		    return(NULL);
7984 		return(ctxt->context->node->parent);
7985             case XML_ATTRIBUTE_NODE: {
7986 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7987 
7988 		return(att->parent);
7989 	    }
7990             case XML_DOCUMENT_NODE:
7991             case XML_DOCUMENT_TYPE_NODE:
7992             case XML_DOCUMENT_FRAG_NODE:
7993             case XML_HTML_DOCUMENT_NODE:
7994 #ifdef LIBXML_DOCB_ENABLED
7995 	    case XML_DOCB_DOCUMENT_NODE:
7996 #endif
7997                 return(NULL);
7998 	    case XML_NAMESPACE_DECL: {
7999 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8000 
8001 		if ((ns->next != NULL) &&
8002 		    (ns->next->type != XML_NAMESPACE_DECL))
8003 		    return((xmlNodePtr) ns->next);
8004                 return(NULL);
8005 	    }
8006 	}
8007     }
8008     return(NULL);
8009 }
8010 
8011 /**
8012  * xmlXPathNextAncestor:
8013  * @ctxt:  the XPath Parser context
8014  * @cur:  the current node in the traversal
8015  *
8016  * Traversal function for the "ancestor" direction
8017  * the ancestor axis contains the ancestors of the context node; the ancestors
8018  * of the context node consist of the parent of context node and the parent's
8019  * parent and so on; the nodes are ordered in reverse document order; thus the
8020  * parent is the first node on the axis, and the parent's parent is the second
8021  * node on the axis
8022  *
8023  * Returns the next element following that axis
8024  */
8025 xmlNodePtr
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8026 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8027     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8028     /*
8029      * the parent of an attribute or namespace node is the element
8030      * to which the attribute or namespace node is attached
8031      * !!!!!!!!!!!!!
8032      */
8033     if (cur == NULL) {
8034 	if (ctxt->context->node == NULL) return(NULL);
8035 	switch (ctxt->context->node->type) {
8036             case XML_ELEMENT_NODE:
8037             case XML_TEXT_NODE:
8038             case XML_CDATA_SECTION_NODE:
8039             case XML_ENTITY_REF_NODE:
8040             case XML_ENTITY_NODE:
8041             case XML_PI_NODE:
8042             case XML_COMMENT_NODE:
8043 	    case XML_DTD_NODE:
8044 	    case XML_ELEMENT_DECL:
8045 	    case XML_ATTRIBUTE_DECL:
8046 	    case XML_ENTITY_DECL:
8047             case XML_NOTATION_NODE:
8048 	    case XML_XINCLUDE_START:
8049 	    case XML_XINCLUDE_END:
8050 		if (ctxt->context->node->parent == NULL)
8051 		    return((xmlNodePtr) ctxt->context->doc);
8052 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8053 		    ((ctxt->context->node->parent->name[0] == ' ') ||
8054 		     (xmlStrEqual(ctxt->context->node->parent->name,
8055 				 BAD_CAST "fake node libxslt"))))
8056 		    return(NULL);
8057 		return(ctxt->context->node->parent);
8058             case XML_ATTRIBUTE_NODE: {
8059 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8060 
8061 		return(tmp->parent);
8062 	    }
8063             case XML_DOCUMENT_NODE:
8064             case XML_DOCUMENT_TYPE_NODE:
8065             case XML_DOCUMENT_FRAG_NODE:
8066             case XML_HTML_DOCUMENT_NODE:
8067 #ifdef LIBXML_DOCB_ENABLED
8068 	    case XML_DOCB_DOCUMENT_NODE:
8069 #endif
8070                 return(NULL);
8071 	    case XML_NAMESPACE_DECL: {
8072 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8073 
8074 		if ((ns->next != NULL) &&
8075 		    (ns->next->type != XML_NAMESPACE_DECL))
8076 		    return((xmlNodePtr) ns->next);
8077 		/* Bad, how did that namespace end up here ? */
8078                 return(NULL);
8079 	    }
8080 	}
8081 	return(NULL);
8082     }
8083     if (cur == ctxt->context->doc->children)
8084 	return((xmlNodePtr) ctxt->context->doc);
8085     if (cur == (xmlNodePtr) ctxt->context->doc)
8086 	return(NULL);
8087     switch (cur->type) {
8088 	case XML_ELEMENT_NODE:
8089 	case XML_TEXT_NODE:
8090 	case XML_CDATA_SECTION_NODE:
8091 	case XML_ENTITY_REF_NODE:
8092 	case XML_ENTITY_NODE:
8093 	case XML_PI_NODE:
8094 	case XML_COMMENT_NODE:
8095 	case XML_NOTATION_NODE:
8096 	case XML_DTD_NODE:
8097         case XML_ELEMENT_DECL:
8098         case XML_ATTRIBUTE_DECL:
8099         case XML_ENTITY_DECL:
8100 	case XML_XINCLUDE_START:
8101 	case XML_XINCLUDE_END:
8102 	    if (cur->parent == NULL)
8103 		return(NULL);
8104 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
8105 		((cur->parent->name[0] == ' ') ||
8106 		 (xmlStrEqual(cur->parent->name,
8107 			      BAD_CAST "fake node libxslt"))))
8108 		return(NULL);
8109 	    return(cur->parent);
8110 	case XML_ATTRIBUTE_NODE: {
8111 	    xmlAttrPtr att = (xmlAttrPtr) cur;
8112 
8113 	    return(att->parent);
8114 	}
8115 	case XML_NAMESPACE_DECL: {
8116 	    xmlNsPtr ns = (xmlNsPtr) cur;
8117 
8118 	    if ((ns->next != NULL) &&
8119 	        (ns->next->type != XML_NAMESPACE_DECL))
8120 	        return((xmlNodePtr) ns->next);
8121 	    /* Bad, how did that namespace end up here ? */
8122             return(NULL);
8123 	}
8124 	case XML_DOCUMENT_NODE:
8125 	case XML_DOCUMENT_TYPE_NODE:
8126 	case XML_DOCUMENT_FRAG_NODE:
8127 	case XML_HTML_DOCUMENT_NODE:
8128 #ifdef LIBXML_DOCB_ENABLED
8129 	case XML_DOCB_DOCUMENT_NODE:
8130 #endif
8131 	    return(NULL);
8132     }
8133     return(NULL);
8134 }
8135 
8136 /**
8137  * xmlXPathNextAncestorOrSelf:
8138  * @ctxt:  the XPath Parser context
8139  * @cur:  the current node in the traversal
8140  *
8141  * Traversal function for the "ancestor-or-self" direction
8142  * he ancestor-or-self axis contains the context node and ancestors of
8143  * the context node in reverse document order; thus the context node is
8144  * the first node on the axis, and the context node's parent the second;
8145  * parent here is defined the same as with the parent axis.
8146  *
8147  * Returns the next element following that axis
8148  */
8149 xmlNodePtr
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8150 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8151     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8152     if (cur == NULL)
8153         return(ctxt->context->node);
8154     return(xmlXPathNextAncestor(ctxt, cur));
8155 }
8156 
8157 /**
8158  * xmlXPathNextFollowingSibling:
8159  * @ctxt:  the XPath Parser context
8160  * @cur:  the current node in the traversal
8161  *
8162  * Traversal function for the "following-sibling" direction
8163  * The following-sibling axis contains the following siblings of the context
8164  * node in document order.
8165  *
8166  * Returns the next element following that axis
8167  */
8168 xmlNodePtr
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8169 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8170     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8171     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8172 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8173 	return(NULL);
8174     if (cur == (xmlNodePtr) ctxt->context->doc)
8175         return(NULL);
8176     if (cur == NULL)
8177         return(ctxt->context->node->next);
8178     return(cur->next);
8179 }
8180 
8181 /**
8182  * xmlXPathNextPrecedingSibling:
8183  * @ctxt:  the XPath Parser context
8184  * @cur:  the current node in the traversal
8185  *
8186  * Traversal function for the "preceding-sibling" direction
8187  * The preceding-sibling axis contains the preceding siblings of the context
8188  * node in reverse document order; the first preceding sibling is first on the
8189  * axis; the sibling preceding that node is the second on the axis and so on.
8190  *
8191  * Returns the next element following that axis
8192  */
8193 xmlNodePtr
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8194 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8195     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8196     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8197 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8198 	return(NULL);
8199     if (cur == (xmlNodePtr) ctxt->context->doc)
8200         return(NULL);
8201     if (cur == NULL)
8202         return(ctxt->context->node->prev);
8203     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8204 	cur = cur->prev;
8205 	if (cur == NULL)
8206 	    return(ctxt->context->node->prev);
8207     }
8208     return(cur->prev);
8209 }
8210 
8211 /**
8212  * xmlXPathNextFollowing:
8213  * @ctxt:  the XPath Parser context
8214  * @cur:  the current node in the traversal
8215  *
8216  * Traversal function for the "following" direction
8217  * The following axis contains all nodes in the same document as the context
8218  * node that are after the context node in document order, excluding any
8219  * descendants and excluding attribute nodes and namespace nodes; the nodes
8220  * are ordered in document order
8221  *
8222  * Returns the next element following that axis
8223  */
8224 xmlNodePtr
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8225 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8226     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8227     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8228         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8229         return(cur->children);
8230 
8231     if (cur == NULL) {
8232         cur = ctxt->context->node;
8233         if (cur->type == XML_ATTRIBUTE_NODE) {
8234             cur = cur->parent;
8235         } else if (cur->type == XML_NAMESPACE_DECL) {
8236             xmlNsPtr ns = (xmlNsPtr) cur;
8237 
8238             if ((ns->next == NULL) ||
8239                 (ns->next->type == XML_NAMESPACE_DECL))
8240                 return (NULL);
8241             cur = (xmlNodePtr) ns->next;
8242         }
8243     }
8244     if (cur == NULL) return(NULL) ; /* ERROR */
8245     if (cur->next != NULL) return(cur->next) ;
8246     do {
8247         cur = cur->parent;
8248         if (cur == NULL) break;
8249         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8250         if (cur->next != NULL) return(cur->next);
8251     } while (cur != NULL);
8252     return(cur);
8253 }
8254 
8255 /*
8256  * xmlXPathIsAncestor:
8257  * @ancestor:  the ancestor node
8258  * @node:  the current node
8259  *
8260  * Check that @ancestor is a @node's ancestor
8261  *
8262  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8263  */
8264 static int
xmlXPathIsAncestor(xmlNodePtr ancestor,xmlNodePtr node)8265 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8266     if ((ancestor == NULL) || (node == NULL)) return(0);
8267     if (node->type == XML_NAMESPACE_DECL)
8268         return(0);
8269     if (ancestor->type == XML_NAMESPACE_DECL)
8270         return(0);
8271     /* nodes need to be in the same document */
8272     if (ancestor->doc != node->doc) return(0);
8273     /* avoid searching if ancestor or node is the root node */
8274     if (ancestor == (xmlNodePtr) node->doc) return(1);
8275     if (node == (xmlNodePtr) ancestor->doc) return(0);
8276     while (node->parent != NULL) {
8277         if (node->parent == ancestor)
8278             return(1);
8279 	node = node->parent;
8280     }
8281     return(0);
8282 }
8283 
8284 /**
8285  * xmlXPathNextPreceding:
8286  * @ctxt:  the XPath Parser context
8287  * @cur:  the current node in the traversal
8288  *
8289  * Traversal function for the "preceding" direction
8290  * the preceding axis contains all nodes in the same document as the context
8291  * node that are before the context node in document order, excluding any
8292  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8293  * ordered in reverse document order
8294  *
8295  * Returns the next element following that axis
8296  */
8297 xmlNodePtr
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8298 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8299 {
8300     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8301     if (cur == NULL) {
8302         cur = ctxt->context->node;
8303         if (cur->type == XML_ATTRIBUTE_NODE) {
8304             cur = cur->parent;
8305         } else if (cur->type == XML_NAMESPACE_DECL) {
8306             xmlNsPtr ns = (xmlNsPtr) cur;
8307 
8308             if ((ns->next == NULL) ||
8309                 (ns->next->type == XML_NAMESPACE_DECL))
8310                 return (NULL);
8311             cur = (xmlNodePtr) ns->next;
8312         }
8313     }
8314     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8315 	return (NULL);
8316     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8317 	cur = cur->prev;
8318     do {
8319         if (cur->prev != NULL) {
8320             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8321             return (cur);
8322         }
8323 
8324         cur = cur->parent;
8325         if (cur == NULL)
8326             return (NULL);
8327         if (cur == ctxt->context->doc->children)
8328             return (NULL);
8329     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8330     return (cur);
8331 }
8332 
8333 /**
8334  * xmlXPathNextPrecedingInternal:
8335  * @ctxt:  the XPath Parser context
8336  * @cur:  the current node in the traversal
8337  *
8338  * Traversal function for the "preceding" direction
8339  * the preceding axis contains all nodes in the same document as the context
8340  * node that are before the context node in document order, excluding any
8341  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8342  * ordered in reverse document order
8343  * This is a faster implementation but internal only since it requires a
8344  * state kept in the parser context: ctxt->ancestor.
8345  *
8346  * Returns the next element following that axis
8347  */
8348 static xmlNodePtr
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8349 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8350                               xmlNodePtr cur)
8351 {
8352     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8353     if (cur == NULL) {
8354         cur = ctxt->context->node;
8355         if (cur == NULL)
8356             return (NULL);
8357         if (cur->type == XML_ATTRIBUTE_NODE) {
8358             cur = cur->parent;
8359         } else if (cur->type == XML_NAMESPACE_DECL) {
8360             xmlNsPtr ns = (xmlNsPtr) cur;
8361 
8362             if ((ns->next == NULL) ||
8363                 (ns->next->type == XML_NAMESPACE_DECL))
8364                 return (NULL);
8365             cur = (xmlNodePtr) ns->next;
8366         }
8367         ctxt->ancestor = cur->parent;
8368     }
8369     if (cur->type == XML_NAMESPACE_DECL)
8370         return(NULL);
8371     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8372 	cur = cur->prev;
8373     while (cur->prev == NULL) {
8374         cur = cur->parent;
8375         if (cur == NULL)
8376             return (NULL);
8377         if (cur == ctxt->context->doc->children)
8378             return (NULL);
8379         if (cur != ctxt->ancestor)
8380             return (cur);
8381         ctxt->ancestor = cur->parent;
8382     }
8383     cur = cur->prev;
8384     while (cur->last != NULL)
8385         cur = cur->last;
8386     return (cur);
8387 }
8388 
8389 /**
8390  * xmlXPathNextNamespace:
8391  * @ctxt:  the XPath Parser context
8392  * @cur:  the current attribute in the traversal
8393  *
8394  * Traversal function for the "namespace" direction
8395  * the namespace axis contains the namespace nodes of the context node;
8396  * the order of nodes on this axis is implementation-defined; the axis will
8397  * be empty unless the context node is an element
8398  *
8399  * We keep the XML namespace node at the end of the list.
8400  *
8401  * Returns the next element following that axis
8402  */
8403 xmlNodePtr
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8404 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8405     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8406     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8407     if (cur == NULL) {
8408         if (ctxt->context->tmpNsList != NULL)
8409 	    xmlFree(ctxt->context->tmpNsList);
8410 	ctxt->context->tmpNsList =
8411 	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8412 	ctxt->context->tmpNsNr = 0;
8413 	if (ctxt->context->tmpNsList != NULL) {
8414 	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8415 		ctxt->context->tmpNsNr++;
8416 	    }
8417 	}
8418 	return((xmlNodePtr) xmlXPathXMLNamespace);
8419     }
8420     if (ctxt->context->tmpNsNr > 0) {
8421 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8422     } else {
8423 	if (ctxt->context->tmpNsList != NULL)
8424 	    xmlFree(ctxt->context->tmpNsList);
8425 	ctxt->context->tmpNsList = NULL;
8426 	return(NULL);
8427     }
8428 }
8429 
8430 /**
8431  * xmlXPathNextAttribute:
8432  * @ctxt:  the XPath Parser context
8433  * @cur:  the current attribute in the traversal
8434  *
8435  * Traversal function for the "attribute" direction
8436  * TODO: support DTD inherited default attributes
8437  *
8438  * Returns the next element following that axis
8439  */
8440 xmlNodePtr
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8441 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8442     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8443     if (ctxt->context->node == NULL)
8444 	return(NULL);
8445     if (ctxt->context->node->type != XML_ELEMENT_NODE)
8446 	return(NULL);
8447     if (cur == NULL) {
8448         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8449 	    return(NULL);
8450         return((xmlNodePtr)ctxt->context->node->properties);
8451     }
8452     return((xmlNodePtr)cur->next);
8453 }
8454 
8455 /************************************************************************
8456  *									*
8457  *		NodeTest Functions					*
8458  *									*
8459  ************************************************************************/
8460 
8461 #define IS_FUNCTION			200
8462 
8463 
8464 /************************************************************************
8465  *									*
8466  *		Implicit tree core function library			*
8467  *									*
8468  ************************************************************************/
8469 
8470 /**
8471  * xmlXPathRoot:
8472  * @ctxt:  the XPath Parser context
8473  *
8474  * Initialize the context to the root of the document
8475  */
8476 void
xmlXPathRoot(xmlXPathParserContextPtr ctxt)8477 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8478     if ((ctxt == NULL) || (ctxt->context == NULL))
8479 	return;
8480     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8481 	(xmlNodePtr) ctxt->context->doc));
8482 }
8483 
8484 /************************************************************************
8485  *									*
8486  *		The explicit core function library			*
8487  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
8488  *									*
8489  ************************************************************************/
8490 
8491 
8492 /**
8493  * xmlXPathLastFunction:
8494  * @ctxt:  the XPath Parser context
8495  * @nargs:  the number of arguments
8496  *
8497  * Implement the last() XPath function
8498  *    number last()
8499  * The last function returns the number of nodes in the context node list.
8500  */
8501 void
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt,int nargs)8502 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8503     CHECK_ARITY(0);
8504     if (ctxt->context->contextSize >= 0) {
8505 	valuePush(ctxt,
8506 	    xmlXPathCacheNewFloat(ctxt->context,
8507 		(double) ctxt->context->contextSize));
8508 #ifdef DEBUG_EXPR
8509 	xmlGenericError(xmlGenericErrorContext,
8510 		"last() : %d\n", ctxt->context->contextSize);
8511 #endif
8512     } else {
8513 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8514     }
8515 }
8516 
8517 /**
8518  * xmlXPathPositionFunction:
8519  * @ctxt:  the XPath Parser context
8520  * @nargs:  the number of arguments
8521  *
8522  * Implement the position() XPath function
8523  *    number position()
8524  * The position function returns the position of the context node in the
8525  * context node list. The first position is 1, and so the last position
8526  * will be equal to last().
8527  */
8528 void
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt,int nargs)8529 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8530     CHECK_ARITY(0);
8531     if (ctxt->context->proximityPosition >= 0) {
8532 	valuePush(ctxt,
8533 	      xmlXPathCacheNewFloat(ctxt->context,
8534 		(double) ctxt->context->proximityPosition));
8535 #ifdef DEBUG_EXPR
8536 	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8537 		ctxt->context->proximityPosition);
8538 #endif
8539     } else {
8540 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8541     }
8542 }
8543 
8544 /**
8545  * xmlXPathCountFunction:
8546  * @ctxt:  the XPath Parser context
8547  * @nargs:  the number of arguments
8548  *
8549  * Implement the count() XPath function
8550  *    number count(node-set)
8551  */
8552 void
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt,int nargs)8553 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8554     xmlXPathObjectPtr cur;
8555 
8556     CHECK_ARITY(1);
8557     if ((ctxt->value == NULL) ||
8558 	((ctxt->value->type != XPATH_NODESET) &&
8559 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8560 	XP_ERROR(XPATH_INVALID_TYPE);
8561     cur = valuePop(ctxt);
8562 
8563     if ((cur == NULL) || (cur->nodesetval == NULL))
8564 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8565     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8566 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8567 	    (double) cur->nodesetval->nodeNr));
8568     } else {
8569 	if ((cur->nodesetval->nodeNr != 1) ||
8570 	    (cur->nodesetval->nodeTab == NULL)) {
8571 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8572 	} else {
8573 	    xmlNodePtr tmp;
8574 	    int i = 0;
8575 
8576 	    tmp = cur->nodesetval->nodeTab[0];
8577 	    if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
8578 		tmp = tmp->children;
8579 		while (tmp != NULL) {
8580 		    tmp = tmp->next;
8581 		    i++;
8582 		}
8583 	    }
8584 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8585 	}
8586     }
8587     xmlXPathReleaseObject(ctxt->context, cur);
8588 }
8589 
8590 /**
8591  * xmlXPathGetElementsByIds:
8592  * @doc:  the document
8593  * @ids:  a whitespace separated list of IDs
8594  *
8595  * Selects elements by their unique ID.
8596  *
8597  * Returns a node-set of selected elements.
8598  */
8599 static xmlNodeSetPtr
xmlXPathGetElementsByIds(xmlDocPtr doc,const xmlChar * ids)8600 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8601     xmlNodeSetPtr ret;
8602     const xmlChar *cur = ids;
8603     xmlChar *ID;
8604     xmlAttrPtr attr;
8605     xmlNodePtr elem = NULL;
8606 
8607     if (ids == NULL) return(NULL);
8608 
8609     ret = xmlXPathNodeSetCreate(NULL);
8610     if (ret == NULL)
8611         return(ret);
8612 
8613     while (IS_BLANK_CH(*cur)) cur++;
8614     while (*cur != 0) {
8615 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8616 	    cur++;
8617 
8618         ID = xmlStrndup(ids, cur - ids);
8619 	if (ID != NULL) {
8620 	    /*
8621 	     * We used to check the fact that the value passed
8622 	     * was an NCName, but this generated much troubles for
8623 	     * me and Aleksey Sanin, people blatantly violated that
8624 	     * constaint, like Visa3D spec.
8625 	     * if (xmlValidateNCName(ID, 1) == 0)
8626 	     */
8627 	    attr = xmlGetID(doc, ID);
8628 	    if (attr != NULL) {
8629 		if (attr->type == XML_ATTRIBUTE_NODE)
8630 		    elem = attr->parent;
8631 		else if (attr->type == XML_ELEMENT_NODE)
8632 		    elem = (xmlNodePtr) attr;
8633 		else
8634 		    elem = NULL;
8635 		if (elem != NULL)
8636 		    xmlXPathNodeSetAdd(ret, elem);
8637 	    }
8638 	    xmlFree(ID);
8639 	}
8640 
8641 	while (IS_BLANK_CH(*cur)) cur++;
8642 	ids = cur;
8643     }
8644     return(ret);
8645 }
8646 
8647 /**
8648  * xmlXPathIdFunction:
8649  * @ctxt:  the XPath Parser context
8650  * @nargs:  the number of arguments
8651  *
8652  * Implement the id() XPath function
8653  *    node-set id(object)
8654  * The id function selects elements by their unique ID
8655  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8656  * then the result is the union of the result of applying id to the
8657  * string value of each of the nodes in the argument node-set. When the
8658  * argument to id is of any other type, the argument is converted to a
8659  * string as if by a call to the string function; the string is split
8660  * into a whitespace-separated list of tokens (whitespace is any sequence
8661  * of characters matching the production S); the result is a node-set
8662  * containing the elements in the same document as the context node that
8663  * have a unique ID equal to any of the tokens in the list.
8664  */
8665 void
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt,int nargs)8666 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8667     xmlChar *tokens;
8668     xmlNodeSetPtr ret;
8669     xmlXPathObjectPtr obj;
8670 
8671     CHECK_ARITY(1);
8672     obj = valuePop(ctxt);
8673     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8674     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8675 	xmlNodeSetPtr ns;
8676 	int i;
8677 
8678 	ret = xmlXPathNodeSetCreate(NULL);
8679         /*
8680          * FIXME -- in an out-of-memory condition this will behave badly.
8681          * The solution is not clear -- we already popped an item from
8682          * ctxt, so the object is in a corrupt state.
8683          */
8684 
8685 	if (obj->nodesetval != NULL) {
8686 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8687 		tokens =
8688 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8689 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8690 		ret = xmlXPathNodeSetMerge(ret, ns);
8691 		xmlXPathFreeNodeSet(ns);
8692 		if (tokens != NULL)
8693 		    xmlFree(tokens);
8694 	    }
8695 	}
8696 	xmlXPathReleaseObject(ctxt->context, obj);
8697 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8698 	return;
8699     }
8700     obj = xmlXPathCacheConvertString(ctxt->context, obj);
8701     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8702     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8703     xmlXPathReleaseObject(ctxt->context, obj);
8704     return;
8705 }
8706 
8707 /**
8708  * xmlXPathLocalNameFunction:
8709  * @ctxt:  the XPath Parser context
8710  * @nargs:  the number of arguments
8711  *
8712  * Implement the local-name() XPath function
8713  *    string local-name(node-set?)
8714  * The local-name function returns a string containing the local part
8715  * of the name of the node in the argument node-set that is first in
8716  * document order. If the node-set is empty or the first node has no
8717  * name, an empty string is returned. If the argument is omitted it
8718  * defaults to the context node.
8719  */
8720 void
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8721 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8722     xmlXPathObjectPtr cur;
8723 
8724     if (ctxt == NULL) return;
8725 
8726     if (nargs == 0) {
8727 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8728 	    ctxt->context->node));
8729 	nargs = 1;
8730     }
8731 
8732     CHECK_ARITY(1);
8733     if ((ctxt->value == NULL) ||
8734 	((ctxt->value->type != XPATH_NODESET) &&
8735 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8736 	XP_ERROR(XPATH_INVALID_TYPE);
8737     cur = valuePop(ctxt);
8738 
8739     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8740 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8741     } else {
8742 	int i = 0; /* Should be first in document order !!!!! */
8743 	switch (cur->nodesetval->nodeTab[i]->type) {
8744 	case XML_ELEMENT_NODE:
8745 	case XML_ATTRIBUTE_NODE:
8746 	case XML_PI_NODE:
8747 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8748 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8749 	    else
8750 		valuePush(ctxt,
8751 		      xmlXPathCacheNewString(ctxt->context,
8752 			cur->nodesetval->nodeTab[i]->name));
8753 	    break;
8754 	case XML_NAMESPACE_DECL:
8755 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8756 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8757 	    break;
8758 	default:
8759 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8760 	}
8761     }
8762     xmlXPathReleaseObject(ctxt->context, cur);
8763 }
8764 
8765 /**
8766  * xmlXPathNamespaceURIFunction:
8767  * @ctxt:  the XPath Parser context
8768  * @nargs:  the number of arguments
8769  *
8770  * Implement the namespace-uri() XPath function
8771  *    string namespace-uri(node-set?)
8772  * The namespace-uri function returns a string containing the
8773  * namespace URI of the expanded name of the node in the argument
8774  * node-set that is first in document order. If the node-set is empty,
8775  * the first node has no name, or the expanded name has no namespace
8776  * URI, an empty string is returned. If the argument is omitted it
8777  * defaults to the context node.
8778  */
8779 void
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt,int nargs)8780 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8781     xmlXPathObjectPtr cur;
8782 
8783     if (ctxt == NULL) return;
8784 
8785     if (nargs == 0) {
8786 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8787 	    ctxt->context->node));
8788 	nargs = 1;
8789     }
8790     CHECK_ARITY(1);
8791     if ((ctxt->value == NULL) ||
8792 	((ctxt->value->type != XPATH_NODESET) &&
8793 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8794 	XP_ERROR(XPATH_INVALID_TYPE);
8795     cur = valuePop(ctxt);
8796 
8797     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8798 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8799     } else {
8800 	int i = 0; /* Should be first in document order !!!!! */
8801 	switch (cur->nodesetval->nodeTab[i]->type) {
8802 	case XML_ELEMENT_NODE:
8803 	case XML_ATTRIBUTE_NODE:
8804 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
8805 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8806 	    else
8807 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8808 			  cur->nodesetval->nodeTab[i]->ns->href));
8809 	    break;
8810 	default:
8811 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8812 	}
8813     }
8814     xmlXPathReleaseObject(ctxt->context, cur);
8815 }
8816 
8817 /**
8818  * xmlXPathNameFunction:
8819  * @ctxt:  the XPath Parser context
8820  * @nargs:  the number of arguments
8821  *
8822  * Implement the name() XPath function
8823  *    string name(node-set?)
8824  * The name function returns a string containing a QName representing
8825  * the name of the node in the argument node-set that is first in document
8826  * order. The QName must represent the name with respect to the namespace
8827  * declarations in effect on the node whose name is being represented.
8828  * Typically, this will be the form in which the name occurred in the XML
8829  * source. This need not be the case if there are namespace declarations
8830  * in effect on the node that associate multiple prefixes with the same
8831  * namespace. However, an implementation may include information about
8832  * the original prefix in its representation of nodes; in this case, an
8833  * implementation can ensure that the returned string is always the same
8834  * as the QName used in the XML source. If the argument it omitted it
8835  * defaults to the context node.
8836  * Libxml keep the original prefix so the "real qualified name" used is
8837  * returned.
8838  */
8839 static void
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8840 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8841 {
8842     xmlXPathObjectPtr cur;
8843 
8844     if (nargs == 0) {
8845 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8846 	    ctxt->context->node));
8847         nargs = 1;
8848     }
8849 
8850     CHECK_ARITY(1);
8851     if ((ctxt->value == NULL) ||
8852         ((ctxt->value->type != XPATH_NODESET) &&
8853          (ctxt->value->type != XPATH_XSLT_TREE)))
8854         XP_ERROR(XPATH_INVALID_TYPE);
8855     cur = valuePop(ctxt);
8856 
8857     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8858         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8859     } else {
8860         int i = 0;              /* Should be first in document order !!!!! */
8861 
8862         switch (cur->nodesetval->nodeTab[i]->type) {
8863             case XML_ELEMENT_NODE:
8864             case XML_ATTRIBUTE_NODE:
8865 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8866 		    valuePush(ctxt,
8867 			xmlXPathCacheNewCString(ctxt->context, ""));
8868 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8869                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8870 		    valuePush(ctxt,
8871 		        xmlXPathCacheNewString(ctxt->context,
8872 			    cur->nodesetval->nodeTab[i]->name));
8873 		} else {
8874 		    xmlChar *fullname;
8875 
8876 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8877 				     cur->nodesetval->nodeTab[i]->ns->prefix,
8878 				     NULL, 0);
8879 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
8880 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8881 		    if (fullname == NULL) {
8882 			XP_ERROR(XPATH_MEMORY_ERROR);
8883 		    }
8884 		    valuePush(ctxt, xmlXPathCacheWrapString(
8885 			ctxt->context, fullname));
8886                 }
8887                 break;
8888             default:
8889 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8890 		    cur->nodesetval->nodeTab[i]));
8891                 xmlXPathLocalNameFunction(ctxt, 1);
8892         }
8893     }
8894     xmlXPathReleaseObject(ctxt->context, cur);
8895 }
8896 
8897 
8898 /**
8899  * xmlXPathStringFunction:
8900  * @ctxt:  the XPath Parser context
8901  * @nargs:  the number of arguments
8902  *
8903  * Implement the string() XPath function
8904  *    string string(object?)
8905  * The string function converts an object to a string as follows:
8906  *    - A node-set is converted to a string by returning the value of
8907  *      the node in the node-set that is first in document order.
8908  *      If the node-set is empty, an empty string is returned.
8909  *    - A number is converted to a string as follows
8910  *      + NaN is converted to the string NaN
8911  *      + positive zero is converted to the string 0
8912  *      + negative zero is converted to the string 0
8913  *      + positive infinity is converted to the string Infinity
8914  *      + negative infinity is converted to the string -Infinity
8915  *      + if the number is an integer, the number is represented in
8916  *        decimal form as a Number with no decimal point and no leading
8917  *        zeros, preceded by a minus sign (-) if the number is negative
8918  *      + otherwise, the number is represented in decimal form as a
8919  *        Number including a decimal point with at least one digit
8920  *        before the decimal point and at least one digit after the
8921  *        decimal point, preceded by a minus sign (-) if the number
8922  *        is negative; there must be no leading zeros before the decimal
8923  *        point apart possibly from the one required digit immediately
8924  *        before the decimal point; beyond the one required digit
8925  *        after the decimal point there must be as many, but only as
8926  *        many, more digits as are needed to uniquely distinguish the
8927  *        number from all other IEEE 754 numeric values.
8928  *    - The boolean false value is converted to the string false.
8929  *      The boolean true value is converted to the string true.
8930  *
8931  * If the argument is omitted, it defaults to a node-set with the
8932  * context node as its only member.
8933  */
8934 void
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt,int nargs)8935 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8936     xmlXPathObjectPtr cur;
8937 
8938     if (ctxt == NULL) return;
8939     if (nargs == 0) {
8940     valuePush(ctxt,
8941 	xmlXPathCacheWrapString(ctxt->context,
8942 	    xmlXPathCastNodeToString(ctxt->context->node)));
8943 	return;
8944     }
8945 
8946     CHECK_ARITY(1);
8947     cur = valuePop(ctxt);
8948     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8949     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8950 }
8951 
8952 /**
8953  * xmlXPathStringLengthFunction:
8954  * @ctxt:  the XPath Parser context
8955  * @nargs:  the number of arguments
8956  *
8957  * Implement the string-length() XPath function
8958  *    number string-length(string?)
8959  * The string-length returns the number of characters in the string
8960  * (see [3.6 Strings]). If the argument is omitted, it defaults to
8961  * the context node converted to a string, in other words the value
8962  * of the context node.
8963  */
8964 void
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt,int nargs)8965 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8966     xmlXPathObjectPtr cur;
8967 
8968     if (nargs == 0) {
8969         if ((ctxt == NULL) || (ctxt->context == NULL))
8970 	    return;
8971 	if (ctxt->context->node == NULL) {
8972 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8973 	} else {
8974 	    xmlChar *content;
8975 
8976 	    content = xmlXPathCastNodeToString(ctxt->context->node);
8977 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8978 		xmlUTF8Strlen(content)));
8979 	    xmlFree(content);
8980 	}
8981 	return;
8982     }
8983     CHECK_ARITY(1);
8984     CAST_TO_STRING;
8985     CHECK_TYPE(XPATH_STRING);
8986     cur = valuePop(ctxt);
8987     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8988 	xmlUTF8Strlen(cur->stringval)));
8989     xmlXPathReleaseObject(ctxt->context, cur);
8990 }
8991 
8992 /**
8993  * xmlXPathConcatFunction:
8994  * @ctxt:  the XPath Parser context
8995  * @nargs:  the number of arguments
8996  *
8997  * Implement the concat() XPath function
8998  *    string concat(string, string, string*)
8999  * The concat function returns the concatenation of its arguments.
9000  */
9001 void
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt,int nargs)9002 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9003     xmlXPathObjectPtr cur, newobj;
9004     xmlChar *tmp;
9005 
9006     if (ctxt == NULL) return;
9007     if (nargs < 2) {
9008 	CHECK_ARITY(2);
9009     }
9010 
9011     CAST_TO_STRING;
9012     cur = valuePop(ctxt);
9013     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
9014 	xmlXPathReleaseObject(ctxt->context, cur);
9015 	return;
9016     }
9017     nargs--;
9018 
9019     while (nargs > 0) {
9020 	CAST_TO_STRING;
9021 	newobj = valuePop(ctxt);
9022 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
9023 	    xmlXPathReleaseObject(ctxt->context, newobj);
9024 	    xmlXPathReleaseObject(ctxt->context, cur);
9025 	    XP_ERROR(XPATH_INVALID_TYPE);
9026 	}
9027 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
9028 	newobj->stringval = cur->stringval;
9029 	cur->stringval = tmp;
9030 	xmlXPathReleaseObject(ctxt->context, newobj);
9031 	nargs--;
9032     }
9033     valuePush(ctxt, cur);
9034 }
9035 
9036 /**
9037  * xmlXPathContainsFunction:
9038  * @ctxt:  the XPath Parser context
9039  * @nargs:  the number of arguments
9040  *
9041  * Implement the contains() XPath function
9042  *    boolean contains(string, string)
9043  * The contains function returns true if the first argument string
9044  * contains the second argument string, and otherwise returns false.
9045  */
9046 void
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt,int nargs)9047 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9048     xmlXPathObjectPtr hay, needle;
9049 
9050     CHECK_ARITY(2);
9051     CAST_TO_STRING;
9052     CHECK_TYPE(XPATH_STRING);
9053     needle = valuePop(ctxt);
9054     CAST_TO_STRING;
9055     hay = valuePop(ctxt);
9056 
9057     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9058 	xmlXPathReleaseObject(ctxt->context, hay);
9059 	xmlXPathReleaseObject(ctxt->context, needle);
9060 	XP_ERROR(XPATH_INVALID_TYPE);
9061     }
9062     if (xmlStrstr(hay->stringval, needle->stringval))
9063 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9064     else
9065 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9066     xmlXPathReleaseObject(ctxt->context, hay);
9067     xmlXPathReleaseObject(ctxt->context, needle);
9068 }
9069 
9070 /**
9071  * xmlXPathStartsWithFunction:
9072  * @ctxt:  the XPath Parser context
9073  * @nargs:  the number of arguments
9074  *
9075  * Implement the starts-with() XPath function
9076  *    boolean starts-with(string, string)
9077  * The starts-with function returns true if the first argument string
9078  * starts with the second argument string, and otherwise returns false.
9079  */
9080 void
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt,int nargs)9081 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9082     xmlXPathObjectPtr hay, needle;
9083     int n;
9084 
9085     CHECK_ARITY(2);
9086     CAST_TO_STRING;
9087     CHECK_TYPE(XPATH_STRING);
9088     needle = valuePop(ctxt);
9089     CAST_TO_STRING;
9090     hay = valuePop(ctxt);
9091 
9092     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9093 	xmlXPathReleaseObject(ctxt->context, hay);
9094 	xmlXPathReleaseObject(ctxt->context, needle);
9095 	XP_ERROR(XPATH_INVALID_TYPE);
9096     }
9097     n = xmlStrlen(needle->stringval);
9098     if (xmlStrncmp(hay->stringval, needle->stringval, n))
9099         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9100     else
9101         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9102     xmlXPathReleaseObject(ctxt->context, hay);
9103     xmlXPathReleaseObject(ctxt->context, needle);
9104 }
9105 
9106 /**
9107  * xmlXPathSubstringFunction:
9108  * @ctxt:  the XPath Parser context
9109  * @nargs:  the number of arguments
9110  *
9111  * Implement the substring() XPath function
9112  *    string substring(string, number, number?)
9113  * The substring function returns the substring of the first argument
9114  * starting at the position specified in the second argument with
9115  * length specified in the third argument. For example,
9116  * substring("12345",2,3) returns "234". If the third argument is not
9117  * specified, it returns the substring starting at the position specified
9118  * in the second argument and continuing to the end of the string. For
9119  * example, substring("12345",2) returns "2345".  More precisely, each
9120  * character in the string (see [3.6 Strings]) is considered to have a
9121  * numeric position: the position of the first character is 1, the position
9122  * of the second character is 2 and so on. The returned substring contains
9123  * those characters for which the position of the character is greater than
9124  * or equal to the second argument and, if the third argument is specified,
9125  * less than the sum of the second and third arguments; the comparisons
9126  * and addition used for the above follow the standard IEEE 754 rules. Thus:
9127  *  - substring("12345", 1.5, 2.6) returns "234"
9128  *  - substring("12345", 0, 3) returns "12"
9129  *  - substring("12345", 0 div 0, 3) returns ""
9130  *  - substring("12345", 1, 0 div 0) returns ""
9131  *  - substring("12345", -42, 1 div 0) returns "12345"
9132  *  - substring("12345", -1 div 0, 1 div 0) returns ""
9133  */
9134 void
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt,int nargs)9135 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9136     xmlXPathObjectPtr str, start, len;
9137     double le=0, in;
9138     int i, l, m;
9139     xmlChar *ret;
9140 
9141     if (nargs < 2) {
9142 	CHECK_ARITY(2);
9143     }
9144     if (nargs > 3) {
9145 	CHECK_ARITY(3);
9146     }
9147     /*
9148      * take care of possible last (position) argument
9149     */
9150     if (nargs == 3) {
9151 	CAST_TO_NUMBER;
9152 	CHECK_TYPE(XPATH_NUMBER);
9153 	len = valuePop(ctxt);
9154 	le = len->floatval;
9155 	xmlXPathReleaseObject(ctxt->context, len);
9156     }
9157 
9158     CAST_TO_NUMBER;
9159     CHECK_TYPE(XPATH_NUMBER);
9160     start = valuePop(ctxt);
9161     in = start->floatval;
9162     xmlXPathReleaseObject(ctxt->context, start);
9163     CAST_TO_STRING;
9164     CHECK_TYPE(XPATH_STRING);
9165     str = valuePop(ctxt);
9166     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9167 
9168     /*
9169      * If last pos not present, calculate last position
9170     */
9171     if (nargs != 3) {
9172 	le = (double)m;
9173 	if (in < 1.0)
9174 	    in = 1.0;
9175     }
9176 
9177     /* Need to check for the special cases where either
9178      * the index is NaN, the length is NaN, or both
9179      * arguments are infinity (relying on Inf + -Inf = NaN)
9180      */
9181     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9182         /*
9183          * To meet the requirements of the spec, the arguments
9184 	 * must be converted to integer format before
9185 	 * initial index calculations are done
9186          *
9187          * First we go to integer form, rounding up
9188 	 * and checking for special cases
9189          */
9190         i = (int) in;
9191         if (((double)i)+0.5 <= in) i++;
9192 
9193 	if (xmlXPathIsInf(le) == 1) {
9194 	    l = m;
9195 	    if (i < 1)
9196 		i = 1;
9197 	}
9198 	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9199 	    l = 0;
9200 	else {
9201 	    l = (int) le;
9202 	    if (((double)l)+0.5 <= le) l++;
9203 	}
9204 
9205 	/* Now we normalize inidices */
9206         i -= 1;
9207         l += i;
9208         if (i < 0)
9209             i = 0;
9210         if (l > m)
9211             l = m;
9212 
9213         /* number of chars to copy */
9214         l -= i;
9215 
9216         ret = xmlUTF8Strsub(str->stringval, i, l);
9217     }
9218     else {
9219         ret = NULL;
9220     }
9221     if (ret == NULL)
9222 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9223     else {
9224 	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9225 	xmlFree(ret);
9226     }
9227     xmlXPathReleaseObject(ctxt->context, str);
9228 }
9229 
9230 /**
9231  * xmlXPathSubstringBeforeFunction:
9232  * @ctxt:  the XPath Parser context
9233  * @nargs:  the number of arguments
9234  *
9235  * Implement the substring-before() XPath function
9236  *    string substring-before(string, string)
9237  * The substring-before function returns the substring of the first
9238  * argument string that precedes the first occurrence of the second
9239  * argument string in the first argument string, or the empty string
9240  * if the first argument string does not contain the second argument
9241  * string. For example, substring-before("1999/04/01","/") returns 1999.
9242  */
9243 void
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt,int nargs)9244 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9245   xmlXPathObjectPtr str;
9246   xmlXPathObjectPtr find;
9247   xmlBufPtr target;
9248   const xmlChar *point;
9249   int offset;
9250 
9251   CHECK_ARITY(2);
9252   CAST_TO_STRING;
9253   find = valuePop(ctxt);
9254   CAST_TO_STRING;
9255   str = valuePop(ctxt);
9256 
9257   target = xmlBufCreate();
9258   if (target) {
9259     point = xmlStrstr(str->stringval, find->stringval);
9260     if (point) {
9261       offset = (int)(point - str->stringval);
9262       xmlBufAdd(target, str->stringval, offset);
9263     }
9264     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9265 	xmlBufContent(target)));
9266     xmlBufFree(target);
9267   }
9268   xmlXPathReleaseObject(ctxt->context, str);
9269   xmlXPathReleaseObject(ctxt->context, find);
9270 }
9271 
9272 /**
9273  * xmlXPathSubstringAfterFunction:
9274  * @ctxt:  the XPath Parser context
9275  * @nargs:  the number of arguments
9276  *
9277  * Implement the substring-after() XPath function
9278  *    string substring-after(string, string)
9279  * The substring-after function returns the substring of the first
9280  * argument string that follows the first occurrence of the second
9281  * argument string in the first argument string, or the empty stringi
9282  * if the first argument string does not contain the second argument
9283  * string. For example, substring-after("1999/04/01","/") returns 04/01,
9284  * and substring-after("1999/04/01","19") returns 99/04/01.
9285  */
9286 void
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt,int nargs)9287 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9288   xmlXPathObjectPtr str;
9289   xmlXPathObjectPtr find;
9290   xmlBufPtr target;
9291   const xmlChar *point;
9292   int offset;
9293 
9294   CHECK_ARITY(2);
9295   CAST_TO_STRING;
9296   find = valuePop(ctxt);
9297   CAST_TO_STRING;
9298   str = valuePop(ctxt);
9299 
9300   target = xmlBufCreate();
9301   if (target) {
9302     point = xmlStrstr(str->stringval, find->stringval);
9303     if (point) {
9304       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9305       xmlBufAdd(target, &str->stringval[offset],
9306 		   xmlStrlen(str->stringval) - offset);
9307     }
9308     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9309 	xmlBufContent(target)));
9310     xmlBufFree(target);
9311   }
9312   xmlXPathReleaseObject(ctxt->context, str);
9313   xmlXPathReleaseObject(ctxt->context, find);
9314 }
9315 
9316 /**
9317  * xmlXPathNormalizeFunction:
9318  * @ctxt:  the XPath Parser context
9319  * @nargs:  the number of arguments
9320  *
9321  * Implement the normalize-space() XPath function
9322  *    string normalize-space(string?)
9323  * The normalize-space function returns the argument string with white
9324  * space normalized by stripping leading and trailing whitespace
9325  * and replacing sequences of whitespace characters by a single
9326  * space. Whitespace characters are the same allowed by the S production
9327  * in XML. If the argument is omitted, it defaults to the context
9328  * node converted to a string, in other words the value of the context node.
9329  */
9330 void
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt,int nargs)9331 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9332   xmlXPathObjectPtr obj = NULL;
9333   xmlChar *source = NULL;
9334   xmlBufPtr target;
9335   xmlChar blank;
9336 
9337   if (ctxt == NULL) return;
9338   if (nargs == 0) {
9339     /* Use current context node */
9340       valuePush(ctxt,
9341 	  xmlXPathCacheWrapString(ctxt->context,
9342 	    xmlXPathCastNodeToString(ctxt->context->node)));
9343     nargs = 1;
9344   }
9345 
9346   CHECK_ARITY(1);
9347   CAST_TO_STRING;
9348   CHECK_TYPE(XPATH_STRING);
9349   obj = valuePop(ctxt);
9350   source = obj->stringval;
9351 
9352   target = xmlBufCreate();
9353   if (target && source) {
9354 
9355     /* Skip leading whitespaces */
9356     while (IS_BLANK_CH(*source))
9357       source++;
9358 
9359     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9360     blank = 0;
9361     while (*source) {
9362       if (IS_BLANK_CH(*source)) {
9363 	blank = 0x20;
9364       } else {
9365 	if (blank) {
9366 	  xmlBufAdd(target, &blank, 1);
9367 	  blank = 0;
9368 	}
9369 	xmlBufAdd(target, source, 1);
9370       }
9371       source++;
9372     }
9373     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9374 	xmlBufContent(target)));
9375     xmlBufFree(target);
9376   }
9377   xmlXPathReleaseObject(ctxt->context, obj);
9378 }
9379 
9380 /**
9381  * xmlXPathTranslateFunction:
9382  * @ctxt:  the XPath Parser context
9383  * @nargs:  the number of arguments
9384  *
9385  * Implement the translate() XPath function
9386  *    string translate(string, string, string)
9387  * The translate function returns the first argument string with
9388  * occurrences of characters in the second argument string replaced
9389  * by the character at the corresponding position in the third argument
9390  * string. For example, translate("bar","abc","ABC") returns the string
9391  * BAr. If there is a character in the second argument string with no
9392  * character at a corresponding position in the third argument string
9393  * (because the second argument string is longer than the third argument
9394  * string), then occurrences of that character in the first argument
9395  * string are removed. For example, translate("--aaa--","abc-","ABC")
9396  * returns "AAA". If a character occurs more than once in second
9397  * argument string, then the first occurrence determines the replacement
9398  * character. If the third argument string is longer than the second
9399  * argument string, then excess characters are ignored.
9400  */
9401 void
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt,int nargs)9402 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9403     xmlXPathObjectPtr str;
9404     xmlXPathObjectPtr from;
9405     xmlXPathObjectPtr to;
9406     xmlBufPtr target;
9407     int offset, max;
9408     xmlChar ch;
9409     const xmlChar *point;
9410     xmlChar *cptr;
9411 
9412     CHECK_ARITY(3);
9413 
9414     CAST_TO_STRING;
9415     to = valuePop(ctxt);
9416     CAST_TO_STRING;
9417     from = valuePop(ctxt);
9418     CAST_TO_STRING;
9419     str = valuePop(ctxt);
9420 
9421     target = xmlBufCreate();
9422     if (target) {
9423 	max = xmlUTF8Strlen(to->stringval);
9424 	for (cptr = str->stringval; (ch=*cptr); ) {
9425 	    offset = xmlUTF8Strloc(from->stringval, cptr);
9426 	    if (offset >= 0) {
9427 		if (offset < max) {
9428 		    point = xmlUTF8Strpos(to->stringval, offset);
9429 		    if (point)
9430 			xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9431 		}
9432 	    } else
9433 		xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9434 
9435 	    /* Step to next character in input */
9436 	    cptr++;
9437 	    if ( ch & 0x80 ) {
9438 		/* if not simple ascii, verify proper format */
9439 		if ( (ch & 0xc0) != 0xc0 ) {
9440 		    xmlGenericError(xmlGenericErrorContext,
9441 			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
9442                     /* not asserting an XPath error is probably better */
9443 		    break;
9444 		}
9445 		/* then skip over remaining bytes for this char */
9446 		while ( (ch <<= 1) & 0x80 )
9447 		    if ( (*cptr++ & 0xc0) != 0x80 ) {
9448 			xmlGenericError(xmlGenericErrorContext,
9449 			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9450                         /* not asserting an XPath error is probably better */
9451 			break;
9452 		    }
9453 		if (ch & 0x80) /* must have had error encountered */
9454 		    break;
9455 	    }
9456 	}
9457     }
9458     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9459 	xmlBufContent(target)));
9460     xmlBufFree(target);
9461     xmlXPathReleaseObject(ctxt->context, str);
9462     xmlXPathReleaseObject(ctxt->context, from);
9463     xmlXPathReleaseObject(ctxt->context, to);
9464 }
9465 
9466 /**
9467  * xmlXPathBooleanFunction:
9468  * @ctxt:  the XPath Parser context
9469  * @nargs:  the number of arguments
9470  *
9471  * Implement the boolean() XPath function
9472  *    boolean boolean(object)
9473  * The boolean function converts its argument to a boolean as follows:
9474  *    - a number is true if and only if it is neither positive or
9475  *      negative zero nor NaN
9476  *    - a node-set is true if and only if it is non-empty
9477  *    - a string is true if and only if its length is non-zero
9478  */
9479 void
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt,int nargs)9480 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9481     xmlXPathObjectPtr cur;
9482 
9483     CHECK_ARITY(1);
9484     cur = valuePop(ctxt);
9485     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9486     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9487     valuePush(ctxt, cur);
9488 }
9489 
9490 /**
9491  * xmlXPathNotFunction:
9492  * @ctxt:  the XPath Parser context
9493  * @nargs:  the number of arguments
9494  *
9495  * Implement the not() XPath function
9496  *    boolean not(boolean)
9497  * The not function returns true if its argument is false,
9498  * and false otherwise.
9499  */
9500 void
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt,int nargs)9501 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9502     CHECK_ARITY(1);
9503     CAST_TO_BOOLEAN;
9504     CHECK_TYPE(XPATH_BOOLEAN);
9505     ctxt->value->boolval = ! ctxt->value->boolval;
9506 }
9507 
9508 /**
9509  * xmlXPathTrueFunction:
9510  * @ctxt:  the XPath Parser context
9511  * @nargs:  the number of arguments
9512  *
9513  * Implement the true() XPath function
9514  *    boolean true()
9515  */
9516 void
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt,int nargs)9517 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9518     CHECK_ARITY(0);
9519     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9520 }
9521 
9522 /**
9523  * xmlXPathFalseFunction:
9524  * @ctxt:  the XPath Parser context
9525  * @nargs:  the number of arguments
9526  *
9527  * Implement the false() XPath function
9528  *    boolean false()
9529  */
9530 void
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt,int nargs)9531 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9532     CHECK_ARITY(0);
9533     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9534 }
9535 
9536 /**
9537  * xmlXPathLangFunction:
9538  * @ctxt:  the XPath Parser context
9539  * @nargs:  the number of arguments
9540  *
9541  * Implement the lang() XPath function
9542  *    boolean lang(string)
9543  * The lang function returns true or false depending on whether the
9544  * language of the context node as specified by xml:lang attributes
9545  * is the same as or is a sublanguage of the language specified by
9546  * the argument string. The language of the context node is determined
9547  * by the value of the xml:lang attribute on the context node, or, if
9548  * the context node has no xml:lang attribute, by the value of the
9549  * xml:lang attribute on the nearest ancestor of the context node that
9550  * has an xml:lang attribute. If there is no such attribute, then lang
9551  * returns false. If there is such an attribute, then lang returns
9552  * true if the attribute value is equal to the argument ignoring case,
9553  * or if there is some suffix starting with - such that the attribute
9554  * value is equal to the argument ignoring that suffix of the attribute
9555  * value and ignoring case.
9556  */
9557 void
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt,int nargs)9558 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9559     xmlXPathObjectPtr val = NULL;
9560     const xmlChar *theLang = NULL;
9561     const xmlChar *lang;
9562     int ret = 0;
9563     int i;
9564 
9565     CHECK_ARITY(1);
9566     CAST_TO_STRING;
9567     CHECK_TYPE(XPATH_STRING);
9568     val = valuePop(ctxt);
9569     lang = val->stringval;
9570     theLang = xmlNodeGetLang(ctxt->context->node);
9571     if ((theLang != NULL) && (lang != NULL)) {
9572         for (i = 0;lang[i] != 0;i++)
9573 	    if (toupper(lang[i]) != toupper(theLang[i]))
9574 	        goto not_equal;
9575 	if ((theLang[i] == 0) || (theLang[i] == '-'))
9576 	    ret = 1;
9577     }
9578 not_equal:
9579     if (theLang != NULL)
9580 	xmlFree((void *)theLang);
9581 
9582     xmlXPathReleaseObject(ctxt->context, val);
9583     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9584 }
9585 
9586 /**
9587  * xmlXPathNumberFunction:
9588  * @ctxt:  the XPath Parser context
9589  * @nargs:  the number of arguments
9590  *
9591  * Implement the number() XPath function
9592  *    number number(object?)
9593  */
9594 void
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt,int nargs)9595 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9596     xmlXPathObjectPtr cur;
9597     double res;
9598 
9599     if (ctxt == NULL) return;
9600     if (nargs == 0) {
9601 	if (ctxt->context->node == NULL) {
9602 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9603 	} else {
9604 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9605 
9606 	    res = xmlXPathStringEvalNumber(content);
9607 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9608 	    xmlFree(content);
9609 	}
9610 	return;
9611     }
9612 
9613     CHECK_ARITY(1);
9614     cur = valuePop(ctxt);
9615     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9616 }
9617 
9618 /**
9619  * xmlXPathSumFunction:
9620  * @ctxt:  the XPath Parser context
9621  * @nargs:  the number of arguments
9622  *
9623  * Implement the sum() XPath function
9624  *    number sum(node-set)
9625  * The sum function returns the sum of the values of the nodes in
9626  * the argument node-set.
9627  */
9628 void
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt,int nargs)9629 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9630     xmlXPathObjectPtr cur;
9631     int i;
9632     double res = 0.0;
9633 
9634     CHECK_ARITY(1);
9635     if ((ctxt->value == NULL) ||
9636 	((ctxt->value->type != XPATH_NODESET) &&
9637 	 (ctxt->value->type != XPATH_XSLT_TREE)))
9638 	XP_ERROR(XPATH_INVALID_TYPE);
9639     cur = valuePop(ctxt);
9640 
9641     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9642 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9643 	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9644 	}
9645     }
9646     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9647     xmlXPathReleaseObject(ctxt->context, cur);
9648 }
9649 
9650 /**
9651  * xmlXPathFloorFunction:
9652  * @ctxt:  the XPath Parser context
9653  * @nargs:  the number of arguments
9654  *
9655  * Implement the floor() XPath function
9656  *    number floor(number)
9657  * The floor function returns the largest (closest to positive infinity)
9658  * number that is not greater than the argument and that is an integer.
9659  */
9660 void
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt,int nargs)9661 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9662     CHECK_ARITY(1);
9663     CAST_TO_NUMBER;
9664     CHECK_TYPE(XPATH_NUMBER);
9665 
9666     ctxt->value->floatval = floor(ctxt->value->floatval);
9667 }
9668 
9669 /**
9670  * xmlXPathCeilingFunction:
9671  * @ctxt:  the XPath Parser context
9672  * @nargs:  the number of arguments
9673  *
9674  * Implement the ceiling() XPath function
9675  *    number ceiling(number)
9676  * The ceiling function returns the smallest (closest to negative infinity)
9677  * number that is not less than the argument and that is an integer.
9678  */
9679 void
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt,int nargs)9680 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9681     CHECK_ARITY(1);
9682     CAST_TO_NUMBER;
9683     CHECK_TYPE(XPATH_NUMBER);
9684 
9685     ctxt->value->floatval = ceil(ctxt->value->floatval);
9686 }
9687 
9688 /**
9689  * xmlXPathRoundFunction:
9690  * @ctxt:  the XPath Parser context
9691  * @nargs:  the number of arguments
9692  *
9693  * Implement the round() XPath function
9694  *    number round(number)
9695  * The round function returns the number that is closest to the
9696  * argument and that is an integer. If there are two such numbers,
9697  * then the one that is closest to positive infinity is returned.
9698  */
9699 void
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt,int nargs)9700 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9701     double f;
9702 
9703     CHECK_ARITY(1);
9704     CAST_TO_NUMBER;
9705     CHECK_TYPE(XPATH_NUMBER);
9706 
9707     f = ctxt->value->floatval;
9708 
9709     if ((f >= -0.5) && (f < 0.5)) {
9710         /* Handles negative zero. */
9711         ctxt->value->floatval *= 0.0;
9712     }
9713     else {
9714         double rounded = floor(f);
9715         if (f - rounded >= 0.5)
9716             rounded += 1.0;
9717         ctxt->value->floatval = rounded;
9718     }
9719 }
9720 
9721 /************************************************************************
9722  *									*
9723  *			The Parser					*
9724  *									*
9725  ************************************************************************/
9726 
9727 /*
9728  * a few forward declarations since we use a recursive call based
9729  * implementation.
9730  */
9731 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9732 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9733 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9734 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9735 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9736 	                                  int qualified);
9737 
9738 /**
9739  * xmlXPathCurrentChar:
9740  * @ctxt:  the XPath parser context
9741  * @cur:  pointer to the beginning of the char
9742  * @len:  pointer to the length of the char read
9743  *
9744  * The current char value, if using UTF-8 this may actually span multiple
9745  * bytes in the input buffer.
9746  *
9747  * Returns the current char value and its length
9748  */
9749 
9750 static int
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt,int * len)9751 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9752     unsigned char c;
9753     unsigned int val;
9754     const xmlChar *cur;
9755 
9756     if (ctxt == NULL)
9757 	return(0);
9758     cur = ctxt->cur;
9759 
9760     /*
9761      * We are supposed to handle UTF8, check it's valid
9762      * From rfc2044: encoding of the Unicode values on UTF-8:
9763      *
9764      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9765      * 0000 0000-0000 007F   0xxxxxxx
9766      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9767      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9768      *
9769      * Check for the 0x110000 limit too
9770      */
9771     c = *cur;
9772     if (c & 0x80) {
9773 	if ((cur[1] & 0xc0) != 0x80)
9774 	    goto encoding_error;
9775 	if ((c & 0xe0) == 0xe0) {
9776 
9777 	    if ((cur[2] & 0xc0) != 0x80)
9778 		goto encoding_error;
9779 	    if ((c & 0xf0) == 0xf0) {
9780 		if (((c & 0xf8) != 0xf0) ||
9781 		    ((cur[3] & 0xc0) != 0x80))
9782 		    goto encoding_error;
9783 		/* 4-byte code */
9784 		*len = 4;
9785 		val = (cur[0] & 0x7) << 18;
9786 		val |= (cur[1] & 0x3f) << 12;
9787 		val |= (cur[2] & 0x3f) << 6;
9788 		val |= cur[3] & 0x3f;
9789 	    } else {
9790 	      /* 3-byte code */
9791 		*len = 3;
9792 		val = (cur[0] & 0xf) << 12;
9793 		val |= (cur[1] & 0x3f) << 6;
9794 		val |= cur[2] & 0x3f;
9795 	    }
9796 	} else {
9797 	  /* 2-byte code */
9798 	    *len = 2;
9799 	    val = (cur[0] & 0x1f) << 6;
9800 	    val |= cur[1] & 0x3f;
9801 	}
9802 	if (!IS_CHAR(val)) {
9803 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9804 	}
9805 	return(val);
9806     } else {
9807 	/* 1-byte code */
9808 	*len = 1;
9809 	return((int) *cur);
9810     }
9811 encoding_error:
9812     /*
9813      * If we detect an UTF8 error that probably means that the
9814      * input encoding didn't get properly advertised in the
9815      * declaration header. Report the error and switch the encoding
9816      * to ISO-Latin-1 (if you don't like this policy, just declare the
9817      * encoding !)
9818      */
9819     *len = 0;
9820     XP_ERROR0(XPATH_ENCODING_ERROR);
9821 }
9822 
9823 /**
9824  * xmlXPathParseNCName:
9825  * @ctxt:  the XPath Parser context
9826  *
9827  * parse an XML namespace non qualified name.
9828  *
9829  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9830  *
9831  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9832  *                       CombiningChar | Extender
9833  *
9834  * Returns the namespace name or NULL
9835  */
9836 
9837 xmlChar *
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt)9838 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9839     const xmlChar *in;
9840     xmlChar *ret;
9841     int count = 0;
9842 
9843     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9844     /*
9845      * Accelerator for simple ASCII names
9846      */
9847     in = ctxt->cur;
9848     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9849 	((*in >= 0x41) && (*in <= 0x5A)) ||
9850 	(*in == '_')) {
9851 	in++;
9852 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9853 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9854 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9855 	       (*in == '_') || (*in == '.') ||
9856 	       (*in == '-'))
9857 	    in++;
9858 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9859             (*in == '[') || (*in == ']') || (*in == ':') ||
9860             (*in == '@') || (*in == '*')) {
9861 	    count = in - ctxt->cur;
9862 	    if (count == 0)
9863 		return(NULL);
9864 	    ret = xmlStrndup(ctxt->cur, count);
9865 	    ctxt->cur = in;
9866 	    return(ret);
9867 	}
9868     }
9869     return(xmlXPathParseNameComplex(ctxt, 0));
9870 }
9871 
9872 
9873 /**
9874  * xmlXPathParseQName:
9875  * @ctxt:  the XPath Parser context
9876  * @prefix:  a xmlChar **
9877  *
9878  * parse an XML qualified name
9879  *
9880  * [NS 5] QName ::= (Prefix ':')? LocalPart
9881  *
9882  * [NS 6] Prefix ::= NCName
9883  *
9884  * [NS 7] LocalPart ::= NCName
9885  *
9886  * Returns the function returns the local part, and prefix is updated
9887  *   to get the Prefix if any.
9888  */
9889 
9890 static xmlChar *
xmlXPathParseQName(xmlXPathParserContextPtr ctxt,xmlChar ** prefix)9891 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9892     xmlChar *ret = NULL;
9893 
9894     *prefix = NULL;
9895     ret = xmlXPathParseNCName(ctxt);
9896     if (ret && CUR == ':') {
9897         *prefix = ret;
9898 	NEXT;
9899 	ret = xmlXPathParseNCName(ctxt);
9900     }
9901     return(ret);
9902 }
9903 
9904 /**
9905  * xmlXPathParseName:
9906  * @ctxt:  the XPath Parser context
9907  *
9908  * parse an XML name
9909  *
9910  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9911  *                  CombiningChar | Extender
9912  *
9913  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9914  *
9915  * Returns the namespace name or NULL
9916  */
9917 
9918 xmlChar *
xmlXPathParseName(xmlXPathParserContextPtr ctxt)9919 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9920     const xmlChar *in;
9921     xmlChar *ret;
9922     size_t count = 0;
9923 
9924     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9925     /*
9926      * Accelerator for simple ASCII names
9927      */
9928     in = ctxt->cur;
9929     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9930 	((*in >= 0x41) && (*in <= 0x5A)) ||
9931 	(*in == '_') || (*in == ':')) {
9932 	in++;
9933 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9934 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9935 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9936 	       (*in == '_') || (*in == '-') ||
9937 	       (*in == ':') || (*in == '.'))
9938 	    in++;
9939 	if ((*in > 0) && (*in < 0x80)) {
9940 	    count = in - ctxt->cur;
9941             if (count > XML_MAX_NAME_LENGTH) {
9942                 ctxt->cur = in;
9943                 XP_ERRORNULL(XPATH_EXPR_ERROR);
9944             }
9945 	    ret = xmlStrndup(ctxt->cur, count);
9946 	    ctxt->cur = in;
9947 	    return(ret);
9948 	}
9949     }
9950     return(xmlXPathParseNameComplex(ctxt, 1));
9951 }
9952 
9953 static xmlChar *
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,int qualified)9954 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9955     xmlChar buf[XML_MAX_NAMELEN + 5];
9956     int len = 0, l;
9957     int c;
9958 
9959     /*
9960      * Handler for more complex cases
9961      */
9962     c = CUR_CHAR(l);
9963     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9964         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9965         (c == '*') || /* accelerators */
9966 	(!IS_LETTER(c) && (c != '_') &&
9967          ((!qualified) || (c != ':')))) {
9968 	return(NULL);
9969     }
9970 
9971     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9972 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9973             (c == '.') || (c == '-') ||
9974 	    (c == '_') || ((qualified) && (c == ':')) ||
9975 	    (IS_COMBINING(c)) ||
9976 	    (IS_EXTENDER(c)))) {
9977 	COPY_BUF(l,buf,len,c);
9978 	NEXTL(l);
9979 	c = CUR_CHAR(l);
9980 	if (len >= XML_MAX_NAMELEN) {
9981 	    /*
9982 	     * Okay someone managed to make a huge name, so he's ready to pay
9983 	     * for the processing speed.
9984 	     */
9985 	    xmlChar *buffer;
9986 	    int max = len * 2;
9987 
9988             if (len > XML_MAX_NAME_LENGTH) {
9989                 XP_ERRORNULL(XPATH_EXPR_ERROR);
9990             }
9991 	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9992 	    if (buffer == NULL) {
9993 		XP_ERRORNULL(XPATH_MEMORY_ERROR);
9994 	    }
9995 	    memcpy(buffer, buf, len);
9996 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9997 		   (c == '.') || (c == '-') ||
9998 		   (c == '_') || ((qualified) && (c == ':')) ||
9999 		   (IS_COMBINING(c)) ||
10000 		   (IS_EXTENDER(c))) {
10001 		if (len + 10 > max) {
10002                     if (max > XML_MAX_NAME_LENGTH) {
10003                         XP_ERRORNULL(XPATH_EXPR_ERROR);
10004                     }
10005 		    max *= 2;
10006 		    buffer = (xmlChar *) xmlRealloc(buffer,
10007 			                            max * sizeof(xmlChar));
10008 		    if (buffer == NULL) {
10009 			XP_ERRORNULL(XPATH_MEMORY_ERROR);
10010 		    }
10011 		}
10012 		COPY_BUF(l,buffer,len,c);
10013 		NEXTL(l);
10014 		c = CUR_CHAR(l);
10015 	    }
10016 	    buffer[len] = 0;
10017 	    return(buffer);
10018 	}
10019     }
10020     if (len == 0)
10021 	return(NULL);
10022     return(xmlStrndup(buf, len));
10023 }
10024 
10025 #define MAX_FRAC 20
10026 
10027 /**
10028  * xmlXPathStringEvalNumber:
10029  * @str:  A string to scan
10030  *
10031  *  [30a]  Float  ::= Number ('e' Digits?)?
10032  *
10033  *  [30]   Number ::=   Digits ('.' Digits?)?
10034  *                    | '.' Digits
10035  *  [31]   Digits ::=   [0-9]+
10036  *
10037  * Compile a Number in the string
10038  * In complement of the Number expression, this function also handles
10039  * negative values : '-' Number.
10040  *
10041  * Returns the double value.
10042  */
10043 double
xmlXPathStringEvalNumber(const xmlChar * str)10044 xmlXPathStringEvalNumber(const xmlChar *str) {
10045     const xmlChar *cur = str;
10046     double ret;
10047     int ok = 0;
10048     int isneg = 0;
10049     int exponent = 0;
10050     int is_exponent_negative = 0;
10051 #ifdef __GNUC__
10052     unsigned long tmp = 0;
10053     double temp;
10054 #endif
10055     if (cur == NULL) return(0);
10056     while (IS_BLANK_CH(*cur)) cur++;
10057     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10058         return(NAN);
10059     }
10060     if (*cur == '-') {
10061 	isneg = 1;
10062 	cur++;
10063     }
10064 
10065 #ifdef __GNUC__
10066     /*
10067      * tmp/temp is a workaround against a gcc compiler bug
10068      * http://veillard.com/gcc.bug
10069      */
10070     ret = 0;
10071     while ((*cur >= '0') && (*cur <= '9')) {
10072 	ret = ret * 10;
10073 	tmp = (*cur - '0');
10074 	ok = 1;
10075 	cur++;
10076 	temp = (double) tmp;
10077 	ret = ret + temp;
10078     }
10079 #else
10080     ret = 0;
10081     while ((*cur >= '0') && (*cur <= '9')) {
10082 	ret = ret * 10 + (*cur - '0');
10083 	ok = 1;
10084 	cur++;
10085     }
10086 #endif
10087 
10088     if (*cur == '.') {
10089 	int v, frac = 0, max;
10090 	double fraction = 0;
10091 
10092         cur++;
10093 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10094 	    return(NAN);
10095 	}
10096         while (*cur == '0') {
10097 	    frac = frac + 1;
10098 	    cur++;
10099         }
10100         max = frac + MAX_FRAC;
10101 	while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10102 	    v = (*cur - '0');
10103 	    fraction = fraction * 10 + v;
10104 	    frac = frac + 1;
10105 	    cur++;
10106 	}
10107 	fraction /= pow(10.0, frac);
10108 	ret = ret + fraction;
10109 	while ((*cur >= '0') && (*cur <= '9'))
10110 	    cur++;
10111     }
10112     if ((*cur == 'e') || (*cur == 'E')) {
10113       cur++;
10114       if (*cur == '-') {
10115 	is_exponent_negative = 1;
10116 	cur++;
10117       } else if (*cur == '+') {
10118         cur++;
10119       }
10120       while ((*cur >= '0') && (*cur <= '9')) {
10121         if (exponent < 1000000)
10122 	  exponent = exponent * 10 + (*cur - '0');
10123 	cur++;
10124       }
10125     }
10126     while (IS_BLANK_CH(*cur)) cur++;
10127     if (*cur != 0) return(NAN);
10128     if (isneg) ret = -ret;
10129     if (is_exponent_negative) exponent = -exponent;
10130     ret *= pow(10.0, (double)exponent);
10131     return(ret);
10132 }
10133 
10134 /**
10135  * xmlXPathCompNumber:
10136  * @ctxt:  the XPath Parser context
10137  *
10138  *  [30]   Number ::=   Digits ('.' Digits?)?
10139  *                    | '.' Digits
10140  *  [31]   Digits ::=   [0-9]+
10141  *
10142  * Compile a Number, then push it on the stack
10143  *
10144  */
10145 static void
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)10146 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10147 {
10148     double ret = 0.0;
10149     int ok = 0;
10150     int exponent = 0;
10151     int is_exponent_negative = 0;
10152 #ifdef __GNUC__
10153     unsigned long tmp = 0;
10154     double temp;
10155 #endif
10156 
10157     CHECK_ERROR;
10158     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10159         XP_ERROR(XPATH_NUMBER_ERROR);
10160     }
10161 #ifdef __GNUC__
10162     /*
10163      * tmp/temp is a workaround against a gcc compiler bug
10164      * http://veillard.com/gcc.bug
10165      */
10166     ret = 0;
10167     while ((CUR >= '0') && (CUR <= '9')) {
10168 	ret = ret * 10;
10169 	tmp = (CUR - '0');
10170         ok = 1;
10171         NEXT;
10172 	temp = (double) tmp;
10173 	ret = ret + temp;
10174     }
10175 #else
10176     ret = 0;
10177     while ((CUR >= '0') && (CUR <= '9')) {
10178 	ret = ret * 10 + (CUR - '0');
10179 	ok = 1;
10180 	NEXT;
10181     }
10182 #endif
10183     if (CUR == '.') {
10184 	int v, frac = 0, max;
10185 	double fraction = 0;
10186 
10187         NEXT;
10188         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10189             XP_ERROR(XPATH_NUMBER_ERROR);
10190         }
10191         while (CUR == '0') {
10192             frac = frac + 1;
10193             NEXT;
10194         }
10195         max = frac + MAX_FRAC;
10196         while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10197 	    v = (CUR - '0');
10198 	    fraction = fraction * 10 + v;
10199 	    frac = frac + 1;
10200             NEXT;
10201         }
10202         fraction /= pow(10.0, frac);
10203         ret = ret + fraction;
10204         while ((CUR >= '0') && (CUR <= '9'))
10205             NEXT;
10206     }
10207     if ((CUR == 'e') || (CUR == 'E')) {
10208         NEXT;
10209         if (CUR == '-') {
10210             is_exponent_negative = 1;
10211             NEXT;
10212         } else if (CUR == '+') {
10213 	    NEXT;
10214 	}
10215         while ((CUR >= '0') && (CUR <= '9')) {
10216             if (exponent < 1000000)
10217                 exponent = exponent * 10 + (CUR - '0');
10218             NEXT;
10219         }
10220         if (is_exponent_negative)
10221             exponent = -exponent;
10222         ret *= pow(10.0, (double) exponent);
10223     }
10224     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10225                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10226 }
10227 
10228 /**
10229  * xmlXPathParseLiteral:
10230  * @ctxt:  the XPath Parser context
10231  *
10232  * Parse a Literal
10233  *
10234  *  [29]   Literal ::=   '"' [^"]* '"'
10235  *                    | "'" [^']* "'"
10236  *
10237  * Returns the value found or NULL in case of error
10238  */
10239 static xmlChar *
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt)10240 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10241     const xmlChar *q;
10242     xmlChar *ret = NULL;
10243 
10244     if (CUR == '"') {
10245         NEXT;
10246 	q = CUR_PTR;
10247 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10248 	    NEXT;
10249 	if (!IS_CHAR_CH(CUR)) {
10250 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10251 	} else {
10252 	    ret = xmlStrndup(q, CUR_PTR - q);
10253 	    NEXT;
10254         }
10255     } else if (CUR == '\'') {
10256         NEXT;
10257 	q = CUR_PTR;
10258 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10259 	    NEXT;
10260 	if (!IS_CHAR_CH(CUR)) {
10261 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10262 	} else {
10263 	    ret = xmlStrndup(q, CUR_PTR - q);
10264 	    NEXT;
10265         }
10266     } else {
10267 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10268     }
10269     return(ret);
10270 }
10271 
10272 /**
10273  * xmlXPathCompLiteral:
10274  * @ctxt:  the XPath Parser context
10275  *
10276  * Parse a Literal and push it on the stack.
10277  *
10278  *  [29]   Literal ::=   '"' [^"]* '"'
10279  *                    | "'" [^']* "'"
10280  *
10281  * TODO: xmlXPathCompLiteral memory allocation could be improved.
10282  */
10283 static void
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt)10284 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10285     const xmlChar *q;
10286     xmlChar *ret = NULL;
10287 
10288     if (CUR == '"') {
10289         NEXT;
10290 	q = CUR_PTR;
10291 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10292 	    NEXT;
10293 	if (!IS_CHAR_CH(CUR)) {
10294 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10295 	} else {
10296 	    ret = xmlStrndup(q, CUR_PTR - q);
10297 	    NEXT;
10298         }
10299     } else if (CUR == '\'') {
10300         NEXT;
10301 	q = CUR_PTR;
10302 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10303 	    NEXT;
10304 	if (!IS_CHAR_CH(CUR)) {
10305 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10306 	} else {
10307 	    ret = xmlStrndup(q, CUR_PTR - q);
10308 	    NEXT;
10309         }
10310     } else {
10311 	XP_ERROR(XPATH_START_LITERAL_ERROR);
10312     }
10313     if (ret == NULL) return;
10314     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10315 	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
10316     xmlFree(ret);
10317 }
10318 
10319 /**
10320  * xmlXPathCompVariableReference:
10321  * @ctxt:  the XPath Parser context
10322  *
10323  * Parse a VariableReference, evaluate it and push it on the stack.
10324  *
10325  * The variable bindings consist of a mapping from variable names
10326  * to variable values. The value of a variable is an object, which can be
10327  * of any of the types that are possible for the value of an expression,
10328  * and may also be of additional types not specified here.
10329  *
10330  * Early evaluation is possible since:
10331  * The variable bindings [...] used to evaluate a subexpression are
10332  * always the same as those used to evaluate the containing expression.
10333  *
10334  *  [36]   VariableReference ::=   '$' QName
10335  */
10336 static void
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt)10337 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10338     xmlChar *name;
10339     xmlChar *prefix;
10340 
10341     SKIP_BLANKS;
10342     if (CUR != '$') {
10343 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10344     }
10345     NEXT;
10346     name = xmlXPathParseQName(ctxt, &prefix);
10347     if (name == NULL) {
10348         xmlFree(prefix);
10349 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10350     }
10351     ctxt->comp->last = -1;
10352     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10353 	           name, prefix);
10354     SKIP_BLANKS;
10355     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10356 	XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10357     }
10358 }
10359 
10360 /**
10361  * xmlXPathIsNodeType:
10362  * @name:  a name string
10363  *
10364  * Is the name given a NodeType one.
10365  *
10366  *  [38]   NodeType ::=   'comment'
10367  *                    | 'text'
10368  *                    | 'processing-instruction'
10369  *                    | 'node'
10370  *
10371  * Returns 1 if true 0 otherwise
10372  */
10373 int
xmlXPathIsNodeType(const xmlChar * name)10374 xmlXPathIsNodeType(const xmlChar *name) {
10375     if (name == NULL)
10376 	return(0);
10377 
10378     if (xmlStrEqual(name, BAD_CAST "node"))
10379 	return(1);
10380     if (xmlStrEqual(name, BAD_CAST "text"))
10381 	return(1);
10382     if (xmlStrEqual(name, BAD_CAST "comment"))
10383 	return(1);
10384     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10385 	return(1);
10386     return(0);
10387 }
10388 
10389 /**
10390  * xmlXPathCompFunctionCall:
10391  * @ctxt:  the XPath Parser context
10392  *
10393  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10394  *  [17]   Argument ::=   Expr
10395  *
10396  * Compile a function call, the evaluation of all arguments are
10397  * pushed on the stack
10398  */
10399 static void
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt)10400 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10401     xmlChar *name;
10402     xmlChar *prefix;
10403     int nbargs = 0;
10404     int sort = 1;
10405 
10406     name = xmlXPathParseQName(ctxt, &prefix);
10407     if (name == NULL) {
10408 	xmlFree(prefix);
10409 	XP_ERROR(XPATH_EXPR_ERROR);
10410     }
10411     SKIP_BLANKS;
10412 #ifdef DEBUG_EXPR
10413     if (prefix == NULL)
10414 	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10415 			name);
10416     else
10417 	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10418 			prefix, name);
10419 #endif
10420 
10421     if (CUR != '(') {
10422 	xmlFree(name);
10423 	xmlFree(prefix);
10424 	XP_ERROR(XPATH_EXPR_ERROR);
10425     }
10426     NEXT;
10427     SKIP_BLANKS;
10428 
10429     /*
10430     * Optimization for count(): we don't need the node-set to be sorted.
10431     */
10432     if ((prefix == NULL) && (name[0] == 'c') &&
10433 	xmlStrEqual(name, BAD_CAST "count"))
10434     {
10435 	sort = 0;
10436     }
10437     ctxt->comp->last = -1;
10438     if (CUR != ')') {
10439 	while (CUR != 0) {
10440 	    int op1 = ctxt->comp->last;
10441 	    ctxt->comp->last = -1;
10442 	    xmlXPathCompileExpr(ctxt, sort);
10443 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
10444 		xmlFree(name);
10445 		xmlFree(prefix);
10446 		return;
10447 	    }
10448 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10449 	    nbargs++;
10450 	    if (CUR == ')') break;
10451 	    if (CUR != ',') {
10452 		xmlFree(name);
10453 		xmlFree(prefix);
10454 		XP_ERROR(XPATH_EXPR_ERROR);
10455 	    }
10456 	    NEXT;
10457 	    SKIP_BLANKS;
10458 	}
10459     }
10460     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10461 	           name, prefix);
10462     NEXT;
10463     SKIP_BLANKS;
10464 }
10465 
10466 /**
10467  * xmlXPathCompPrimaryExpr:
10468  * @ctxt:  the XPath Parser context
10469  *
10470  *  [15]   PrimaryExpr ::=   VariableReference
10471  *                | '(' Expr ')'
10472  *                | Literal
10473  *                | Number
10474  *                | FunctionCall
10475  *
10476  * Compile a primary expression.
10477  */
10478 static void
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt)10479 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10480     SKIP_BLANKS;
10481     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10482     else if (CUR == '(') {
10483 	NEXT;
10484 	SKIP_BLANKS;
10485 	xmlXPathCompileExpr(ctxt, 1);
10486 	CHECK_ERROR;
10487 	if (CUR != ')') {
10488 	    XP_ERROR(XPATH_EXPR_ERROR);
10489 	}
10490 	NEXT;
10491 	SKIP_BLANKS;
10492     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10493 	xmlXPathCompNumber(ctxt);
10494     } else if ((CUR == '\'') || (CUR == '"')) {
10495 	xmlXPathCompLiteral(ctxt);
10496     } else {
10497 	xmlXPathCompFunctionCall(ctxt);
10498     }
10499     SKIP_BLANKS;
10500 }
10501 
10502 /**
10503  * xmlXPathCompFilterExpr:
10504  * @ctxt:  the XPath Parser context
10505  *
10506  *  [20]   FilterExpr ::=   PrimaryExpr
10507  *               | FilterExpr Predicate
10508  *
10509  * Compile a filter expression.
10510  * Square brackets are used to filter expressions in the same way that
10511  * they are used in location paths. It is an error if the expression to
10512  * be filtered does not evaluate to a node-set. The context node list
10513  * used for evaluating the expression in square brackets is the node-set
10514  * to be filtered listed in document order.
10515  */
10516 
10517 static void
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt)10518 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10519     xmlXPathCompPrimaryExpr(ctxt);
10520     CHECK_ERROR;
10521     SKIP_BLANKS;
10522 
10523     while (CUR == '[') {
10524 	xmlXPathCompPredicate(ctxt, 1);
10525 	SKIP_BLANKS;
10526     }
10527 
10528 
10529 }
10530 
10531 /**
10532  * xmlXPathScanName:
10533  * @ctxt:  the XPath Parser context
10534  *
10535  * Trickery: parse an XML name but without consuming the input flow
10536  * Needed to avoid insanity in the parser state.
10537  *
10538  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10539  *                  CombiningChar | Extender
10540  *
10541  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10542  *
10543  * [6] Names ::= Name (S Name)*
10544  *
10545  * Returns the Name parsed or NULL
10546  */
10547 
10548 static xmlChar *
xmlXPathScanName(xmlXPathParserContextPtr ctxt)10549 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10550     int len = 0, l;
10551     int c;
10552     const xmlChar *cur;
10553     xmlChar *ret;
10554 
10555     cur = ctxt->cur;
10556 
10557     c = CUR_CHAR(l);
10558     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10559 	(!IS_LETTER(c) && (c != '_') &&
10560          (c != ':'))) {
10561 	return(NULL);
10562     }
10563 
10564     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10565 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10566             (c == '.') || (c == '-') ||
10567 	    (c == '_') || (c == ':') ||
10568 	    (IS_COMBINING(c)) ||
10569 	    (IS_EXTENDER(c)))) {
10570 	len += l;
10571 	NEXTL(l);
10572 	c = CUR_CHAR(l);
10573     }
10574     ret = xmlStrndup(cur, ctxt->cur - cur);
10575     ctxt->cur = cur;
10576     return(ret);
10577 }
10578 
10579 /**
10580  * xmlXPathCompPathExpr:
10581  * @ctxt:  the XPath Parser context
10582  *
10583  *  [19]   PathExpr ::=   LocationPath
10584  *               | FilterExpr
10585  *               | FilterExpr '/' RelativeLocationPath
10586  *               | FilterExpr '//' RelativeLocationPath
10587  *
10588  * Compile a path expression.
10589  * The / operator and // operators combine an arbitrary expression
10590  * and a relative location path. It is an error if the expression
10591  * does not evaluate to a node-set.
10592  * The / operator does composition in the same way as when / is
10593  * used in a location path. As in location paths, // is short for
10594  * /descendant-or-self::node()/.
10595  */
10596 
10597 static void
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt)10598 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10599     int lc = 1;           /* Should we branch to LocationPath ?         */
10600     xmlChar *name = NULL; /* we may have to preparse a name to find out */
10601 
10602     SKIP_BLANKS;
10603     if ((CUR == '$') || (CUR == '(') ||
10604 	(IS_ASCII_DIGIT(CUR)) ||
10605         (CUR == '\'') || (CUR == '"') ||
10606 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10607 	lc = 0;
10608     } else if (CUR == '*') {
10609 	/* relative or absolute location path */
10610 	lc = 1;
10611     } else if (CUR == '/') {
10612 	/* relative or absolute location path */
10613 	lc = 1;
10614     } else if (CUR == '@') {
10615 	/* relative abbreviated attribute location path */
10616 	lc = 1;
10617     } else if (CUR == '.') {
10618 	/* relative abbreviated attribute location path */
10619 	lc = 1;
10620     } else {
10621 	/*
10622 	 * Problem is finding if we have a name here whether it's:
10623 	 *   - a nodetype
10624 	 *   - a function call in which case it's followed by '('
10625 	 *   - an axis in which case it's followed by ':'
10626 	 *   - a element name
10627 	 * We do an a priori analysis here rather than having to
10628 	 * maintain parsed token content through the recursive function
10629 	 * calls. This looks uglier but makes the code easier to
10630 	 * read/write/debug.
10631 	 */
10632 	SKIP_BLANKS;
10633 	name = xmlXPathScanName(ctxt);
10634 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10635 #ifdef DEBUG_STEP
10636 	    xmlGenericError(xmlGenericErrorContext,
10637 		    "PathExpr: Axis\n");
10638 #endif
10639 	    lc = 1;
10640 	    xmlFree(name);
10641 	} else if (name != NULL) {
10642 	    int len =xmlStrlen(name);
10643 
10644 
10645 	    while (NXT(len) != 0) {
10646 		if (NXT(len) == '/') {
10647 		    /* element name */
10648 #ifdef DEBUG_STEP
10649 		    xmlGenericError(xmlGenericErrorContext,
10650 			    "PathExpr: AbbrRelLocation\n");
10651 #endif
10652 		    lc = 1;
10653 		    break;
10654 		} else if (IS_BLANK_CH(NXT(len))) {
10655 		    /* ignore blanks */
10656 		    ;
10657 		} else if (NXT(len) == ':') {
10658 #ifdef DEBUG_STEP
10659 		    xmlGenericError(xmlGenericErrorContext,
10660 			    "PathExpr: AbbrRelLocation\n");
10661 #endif
10662 		    lc = 1;
10663 		    break;
10664 		} else if ((NXT(len) == '(')) {
10665 		    /* Node Type or Function */
10666 		    if (xmlXPathIsNodeType(name)) {
10667 #ifdef DEBUG_STEP
10668 		        xmlGenericError(xmlGenericErrorContext,
10669 				"PathExpr: Type search\n");
10670 #endif
10671 			lc = 1;
10672 #ifdef LIBXML_XPTR_ENABLED
10673                     } else if (ctxt->xptr &&
10674                                xmlStrEqual(name, BAD_CAST "range-to")) {
10675                         lc = 1;
10676 #endif
10677 		    } else {
10678 #ifdef DEBUG_STEP
10679 		        xmlGenericError(xmlGenericErrorContext,
10680 				"PathExpr: function call\n");
10681 #endif
10682 			lc = 0;
10683 		    }
10684                     break;
10685 		} else if ((NXT(len) == '[')) {
10686 		    /* element name */
10687 #ifdef DEBUG_STEP
10688 		    xmlGenericError(xmlGenericErrorContext,
10689 			    "PathExpr: AbbrRelLocation\n");
10690 #endif
10691 		    lc = 1;
10692 		    break;
10693 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10694 			   (NXT(len) == '=')) {
10695 		    lc = 1;
10696 		    break;
10697 		} else {
10698 		    lc = 1;
10699 		    break;
10700 		}
10701 		len++;
10702 	    }
10703 	    if (NXT(len) == 0) {
10704 #ifdef DEBUG_STEP
10705 		xmlGenericError(xmlGenericErrorContext,
10706 			"PathExpr: AbbrRelLocation\n");
10707 #endif
10708 		/* element name */
10709 		lc = 1;
10710 	    }
10711 	    xmlFree(name);
10712 	} else {
10713 	    /* make sure all cases are covered explicitly */
10714 	    XP_ERROR(XPATH_EXPR_ERROR);
10715 	}
10716     }
10717 
10718     if (lc) {
10719 	if (CUR == '/') {
10720 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10721 	} else {
10722 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10723 	}
10724 	xmlXPathCompLocationPath(ctxt);
10725     } else {
10726 	xmlXPathCompFilterExpr(ctxt);
10727 	CHECK_ERROR;
10728 	if ((CUR == '/') && (NXT(1) == '/')) {
10729 	    SKIP(2);
10730 	    SKIP_BLANKS;
10731 
10732 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10733 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10734 
10735 	    xmlXPathCompRelativeLocationPath(ctxt);
10736 	} else if (CUR == '/') {
10737 	    xmlXPathCompRelativeLocationPath(ctxt);
10738 	}
10739     }
10740     SKIP_BLANKS;
10741 }
10742 
10743 /**
10744  * xmlXPathCompUnionExpr:
10745  * @ctxt:  the XPath Parser context
10746  *
10747  *  [18]   UnionExpr ::=   PathExpr
10748  *               | UnionExpr '|' PathExpr
10749  *
10750  * Compile an union expression.
10751  */
10752 
10753 static void
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt)10754 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10755     xmlXPathCompPathExpr(ctxt);
10756     CHECK_ERROR;
10757     SKIP_BLANKS;
10758     while (CUR == '|') {
10759 	int op1 = ctxt->comp->last;
10760 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10761 
10762 	NEXT;
10763 	SKIP_BLANKS;
10764 	xmlXPathCompPathExpr(ctxt);
10765 
10766 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10767 
10768 	SKIP_BLANKS;
10769     }
10770 }
10771 
10772 /**
10773  * xmlXPathCompUnaryExpr:
10774  * @ctxt:  the XPath Parser context
10775  *
10776  *  [27]   UnaryExpr ::=   UnionExpr
10777  *                   | '-' UnaryExpr
10778  *
10779  * Compile an unary expression.
10780  */
10781 
10782 static void
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt)10783 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10784     int minus = 0;
10785     int found = 0;
10786 
10787     SKIP_BLANKS;
10788     while (CUR == '-') {
10789         minus = 1 - minus;
10790 	found = 1;
10791 	NEXT;
10792 	SKIP_BLANKS;
10793     }
10794 
10795     xmlXPathCompUnionExpr(ctxt);
10796     CHECK_ERROR;
10797     if (found) {
10798 	if (minus)
10799 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10800 	else
10801 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10802     }
10803 }
10804 
10805 /**
10806  * xmlXPathCompMultiplicativeExpr:
10807  * @ctxt:  the XPath Parser context
10808  *
10809  *  [26]   MultiplicativeExpr ::=   UnaryExpr
10810  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10811  *                   | MultiplicativeExpr 'div' UnaryExpr
10812  *                   | MultiplicativeExpr 'mod' UnaryExpr
10813  *  [34]   MultiplyOperator ::=   '*'
10814  *
10815  * Compile an Additive expression.
10816  */
10817 
10818 static void
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt)10819 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10820     xmlXPathCompUnaryExpr(ctxt);
10821     CHECK_ERROR;
10822     SKIP_BLANKS;
10823     while ((CUR == '*') ||
10824            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10825            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10826 	int op = -1;
10827 	int op1 = ctxt->comp->last;
10828 
10829         if (CUR == '*') {
10830 	    op = 0;
10831 	    NEXT;
10832 	} else if (CUR == 'd') {
10833 	    op = 1;
10834 	    SKIP(3);
10835 	} else if (CUR == 'm') {
10836 	    op = 2;
10837 	    SKIP(3);
10838 	}
10839 	SKIP_BLANKS;
10840         xmlXPathCompUnaryExpr(ctxt);
10841 	CHECK_ERROR;
10842 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10843 	SKIP_BLANKS;
10844     }
10845 }
10846 
10847 /**
10848  * xmlXPathCompAdditiveExpr:
10849  * @ctxt:  the XPath Parser context
10850  *
10851  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10852  *                   | AdditiveExpr '+' MultiplicativeExpr
10853  *                   | AdditiveExpr '-' MultiplicativeExpr
10854  *
10855  * Compile an Additive expression.
10856  */
10857 
10858 static void
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt)10859 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10860 
10861     xmlXPathCompMultiplicativeExpr(ctxt);
10862     CHECK_ERROR;
10863     SKIP_BLANKS;
10864     while ((CUR == '+') || (CUR == '-')) {
10865 	int plus;
10866 	int op1 = ctxt->comp->last;
10867 
10868         if (CUR == '+') plus = 1;
10869 	else plus = 0;
10870 	NEXT;
10871 	SKIP_BLANKS;
10872         xmlXPathCompMultiplicativeExpr(ctxt);
10873 	CHECK_ERROR;
10874 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10875 	SKIP_BLANKS;
10876     }
10877 }
10878 
10879 /**
10880  * xmlXPathCompRelationalExpr:
10881  * @ctxt:  the XPath Parser context
10882  *
10883  *  [24]   RelationalExpr ::=   AdditiveExpr
10884  *                 | RelationalExpr '<' AdditiveExpr
10885  *                 | RelationalExpr '>' AdditiveExpr
10886  *                 | RelationalExpr '<=' AdditiveExpr
10887  *                 | RelationalExpr '>=' AdditiveExpr
10888  *
10889  *  A <= B > C is allowed ? Answer from James, yes with
10890  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10891  *  which is basically what got implemented.
10892  *
10893  * Compile a Relational expression, then push the result
10894  * on the stack
10895  */
10896 
10897 static void
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt)10898 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10899     xmlXPathCompAdditiveExpr(ctxt);
10900     CHECK_ERROR;
10901     SKIP_BLANKS;
10902     while ((CUR == '<') ||
10903            (CUR == '>') ||
10904            ((CUR == '<') && (NXT(1) == '=')) ||
10905            ((CUR == '>') && (NXT(1) == '='))) {
10906 	int inf, strict;
10907 	int op1 = ctxt->comp->last;
10908 
10909         if (CUR == '<') inf = 1;
10910 	else inf = 0;
10911 	if (NXT(1) == '=') strict = 0;
10912 	else strict = 1;
10913 	NEXT;
10914 	if (!strict) NEXT;
10915 	SKIP_BLANKS;
10916         xmlXPathCompAdditiveExpr(ctxt);
10917 	CHECK_ERROR;
10918 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10919 	SKIP_BLANKS;
10920     }
10921 }
10922 
10923 /**
10924  * xmlXPathCompEqualityExpr:
10925  * @ctxt:  the XPath Parser context
10926  *
10927  *  [23]   EqualityExpr ::=   RelationalExpr
10928  *                 | EqualityExpr '=' RelationalExpr
10929  *                 | EqualityExpr '!=' RelationalExpr
10930  *
10931  *  A != B != C is allowed ? Answer from James, yes with
10932  *  (RelationalExpr = RelationalExpr) = RelationalExpr
10933  *  (RelationalExpr != RelationalExpr) != RelationalExpr
10934  *  which is basically what got implemented.
10935  *
10936  * Compile an Equality expression.
10937  *
10938  */
10939 static void
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt)10940 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10941     xmlXPathCompRelationalExpr(ctxt);
10942     CHECK_ERROR;
10943     SKIP_BLANKS;
10944     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10945 	int eq;
10946 	int op1 = ctxt->comp->last;
10947 
10948         if (CUR == '=') eq = 1;
10949 	else eq = 0;
10950 	NEXT;
10951 	if (!eq) NEXT;
10952 	SKIP_BLANKS;
10953         xmlXPathCompRelationalExpr(ctxt);
10954 	CHECK_ERROR;
10955 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10956 	SKIP_BLANKS;
10957     }
10958 }
10959 
10960 /**
10961  * xmlXPathCompAndExpr:
10962  * @ctxt:  the XPath Parser context
10963  *
10964  *  [22]   AndExpr ::=   EqualityExpr
10965  *                 | AndExpr 'and' EqualityExpr
10966  *
10967  * Compile an AND expression.
10968  *
10969  */
10970 static void
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt)10971 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10972     xmlXPathCompEqualityExpr(ctxt);
10973     CHECK_ERROR;
10974     SKIP_BLANKS;
10975     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10976 	int op1 = ctxt->comp->last;
10977         SKIP(3);
10978 	SKIP_BLANKS;
10979         xmlXPathCompEqualityExpr(ctxt);
10980 	CHECK_ERROR;
10981 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10982 	SKIP_BLANKS;
10983     }
10984 }
10985 
10986 /**
10987  * xmlXPathCompileExpr:
10988  * @ctxt:  the XPath Parser context
10989  *
10990  *  [14]   Expr ::=   OrExpr
10991  *  [21]   OrExpr ::=   AndExpr
10992  *                 | OrExpr 'or' AndExpr
10993  *
10994  * Parse and compile an expression
10995  */
10996 static void
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt,int sort)10997 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10998     xmlXPathCompAndExpr(ctxt);
10999     CHECK_ERROR;
11000     SKIP_BLANKS;
11001     while ((CUR == 'o') && (NXT(1) == 'r')) {
11002 	int op1 = ctxt->comp->last;
11003         SKIP(2);
11004 	SKIP_BLANKS;
11005         xmlXPathCompAndExpr(ctxt);
11006 	CHECK_ERROR;
11007 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
11008 	SKIP_BLANKS;
11009     }
11010     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
11011 	/* more ops could be optimized too */
11012 	/*
11013 	* This is the main place to eliminate sorting for
11014 	* operations which don't require a sorted node-set.
11015 	* E.g. count().
11016 	*/
11017 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11018     }
11019 }
11020 
11021 /**
11022  * xmlXPathCompPredicate:
11023  * @ctxt:  the XPath Parser context
11024  * @filter:  act as a filter
11025  *
11026  *  [8]   Predicate ::=   '[' PredicateExpr ']'
11027  *  [9]   PredicateExpr ::=   Expr
11028  *
11029  * Compile a predicate expression
11030  */
11031 static void
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt,int filter)11032 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11033     int op1 = ctxt->comp->last;
11034 
11035     SKIP_BLANKS;
11036     if (CUR != '[') {
11037 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11038     }
11039     NEXT;
11040     SKIP_BLANKS;
11041 
11042     ctxt->comp->last = -1;
11043     /*
11044     * This call to xmlXPathCompileExpr() will deactivate sorting
11045     * of the predicate result.
11046     * TODO: Sorting is still activated for filters, since I'm not
11047     *  sure if needed. Normally sorting should not be needed, since
11048     *  a filter can only diminish the number of items in a sequence,
11049     *  but won't change its order; so if the initial sequence is sorted,
11050     *  subsequent sorting is not needed.
11051     */
11052     if (! filter)
11053 	xmlXPathCompileExpr(ctxt, 0);
11054     else
11055 	xmlXPathCompileExpr(ctxt, 1);
11056     CHECK_ERROR;
11057 
11058     if (CUR != ']') {
11059 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11060     }
11061 
11062     if (filter)
11063 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11064     else
11065 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11066 
11067     NEXT;
11068     SKIP_BLANKS;
11069 }
11070 
11071 /**
11072  * xmlXPathCompNodeTest:
11073  * @ctxt:  the XPath Parser context
11074  * @test:  pointer to a xmlXPathTestVal
11075  * @type:  pointer to a xmlXPathTypeVal
11076  * @prefix:  placeholder for a possible name prefix
11077  *
11078  * [7] NodeTest ::=   NameTest
11079  *		    | NodeType '(' ')'
11080  *		    | 'processing-instruction' '(' Literal ')'
11081  *
11082  * [37] NameTest ::=  '*'
11083  *		    | NCName ':' '*'
11084  *		    | QName
11085  * [38] NodeType ::= 'comment'
11086  *		   | 'text'
11087  *		   | 'processing-instruction'
11088  *		   | 'node'
11089  *
11090  * Returns the name found and updates @test, @type and @prefix appropriately
11091  */
11092 static xmlChar *
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt,xmlXPathTestVal * test,xmlXPathTypeVal * type,const xmlChar ** prefix,xmlChar * name)11093 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11094 	             xmlXPathTypeVal *type, const xmlChar **prefix,
11095 		     xmlChar *name) {
11096     int blanks;
11097 
11098     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11099 	STRANGE;
11100 	return(NULL);
11101     }
11102     *type = (xmlXPathTypeVal) 0;
11103     *test = (xmlXPathTestVal) 0;
11104     *prefix = NULL;
11105     SKIP_BLANKS;
11106 
11107     if ((name == NULL) && (CUR == '*')) {
11108 	/*
11109 	 * All elements
11110 	 */
11111 	NEXT;
11112 	*test = NODE_TEST_ALL;
11113 	return(NULL);
11114     }
11115 
11116     if (name == NULL)
11117 	name = xmlXPathParseNCName(ctxt);
11118     if (name == NULL) {
11119 	XP_ERRORNULL(XPATH_EXPR_ERROR);
11120     }
11121 
11122     blanks = IS_BLANK_CH(CUR);
11123     SKIP_BLANKS;
11124     if (CUR == '(') {
11125 	NEXT;
11126 	/*
11127 	 * NodeType or PI search
11128 	 */
11129 	if (xmlStrEqual(name, BAD_CAST "comment"))
11130 	    *type = NODE_TYPE_COMMENT;
11131 	else if (xmlStrEqual(name, BAD_CAST "node"))
11132 	    *type = NODE_TYPE_NODE;
11133 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11134 	    *type = NODE_TYPE_PI;
11135 	else if (xmlStrEqual(name, BAD_CAST "text"))
11136 	    *type = NODE_TYPE_TEXT;
11137 	else {
11138 	    if (name != NULL)
11139 		xmlFree(name);
11140 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11141 	}
11142 
11143 	*test = NODE_TEST_TYPE;
11144 
11145 	SKIP_BLANKS;
11146 	if (*type == NODE_TYPE_PI) {
11147 	    /*
11148 	     * Specific case: search a PI by name.
11149 	     */
11150 	    if (name != NULL)
11151 		xmlFree(name);
11152 	    name = NULL;
11153 	    if (CUR != ')') {
11154 		name = xmlXPathParseLiteral(ctxt);
11155 		CHECK_ERROR NULL;
11156 		*test = NODE_TEST_PI;
11157 		SKIP_BLANKS;
11158 	    }
11159 	}
11160 	if (CUR != ')') {
11161 	    if (name != NULL)
11162 		xmlFree(name);
11163 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11164 	}
11165 	NEXT;
11166 	return(name);
11167     }
11168     *test = NODE_TEST_NAME;
11169     if ((!blanks) && (CUR == ':')) {
11170 	NEXT;
11171 
11172 	/*
11173 	 * Since currently the parser context don't have a
11174 	 * namespace list associated:
11175 	 * The namespace name for this prefix can be computed
11176 	 * only at evaluation time. The compilation is done
11177 	 * outside of any context.
11178 	 */
11179 #if 0
11180 	*prefix = xmlXPathNsLookup(ctxt->context, name);
11181 	if (name != NULL)
11182 	    xmlFree(name);
11183 	if (*prefix == NULL) {
11184 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11185 	}
11186 #else
11187 	*prefix = name;
11188 #endif
11189 
11190 	if (CUR == '*') {
11191 	    /*
11192 	     * All elements
11193 	     */
11194 	    NEXT;
11195 	    *test = NODE_TEST_ALL;
11196 	    return(NULL);
11197 	}
11198 
11199 	name = xmlXPathParseNCName(ctxt);
11200 	if (name == NULL) {
11201 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11202 	}
11203     }
11204     return(name);
11205 }
11206 
11207 /**
11208  * xmlXPathIsAxisName:
11209  * @name:  a preparsed name token
11210  *
11211  * [6] AxisName ::=   'ancestor'
11212  *                  | 'ancestor-or-self'
11213  *                  | 'attribute'
11214  *                  | 'child'
11215  *                  | 'descendant'
11216  *                  | 'descendant-or-self'
11217  *                  | 'following'
11218  *                  | 'following-sibling'
11219  *                  | 'namespace'
11220  *                  | 'parent'
11221  *                  | 'preceding'
11222  *                  | 'preceding-sibling'
11223  *                  | 'self'
11224  *
11225  * Returns the axis or 0
11226  */
11227 static xmlXPathAxisVal
xmlXPathIsAxisName(const xmlChar * name)11228 xmlXPathIsAxisName(const xmlChar *name) {
11229     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11230     switch (name[0]) {
11231 	case 'a':
11232 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
11233 		ret = AXIS_ANCESTOR;
11234 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11235 		ret = AXIS_ANCESTOR_OR_SELF;
11236 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
11237 		ret = AXIS_ATTRIBUTE;
11238 	    break;
11239 	case 'c':
11240 	    if (xmlStrEqual(name, BAD_CAST "child"))
11241 		ret = AXIS_CHILD;
11242 	    break;
11243 	case 'd':
11244 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
11245 		ret = AXIS_DESCENDANT;
11246 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11247 		ret = AXIS_DESCENDANT_OR_SELF;
11248 	    break;
11249 	case 'f':
11250 	    if (xmlStrEqual(name, BAD_CAST "following"))
11251 		ret = AXIS_FOLLOWING;
11252 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11253 		ret = AXIS_FOLLOWING_SIBLING;
11254 	    break;
11255 	case 'n':
11256 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
11257 		ret = AXIS_NAMESPACE;
11258 	    break;
11259 	case 'p':
11260 	    if (xmlStrEqual(name, BAD_CAST "parent"))
11261 		ret = AXIS_PARENT;
11262 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
11263 		ret = AXIS_PRECEDING;
11264 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11265 		ret = AXIS_PRECEDING_SIBLING;
11266 	    break;
11267 	case 's':
11268 	    if (xmlStrEqual(name, BAD_CAST "self"))
11269 		ret = AXIS_SELF;
11270 	    break;
11271     }
11272     return(ret);
11273 }
11274 
11275 /**
11276  * xmlXPathCompStep:
11277  * @ctxt:  the XPath Parser context
11278  *
11279  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11280  *                  | AbbreviatedStep
11281  *
11282  * [12] AbbreviatedStep ::=   '.' | '..'
11283  *
11284  * [5] AxisSpecifier ::= AxisName '::'
11285  *                  | AbbreviatedAxisSpecifier
11286  *
11287  * [13] AbbreviatedAxisSpecifier ::= '@'?
11288  *
11289  * Modified for XPtr range support as:
11290  *
11291  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11292  *                     | AbbreviatedStep
11293  *                     | 'range-to' '(' Expr ')' Predicate*
11294  *
11295  * Compile one step in a Location Path
11296  * A location step of . is short for self::node(). This is
11297  * particularly useful in conjunction with //. For example, the
11298  * location path .//para is short for
11299  * self::node()/descendant-or-self::node()/child::para
11300  * and so will select all para descendant elements of the context
11301  * node.
11302  * Similarly, a location step of .. is short for parent::node().
11303  * For example, ../title is short for parent::node()/child::title
11304  * and so will select the title children of the parent of the context
11305  * node.
11306  */
11307 static void
xmlXPathCompStep(xmlXPathParserContextPtr ctxt)11308 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11309 #ifdef LIBXML_XPTR_ENABLED
11310     int rangeto = 0;
11311     int op2 = -1;
11312 #endif
11313 
11314     SKIP_BLANKS;
11315     if ((CUR == '.') && (NXT(1) == '.')) {
11316 	SKIP(2);
11317 	SKIP_BLANKS;
11318 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11319 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11320     } else if (CUR == '.') {
11321 	NEXT;
11322 	SKIP_BLANKS;
11323     } else {
11324 	xmlChar *name = NULL;
11325 	const xmlChar *prefix = NULL;
11326 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
11327 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11328 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11329 	int op1;
11330 
11331 	/*
11332 	 * The modification needed for XPointer change to the production
11333 	 */
11334 #ifdef LIBXML_XPTR_ENABLED
11335 	if (ctxt->xptr) {
11336 	    name = xmlXPathParseNCName(ctxt);
11337 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11338                 op2 = ctxt->comp->last;
11339 		xmlFree(name);
11340 		SKIP_BLANKS;
11341 		if (CUR != '(') {
11342 		    XP_ERROR(XPATH_EXPR_ERROR);
11343 		}
11344 		NEXT;
11345 		SKIP_BLANKS;
11346 
11347 		xmlXPathCompileExpr(ctxt, 1);
11348 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11349 		CHECK_ERROR;
11350 
11351 		SKIP_BLANKS;
11352 		if (CUR != ')') {
11353 		    XP_ERROR(XPATH_EXPR_ERROR);
11354 		}
11355 		NEXT;
11356 		rangeto = 1;
11357 		goto eval_predicates;
11358 	    }
11359 	}
11360 #endif
11361 	if (CUR == '*') {
11362 	    axis = AXIS_CHILD;
11363 	} else {
11364 	    if (name == NULL)
11365 		name = xmlXPathParseNCName(ctxt);
11366 	    if (name != NULL) {
11367 		axis = xmlXPathIsAxisName(name);
11368 		if (axis != 0) {
11369 		    SKIP_BLANKS;
11370 		    if ((CUR == ':') && (NXT(1) == ':')) {
11371 			SKIP(2);
11372 			xmlFree(name);
11373 			name = NULL;
11374 		    } else {
11375 			/* an element name can conflict with an axis one :-\ */
11376 			axis = AXIS_CHILD;
11377 		    }
11378 		} else {
11379 		    axis = AXIS_CHILD;
11380 		}
11381 	    } else if (CUR == '@') {
11382 		NEXT;
11383 		axis = AXIS_ATTRIBUTE;
11384 	    } else {
11385 		axis = AXIS_CHILD;
11386 	    }
11387 	}
11388 
11389         if (ctxt->error != XPATH_EXPRESSION_OK) {
11390             xmlFree(name);
11391             return;
11392         }
11393 
11394 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11395 	if (test == 0)
11396 	    return;
11397 
11398         if ((prefix != NULL) && (ctxt->context != NULL) &&
11399 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11400 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11401 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11402 	    }
11403 	}
11404 #ifdef DEBUG_STEP
11405 	xmlGenericError(xmlGenericErrorContext,
11406 		"Basis : computing new set\n");
11407 #endif
11408 
11409 #ifdef DEBUG_STEP
11410 	xmlGenericError(xmlGenericErrorContext, "Basis : ");
11411 	if (ctxt->value == NULL)
11412 	    xmlGenericError(xmlGenericErrorContext, "no value\n");
11413 	else if (ctxt->value->nodesetval == NULL)
11414 	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
11415 	else
11416 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11417 #endif
11418 
11419 #ifdef LIBXML_XPTR_ENABLED
11420 eval_predicates:
11421 #endif
11422 	op1 = ctxt->comp->last;
11423 	ctxt->comp->last = -1;
11424 
11425 	SKIP_BLANKS;
11426 	while (CUR == '[') {
11427 	    xmlXPathCompPredicate(ctxt, 0);
11428 	}
11429 
11430 #ifdef LIBXML_XPTR_ENABLED
11431 	if (rangeto) {
11432 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11433 	} else
11434 #endif
11435 	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11436 			   test, type, (void *)prefix, (void *)name);
11437 
11438     }
11439 #ifdef DEBUG_STEP
11440     xmlGenericError(xmlGenericErrorContext, "Step : ");
11441     if (ctxt->value == NULL)
11442 	xmlGenericError(xmlGenericErrorContext, "no value\n");
11443     else if (ctxt->value->nodesetval == NULL)
11444 	xmlGenericError(xmlGenericErrorContext, "Empty\n");
11445     else
11446 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11447 		ctxt->value->nodesetval);
11448 #endif
11449 }
11450 
11451 /**
11452  * xmlXPathCompRelativeLocationPath:
11453  * @ctxt:  the XPath Parser context
11454  *
11455  *  [3]   RelativeLocationPath ::=   Step
11456  *                     | RelativeLocationPath '/' Step
11457  *                     | AbbreviatedRelativeLocationPath
11458  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11459  *
11460  * Compile a relative location path.
11461  */
11462 static void
xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt)11463 xmlXPathCompRelativeLocationPath
11464 (xmlXPathParserContextPtr ctxt) {
11465     SKIP_BLANKS;
11466     if ((CUR == '/') && (NXT(1) == '/')) {
11467 	SKIP(2);
11468 	SKIP_BLANKS;
11469 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11470 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11471     } else if (CUR == '/') {
11472 	    NEXT;
11473 	SKIP_BLANKS;
11474     }
11475     xmlXPathCompStep(ctxt);
11476     CHECK_ERROR;
11477     SKIP_BLANKS;
11478     while (CUR == '/') {
11479 	if ((CUR == '/') && (NXT(1) == '/')) {
11480 	    SKIP(2);
11481 	    SKIP_BLANKS;
11482 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11483 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11484 	    xmlXPathCompStep(ctxt);
11485 	} else if (CUR == '/') {
11486 	    NEXT;
11487 	    SKIP_BLANKS;
11488 	    xmlXPathCompStep(ctxt);
11489 	}
11490 	SKIP_BLANKS;
11491     }
11492 }
11493 
11494 /**
11495  * xmlXPathCompLocationPath:
11496  * @ctxt:  the XPath Parser context
11497  *
11498  *  [1]   LocationPath ::=   RelativeLocationPath
11499  *                     | AbsoluteLocationPath
11500  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11501  *                     | AbbreviatedAbsoluteLocationPath
11502  *  [10]   AbbreviatedAbsoluteLocationPath ::=
11503  *                           '//' RelativeLocationPath
11504  *
11505  * Compile a location path
11506  *
11507  * // is short for /descendant-or-self::node()/. For example,
11508  * //para is short for /descendant-or-self::node()/child::para and
11509  * so will select any para element in the document (even a para element
11510  * that is a document element will be selected by //para since the
11511  * document element node is a child of the root node); div//para is
11512  * short for div/descendant-or-self::node()/child::para and so will
11513  * select all para descendants of div children.
11514  */
11515 static void
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt)11516 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11517     SKIP_BLANKS;
11518     if (CUR != '/') {
11519         xmlXPathCompRelativeLocationPath(ctxt);
11520     } else {
11521 	while (CUR == '/') {
11522 	    if ((CUR == '/') && (NXT(1) == '/')) {
11523 		SKIP(2);
11524 		SKIP_BLANKS;
11525 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11526 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11527 		xmlXPathCompRelativeLocationPath(ctxt);
11528 	    } else if (CUR == '/') {
11529 		NEXT;
11530 		SKIP_BLANKS;
11531 		if ((CUR != 0 ) &&
11532 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11533 		     (CUR == '@') || (CUR == '*')))
11534 		    xmlXPathCompRelativeLocationPath(ctxt);
11535 	    }
11536 	    CHECK_ERROR;
11537 	}
11538     }
11539 }
11540 
11541 /************************************************************************
11542  *									*
11543  *		XPath precompiled expression evaluation			*
11544  *									*
11545  ************************************************************************/
11546 
11547 static int
11548 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11549 
11550 #ifdef DEBUG_STEP
11551 static void
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,int nbNodes)11552 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11553 			  int nbNodes)
11554 {
11555     xmlGenericError(xmlGenericErrorContext, "new step : ");
11556     switch (op->value) {
11557         case AXIS_ANCESTOR:
11558             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11559             break;
11560         case AXIS_ANCESTOR_OR_SELF:
11561             xmlGenericError(xmlGenericErrorContext,
11562                             "axis 'ancestors-or-self' ");
11563             break;
11564         case AXIS_ATTRIBUTE:
11565             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11566             break;
11567         case AXIS_CHILD:
11568             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11569             break;
11570         case AXIS_DESCENDANT:
11571             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11572             break;
11573         case AXIS_DESCENDANT_OR_SELF:
11574             xmlGenericError(xmlGenericErrorContext,
11575                             "axis 'descendant-or-self' ");
11576             break;
11577         case AXIS_FOLLOWING:
11578             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11579             break;
11580         case AXIS_FOLLOWING_SIBLING:
11581             xmlGenericError(xmlGenericErrorContext,
11582                             "axis 'following-siblings' ");
11583             break;
11584         case AXIS_NAMESPACE:
11585             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11586             break;
11587         case AXIS_PARENT:
11588             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11589             break;
11590         case AXIS_PRECEDING:
11591             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11592             break;
11593         case AXIS_PRECEDING_SIBLING:
11594             xmlGenericError(xmlGenericErrorContext,
11595                             "axis 'preceding-sibling' ");
11596             break;
11597         case AXIS_SELF:
11598             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11599             break;
11600     }
11601     xmlGenericError(xmlGenericErrorContext,
11602 	" context contains %d nodes\n", nbNodes);
11603     switch (op->value2) {
11604         case NODE_TEST_NONE:
11605             xmlGenericError(xmlGenericErrorContext,
11606                             "           searching for none !!!\n");
11607             break;
11608         case NODE_TEST_TYPE:
11609             xmlGenericError(xmlGenericErrorContext,
11610                             "           searching for type %d\n", op->value3);
11611             break;
11612         case NODE_TEST_PI:
11613             xmlGenericError(xmlGenericErrorContext,
11614                             "           searching for PI !!!\n");
11615             break;
11616         case NODE_TEST_ALL:
11617             xmlGenericError(xmlGenericErrorContext,
11618                             "           searching for *\n");
11619             break;
11620         case NODE_TEST_NS:
11621             xmlGenericError(xmlGenericErrorContext,
11622                             "           searching for namespace %s\n",
11623                             op->value5);
11624             break;
11625         case NODE_TEST_NAME:
11626             xmlGenericError(xmlGenericErrorContext,
11627                             "           searching for name %s\n", op->value5);
11628             if (op->value4)
11629                 xmlGenericError(xmlGenericErrorContext,
11630                                 "           with namespace %s\n", op->value4);
11631             break;
11632     }
11633     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11634 }
11635 #endif /* DEBUG_STEP */
11636 
11637 static int
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int contextSize,int hasNsNodes)11638 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11639 			    xmlXPathStepOpPtr op,
11640 			    xmlNodeSetPtr set,
11641 			    int contextSize,
11642 			    int hasNsNodes)
11643 {
11644     if (op->ch1 != -1) {
11645 	xmlXPathCompExprPtr comp = ctxt->comp;
11646 	/*
11647 	* Process inner predicates first.
11648 	*/
11649 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11650 	    /*
11651 	    * TODO: raise an internal error.
11652 	    */
11653 	}
11654 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11655 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11656 	CHECK_ERROR0;
11657 	if (contextSize <= 0)
11658 	    return(0);
11659     }
11660     if (op->ch2 != -1) {
11661 	xmlXPathContextPtr xpctxt = ctxt->context;
11662 	xmlNodePtr contextNode, oldContextNode;
11663 	xmlDocPtr oldContextDoc;
11664         int oldcs, oldpp;
11665 	int i, res, contextPos = 0, newContextSize;
11666 	xmlXPathStepOpPtr exprOp;
11667 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11668 
11669 #ifdef LIBXML_XPTR_ENABLED
11670 	/*
11671 	* URGENT TODO: Check the following:
11672 	*  We don't expect location sets if evaluating prediates, right?
11673 	*  Only filters should expect location sets, right?
11674 	*/
11675 #endif
11676 	/*
11677 	* SPEC XPath 1.0:
11678 	*  "For each node in the node-set to be filtered, the
11679 	*  PredicateExpr is evaluated with that node as the
11680 	*  context node, with the number of nodes in the
11681 	*  node-set as the context size, and with the proximity
11682 	*  position of the node in the node-set with respect to
11683 	*  the axis as the context position;"
11684 	* @oldset is the node-set" to be filtered.
11685 	*
11686 	* SPEC XPath 1.0:
11687 	*  "only predicates change the context position and
11688 	*  context size (see [2.4 Predicates])."
11689 	* Example:
11690 	*   node-set  context pos
11691 	*    nA         1
11692 	*    nB         2
11693 	*    nC         3
11694 	*   After applying predicate [position() > 1] :
11695 	*   node-set  context pos
11696 	*    nB         1
11697 	*    nC         2
11698 	*/
11699 	oldContextNode = xpctxt->node;
11700 	oldContextDoc = xpctxt->doc;
11701         oldcs = xpctxt->contextSize;
11702         oldpp = xpctxt->proximityPosition;
11703 	/*
11704 	* Get the expression of this predicate.
11705 	*/
11706 	exprOp = &ctxt->comp->steps[op->ch2];
11707 	newContextSize = 0;
11708 	for (i = 0; i < set->nodeNr; i++) {
11709 	    if (set->nodeTab[i] == NULL)
11710 		continue;
11711 
11712 	    contextNode = set->nodeTab[i];
11713 	    xpctxt->node = contextNode;
11714 	    xpctxt->contextSize = contextSize;
11715 	    xpctxt->proximityPosition = ++contextPos;
11716 
11717 	    /*
11718 	    * Also set the xpath document in case things like
11719 	    * key() are evaluated in the predicate.
11720 	    */
11721 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11722 		(contextNode->doc != NULL))
11723 		xpctxt->doc = contextNode->doc;
11724 	    /*
11725 	    * Evaluate the predicate expression with 1 context node
11726 	    * at a time; this node is packaged into a node set; this
11727 	    * node set is handed over to the evaluation mechanism.
11728 	    */
11729 	    if (contextObj == NULL)
11730 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11731 	    else {
11732 		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11733 		    contextNode) < 0) {
11734 		    ctxt->error = XPATH_MEMORY_ERROR;
11735 		    goto evaluation_exit;
11736 		}
11737 	    }
11738 
11739 	    valuePush(ctxt, contextObj);
11740 
11741 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11742 
11743 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11744 		xmlXPathNodeSetClear(set, hasNsNodes);
11745 		newContextSize = 0;
11746 		goto evaluation_exit;
11747 	    }
11748 
11749 	    if (res != 0) {
11750 		newContextSize++;
11751 	    } else {
11752 		/*
11753 		* Remove the entry from the initial node set.
11754 		*/
11755 		set->nodeTab[i] = NULL;
11756 		if (contextNode->type == XML_NAMESPACE_DECL)
11757 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11758 	    }
11759 	    if (ctxt->value == contextObj) {
11760 		/*
11761 		* Don't free the temporary XPath object holding the
11762 		* context node, in order to avoid massive recreation
11763 		* inside this loop.
11764 		*/
11765 		valuePop(ctxt);
11766 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11767 	    } else {
11768 		/*
11769 		* TODO: The object was lost in the evaluation machinery.
11770 		*  Can this happen? Maybe in internal-error cases.
11771 		*/
11772 		contextObj = NULL;
11773 	    }
11774 	}
11775 
11776 	if (contextObj != NULL) {
11777 	    if (ctxt->value == contextObj)
11778 		valuePop(ctxt);
11779 	    xmlXPathReleaseObject(xpctxt, contextObj);
11780 	}
11781 evaluation_exit:
11782 	if (exprRes != NULL)
11783 	    xmlXPathReleaseObject(ctxt->context, exprRes);
11784 	/*
11785 	* Reset/invalidate the context.
11786 	*/
11787 	xpctxt->node = oldContextNode;
11788 	xpctxt->doc = oldContextDoc;
11789 	xpctxt->contextSize = oldcs;
11790 	xpctxt->proximityPosition = oldpp;
11791 	return(newContextSize);
11792     }
11793     return(contextSize);
11794 }
11795 
11796 static int
xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int contextSize,int minPos,int maxPos,int hasNsNodes)11797 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11798 				      xmlXPathStepOpPtr op,
11799 				      xmlNodeSetPtr set,
11800 				      int contextSize,
11801 				      int minPos,
11802 				      int maxPos,
11803 				      int hasNsNodes)
11804 {
11805     if (op->ch1 != -1) {
11806 	xmlXPathCompExprPtr comp = ctxt->comp;
11807 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11808 	    /*
11809 	    * TODO: raise an internal error.
11810 	    */
11811 	}
11812 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11813 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11814 	CHECK_ERROR0;
11815 	if (contextSize <= 0)
11816 	    return(0);
11817     }
11818     /*
11819     * Check if the node set contains a sufficient number of nodes for
11820     * the requested range.
11821     */
11822     if (contextSize < minPos) {
11823 	xmlXPathNodeSetClear(set, hasNsNodes);
11824 	return(0);
11825     }
11826     if (op->ch2 == -1) {
11827 	/*
11828 	* TODO: Can this ever happen?
11829 	*/
11830 	return (contextSize);
11831     } else {
11832 	xmlDocPtr oldContextDoc;
11833         int oldcs, oldpp;
11834 	int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11835 	xmlXPathStepOpPtr exprOp;
11836 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11837 	xmlNodePtr oldContextNode, contextNode = NULL;
11838 	xmlXPathContextPtr xpctxt = ctxt->context;
11839         int frame;
11840 
11841 #ifdef LIBXML_XPTR_ENABLED
11842 	    /*
11843 	    * URGENT TODO: Check the following:
11844 	    *  We don't expect location sets if evaluating prediates, right?
11845 	    *  Only filters should expect location sets, right?
11846 	*/
11847 #endif /* LIBXML_XPTR_ENABLED */
11848 
11849 	/*
11850 	* Save old context.
11851 	*/
11852 	oldContextNode = xpctxt->node;
11853 	oldContextDoc = xpctxt->doc;
11854         oldcs = xpctxt->contextSize;
11855         oldpp = xpctxt->proximityPosition;
11856 	/*
11857 	* Get the expression of this predicate.
11858 	*/
11859 	exprOp = &ctxt->comp->steps[op->ch2];
11860 	for (i = 0; i < set->nodeNr; i++) {
11861             xmlXPathObjectPtr tmp;
11862 
11863 	    if (set->nodeTab[i] == NULL)
11864 		continue;
11865 
11866 	    contextNode = set->nodeTab[i];
11867 	    xpctxt->node = contextNode;
11868 	    xpctxt->contextSize = contextSize;
11869 	    xpctxt->proximityPosition = ++contextPos;
11870 
11871 	    /*
11872 	    * Initialize the new set.
11873 	    * Also set the xpath document in case things like
11874 	    * key() evaluation are attempted on the predicate
11875 	    */
11876 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11877 		(contextNode->doc != NULL))
11878 		xpctxt->doc = contextNode->doc;
11879 	    /*
11880 	    * Evaluate the predicate expression with 1 context node
11881 	    * at a time; this node is packaged into a node set; this
11882 	    * node set is handed over to the evaluation mechanism.
11883 	    */
11884 	    if (contextObj == NULL)
11885 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11886 	    else {
11887 		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11888 		    contextNode) < 0) {
11889 		    ctxt->error = XPATH_MEMORY_ERROR;
11890 		    goto evaluation_exit;
11891 		}
11892 	    }
11893 
11894 	    valuePush(ctxt, contextObj);
11895             frame = xmlXPathSetFrame(ctxt);
11896 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11897             xmlXPathPopFrame(ctxt, frame);
11898             tmp = valuePop(ctxt);
11899 
11900 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11901                 while (tmp != contextObj) {
11902                     /*
11903                      * Free up the result
11904                      * then pop off contextObj, which will be freed later
11905                      */
11906                     xmlXPathReleaseObject(xpctxt, tmp);
11907                     tmp = valuePop(ctxt);
11908                 }
11909 		goto evaluation_error;
11910 	    }
11911             /* push the result back onto the stack */
11912             valuePush(ctxt, tmp);
11913 
11914 	    if (res)
11915 		pos++;
11916 
11917 	    if (res && (pos >= minPos) && (pos <= maxPos)) {
11918 		/*
11919 		* Fits in the requested range.
11920 		*/
11921 		newContextSize++;
11922 		if (minPos == maxPos) {
11923 		    /*
11924 		    * Only 1 node was requested.
11925 		    */
11926 		    if (contextNode->type == XML_NAMESPACE_DECL) {
11927 			/*
11928 			* As always: take care of those nasty
11929 			* namespace nodes.
11930 			*/
11931 			set->nodeTab[i] = NULL;
11932 		    }
11933 		    xmlXPathNodeSetClear(set, hasNsNodes);
11934 		    set->nodeNr = 1;
11935 		    set->nodeTab[0] = contextNode;
11936 		    goto evaluation_exit;
11937 		}
11938 		if (pos == maxPos) {
11939 		    /*
11940 		    * We are done.
11941 		    */
11942 		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11943 		    goto evaluation_exit;
11944 		}
11945 	    } else {
11946 		/*
11947 		* Remove the entry from the initial node set.
11948 		*/
11949 		set->nodeTab[i] = NULL;
11950 		if (contextNode->type == XML_NAMESPACE_DECL)
11951 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11952 	    }
11953 	    if (exprRes != NULL) {
11954 		xmlXPathReleaseObject(ctxt->context, exprRes);
11955 		exprRes = NULL;
11956 	    }
11957 	    if (ctxt->value == contextObj) {
11958 		/*
11959 		* Don't free the temporary XPath object holding the
11960 		* context node, in order to avoid massive recreation
11961 		* inside this loop.
11962 		*/
11963 		valuePop(ctxt);
11964 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11965 	    } else {
11966 		/*
11967 		* The object was lost in the evaluation machinery.
11968 		* Can this happen? Maybe in case of internal-errors.
11969 		*/
11970 		contextObj = NULL;
11971 	    }
11972 	}
11973 	goto evaluation_exit;
11974 
11975 evaluation_error:
11976 	xmlXPathNodeSetClear(set, hasNsNodes);
11977 	newContextSize = 0;
11978 
11979 evaluation_exit:
11980 	if (contextObj != NULL) {
11981 	    if (ctxt->value == contextObj)
11982 		valuePop(ctxt);
11983 	    xmlXPathReleaseObject(xpctxt, contextObj);
11984 	}
11985 	if (exprRes != NULL)
11986 	    xmlXPathReleaseObject(ctxt->context, exprRes);
11987 	/*
11988 	* Reset/invalidate the context.
11989 	*/
11990 	xpctxt->node = oldContextNode;
11991 	xpctxt->doc = oldContextDoc;
11992 	xpctxt->contextSize = oldcs;
11993 	xpctxt->proximityPosition = oldpp;
11994 	return(newContextSize);
11995     }
11996     return(contextSize);
11997 }
11998 
11999 static int
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int * maxPos)12000 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
12001 			    xmlXPathStepOpPtr op,
12002 			    int *maxPos)
12003 {
12004 
12005     xmlXPathStepOpPtr exprOp;
12006 
12007     /*
12008     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12009     */
12010 
12011     /*
12012     * If not -1, then ch1 will point to:
12013     * 1) For predicates (XPATH_OP_PREDICATE):
12014     *    - an inner predicate operator
12015     * 2) For filters (XPATH_OP_FILTER):
12016     *    - an inner filter operater OR
12017     *    - an expression selecting the node set.
12018     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
12019     */
12020     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12021 	return(0);
12022 
12023     if (op->ch2 != -1) {
12024 	exprOp = &ctxt->comp->steps[op->ch2];
12025     } else
12026 	return(0);
12027 
12028     if ((exprOp != NULL) &&
12029 	(exprOp->op == XPATH_OP_VALUE) &&
12030 	(exprOp->value4 != NULL) &&
12031 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12032     {
12033         double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12034 
12035 	/*
12036 	* We have a "[n]" predicate here.
12037 	* TODO: Unfortunately this simplistic test here is not
12038 	* able to detect a position() predicate in compound
12039 	* expressions like "[@attr = 'a" and position() = 1],
12040 	* and even not the usage of position() in
12041 	* "[position() = 1]"; thus - obviously - a position-range,
12042 	* like it "[position() < 5]", is also not detected.
12043 	* Maybe we could rewrite the AST to ease the optimization.
12044 	*/
12045 
12046         if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
12047 	    *maxPos = (int) floatval;
12048             if (floatval == (double) *maxPos)
12049                 return(1);
12050         }
12051     }
12052     return(0);
12053 }
12054 
12055 static int
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first,xmlNodePtr * last,int toBool)12056 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12057                            xmlXPathStepOpPtr op,
12058 			   xmlNodePtr * first, xmlNodePtr * last,
12059 			   int toBool)
12060 {
12061 
12062 #define XP_TEST_HIT \
12063     if (hasAxisRange != 0) { \
12064 	if (++pos == maxPos) { \
12065 	    if (addNode(seq, cur) < 0) \
12066 	        ctxt->error = XPATH_MEMORY_ERROR; \
12067 	    goto axis_range_end; } \
12068     } else { \
12069 	if (addNode(seq, cur) < 0) \
12070 	    ctxt->error = XPATH_MEMORY_ERROR; \
12071 	if (breakOnFirstHit) goto first_hit; }
12072 
12073 #define XP_TEST_HIT_NS \
12074     if (hasAxisRange != 0) { \
12075 	if (++pos == maxPos) { \
12076 	    hasNsNodes = 1; \
12077 	    if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12078 	        ctxt->error = XPATH_MEMORY_ERROR; \
12079 	goto axis_range_end; } \
12080     } else { \
12081 	hasNsNodes = 1; \
12082 	if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12083 	    ctxt->error = XPATH_MEMORY_ERROR; \
12084 	if (breakOnFirstHit) goto first_hit; }
12085 
12086     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12087     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12088     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12089     const xmlChar *prefix = op->value4;
12090     const xmlChar *name = op->value5;
12091     const xmlChar *URI = NULL;
12092 
12093 #ifdef DEBUG_STEP
12094     int nbMatches = 0, prevMatches = 0;
12095 #endif
12096     int total = 0, hasNsNodes = 0;
12097     /* The popped object holding the context nodes */
12098     xmlXPathObjectPtr obj;
12099     /* The set of context nodes for the node tests */
12100     xmlNodeSetPtr contextSeq;
12101     int contextIdx;
12102     xmlNodePtr contextNode;
12103     /* The final resulting node set wrt to all context nodes */
12104     xmlNodeSetPtr outSeq;
12105     /*
12106     * The temporary resulting node set wrt 1 context node.
12107     * Used to feed predicate evaluation.
12108     */
12109     xmlNodeSetPtr seq;
12110     xmlNodePtr cur;
12111     /* First predicate operator */
12112     xmlXPathStepOpPtr predOp;
12113     int maxPos; /* The requested position() (when a "[n]" predicate) */
12114     int hasPredicateRange, hasAxisRange, pos, size, newSize;
12115     int breakOnFirstHit;
12116 
12117     xmlXPathTraversalFunction next = NULL;
12118     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12119     xmlXPathNodeSetMergeFunction mergeAndClear;
12120     xmlNodePtr oldContextNode;
12121     xmlXPathContextPtr xpctxt = ctxt->context;
12122 
12123 
12124     CHECK_TYPE0(XPATH_NODESET);
12125     obj = valuePop(ctxt);
12126     /*
12127     * Setup namespaces.
12128     */
12129     if (prefix != NULL) {
12130         URI = xmlXPathNsLookup(xpctxt, prefix);
12131         if (URI == NULL) {
12132 	    xmlXPathReleaseObject(xpctxt, obj);
12133             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12134 	}
12135     }
12136     /*
12137     * Setup axis.
12138     *
12139     * MAYBE FUTURE TODO: merging optimizations:
12140     * - If the nodes to be traversed wrt to the initial nodes and
12141     *   the current axis cannot overlap, then we could avoid searching
12142     *   for duplicates during the merge.
12143     *   But the question is how/when to evaluate if they cannot overlap.
12144     *   Example: if we know that for two initial nodes, the one is
12145     *   not in the ancestor-or-self axis of the other, then we could safely
12146     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12147     *   the descendant-or-self axis.
12148     */
12149     mergeAndClear = xmlXPathNodeSetMergeAndClear;
12150     switch (axis) {
12151         case AXIS_ANCESTOR:
12152             first = NULL;
12153             next = xmlXPathNextAncestor;
12154             break;
12155         case AXIS_ANCESTOR_OR_SELF:
12156             first = NULL;
12157             next = xmlXPathNextAncestorOrSelf;
12158             break;
12159         case AXIS_ATTRIBUTE:
12160             first = NULL;
12161 	    last = NULL;
12162             next = xmlXPathNextAttribute;
12163 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12164             break;
12165         case AXIS_CHILD:
12166 	    last = NULL;
12167 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12168 		(type == NODE_TYPE_NODE))
12169 	    {
12170 		/*
12171 		* Optimization if an element node type is 'element'.
12172 		*/
12173 		next = xmlXPathNextChildElement;
12174 	    } else
12175 		next = xmlXPathNextChild;
12176 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12177             break;
12178         case AXIS_DESCENDANT:
12179 	    last = NULL;
12180             next = xmlXPathNextDescendant;
12181             break;
12182         case AXIS_DESCENDANT_OR_SELF:
12183 	    last = NULL;
12184             next = xmlXPathNextDescendantOrSelf;
12185             break;
12186         case AXIS_FOLLOWING:
12187 	    last = NULL;
12188             next = xmlXPathNextFollowing;
12189             break;
12190         case AXIS_FOLLOWING_SIBLING:
12191 	    last = NULL;
12192             next = xmlXPathNextFollowingSibling;
12193             break;
12194         case AXIS_NAMESPACE:
12195             first = NULL;
12196 	    last = NULL;
12197             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12198 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12199             break;
12200         case AXIS_PARENT:
12201             first = NULL;
12202             next = xmlXPathNextParent;
12203             break;
12204         case AXIS_PRECEDING:
12205             first = NULL;
12206             next = xmlXPathNextPrecedingInternal;
12207             break;
12208         case AXIS_PRECEDING_SIBLING:
12209             first = NULL;
12210             next = xmlXPathNextPrecedingSibling;
12211             break;
12212         case AXIS_SELF:
12213             first = NULL;
12214 	    last = NULL;
12215             next = xmlXPathNextSelf;
12216 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12217             break;
12218     }
12219 
12220 #ifdef DEBUG_STEP
12221     xmlXPathDebugDumpStepAxis(op,
12222 	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12223 #endif
12224 
12225     if (next == NULL) {
12226 	xmlXPathReleaseObject(xpctxt, obj);
12227         return(0);
12228     }
12229     contextSeq = obj->nodesetval;
12230     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12231 	xmlXPathReleaseObject(xpctxt, obj);
12232         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12233         return(0);
12234     }
12235     /*
12236     * Predicate optimization ---------------------------------------------
12237     * If this step has a last predicate, which contains a position(),
12238     * then we'll optimize (although not exactly "position()", but only
12239     * the  short-hand form, i.e., "[n]".
12240     *
12241     * Example - expression "/foo[parent::bar][1]":
12242     *
12243     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12244     *   ROOT                               -- op->ch1
12245     *   PREDICATE                          -- op->ch2 (predOp)
12246     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12247     *       SORT
12248     *         COLLECT  'parent' 'name' 'node' bar
12249     *           NODE
12250     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12251     *
12252     */
12253     maxPos = 0;
12254     predOp = NULL;
12255     hasPredicateRange = 0;
12256     hasAxisRange = 0;
12257     if (op->ch2 != -1) {
12258 	/*
12259 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
12260 	*/
12261 	predOp = &ctxt->comp->steps[op->ch2];
12262 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12263 	    if (predOp->ch1 != -1) {
12264 		/*
12265 		* Use the next inner predicate operator.
12266 		*/
12267 		predOp = &ctxt->comp->steps[predOp->ch1];
12268 		hasPredicateRange = 1;
12269 	    } else {
12270 		/*
12271 		* There's no other predicate than the [n] predicate.
12272 		*/
12273 		predOp = NULL;
12274 		hasAxisRange = 1;
12275 	    }
12276 	}
12277     }
12278     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12279     /*
12280     * Axis traversal -----------------------------------------------------
12281     */
12282     /*
12283      * 2.3 Node Tests
12284      *  - For the attribute axis, the principal node type is attribute.
12285      *  - For the namespace axis, the principal node type is namespace.
12286      *  - For other axes, the principal node type is element.
12287      *
12288      * A node test * is true for any node of the
12289      * principal node type. For example, child::* will
12290      * select all element children of the context node
12291      */
12292     oldContextNode = xpctxt->node;
12293     addNode = xmlXPathNodeSetAddUnique;
12294     outSeq = NULL;
12295     seq = NULL;
12296     contextNode = NULL;
12297     contextIdx = 0;
12298 
12299 
12300     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12301            (ctxt->error == XPATH_EXPRESSION_OK)) {
12302 	xpctxt->node = contextSeq->nodeTab[contextIdx++];
12303 
12304 	if (seq == NULL) {
12305 	    seq = xmlXPathNodeSetCreate(NULL);
12306 	    if (seq == NULL) {
12307 		total = 0;
12308 		goto error;
12309 	    }
12310 	}
12311 	/*
12312 	* Traverse the axis and test the nodes.
12313 	*/
12314 	pos = 0;
12315 	cur = NULL;
12316 	hasNsNodes = 0;
12317         do {
12318             cur = next(ctxt, cur);
12319             if (cur == NULL)
12320                 break;
12321 
12322 	    /*
12323 	    * QUESTION TODO: What does the "first" and "last" stuff do?
12324 	    */
12325             if ((first != NULL) && (*first != NULL)) {
12326 		if (*first == cur)
12327 		    break;
12328 		if (((total % 256) == 0) &&
12329 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12330 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12331 #else
12332 		    (xmlXPathCmpNodes(*first, cur) >= 0))
12333 #endif
12334 		{
12335 		    break;
12336 		}
12337 	    }
12338 	    if ((last != NULL) && (*last != NULL)) {
12339 		if (*last == cur)
12340 		    break;
12341 		if (((total % 256) == 0) &&
12342 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12343 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12344 #else
12345 		    (xmlXPathCmpNodes(cur, *last) >= 0))
12346 #endif
12347 		{
12348 		    break;
12349 		}
12350 	    }
12351 
12352             total++;
12353 
12354 #ifdef DEBUG_STEP
12355             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12356 #endif
12357 
12358 	    switch (test) {
12359                 case NODE_TEST_NONE:
12360 		    total = 0;
12361                     STRANGE
12362 		    goto error;
12363                 case NODE_TEST_TYPE:
12364 		    if (type == NODE_TYPE_NODE) {
12365 			switch (cur->type) {
12366 			    case XML_DOCUMENT_NODE:
12367 			    case XML_HTML_DOCUMENT_NODE:
12368 #ifdef LIBXML_DOCB_ENABLED
12369 			    case XML_DOCB_DOCUMENT_NODE:
12370 #endif
12371 			    case XML_ELEMENT_NODE:
12372 			    case XML_ATTRIBUTE_NODE:
12373 			    case XML_PI_NODE:
12374 			    case XML_COMMENT_NODE:
12375 			    case XML_CDATA_SECTION_NODE:
12376 			    case XML_TEXT_NODE:
12377 				XP_TEST_HIT
12378 				break;
12379 			    case XML_NAMESPACE_DECL: {
12380 				if (axis == AXIS_NAMESPACE) {
12381 				    XP_TEST_HIT_NS
12382 				} else {
12383 	                            hasNsNodes = 1;
12384 				    XP_TEST_HIT
12385 				}
12386 				break;
12387                             }
12388 			    default:
12389 				break;
12390 			}
12391 		    } else if (cur->type == (xmlElementType) type) {
12392 			if (cur->type == XML_NAMESPACE_DECL)
12393 			    XP_TEST_HIT_NS
12394 			else
12395 			    XP_TEST_HIT
12396 		    } else if ((type == NODE_TYPE_TEXT) &&
12397 			 (cur->type == XML_CDATA_SECTION_NODE))
12398 		    {
12399 			XP_TEST_HIT
12400 		    }
12401 		    break;
12402                 case NODE_TEST_PI:
12403                     if ((cur->type == XML_PI_NODE) &&
12404                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12405 		    {
12406 			XP_TEST_HIT
12407                     }
12408                     break;
12409                 case NODE_TEST_ALL:
12410                     if (axis == AXIS_ATTRIBUTE) {
12411                         if (cur->type == XML_ATTRIBUTE_NODE)
12412 			{
12413                             if (prefix == NULL)
12414 			    {
12415 				XP_TEST_HIT
12416                             } else if ((cur->ns != NULL) &&
12417 				(xmlStrEqual(URI, cur->ns->href)))
12418 			    {
12419 				XP_TEST_HIT
12420                             }
12421                         }
12422                     } else if (axis == AXIS_NAMESPACE) {
12423                         if (cur->type == XML_NAMESPACE_DECL)
12424 			{
12425 			    XP_TEST_HIT_NS
12426                         }
12427                     } else {
12428                         if (cur->type == XML_ELEMENT_NODE) {
12429                             if (prefix == NULL)
12430 			    {
12431 				XP_TEST_HIT
12432 
12433                             } else if ((cur->ns != NULL) &&
12434 				(xmlStrEqual(URI, cur->ns->href)))
12435 			    {
12436 				XP_TEST_HIT
12437                             }
12438                         }
12439                     }
12440                     break;
12441                 case NODE_TEST_NS:{
12442                         TODO;
12443                         break;
12444                     }
12445                 case NODE_TEST_NAME:
12446                     if (axis == AXIS_ATTRIBUTE) {
12447                         if (cur->type != XML_ATTRIBUTE_NODE)
12448 			    break;
12449 		    } else if (axis == AXIS_NAMESPACE) {
12450                         if (cur->type != XML_NAMESPACE_DECL)
12451 			    break;
12452 		    } else {
12453 		        if (cur->type != XML_ELEMENT_NODE)
12454 			    break;
12455 		    }
12456                     switch (cur->type) {
12457                         case XML_ELEMENT_NODE:
12458                             if (xmlStrEqual(name, cur->name)) {
12459                                 if (prefix == NULL) {
12460                                     if (cur->ns == NULL)
12461 				    {
12462 					XP_TEST_HIT
12463                                     }
12464                                 } else {
12465                                     if ((cur->ns != NULL) &&
12466                                         (xmlStrEqual(URI, cur->ns->href)))
12467 				    {
12468 					XP_TEST_HIT
12469                                     }
12470                                 }
12471                             }
12472                             break;
12473                         case XML_ATTRIBUTE_NODE:{
12474                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12475 
12476                                 if (xmlStrEqual(name, attr->name)) {
12477                                     if (prefix == NULL) {
12478                                         if ((attr->ns == NULL) ||
12479                                             (attr->ns->prefix == NULL))
12480 					{
12481 					    XP_TEST_HIT
12482                                         }
12483                                     } else {
12484                                         if ((attr->ns != NULL) &&
12485                                             (xmlStrEqual(URI,
12486 					      attr->ns->href)))
12487 					{
12488 					    XP_TEST_HIT
12489                                         }
12490                                     }
12491                                 }
12492                                 break;
12493                             }
12494                         case XML_NAMESPACE_DECL:
12495                             if (cur->type == XML_NAMESPACE_DECL) {
12496                                 xmlNsPtr ns = (xmlNsPtr) cur;
12497 
12498                                 if ((ns->prefix != NULL) && (name != NULL)
12499                                     && (xmlStrEqual(ns->prefix, name)))
12500 				{
12501 				    XP_TEST_HIT_NS
12502                                 }
12503                             }
12504                             break;
12505                         default:
12506                             break;
12507                     }
12508                     break;
12509 	    } /* switch(test) */
12510         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12511 
12512 	goto apply_predicates;
12513 
12514 axis_range_end: /* ----------------------------------------------------- */
12515 	/*
12516 	* We have a "/foo[n]", and position() = n was reached.
12517 	* Note that we can have as well "/foo/::parent::foo[1]", so
12518 	* a duplicate-aware merge is still needed.
12519 	* Merge with the result.
12520 	*/
12521 	if (outSeq == NULL) {
12522 	    outSeq = seq;
12523 	    seq = NULL;
12524 	} else
12525 	    outSeq = mergeAndClear(outSeq, seq, 0);
12526 	/*
12527 	* Break if only a true/false result was requested.
12528 	*/
12529 	if (toBool)
12530 	    break;
12531 	continue;
12532 
12533 first_hit: /* ---------------------------------------------------------- */
12534 	/*
12535 	* Break if only a true/false result was requested and
12536 	* no predicates existed and a node test succeeded.
12537 	*/
12538 	if (outSeq == NULL) {
12539 	    outSeq = seq;
12540 	    seq = NULL;
12541 	} else
12542 	    outSeq = mergeAndClear(outSeq, seq, 0);
12543 	break;
12544 
12545 #ifdef DEBUG_STEP
12546 	if (seq != NULL)
12547 	    nbMatches += seq->nodeNr;
12548 #endif
12549 
12550 apply_predicates: /* --------------------------------------------------- */
12551         if (ctxt->error != XPATH_EXPRESSION_OK)
12552 	    goto error;
12553 
12554         /*
12555 	* Apply predicates.
12556 	*/
12557         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12558 	    /*
12559 	    * E.g. when we have a "/foo[some expression][n]".
12560 	    */
12561 	    /*
12562 	    * QUESTION TODO: The old predicate evaluation took into
12563 	    *  account location-sets.
12564 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12565 	    *  Do we expect such a set here?
12566 	    *  All what I learned now from the evaluation semantics
12567 	    *  does not indicate that a location-set will be processed
12568 	    *  here, so this looks OK.
12569 	    */
12570 	    /*
12571 	    * Iterate over all predicates, starting with the outermost
12572 	    * predicate.
12573 	    * TODO: Problem: we cannot execute the inner predicates first
12574 	    *  since we cannot go back *up* the operator tree!
12575 	    *  Options we have:
12576 	    *  1) Use of recursive functions (like is it currently done
12577 	    *     via xmlXPathCompOpEval())
12578 	    *  2) Add a predicate evaluation information stack to the
12579 	    *     context struct
12580 	    *  3) Change the way the operators are linked; we need a
12581 	    *     "parent" field on xmlXPathStepOp
12582 	    *
12583 	    * For the moment, I'll try to solve this with a recursive
12584 	    * function: xmlXPathCompOpEvalPredicate().
12585 	    */
12586 	    size = seq->nodeNr;
12587 	    if (hasPredicateRange != 0)
12588 		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12589 		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
12590 	    else
12591 		newSize = xmlXPathCompOpEvalPredicate(ctxt,
12592 		    predOp, seq, size, hasNsNodes);
12593 
12594 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12595 		total = 0;
12596 		goto error;
12597 	    }
12598 	    /*
12599 	    * Add the filtered set of nodes to the result node set.
12600 	    */
12601 	    if (newSize == 0) {
12602 		/*
12603 		* The predicates filtered all nodes out.
12604 		*/
12605 		xmlXPathNodeSetClear(seq, hasNsNodes);
12606 	    } else if (seq->nodeNr > 0) {
12607 		/*
12608 		* Add to result set.
12609 		*/
12610 		if (outSeq == NULL) {
12611 		    if (size != newSize) {
12612 			/*
12613 			* We need to merge and clear here, since
12614 			* the sequence will contained NULLed entries.
12615 			*/
12616 			outSeq = mergeAndClear(NULL, seq, 1);
12617 		    } else {
12618 			outSeq = seq;
12619 			seq = NULL;
12620 		    }
12621 		} else
12622 		    outSeq = mergeAndClear(outSeq, seq,
12623 			(size != newSize) ? 1: 0);
12624 		/*
12625 		* Break if only a true/false result was requested.
12626 		*/
12627 		if (toBool)
12628 		    break;
12629 	    }
12630         } else if (seq->nodeNr > 0) {
12631 	    /*
12632 	    * Add to result set.
12633 	    */
12634 	    if (outSeq == NULL) {
12635 		outSeq = seq;
12636 		seq = NULL;
12637 	    } else {
12638 		outSeq = mergeAndClear(outSeq, seq, 0);
12639 	    }
12640 	}
12641     }
12642 
12643 error:
12644     if ((obj->boolval) && (obj->user != NULL)) {
12645 	/*
12646 	* QUESTION TODO: What does this do and why?
12647 	* TODO: Do we have to do this also for the "error"
12648 	* cleanup further down?
12649 	*/
12650 	ctxt->value->boolval = 1;
12651 	ctxt->value->user = obj->user;
12652 	obj->user = NULL;
12653 	obj->boolval = 0;
12654     }
12655     xmlXPathReleaseObject(xpctxt, obj);
12656 
12657     /*
12658     * Ensure we return at least an emtpy set.
12659     */
12660     if (outSeq == NULL) {
12661 	if ((seq != NULL) && (seq->nodeNr == 0))
12662 	    outSeq = seq;
12663 	else
12664 	    outSeq = xmlXPathNodeSetCreate(NULL);
12665         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12666     }
12667     if ((seq != NULL) && (seq != outSeq)) {
12668 	 xmlXPathFreeNodeSet(seq);
12669     }
12670     /*
12671     * Hand over the result. Better to push the set also in
12672     * case of errors.
12673     */
12674     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12675     /*
12676     * Reset the context node.
12677     */
12678     xpctxt->node = oldContextNode;
12679     /*
12680     * When traversing the namespace axis in "toBool" mode, it's
12681     * possible that tmpNsList wasn't freed.
12682     */
12683     if (xpctxt->tmpNsList != NULL) {
12684         xmlFree(xpctxt->tmpNsList);
12685         xpctxt->tmpNsList = NULL;
12686     }
12687 
12688 #ifdef DEBUG_STEP
12689     xmlGenericError(xmlGenericErrorContext,
12690 	"\nExamined %d nodes, found %d nodes at that step\n",
12691 	total, nbMatches);
12692 #endif
12693 
12694     return(total);
12695 }
12696 
12697 static int
12698 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12699 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12700 
12701 /**
12702  * xmlXPathCompOpEvalFirst:
12703  * @ctxt:  the XPath parser context with the compiled expression
12704  * @op:  an XPath compiled operation
12705  * @first:  the first elem found so far
12706  *
12707  * Evaluate the Precompiled XPath operation searching only the first
12708  * element in document order
12709  *
12710  * Returns the number of examined objects.
12711  */
12712 static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12713 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12714                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12715 {
12716     int total = 0, cur;
12717     xmlXPathCompExprPtr comp;
12718     xmlXPathObjectPtr arg1, arg2;
12719 
12720     CHECK_ERROR0;
12721     comp = ctxt->comp;
12722     switch (op->op) {
12723         case XPATH_OP_END:
12724             return (0);
12725         case XPATH_OP_UNION:
12726             total =
12727                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12728                                         first);
12729 	    CHECK_ERROR0;
12730             if ((ctxt->value != NULL)
12731                 && (ctxt->value->type == XPATH_NODESET)
12732                 && (ctxt->value->nodesetval != NULL)
12733                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12734                 /*
12735                  * limit tree traversing to first node in the result
12736                  */
12737 		/*
12738 		* OPTIMIZE TODO: This implicitely sorts
12739 		*  the result, even if not needed. E.g. if the argument
12740 		*  of the count() function, no sorting is needed.
12741 		* OPTIMIZE TODO: How do we know if the node-list wasn't
12742 		*  aready sorted?
12743 		*/
12744 		if (ctxt->value->nodesetval->nodeNr > 1)
12745 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12746                 *first = ctxt->value->nodesetval->nodeTab[0];
12747             }
12748             cur =
12749                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12750                                         first);
12751 	    CHECK_ERROR0;
12752 
12753             arg2 = valuePop(ctxt);
12754             arg1 = valuePop(ctxt);
12755             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12756                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12757 	        xmlXPathReleaseObject(ctxt->context, arg1);
12758 	        xmlXPathReleaseObject(ctxt->context, arg2);
12759                 XP_ERROR0(XPATH_INVALID_TYPE);
12760             }
12761 
12762             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12763                                                     arg2->nodesetval);
12764             valuePush(ctxt, arg1);
12765 	    xmlXPathReleaseObject(ctxt->context, arg2);
12766             /* optimizer */
12767 	    if (total > cur)
12768 		xmlXPathCompSwap(op);
12769             return (total + cur);
12770         case XPATH_OP_ROOT:
12771             xmlXPathRoot(ctxt);
12772             return (0);
12773         case XPATH_OP_NODE:
12774             if (op->ch1 != -1)
12775                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12776 	    CHECK_ERROR0;
12777             if (op->ch2 != -1)
12778                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12779 	    CHECK_ERROR0;
12780 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12781 		ctxt->context->node));
12782             return (total);
12783         case XPATH_OP_COLLECT:{
12784                 if (op->ch1 == -1)
12785                     return (total);
12786 
12787                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12788 		CHECK_ERROR0;
12789 
12790                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12791                 return (total);
12792             }
12793         case XPATH_OP_VALUE:
12794             valuePush(ctxt,
12795                       xmlXPathCacheObjectCopy(ctxt->context,
12796 			(xmlXPathObjectPtr) op->value4));
12797             return (0);
12798         case XPATH_OP_SORT:
12799             if (op->ch1 != -1)
12800                 total +=
12801                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12802                                             first);
12803 	    CHECK_ERROR0;
12804             if ((ctxt->value != NULL)
12805                 && (ctxt->value->type == XPATH_NODESET)
12806                 && (ctxt->value->nodesetval != NULL)
12807 		&& (ctxt->value->nodesetval->nodeNr > 1))
12808                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12809             return (total);
12810 #ifdef XP_OPTIMIZED_FILTER_FIRST
12811 	case XPATH_OP_FILTER:
12812                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12813             return (total);
12814 #endif
12815         default:
12816             return (xmlXPathCompOpEval(ctxt, op));
12817     }
12818 }
12819 
12820 /**
12821  * xmlXPathCompOpEvalLast:
12822  * @ctxt:  the XPath parser context with the compiled expression
12823  * @op:  an XPath compiled operation
12824  * @last:  the last elem found so far
12825  *
12826  * Evaluate the Precompiled XPath operation searching only the last
12827  * element in document order
12828  *
12829  * Returns the number of nodes traversed
12830  */
12831 static int
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * last)12832 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12833                        xmlNodePtr * last)
12834 {
12835     int total = 0, cur;
12836     xmlXPathCompExprPtr comp;
12837     xmlXPathObjectPtr arg1, arg2;
12838 
12839     CHECK_ERROR0;
12840     comp = ctxt->comp;
12841     switch (op->op) {
12842         case XPATH_OP_END:
12843             return (0);
12844         case XPATH_OP_UNION:
12845             total =
12846                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12847 	    CHECK_ERROR0;
12848             if ((ctxt->value != NULL)
12849                 && (ctxt->value->type == XPATH_NODESET)
12850                 && (ctxt->value->nodesetval != NULL)
12851                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12852                 /*
12853                  * limit tree traversing to first node in the result
12854                  */
12855 		if (ctxt->value->nodesetval->nodeNr > 1)
12856 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12857                 *last =
12858                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12859                                                      nodesetval->nodeNr -
12860                                                      1];
12861             }
12862             cur =
12863                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12864 	    CHECK_ERROR0;
12865             if ((ctxt->value != NULL)
12866                 && (ctxt->value->type == XPATH_NODESET)
12867                 && (ctxt->value->nodesetval != NULL)
12868                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12869             }
12870 
12871             arg2 = valuePop(ctxt);
12872             arg1 = valuePop(ctxt);
12873             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12874                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12875 	        xmlXPathReleaseObject(ctxt->context, arg1);
12876 	        xmlXPathReleaseObject(ctxt->context, arg2);
12877                 XP_ERROR0(XPATH_INVALID_TYPE);
12878             }
12879 
12880             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12881                                                     arg2->nodesetval);
12882             valuePush(ctxt, arg1);
12883 	    xmlXPathReleaseObject(ctxt->context, arg2);
12884             /* optimizer */
12885 	    if (total > cur)
12886 		xmlXPathCompSwap(op);
12887             return (total + cur);
12888         case XPATH_OP_ROOT:
12889             xmlXPathRoot(ctxt);
12890             return (0);
12891         case XPATH_OP_NODE:
12892             if (op->ch1 != -1)
12893                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12894 	    CHECK_ERROR0;
12895             if (op->ch2 != -1)
12896                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12897 	    CHECK_ERROR0;
12898 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12899 		ctxt->context->node));
12900             return (total);
12901         case XPATH_OP_COLLECT:{
12902                 if (op->ch1 == -1)
12903                     return (0);
12904 
12905                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12906 		CHECK_ERROR0;
12907 
12908                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12909                 return (total);
12910             }
12911         case XPATH_OP_VALUE:
12912             valuePush(ctxt,
12913                       xmlXPathCacheObjectCopy(ctxt->context,
12914 			(xmlXPathObjectPtr) op->value4));
12915             return (0);
12916         case XPATH_OP_SORT:
12917             if (op->ch1 != -1)
12918                 total +=
12919                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12920                                            last);
12921 	    CHECK_ERROR0;
12922             if ((ctxt->value != NULL)
12923                 && (ctxt->value->type == XPATH_NODESET)
12924                 && (ctxt->value->nodesetval != NULL)
12925 		&& (ctxt->value->nodesetval->nodeNr > 1))
12926                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12927             return (total);
12928         default:
12929             return (xmlXPathCompOpEval(ctxt, op));
12930     }
12931 }
12932 
12933 #ifdef XP_OPTIMIZED_FILTER_FIRST
12934 static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12935 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12936 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
12937 {
12938     int total = 0;
12939     xmlXPathCompExprPtr comp;
12940     xmlXPathObjectPtr res;
12941     xmlXPathObjectPtr obj;
12942     xmlNodeSetPtr oldset;
12943     xmlNodePtr oldnode;
12944     xmlDocPtr oldDoc;
12945     int oldcs, oldpp;
12946     int i;
12947 
12948     CHECK_ERROR0;
12949     comp = ctxt->comp;
12950     /*
12951     * Optimization for ()[last()] selection i.e. the last elem
12952     */
12953     if ((op->ch1 != -1) && (op->ch2 != -1) &&
12954 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12955 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12956 	int f = comp->steps[op->ch2].ch1;
12957 
12958 	if ((f != -1) &&
12959 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12960 	    (comp->steps[f].value5 == NULL) &&
12961 	    (comp->steps[f].value == 0) &&
12962 	    (comp->steps[f].value4 != NULL) &&
12963 	    (xmlStrEqual
12964 	    (comp->steps[f].value4, BAD_CAST "last"))) {
12965 	    xmlNodePtr last = NULL;
12966 
12967 	    total +=
12968 		xmlXPathCompOpEvalLast(ctxt,
12969 		    &comp->steps[op->ch1],
12970 		    &last);
12971 	    CHECK_ERROR0;
12972 	    /*
12973 	    * The nodeset should be in document order,
12974 	    * Keep only the last value
12975 	    */
12976 	    if ((ctxt->value != NULL) &&
12977 		(ctxt->value->type == XPATH_NODESET) &&
12978 		(ctxt->value->nodesetval != NULL) &&
12979 		(ctxt->value->nodesetval->nodeTab != NULL) &&
12980 		(ctxt->value->nodesetval->nodeNr > 1)) {
12981                 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12982 		*first = *(ctxt->value->nodesetval->nodeTab);
12983 	    }
12984 	    return (total);
12985 	}
12986     }
12987 
12988     if (op->ch1 != -1)
12989 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12990     CHECK_ERROR0;
12991     if (op->ch2 == -1)
12992 	return (total);
12993     if (ctxt->value == NULL)
12994 	return (total);
12995 
12996 #ifdef LIBXML_XPTR_ENABLED
12997     /*
12998     * Hum are we filtering the result of an XPointer expression
12999     */
13000     if (ctxt->value->type == XPATH_LOCATIONSET) {
13001 	xmlXPathObjectPtr tmp = NULL;
13002 	xmlLocationSetPtr newlocset = NULL;
13003 	xmlLocationSetPtr oldlocset;
13004 
13005 	/*
13006 	* Extract the old locset, and then evaluate the result of the
13007 	* expression for all the element in the locset. use it to grow
13008 	* up a new locset.
13009 	*/
13010 	CHECK_TYPE0(XPATH_LOCATIONSET);
13011 
13012 	if ((ctxt->value->user == NULL) ||
13013             (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13014 	    return (total);
13015 
13016 	obj = valuePop(ctxt);
13017 	oldlocset = obj->user;
13018         oldnode = ctxt->context->node;
13019         oldcs = ctxt->context->contextSize;
13020         oldpp = ctxt->context->proximityPosition;
13021 
13022 	newlocset = xmlXPtrLocationSetCreate(NULL);
13023 
13024 	for (i = 0; i < oldlocset->locNr; i++) {
13025 	    /*
13026 	    * Run the evaluation with a node list made of a
13027 	    * single item in the nodelocset.
13028 	    */
13029 	    ctxt->context->node = oldlocset->locTab[i]->user;
13030 	    ctxt->context->contextSize = oldlocset->locNr;
13031 	    ctxt->context->proximityPosition = i + 1;
13032 	    if (tmp == NULL) {
13033 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13034 		    ctxt->context->node);
13035 	    } else {
13036 		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13037 		                             ctxt->context->node) < 0) {
13038 		    ctxt->error = XPATH_MEMORY_ERROR;
13039 		}
13040 	    }
13041 	    valuePush(ctxt, tmp);
13042 	    if (op->ch2 != -1)
13043 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13044 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13045                 xmlXPtrFreeLocationSet(newlocset);
13046                 goto xptr_error;
13047 	    }
13048 	    /*
13049 	    * The result of the evaluation need to be tested to
13050 	    * decided whether the filter succeeded or not
13051 	    */
13052 	    res = valuePop(ctxt);
13053 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13054 		xmlXPtrLocationSetAdd(newlocset,
13055 		    xmlXPathCacheObjectCopy(ctxt->context,
13056 			oldlocset->locTab[i]));
13057 	    }
13058 	    /*
13059 	    * Cleanup
13060 	    */
13061 	    if (res != NULL) {
13062 		xmlXPathReleaseObject(ctxt->context, res);
13063 	    }
13064 	    if (ctxt->value == tmp) {
13065 		valuePop(ctxt);
13066 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13067 		/*
13068 		* REVISIT TODO: Don't create a temporary nodeset
13069 		* for everly iteration.
13070 		*/
13071 		/* OLD: xmlXPathFreeObject(res); */
13072 	    } else
13073 		tmp = NULL;
13074 	    /*
13075 	    * Only put the first node in the result, then leave.
13076 	    */
13077 	    if (newlocset->locNr > 0) {
13078 		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
13079 		break;
13080 	    }
13081 	}
13082 	if (tmp != NULL) {
13083 	    xmlXPathReleaseObject(ctxt->context, tmp);
13084 	}
13085 	/*
13086 	* The result is used as the new evaluation locset.
13087 	*/
13088 	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13089 xptr_error:
13090 	xmlXPathReleaseObject(ctxt->context, obj);
13091 	ctxt->context->node = oldnode;
13092 	ctxt->context->contextSize = oldcs;
13093 	ctxt->context->proximityPosition = oldpp;
13094 	return (total);
13095     }
13096 #endif /* LIBXML_XPTR_ENABLED */
13097 
13098     /*
13099     * Extract the old set, and then evaluate the result of the
13100     * expression for all the element in the set. use it to grow
13101     * up a new set.
13102     */
13103     CHECK_TYPE0(XPATH_NODESET);
13104 
13105     if ((ctxt->value->nodesetval != NULL) &&
13106         (ctxt->value->nodesetval->nodeNr != 0)) {
13107 	xmlNodeSetPtr newset;
13108 	xmlXPathObjectPtr tmp = NULL;
13109 
13110         obj = valuePop(ctxt);
13111         oldset = obj->nodesetval;
13112         oldnode = ctxt->context->node;
13113         oldDoc = ctxt->context->doc;
13114         oldcs = ctxt->context->contextSize;
13115         oldpp = ctxt->context->proximityPosition;
13116 
13117 	/*
13118 	* Initialize the new set.
13119 	* Also set the xpath document in case things like
13120 	* key() evaluation are attempted on the predicate
13121 	*/
13122 	newset = xmlXPathNodeSetCreate(NULL);
13123         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13124 
13125 	for (i = 0; i < oldset->nodeNr; i++) {
13126 	    /*
13127 	    * Run the evaluation with a node list made of
13128 	    * a single item in the nodeset.
13129 	    */
13130 	    ctxt->context->node = oldset->nodeTab[i];
13131 	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13132 		(oldset->nodeTab[i]->doc != NULL))
13133 		ctxt->context->doc = oldset->nodeTab[i]->doc;
13134 	    if (tmp == NULL) {
13135 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13136 		    ctxt->context->node);
13137 	    } else {
13138 		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13139 		                             ctxt->context->node) < 0) {
13140 		    ctxt->error = XPATH_MEMORY_ERROR;
13141 		}
13142 	    }
13143 	    valuePush(ctxt, tmp);
13144 	    ctxt->context->contextSize = oldset->nodeNr;
13145 	    ctxt->context->proximityPosition = i + 1;
13146 	    if (op->ch2 != -1)
13147 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13148 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13149 		xmlXPathFreeNodeSet(newset);
13150                 goto error;
13151 	    }
13152 	    /*
13153 	    * The result of the evaluation needs to be tested to
13154 	    * decide whether the filter succeeded or not
13155 	    */
13156 	    res = valuePop(ctxt);
13157 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13158 		if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13159 		    ctxt->error = XPATH_MEMORY_ERROR;
13160 	    }
13161 	    /*
13162 	    * Cleanup
13163 	    */
13164 	    if (res != NULL) {
13165 		xmlXPathReleaseObject(ctxt->context, res);
13166 	    }
13167 	    if (ctxt->value == tmp) {
13168 		valuePop(ctxt);
13169 		/*
13170 		* Don't free the temporary nodeset
13171 		* in order to avoid massive recreation inside this
13172 		* loop.
13173 		*/
13174 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13175 	    } else
13176 		tmp = NULL;
13177 	    /*
13178 	    * Only put the first node in the result, then leave.
13179 	    */
13180 	    if (newset->nodeNr > 0) {
13181 		*first = *(newset->nodeTab);
13182 		break;
13183 	    }
13184 	}
13185 	if (tmp != NULL) {
13186 	    xmlXPathReleaseObject(ctxt->context, tmp);
13187 	}
13188 	/*
13189 	* The result is used as the new evaluation set.
13190 	*/
13191 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13192 error:
13193 	xmlXPathReleaseObject(ctxt->context, obj);
13194 	ctxt->context->node = oldnode;
13195 	ctxt->context->doc = oldDoc;
13196 	ctxt->context->contextSize = oldcs;
13197 	ctxt->context->proximityPosition = oldpp;
13198     }
13199     return(total);
13200 }
13201 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13202 
13203 /**
13204  * xmlXPathCompOpEval:
13205  * @ctxt:  the XPath parser context with the compiled expression
13206  * @op:  an XPath compiled operation
13207  *
13208  * Evaluate the Precompiled XPath operation
13209  * Returns the number of nodes traversed
13210  */
13211 static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op)13212 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13213 {
13214     int total = 0;
13215     int equal, ret;
13216     xmlXPathCompExprPtr comp;
13217     xmlXPathObjectPtr arg1, arg2;
13218 
13219     CHECK_ERROR0;
13220     comp = ctxt->comp;
13221     switch (op->op) {
13222         case XPATH_OP_END:
13223             return (0);
13224         case XPATH_OP_AND:
13225             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13226 	    CHECK_ERROR0;
13227             xmlXPathBooleanFunction(ctxt, 1);
13228             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13229                 return (total);
13230             arg2 = valuePop(ctxt);
13231             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13232 	    if (ctxt->error) {
13233 		xmlXPathFreeObject(arg2);
13234 		return(0);
13235 	    }
13236             xmlXPathBooleanFunction(ctxt, 1);
13237             if (ctxt->value != NULL)
13238                 ctxt->value->boolval &= arg2->boolval;
13239 	    xmlXPathReleaseObject(ctxt->context, arg2);
13240             return (total);
13241         case XPATH_OP_OR:
13242             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13243 	    CHECK_ERROR0;
13244             xmlXPathBooleanFunction(ctxt, 1);
13245             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13246                 return (total);
13247             arg2 = valuePop(ctxt);
13248             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13249 	    if (ctxt->error) {
13250 		xmlXPathFreeObject(arg2);
13251 		return(0);
13252 	    }
13253             xmlXPathBooleanFunction(ctxt, 1);
13254             if (ctxt->value != NULL)
13255                 ctxt->value->boolval |= arg2->boolval;
13256 	    xmlXPathReleaseObject(ctxt->context, arg2);
13257             return (total);
13258         case XPATH_OP_EQUAL:
13259             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13260 	    CHECK_ERROR0;
13261             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13262 	    CHECK_ERROR0;
13263 	    if (op->value)
13264 		equal = xmlXPathEqualValues(ctxt);
13265 	    else
13266 		equal = xmlXPathNotEqualValues(ctxt);
13267 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13268             return (total);
13269         case XPATH_OP_CMP:
13270             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13271 	    CHECK_ERROR0;
13272             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13273 	    CHECK_ERROR0;
13274             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13275 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13276             return (total);
13277         case XPATH_OP_PLUS:
13278             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13279 	    CHECK_ERROR0;
13280             if (op->ch2 != -1) {
13281                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13282 	    }
13283 	    CHECK_ERROR0;
13284             if (op->value == 0)
13285                 xmlXPathSubValues(ctxt);
13286             else if (op->value == 1)
13287                 xmlXPathAddValues(ctxt);
13288             else if (op->value == 2)
13289                 xmlXPathValueFlipSign(ctxt);
13290             else if (op->value == 3) {
13291                 CAST_TO_NUMBER;
13292                 CHECK_TYPE0(XPATH_NUMBER);
13293             }
13294             return (total);
13295         case XPATH_OP_MULT:
13296             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13297 	    CHECK_ERROR0;
13298             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13299 	    CHECK_ERROR0;
13300             if (op->value == 0)
13301                 xmlXPathMultValues(ctxt);
13302             else if (op->value == 1)
13303                 xmlXPathDivValues(ctxt);
13304             else if (op->value == 2)
13305                 xmlXPathModValues(ctxt);
13306             return (total);
13307         case XPATH_OP_UNION:
13308             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13309 	    CHECK_ERROR0;
13310             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13311 	    CHECK_ERROR0;
13312 
13313             arg2 = valuePop(ctxt);
13314             arg1 = valuePop(ctxt);
13315             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13316                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13317 	        xmlXPathReleaseObject(ctxt->context, arg1);
13318 	        xmlXPathReleaseObject(ctxt->context, arg2);
13319                 XP_ERROR0(XPATH_INVALID_TYPE);
13320             }
13321 
13322 	    if ((arg1->nodesetval == NULL) ||
13323 		((arg2->nodesetval != NULL) &&
13324 		 (arg2->nodesetval->nodeNr != 0)))
13325 	    {
13326 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13327 							arg2->nodesetval);
13328 	    }
13329 
13330             valuePush(ctxt, arg1);
13331 	    xmlXPathReleaseObject(ctxt->context, arg2);
13332             return (total);
13333         case XPATH_OP_ROOT:
13334             xmlXPathRoot(ctxt);
13335             return (total);
13336         case XPATH_OP_NODE:
13337             if (op->ch1 != -1)
13338                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13339 	    CHECK_ERROR0;
13340             if (op->ch2 != -1)
13341                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13342 	    CHECK_ERROR0;
13343 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13344 		ctxt->context->node));
13345             return (total);
13346         case XPATH_OP_COLLECT:{
13347                 if (op->ch1 == -1)
13348                     return (total);
13349 
13350                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13351 		CHECK_ERROR0;
13352 
13353                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13354                 return (total);
13355             }
13356         case XPATH_OP_VALUE:
13357             valuePush(ctxt,
13358                       xmlXPathCacheObjectCopy(ctxt->context,
13359 			(xmlXPathObjectPtr) op->value4));
13360             return (total);
13361         case XPATH_OP_VARIABLE:{
13362 		xmlXPathObjectPtr val;
13363 
13364                 if (op->ch1 != -1)
13365                     total +=
13366                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13367                 if (op->value5 == NULL) {
13368 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13369 		    if (val == NULL)
13370 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13371                     valuePush(ctxt, val);
13372 		} else {
13373                     const xmlChar *URI;
13374 
13375                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13376                     if (URI == NULL) {
13377                         xmlGenericError(xmlGenericErrorContext,
13378             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13379                                     (char *) op->value4, (char *)op->value5);
13380                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13381                         return (total);
13382                     }
13383 		    val = xmlXPathVariableLookupNS(ctxt->context,
13384                                                        op->value4, URI);
13385 		    if (val == NULL)
13386 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13387                     valuePush(ctxt, val);
13388                 }
13389                 return (total);
13390             }
13391         case XPATH_OP_FUNCTION:{
13392                 xmlXPathFunction func;
13393                 const xmlChar *oldFunc, *oldFuncURI;
13394 		int i;
13395                 int frame;
13396 
13397                 frame = xmlXPathSetFrame(ctxt);
13398                 if (op->ch1 != -1) {
13399                     total +=
13400                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13401                     if (ctxt->error != XPATH_EXPRESSION_OK) {
13402                         xmlXPathPopFrame(ctxt, frame);
13403                         return (total);
13404                     }
13405                 }
13406 		if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13407 		    xmlGenericError(xmlGenericErrorContext,
13408 			    "xmlXPathCompOpEval: parameter error\n");
13409 		    ctxt->error = XPATH_INVALID_OPERAND;
13410                     xmlXPathPopFrame(ctxt, frame);
13411 		    return (total);
13412 		}
13413 		for (i = 0; i < op->value; i++) {
13414 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13415 			xmlGenericError(xmlGenericErrorContext,
13416 				"xmlXPathCompOpEval: parameter error\n");
13417 			ctxt->error = XPATH_INVALID_OPERAND;
13418                         xmlXPathPopFrame(ctxt, frame);
13419 			return (total);
13420 		    }
13421                 }
13422                 if (op->cache != NULL)
13423                     func = op->cache;
13424                 else {
13425                     const xmlChar *URI = NULL;
13426 
13427                     if (op->value5 == NULL)
13428                         func =
13429                             xmlXPathFunctionLookup(ctxt->context,
13430                                                    op->value4);
13431                     else {
13432                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
13433                         if (URI == NULL) {
13434                             xmlGenericError(xmlGenericErrorContext,
13435             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13436                                     (char *)op->value4, (char *)op->value5);
13437                             xmlXPathPopFrame(ctxt, frame);
13438                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13439                             return (total);
13440                         }
13441                         func = xmlXPathFunctionLookupNS(ctxt->context,
13442                                                         op->value4, URI);
13443                     }
13444                     if (func == NULL) {
13445                         xmlGenericError(xmlGenericErrorContext,
13446                                 "xmlXPathCompOpEval: function %s not found\n",
13447                                         (char *)op->value4);
13448                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13449                     }
13450                     op->cache = func;
13451                     op->cacheURI = (void *) URI;
13452                 }
13453                 oldFunc = ctxt->context->function;
13454                 oldFuncURI = ctxt->context->functionURI;
13455                 ctxt->context->function = op->value4;
13456                 ctxt->context->functionURI = op->cacheURI;
13457                 func(ctxt, op->value);
13458                 ctxt->context->function = oldFunc;
13459                 ctxt->context->functionURI = oldFuncURI;
13460                 xmlXPathPopFrame(ctxt, frame);
13461                 return (total);
13462             }
13463         case XPATH_OP_ARG:
13464             if (op->ch1 != -1) {
13465                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13466 	        CHECK_ERROR0;
13467             }
13468             if (op->ch2 != -1) {
13469                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13470 	        CHECK_ERROR0;
13471 	    }
13472             return (total);
13473         case XPATH_OP_PREDICATE:
13474         case XPATH_OP_FILTER:{
13475                 xmlXPathObjectPtr res;
13476                 xmlXPathObjectPtr obj, tmp;
13477                 xmlNodeSetPtr newset = NULL;
13478                 xmlNodeSetPtr oldset;
13479                 xmlNodePtr oldnode;
13480 		xmlDocPtr oldDoc;
13481                 int oldcs, oldpp;
13482                 int i;
13483 
13484                 /*
13485                  * Optimization for ()[1] selection i.e. the first elem
13486                  */
13487                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13488 #ifdef XP_OPTIMIZED_FILTER_FIRST
13489 		    /*
13490 		    * FILTER TODO: Can we assume that the inner processing
13491 		    *  will result in an ordered list if we have an
13492 		    *  XPATH_OP_FILTER?
13493 		    *  What about an additional field or flag on
13494 		    *  xmlXPathObject like @sorted ? This way we wouln'd need
13495 		    *  to assume anything, so it would be more robust and
13496 		    *  easier to optimize.
13497 		    */
13498                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13499 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13500 #else
13501 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13502 #endif
13503                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13504                     xmlXPathObjectPtr val;
13505 
13506                     val = comp->steps[op->ch2].value4;
13507                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13508                         (val->floatval == 1.0)) {
13509                         xmlNodePtr first = NULL;
13510 
13511                         total +=
13512                             xmlXPathCompOpEvalFirst(ctxt,
13513                                                     &comp->steps[op->ch1],
13514                                                     &first);
13515 			CHECK_ERROR0;
13516                         /*
13517                          * The nodeset should be in document order,
13518                          * Keep only the first value
13519                          */
13520                         if ((ctxt->value != NULL) &&
13521                             (ctxt->value->type == XPATH_NODESET) &&
13522                             (ctxt->value->nodesetval != NULL) &&
13523                             (ctxt->value->nodesetval->nodeNr > 1))
13524                             xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13525                                                         1, 1);
13526                         return (total);
13527                     }
13528                 }
13529                 /*
13530                  * Optimization for ()[last()] selection i.e. the last elem
13531                  */
13532                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13533                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13534                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13535                     int f = comp->steps[op->ch2].ch1;
13536 
13537                     if ((f != -1) &&
13538                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13539                         (comp->steps[f].value5 == NULL) &&
13540                         (comp->steps[f].value == 0) &&
13541                         (comp->steps[f].value4 != NULL) &&
13542                         (xmlStrEqual
13543                          (comp->steps[f].value4, BAD_CAST "last"))) {
13544                         xmlNodePtr last = NULL;
13545 
13546                         total +=
13547                             xmlXPathCompOpEvalLast(ctxt,
13548                                                    &comp->steps[op->ch1],
13549                                                    &last);
13550 			CHECK_ERROR0;
13551                         /*
13552                          * The nodeset should be in document order,
13553                          * Keep only the last value
13554                          */
13555                         if ((ctxt->value != NULL) &&
13556                             (ctxt->value->type == XPATH_NODESET) &&
13557                             (ctxt->value->nodesetval != NULL) &&
13558                             (ctxt->value->nodesetval->nodeTab != NULL) &&
13559                             (ctxt->value->nodesetval->nodeNr > 1))
13560                             xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13561                         return (total);
13562                     }
13563                 }
13564 		/*
13565 		* Process inner predicates first.
13566 		* Example "index[parent::book][1]":
13567 		* ...
13568 		*   PREDICATE   <-- we are here "[1]"
13569 		*     PREDICATE <-- process "[parent::book]" first
13570 		*       SORT
13571 		*         COLLECT  'parent' 'name' 'node' book
13572 		*           NODE
13573 		*     ELEM Object is a number : 1
13574 		*/
13575                 if (op->ch1 != -1)
13576                     total +=
13577                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13578 		CHECK_ERROR0;
13579                 if (op->ch2 == -1)
13580                     return (total);
13581                 if (ctxt->value == NULL)
13582                     return (total);
13583 
13584 #ifdef LIBXML_XPTR_ENABLED
13585                 /*
13586                  * Hum are we filtering the result of an XPointer expression
13587                  */
13588                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13589                     xmlLocationSetPtr newlocset = NULL;
13590                     xmlLocationSetPtr oldlocset;
13591 
13592                     /*
13593                      * Extract the old locset, and then evaluate the result of the
13594                      * expression for all the element in the locset. use it to grow
13595                      * up a new locset.
13596                      */
13597                     CHECK_TYPE0(XPATH_LOCATIONSET);
13598 
13599                     if ((ctxt->value->user == NULL) ||
13600                         (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13601                         return (total);
13602 
13603                     obj = valuePop(ctxt);
13604                     oldlocset = obj->user;
13605                     oldnode = ctxt->context->node;
13606                     oldcs = ctxt->context->contextSize;
13607                     oldpp = ctxt->context->proximityPosition;
13608 
13609                     newlocset = xmlXPtrLocationSetCreate(NULL);
13610 
13611                     for (i = 0; i < oldlocset->locNr; i++) {
13612                         /*
13613                          * Run the evaluation with a node list made of a
13614                          * single item in the nodelocset.
13615                          */
13616                         ctxt->context->node = oldlocset->locTab[i]->user;
13617                         ctxt->context->contextSize = oldlocset->locNr;
13618                         ctxt->context->proximityPosition = i + 1;
13619 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13620 			    ctxt->context->node);
13621                         valuePush(ctxt, tmp);
13622 
13623                         if (op->ch2 != -1)
13624                             total +=
13625                                 xmlXPathCompOpEval(ctxt,
13626                                                    &comp->steps[op->ch2]);
13627 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13628                             xmlXPtrFreeLocationSet(newlocset);
13629                             goto filter_xptr_error;
13630 			}
13631 
13632                         /*
13633                          * The result of the evaluation need to be tested to
13634                          * decided whether the filter succeeded or not
13635                          */
13636                         res = valuePop(ctxt);
13637                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13638                             xmlXPtrLocationSetAdd(newlocset,
13639                                                   xmlXPathObjectCopy
13640                                                   (oldlocset->locTab[i]));
13641                         }
13642 
13643                         /*
13644                          * Cleanup
13645                          */
13646                         if (res != NULL) {
13647 			    xmlXPathReleaseObject(ctxt->context, res);
13648 			}
13649                         if (ctxt->value == tmp) {
13650                             res = valuePop(ctxt);
13651 			    xmlXPathReleaseObject(ctxt->context, res);
13652                         }
13653                     }
13654 
13655                     /*
13656                      * The result is used as the new evaluation locset.
13657                      */
13658                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13659 filter_xptr_error:
13660 		    xmlXPathReleaseObject(ctxt->context, obj);
13661                     ctxt->context->node = oldnode;
13662                     ctxt->context->contextSize = oldcs;
13663                     ctxt->context->proximityPosition = oldpp;
13664                     return (total);
13665                 }
13666 #endif /* LIBXML_XPTR_ENABLED */
13667 
13668                 /*
13669                  * Extract the old set, and then evaluate the result of the
13670                  * expression for all the element in the set. use it to grow
13671                  * up a new set.
13672                  */
13673                 CHECK_TYPE0(XPATH_NODESET);
13674 
13675                 if ((ctxt->value->nodesetval != NULL) &&
13676                     (ctxt->value->nodesetval->nodeNr != 0)) {
13677                     obj = valuePop(ctxt);
13678                     oldset = obj->nodesetval;
13679                     oldnode = ctxt->context->node;
13680                     oldDoc = ctxt->context->doc;
13681                     oldcs = ctxt->context->contextSize;
13682                     oldpp = ctxt->context->proximityPosition;
13683 		    tmp = NULL;
13684                     /*
13685                      * Initialize the new set.
13686 		     * Also set the xpath document in case things like
13687 		     * key() evaluation are attempted on the predicate
13688                      */
13689                     newset = xmlXPathNodeSetCreate(NULL);
13690 		    /*
13691 		    * SPEC XPath 1.0:
13692 		    *  "For each node in the node-set to be filtered, the
13693 		    *  PredicateExpr is evaluated with that node as the
13694 		    *  context node, with the number of nodes in the
13695 		    *  node-set as the context size, and with the proximity
13696 		    *  position of the node in the node-set with respect to
13697 		    *  the axis as the context position;"
13698 		    * @oldset is the node-set" to be filtered.
13699 		    *
13700 		    * SPEC XPath 1.0:
13701 		    *  "only predicates change the context position and
13702 		    *  context size (see [2.4 Predicates])."
13703 		    * Example:
13704 		    *   node-set  context pos
13705 		    *    nA         1
13706 		    *    nB         2
13707 		    *    nC         3
13708 		    *   After applying predicate [position() > 1] :
13709 		    *   node-set  context pos
13710 		    *    nB         1
13711 		    *    nC         2
13712 		    *
13713 		    * removed the first node in the node-set, then
13714 		    * the context position of the
13715 		    */
13716                     for (i = 0; i < oldset->nodeNr; i++) {
13717                         /*
13718                          * Run the evaluation with a node list made of
13719                          * a single item in the nodeset.
13720                          */
13721                         ctxt->context->node = oldset->nodeTab[i];
13722 			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13723 			    (oldset->nodeTab[i]->doc != NULL))
13724 		            ctxt->context->doc = oldset->nodeTab[i]->doc;
13725 			if (tmp == NULL) {
13726 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13727 				ctxt->context->node);
13728 			} else {
13729 			    if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13730 				               ctxt->context->node) < 0) {
13731 				ctxt->error = XPATH_MEMORY_ERROR;
13732 			    }
13733 			}
13734                         valuePush(ctxt, tmp);
13735                         ctxt->context->contextSize = oldset->nodeNr;
13736                         ctxt->context->proximityPosition = i + 1;
13737 			/*
13738 			* Evaluate the predicate against the context node.
13739 			* Can/should we optimize position() predicates
13740 			* here (e.g. "[1]")?
13741 			*/
13742                         if (op->ch2 != -1)
13743                             total +=
13744                                 xmlXPathCompOpEval(ctxt,
13745                                                    &comp->steps[op->ch2]);
13746 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13747 			    xmlXPathFreeNodeSet(newset);
13748                             goto filter_error;
13749 			}
13750 
13751                         /*
13752                          * The result of the evaluation needs to be tested to
13753                          * decide whether the filter succeeded or not
13754                          */
13755 			/*
13756 			* OPTIMIZE TODO: Can we use
13757 			* xmlXPathNodeSetAdd*Unique()* instead?
13758 			*/
13759                         res = valuePop(ctxt);
13760                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13761                             if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13762 			        < 0)
13763 				ctxt->error = XPATH_MEMORY_ERROR;
13764                         }
13765 
13766                         /*
13767                          * Cleanup
13768                          */
13769                         if (res != NULL) {
13770 			    xmlXPathReleaseObject(ctxt->context, res);
13771 			}
13772                         if (ctxt->value == tmp) {
13773                             valuePop(ctxt);
13774 			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
13775 			    /*
13776 			    * Don't free the temporary nodeset
13777 			    * in order to avoid massive recreation inside this
13778 			    * loop.
13779 			    */
13780                         } else
13781 			    tmp = NULL;
13782                     }
13783 		    if (tmp != NULL)
13784 			xmlXPathReleaseObject(ctxt->context, tmp);
13785                     /*
13786                      * The result is used as the new evaluation set.
13787                      */
13788 		    valuePush(ctxt,
13789 			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13790 filter_error:
13791 		    xmlXPathReleaseObject(ctxt->context, obj);
13792 		    ctxt->context->node = oldnode;
13793 		    ctxt->context->doc = oldDoc;
13794                     ctxt->context->contextSize = oldcs;
13795                     ctxt->context->proximityPosition = oldpp;
13796                 }
13797                 return (total);
13798             }
13799         case XPATH_OP_SORT:
13800             if (op->ch1 != -1)
13801                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13802 	    CHECK_ERROR0;
13803             if ((ctxt->value != NULL) &&
13804                 (ctxt->value->type == XPATH_NODESET) &&
13805                 (ctxt->value->nodesetval != NULL) &&
13806 		(ctxt->value->nodesetval->nodeNr > 1))
13807 	    {
13808                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13809 	    }
13810             return (total);
13811 #ifdef LIBXML_XPTR_ENABLED
13812         case XPATH_OP_RANGETO:{
13813                 xmlXPathObjectPtr range;
13814                 xmlXPathObjectPtr res, obj;
13815                 xmlXPathObjectPtr tmp;
13816                 xmlLocationSetPtr newlocset = NULL;
13817 		    xmlLocationSetPtr oldlocset;
13818                 xmlNodeSetPtr oldset;
13819                 xmlNodePtr oldnode = ctxt->context->node;
13820                 int oldcs = ctxt->context->contextSize;
13821                 int oldpp = ctxt->context->proximityPosition;
13822                 int i, j;
13823 
13824                 if (op->ch1 != -1) {
13825                     total +=
13826                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13827                     CHECK_ERROR0;
13828                 }
13829                 if (ctxt->value == NULL) {
13830                     XP_ERROR0(XPATH_INVALID_OPERAND);
13831                 }
13832                 if (op->ch2 == -1)
13833                     return (total);
13834 
13835                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13836                     /*
13837                      * Extract the old locset, and then evaluate the result of the
13838                      * expression for all the element in the locset. use it to grow
13839                      * up a new locset.
13840                      */
13841                     CHECK_TYPE0(XPATH_LOCATIONSET);
13842 
13843                     if ((ctxt->value->user == NULL) ||
13844                         (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13845                         return (total);
13846 
13847                     obj = valuePop(ctxt);
13848                     oldlocset = obj->user;
13849 
13850                     newlocset = xmlXPtrLocationSetCreate(NULL);
13851 
13852                     for (i = 0; i < oldlocset->locNr; i++) {
13853                         /*
13854                          * Run the evaluation with a node list made of a
13855                          * single item in the nodelocset.
13856                          */
13857                         ctxt->context->node = oldlocset->locTab[i]->user;
13858                         ctxt->context->contextSize = oldlocset->locNr;
13859                         ctxt->context->proximityPosition = i + 1;
13860 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13861 			    ctxt->context->node);
13862                         valuePush(ctxt, tmp);
13863 
13864                         if (op->ch2 != -1)
13865                             total +=
13866                                 xmlXPathCompOpEval(ctxt,
13867                                                    &comp->steps[op->ch2]);
13868 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13869                             xmlXPtrFreeLocationSet(newlocset);
13870                             goto rangeto_error;
13871 			}
13872 
13873                         res = valuePop(ctxt);
13874 			if (res->type == XPATH_LOCATIONSET) {
13875 			    xmlLocationSetPtr rloc =
13876 			        (xmlLocationSetPtr)res->user;
13877 			    for (j=0; j<rloc->locNr; j++) {
13878 			        range = xmlXPtrNewRange(
13879 				  oldlocset->locTab[i]->user,
13880 				  oldlocset->locTab[i]->index,
13881 				  rloc->locTab[j]->user2,
13882 				  rloc->locTab[j]->index2);
13883 				if (range != NULL) {
13884 				    xmlXPtrLocationSetAdd(newlocset, range);
13885 				}
13886 			    }
13887 			} else {
13888 			    range = xmlXPtrNewRangeNodeObject(
13889 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
13890                             if (range != NULL) {
13891                                 xmlXPtrLocationSetAdd(newlocset,range);
13892 			    }
13893                         }
13894 
13895                         /*
13896                          * Cleanup
13897                          */
13898                         if (res != NULL) {
13899 			    xmlXPathReleaseObject(ctxt->context, res);
13900 			}
13901                         if (ctxt->value == tmp) {
13902                             res = valuePop(ctxt);
13903 			    xmlXPathReleaseObject(ctxt->context, res);
13904                         }
13905                     }
13906 		} else {	/* Not a location set */
13907                     CHECK_TYPE0(XPATH_NODESET);
13908                     obj = valuePop(ctxt);
13909                     oldset = obj->nodesetval;
13910 
13911                     newlocset = xmlXPtrLocationSetCreate(NULL);
13912 
13913                     if (oldset != NULL) {
13914                         for (i = 0; i < oldset->nodeNr; i++) {
13915                             /*
13916                              * Run the evaluation with a node list made of a single item
13917                              * in the nodeset.
13918                              */
13919                             ctxt->context->node = oldset->nodeTab[i];
13920 			    /*
13921 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
13922 			    */
13923 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13924 				ctxt->context->node);
13925                             valuePush(ctxt, tmp);
13926 
13927                             if (op->ch2 != -1)
13928                                 total +=
13929                                     xmlXPathCompOpEval(ctxt,
13930                                                    &comp->steps[op->ch2]);
13931 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
13932                                 xmlXPtrFreeLocationSet(newlocset);
13933                                 goto rangeto_error;
13934 			    }
13935 
13936                             res = valuePop(ctxt);
13937                             range =
13938                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13939                                                       res);
13940                             if (range != NULL) {
13941                                 xmlXPtrLocationSetAdd(newlocset, range);
13942                             }
13943 
13944                             /*
13945                              * Cleanup
13946                              */
13947                             if (res != NULL) {
13948 				xmlXPathReleaseObject(ctxt->context, res);
13949 			    }
13950                             if (ctxt->value == tmp) {
13951                                 res = valuePop(ctxt);
13952 				xmlXPathReleaseObject(ctxt->context, res);
13953                             }
13954                         }
13955                     }
13956                 }
13957 
13958                 /*
13959                  * The result is used as the new evaluation set.
13960                  */
13961                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13962 rangeto_error:
13963 		xmlXPathReleaseObject(ctxt->context, obj);
13964                 ctxt->context->node = oldnode;
13965                 ctxt->context->contextSize = oldcs;
13966                 ctxt->context->proximityPosition = oldpp;
13967                 return (total);
13968             }
13969 #endif /* LIBXML_XPTR_ENABLED */
13970     }
13971     xmlGenericError(xmlGenericErrorContext,
13972                     "XPath: unknown precompiled operation %d\n", op->op);
13973     ctxt->error = XPATH_INVALID_OPERAND;
13974     return (total);
13975 }
13976 
13977 /**
13978  * xmlXPathCompOpEvalToBoolean:
13979  * @ctxt:  the XPath parser context
13980  *
13981  * Evaluates if the expression evaluates to true.
13982  *
13983  * Returns 1 if true, 0 if false and -1 on API or internal errors.
13984  */
13985 static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int isPredicate)13986 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13987 			    xmlXPathStepOpPtr op,
13988 			    int isPredicate)
13989 {
13990     xmlXPathObjectPtr resObj = NULL;
13991 
13992 start:
13993     /* comp = ctxt->comp; */
13994     switch (op->op) {
13995         case XPATH_OP_END:
13996             return (0);
13997 	case XPATH_OP_VALUE:
13998 	    resObj = (xmlXPathObjectPtr) op->value4;
13999 	    if (isPredicate)
14000 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14001 	    return(xmlXPathCastToBoolean(resObj));
14002 	case XPATH_OP_SORT:
14003 	    /*
14004 	    * We don't need sorting for boolean results. Skip this one.
14005 	    */
14006             if (op->ch1 != -1) {
14007 		op = &ctxt->comp->steps[op->ch1];
14008 		goto start;
14009 	    }
14010 	    return(0);
14011 	case XPATH_OP_COLLECT:
14012 	    if (op->ch1 == -1)
14013 		return(0);
14014 
14015             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14016 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14017 		return(-1);
14018 
14019             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14020 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14021 		return(-1);
14022 
14023 	    resObj = valuePop(ctxt);
14024 	    if (resObj == NULL)
14025 		return(-1);
14026 	    break;
14027 	default:
14028 	    /*
14029 	    * Fallback to call xmlXPathCompOpEval().
14030 	    */
14031 	    xmlXPathCompOpEval(ctxt, op);
14032 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14033 		return(-1);
14034 
14035 	    resObj = valuePop(ctxt);
14036 	    if (resObj == NULL)
14037 		return(-1);
14038 	    break;
14039     }
14040 
14041     if (resObj) {
14042 	int res;
14043 
14044 	if (resObj->type == XPATH_BOOLEAN) {
14045 	    res = resObj->boolval;
14046 	} else if (isPredicate) {
14047 	    /*
14048 	    * For predicates a result of type "number" is handled
14049 	    * differently:
14050 	    * SPEC XPath 1.0:
14051 	    * "If the result is a number, the result will be converted
14052 	    *  to true if the number is equal to the context position
14053 	    *  and will be converted to false otherwise;"
14054 	    */
14055 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14056 	} else {
14057 	    res = xmlXPathCastToBoolean(resObj);
14058 	}
14059 	xmlXPathReleaseObject(ctxt->context, resObj);
14060 	return(res);
14061     }
14062 
14063     return(0);
14064 }
14065 
14066 #ifdef XPATH_STREAMING
14067 /**
14068  * xmlXPathRunStreamEval:
14069  * @ctxt:  the XPath parser context with the compiled expression
14070  *
14071  * Evaluate the Precompiled Streamable XPath expression in the given context.
14072  */
14073 static int
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt,xmlPatternPtr comp,xmlXPathObjectPtr * resultSeq,int toBool)14074 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14075 		      xmlXPathObjectPtr *resultSeq, int toBool)
14076 {
14077     int max_depth, min_depth;
14078     int from_root;
14079     int ret, depth;
14080     int eval_all_nodes;
14081     xmlNodePtr cur = NULL, limit = NULL;
14082     xmlStreamCtxtPtr patstream = NULL;
14083 
14084     int nb_nodes = 0;
14085 
14086     if ((ctxt == NULL) || (comp == NULL))
14087         return(-1);
14088     max_depth = xmlPatternMaxDepth(comp);
14089     if (max_depth == -1)
14090         return(-1);
14091     if (max_depth == -2)
14092         max_depth = 10000;
14093     min_depth = xmlPatternMinDepth(comp);
14094     if (min_depth == -1)
14095         return(-1);
14096     from_root = xmlPatternFromRoot(comp);
14097     if (from_root < 0)
14098         return(-1);
14099 #if 0
14100     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14101 #endif
14102 
14103     if (! toBool) {
14104 	if (resultSeq == NULL)
14105 	    return(-1);
14106 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14107 	if (*resultSeq == NULL)
14108 	    return(-1);
14109     }
14110 
14111     /*
14112      * handle the special cases of "/" amd "." being matched
14113      */
14114     if (min_depth == 0) {
14115 	if (from_root) {
14116 	    /* Select "/" */
14117 	    if (toBool)
14118 		return(1);
14119 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14120 		                     (xmlNodePtr) ctxt->doc);
14121 	} else {
14122 	    /* Select "self::node()" */
14123 	    if (toBool)
14124 		return(1);
14125 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14126 	}
14127     }
14128     if (max_depth == 0) {
14129 	return(0);
14130     }
14131 
14132     if (from_root) {
14133         cur = (xmlNodePtr)ctxt->doc;
14134     } else if (ctxt->node != NULL) {
14135         switch (ctxt->node->type) {
14136             case XML_ELEMENT_NODE:
14137             case XML_DOCUMENT_NODE:
14138             case XML_DOCUMENT_FRAG_NODE:
14139             case XML_HTML_DOCUMENT_NODE:
14140 #ifdef LIBXML_DOCB_ENABLED
14141             case XML_DOCB_DOCUMENT_NODE:
14142 #endif
14143 	        cur = ctxt->node;
14144 		break;
14145             case XML_ATTRIBUTE_NODE:
14146             case XML_TEXT_NODE:
14147             case XML_CDATA_SECTION_NODE:
14148             case XML_ENTITY_REF_NODE:
14149             case XML_ENTITY_NODE:
14150             case XML_PI_NODE:
14151             case XML_COMMENT_NODE:
14152             case XML_NOTATION_NODE:
14153             case XML_DTD_NODE:
14154             case XML_DOCUMENT_TYPE_NODE:
14155             case XML_ELEMENT_DECL:
14156             case XML_ATTRIBUTE_DECL:
14157             case XML_ENTITY_DECL:
14158             case XML_NAMESPACE_DECL:
14159             case XML_XINCLUDE_START:
14160             case XML_XINCLUDE_END:
14161 		break;
14162 	}
14163 	limit = cur;
14164     }
14165     if (cur == NULL) {
14166         return(0);
14167     }
14168 
14169     patstream = xmlPatternGetStreamCtxt(comp);
14170     if (patstream == NULL) {
14171 	/*
14172 	* QUESTION TODO: Is this an error?
14173 	*/
14174 	return(0);
14175     }
14176 
14177     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14178 
14179     if (from_root) {
14180 	ret = xmlStreamPush(patstream, NULL, NULL);
14181 	if (ret < 0) {
14182 	} else if (ret == 1) {
14183 	    if (toBool)
14184 		goto return_1;
14185 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14186 	}
14187     }
14188     depth = 0;
14189     goto scan_children;
14190 next_node:
14191     do {
14192         nb_nodes++;
14193 
14194 	switch (cur->type) {
14195 	    case XML_ELEMENT_NODE:
14196 	    case XML_TEXT_NODE:
14197 	    case XML_CDATA_SECTION_NODE:
14198 	    case XML_COMMENT_NODE:
14199 	    case XML_PI_NODE:
14200 		if (cur->type == XML_ELEMENT_NODE) {
14201 		    ret = xmlStreamPush(patstream, cur->name,
14202 				(cur->ns ? cur->ns->href : NULL));
14203 		} else if (eval_all_nodes)
14204 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14205 		else
14206 		    break;
14207 
14208 		if (ret < 0) {
14209 		    /* NOP. */
14210 		} else if (ret == 1) {
14211 		    if (toBool)
14212 			goto return_1;
14213 		    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14214 		        < 0) {
14215 			ctxt->lastError.domain = XML_FROM_XPATH;
14216 			ctxt->lastError.code = XML_ERR_NO_MEMORY;
14217 		    }
14218 		}
14219 		if ((cur->children == NULL) || (depth >= max_depth)) {
14220 		    ret = xmlStreamPop(patstream);
14221 		    while (cur->next != NULL) {
14222 			cur = cur->next;
14223 			if ((cur->type != XML_ENTITY_DECL) &&
14224 			    (cur->type != XML_DTD_NODE))
14225 			    goto next_node;
14226 		    }
14227 		}
14228 	    default:
14229 		break;
14230 	}
14231 
14232 scan_children:
14233 	if (cur->type == XML_NAMESPACE_DECL) break;
14234 	if ((cur->children != NULL) && (depth < max_depth)) {
14235 	    /*
14236 	     * Do not descend on entities declarations
14237 	     */
14238 	    if (cur->children->type != XML_ENTITY_DECL) {
14239 		cur = cur->children;
14240 		depth++;
14241 		/*
14242 		 * Skip DTDs
14243 		 */
14244 		if (cur->type != XML_DTD_NODE)
14245 		    continue;
14246 	    }
14247 	}
14248 
14249 	if (cur == limit)
14250 	    break;
14251 
14252 	while (cur->next != NULL) {
14253 	    cur = cur->next;
14254 	    if ((cur->type != XML_ENTITY_DECL) &&
14255 		(cur->type != XML_DTD_NODE))
14256 		goto next_node;
14257 	}
14258 
14259 	do {
14260 	    cur = cur->parent;
14261 	    depth--;
14262 	    if ((cur == NULL) || (cur == limit))
14263 	        goto done;
14264 	    if (cur->type == XML_ELEMENT_NODE) {
14265 		ret = xmlStreamPop(patstream);
14266 	    } else if ((eval_all_nodes) &&
14267 		((cur->type == XML_TEXT_NODE) ||
14268 		 (cur->type == XML_CDATA_SECTION_NODE) ||
14269 		 (cur->type == XML_COMMENT_NODE) ||
14270 		 (cur->type == XML_PI_NODE)))
14271 	    {
14272 		ret = xmlStreamPop(patstream);
14273 	    }
14274 	    if (cur->next != NULL) {
14275 		cur = cur->next;
14276 		break;
14277 	    }
14278 	} while (cur != NULL);
14279 
14280     } while ((cur != NULL) && (depth >= 0));
14281 
14282 done:
14283 
14284 #if 0
14285     printf("stream eval: checked %d nodes selected %d\n",
14286            nb_nodes, retObj->nodesetval->nodeNr);
14287 #endif
14288 
14289     if (patstream)
14290 	xmlFreeStreamCtxt(patstream);
14291     return(0);
14292 
14293 return_1:
14294     if (patstream)
14295 	xmlFreeStreamCtxt(patstream);
14296     return(1);
14297 }
14298 #endif /* XPATH_STREAMING */
14299 
14300 /**
14301  * xmlXPathRunEval:
14302  * @ctxt:  the XPath parser context with the compiled expression
14303  * @toBool:  evaluate to a boolean result
14304  *
14305  * Evaluate the Precompiled XPath expression in the given context.
14306  */
14307 static int
xmlXPathRunEval(xmlXPathParserContextPtr ctxt,int toBool)14308 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14309 {
14310     xmlXPathCompExprPtr comp;
14311 
14312     if ((ctxt == NULL) || (ctxt->comp == NULL))
14313 	return(-1);
14314 
14315     if (ctxt->valueTab == NULL) {
14316 	/* Allocate the value stack */
14317 	ctxt->valueTab = (xmlXPathObjectPtr *)
14318 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14319 	if (ctxt->valueTab == NULL) {
14320 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14321 	    xmlFree(ctxt);
14322 	}
14323 	ctxt->valueNr = 0;
14324 	ctxt->valueMax = 10;
14325 	ctxt->value = NULL;
14326         ctxt->valueFrame = 0;
14327     }
14328 #ifdef XPATH_STREAMING
14329     if (ctxt->comp->stream) {
14330 	int res;
14331 
14332 	if (toBool) {
14333 	    /*
14334 	    * Evaluation to boolean result.
14335 	    */
14336 	    res = xmlXPathRunStreamEval(ctxt->context,
14337 		ctxt->comp->stream, NULL, 1);
14338 	    if (res != -1)
14339 		return(res);
14340 	} else {
14341 	    xmlXPathObjectPtr resObj = NULL;
14342 
14343 	    /*
14344 	    * Evaluation to a sequence.
14345 	    */
14346 	    res = xmlXPathRunStreamEval(ctxt->context,
14347 		ctxt->comp->stream, &resObj, 0);
14348 
14349 	    if ((res != -1) && (resObj != NULL)) {
14350 		valuePush(ctxt, resObj);
14351 		return(0);
14352 	    }
14353 	    if (resObj != NULL)
14354 		xmlXPathReleaseObject(ctxt->context, resObj);
14355 	}
14356 	/*
14357 	* QUESTION TODO: This falls back to normal XPath evaluation
14358 	* if res == -1. Is this intended?
14359 	*/
14360     }
14361 #endif
14362     comp = ctxt->comp;
14363     if (comp->last < 0) {
14364 	xmlGenericError(xmlGenericErrorContext,
14365 	    "xmlXPathRunEval: last is less than zero\n");
14366 	return(-1);
14367     }
14368     if (toBool)
14369 	return(xmlXPathCompOpEvalToBoolean(ctxt,
14370 	    &comp->steps[comp->last], 0));
14371     else
14372 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14373 
14374     return(0);
14375 }
14376 
14377 /************************************************************************
14378  *									*
14379  *			Public interfaces				*
14380  *									*
14381  ************************************************************************/
14382 
14383 /**
14384  * xmlXPathEvalPredicate:
14385  * @ctxt:  the XPath context
14386  * @res:  the Predicate Expression evaluation result
14387  *
14388  * Evaluate a predicate result for the current node.
14389  * A PredicateExpr is evaluated by evaluating the Expr and converting
14390  * the result to a boolean. If the result is a number, the result will
14391  * be converted to true if the number is equal to the position of the
14392  * context node in the context node list (as returned by the position
14393  * function) and will be converted to false otherwise; if the result
14394  * is not a number, then the result will be converted as if by a call
14395  * to the boolean function.
14396  *
14397  * Returns 1 if predicate is true, 0 otherwise
14398  */
14399 int
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt,xmlXPathObjectPtr res)14400 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14401     if ((ctxt == NULL) || (res == NULL)) return(0);
14402     switch (res->type) {
14403         case XPATH_BOOLEAN:
14404 	    return(res->boolval);
14405         case XPATH_NUMBER:
14406 	    return(res->floatval == ctxt->proximityPosition);
14407         case XPATH_NODESET:
14408         case XPATH_XSLT_TREE:
14409 	    if (res->nodesetval == NULL)
14410 		return(0);
14411 	    return(res->nodesetval->nodeNr != 0);
14412         case XPATH_STRING:
14413 	    return((res->stringval != NULL) &&
14414 	           (xmlStrlen(res->stringval) != 0));
14415         default:
14416 	    STRANGE
14417     }
14418     return(0);
14419 }
14420 
14421 /**
14422  * xmlXPathEvaluatePredicateResult:
14423  * @ctxt:  the XPath Parser context
14424  * @res:  the Predicate Expression evaluation result
14425  *
14426  * Evaluate a predicate result for the current node.
14427  * A PredicateExpr is evaluated by evaluating the Expr and converting
14428  * the result to a boolean. If the result is a number, the result will
14429  * be converted to true if the number is equal to the position of the
14430  * context node in the context node list (as returned by the position
14431  * function) and will be converted to false otherwise; if the result
14432  * is not a number, then the result will be converted as if by a call
14433  * to the boolean function.
14434  *
14435  * Returns 1 if predicate is true, 0 otherwise
14436  */
14437 int
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr res)14438 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14439                                 xmlXPathObjectPtr res) {
14440     if ((ctxt == NULL) || (res == NULL)) return(0);
14441     switch (res->type) {
14442         case XPATH_BOOLEAN:
14443 	    return(res->boolval);
14444         case XPATH_NUMBER:
14445 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14446 	    return((res->floatval == ctxt->context->proximityPosition) &&
14447 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14448 #else
14449 	    return(res->floatval == ctxt->context->proximityPosition);
14450 #endif
14451         case XPATH_NODESET:
14452         case XPATH_XSLT_TREE:
14453 	    if (res->nodesetval == NULL)
14454 		return(0);
14455 	    return(res->nodesetval->nodeNr != 0);
14456         case XPATH_STRING:
14457 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
14458 #ifdef LIBXML_XPTR_ENABLED
14459 	case XPATH_LOCATIONSET:{
14460 	    xmlLocationSetPtr ptr = res->user;
14461 	    if (ptr == NULL)
14462 	        return(0);
14463 	    return (ptr->locNr != 0);
14464 	    }
14465 #endif
14466         default:
14467 	    STRANGE
14468     }
14469     return(0);
14470 }
14471 
14472 #ifdef XPATH_STREAMING
14473 /**
14474  * xmlXPathTryStreamCompile:
14475  * @ctxt: an XPath context
14476  * @str:  the XPath expression
14477  *
14478  * Try to compile the XPath expression as a streamable subset.
14479  *
14480  * Returns the compiled expression or NULL if failed to compile.
14481  */
14482 static xmlXPathCompExprPtr
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14483 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14484     /*
14485      * Optimization: use streaming patterns when the XPath expression can
14486      * be compiled to a stream lookup
14487      */
14488     xmlPatternPtr stream;
14489     xmlXPathCompExprPtr comp;
14490     xmlDictPtr dict = NULL;
14491     const xmlChar **namespaces = NULL;
14492     xmlNsPtr ns;
14493     int i, j;
14494 
14495     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14496         (!xmlStrchr(str, '@'))) {
14497 	const xmlChar *tmp;
14498 
14499 	/*
14500 	 * We don't try to handle expressions using the verbose axis
14501 	 * specifiers ("::"), just the simplied form at this point.
14502 	 * Additionally, if there is no list of namespaces available and
14503 	 *  there's a ":" in the expression, indicating a prefixed QName,
14504 	 *  then we won't try to compile either. xmlPatterncompile() needs
14505 	 *  to have a list of namespaces at compilation time in order to
14506 	 *  compile prefixed name tests.
14507 	 */
14508 	tmp = xmlStrchr(str, ':');
14509 	if ((tmp != NULL) &&
14510 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14511 	    return(NULL);
14512 
14513 	if (ctxt != NULL) {
14514 	    dict = ctxt->dict;
14515 	    if (ctxt->nsNr > 0) {
14516 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14517 		if (namespaces == NULL) {
14518 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14519 		    return(NULL);
14520 		}
14521 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14522 		    ns = ctxt->namespaces[j];
14523 		    namespaces[i++] = ns->href;
14524 		    namespaces[i++] = ns->prefix;
14525 		}
14526 		namespaces[i++] = NULL;
14527 		namespaces[i] = NULL;
14528 	    }
14529 	}
14530 
14531 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14532 			&namespaces[0]);
14533 	if (namespaces != NULL) {
14534 	    xmlFree((xmlChar **)namespaces);
14535 	}
14536 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14537 	    comp = xmlXPathNewCompExpr();
14538 	    if (comp == NULL) {
14539 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14540 		return(NULL);
14541 	    }
14542 	    comp->stream = stream;
14543 	    comp->dict = dict;
14544 	    if (comp->dict)
14545 		xmlDictReference(comp->dict);
14546 	    return(comp);
14547 	}
14548 	xmlFreePattern(stream);
14549     }
14550     return(NULL);
14551 }
14552 #endif /* XPATH_STREAMING */
14553 
14554 static void
xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op)14555 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14556 {
14557     /*
14558     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14559     * internal representation.
14560     */
14561 
14562     if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14563         (op->ch1 != -1) &&
14564         (op->ch2 == -1 /* no predicate */))
14565     {
14566         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14567 
14568         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14569             ((xmlXPathAxisVal) prevop->value ==
14570                 AXIS_DESCENDANT_OR_SELF) &&
14571             (prevop->ch2 == -1) &&
14572             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14573             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14574         {
14575             /*
14576             * This is a "descendant-or-self::node()" without predicates.
14577             * Try to eliminate it.
14578             */
14579 
14580             switch ((xmlXPathAxisVal) op->value) {
14581                 case AXIS_CHILD:
14582                 case AXIS_DESCENDANT:
14583                     /*
14584                     * Convert "descendant-or-self::node()/child::" or
14585                     * "descendant-or-self::node()/descendant::" to
14586                     * "descendant::"
14587                     */
14588                     op->ch1   = prevop->ch1;
14589                     op->value = AXIS_DESCENDANT;
14590                     break;
14591                 case AXIS_SELF:
14592                 case AXIS_DESCENDANT_OR_SELF:
14593                     /*
14594                     * Convert "descendant-or-self::node()/self::" or
14595                     * "descendant-or-self::node()/descendant-or-self::" to
14596                     * to "descendant-or-self::"
14597                     */
14598                     op->ch1   = prevop->ch1;
14599                     op->value = AXIS_DESCENDANT_OR_SELF;
14600                     break;
14601                 default:
14602                     break;
14603             }
14604 	}
14605     }
14606 
14607     /* OP_VALUE has invalid ch1. */
14608     if (op->op == XPATH_OP_VALUE)
14609         return;
14610 
14611     /* Recurse */
14612     if (op->ch1 != -1)
14613         xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
14614     if (op->ch2 != -1)
14615 	xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
14616 }
14617 
14618 /**
14619  * xmlXPathCtxtCompile:
14620  * @ctxt: an XPath context
14621  * @str:  the XPath expression
14622  *
14623  * Compile an XPath expression
14624  *
14625  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14626  *         the caller has to free the object.
14627  */
14628 xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14629 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14630     xmlXPathParserContextPtr pctxt;
14631     xmlXPathCompExprPtr comp;
14632 
14633 #ifdef XPATH_STREAMING
14634     comp = xmlXPathTryStreamCompile(ctxt, str);
14635     if (comp != NULL)
14636         return(comp);
14637 #endif
14638 
14639     xmlXPathInit();
14640 
14641     pctxt = xmlXPathNewParserContext(str, ctxt);
14642     if (pctxt == NULL)
14643         return NULL;
14644     xmlXPathCompileExpr(pctxt, 1);
14645 
14646     if( pctxt->error != XPATH_EXPRESSION_OK )
14647     {
14648         xmlXPathFreeParserContext(pctxt);
14649         return(NULL);
14650     }
14651 
14652     if (*pctxt->cur != 0) {
14653 	/*
14654 	 * aleksey: in some cases this line prints *second* error message
14655 	 * (see bug #78858) and probably this should be fixed.
14656 	 * However, we are not sure that all error messages are printed
14657 	 * out in other places. It's not critical so we leave it as-is for now
14658 	 */
14659 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14660 	comp = NULL;
14661     } else {
14662 	comp = pctxt->comp;
14663 	pctxt->comp = NULL;
14664     }
14665     xmlXPathFreeParserContext(pctxt);
14666 
14667     if (comp != NULL) {
14668 	comp->expr = xmlStrdup(str);
14669 #ifdef DEBUG_EVAL_COUNTS
14670 	comp->string = xmlStrdup(str);
14671 	comp->nb = 0;
14672 #endif
14673 	if ((comp->nbStep > 1) && (comp->last >= 0)) {
14674 	    xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
14675 	}
14676     }
14677     return(comp);
14678 }
14679 
14680 /**
14681  * xmlXPathCompile:
14682  * @str:  the XPath expression
14683  *
14684  * Compile an XPath expression
14685  *
14686  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14687  *         the caller has to free the object.
14688  */
14689 xmlXPathCompExprPtr
xmlXPathCompile(const xmlChar * str)14690 xmlXPathCompile(const xmlChar *str) {
14691     return(xmlXPathCtxtCompile(NULL, str));
14692 }
14693 
14694 /**
14695  * xmlXPathCompiledEvalInternal:
14696  * @comp:  the compiled XPath expression
14697  * @ctxt:  the XPath context
14698  * @resObj: the resulting XPath object or NULL
14699  * @toBool: 1 if only a boolean result is requested
14700  *
14701  * Evaluate the Precompiled XPath expression in the given context.
14702  * The caller has to free @resObj.
14703  *
14704  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14705  *         the caller has to free the object.
14706  */
14707 static int
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt,xmlXPathObjectPtr * resObjPtr,int toBool)14708 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14709 			     xmlXPathContextPtr ctxt,
14710 			     xmlXPathObjectPtr *resObjPtr,
14711 			     int toBool)
14712 {
14713     xmlXPathParserContextPtr pctxt;
14714     xmlXPathObjectPtr resObj;
14715 #ifndef LIBXML_THREAD_ENABLED
14716     static int reentance = 0;
14717 #endif
14718     int res;
14719 
14720     CHECK_CTXT_NEG(ctxt)
14721 
14722     if (comp == NULL)
14723 	return(-1);
14724     xmlXPathInit();
14725 
14726 #ifndef LIBXML_THREAD_ENABLED
14727     reentance++;
14728     if (reentance > 1)
14729 	xmlXPathDisableOptimizer = 1;
14730 #endif
14731 
14732 #ifdef DEBUG_EVAL_COUNTS
14733     comp->nb++;
14734     if ((comp->string != NULL) && (comp->nb > 100)) {
14735 	fprintf(stderr, "100 x %s\n", comp->string);
14736 	comp->nb = 0;
14737     }
14738 #endif
14739     pctxt = xmlXPathCompParserContext(comp, ctxt);
14740     res = xmlXPathRunEval(pctxt, toBool);
14741 
14742     if (pctxt->error != XPATH_EXPRESSION_OK) {
14743         resObj = NULL;
14744     } else {
14745         resObj = valuePop(pctxt);
14746         if (resObj == NULL) {
14747             if (!toBool)
14748                 xmlGenericError(xmlGenericErrorContext,
14749                     "xmlXPathCompiledEval: No result on the stack.\n");
14750         } else if (pctxt->valueNr > 0) {
14751             xmlGenericError(xmlGenericErrorContext,
14752                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14753                 pctxt->valueNr);
14754         }
14755     }
14756 
14757     if (resObjPtr)
14758         *resObjPtr = resObj;
14759     else
14760         xmlXPathReleaseObject(ctxt, resObj);
14761 
14762     pctxt->comp = NULL;
14763     xmlXPathFreeParserContext(pctxt);
14764 #ifndef LIBXML_THREAD_ENABLED
14765     reentance--;
14766 #endif
14767 
14768     return(res);
14769 }
14770 
14771 /**
14772  * xmlXPathCompiledEval:
14773  * @comp:  the compiled XPath expression
14774  * @ctx:  the XPath context
14775  *
14776  * Evaluate the Precompiled XPath expression in the given context.
14777  *
14778  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14779  *         the caller has to free the object.
14780  */
14781 xmlXPathObjectPtr
xmlXPathCompiledEval(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctx)14782 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14783 {
14784     xmlXPathObjectPtr res = NULL;
14785 
14786     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14787     return(res);
14788 }
14789 
14790 /**
14791  * xmlXPathCompiledEvalToBoolean:
14792  * @comp:  the compiled XPath expression
14793  * @ctxt:  the XPath context
14794  *
14795  * Applies the XPath boolean() function on the result of the given
14796  * compiled expression.
14797  *
14798  * Returns 1 if the expression evaluated to true, 0 if to false and
14799  *         -1 in API and internal errors.
14800  */
14801 int
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)14802 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14803 			      xmlXPathContextPtr ctxt)
14804 {
14805     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14806 }
14807 
14808 /**
14809  * xmlXPathEvalExpr:
14810  * @ctxt:  the XPath Parser context
14811  *
14812  * Parse and evaluate an XPath expression in the given context,
14813  * then push the result on the context stack
14814  */
14815 void
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt)14816 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14817 #ifdef XPATH_STREAMING
14818     xmlXPathCompExprPtr comp;
14819 #endif
14820 
14821     if (ctxt == NULL) return;
14822 
14823 #ifdef XPATH_STREAMING
14824     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14825     if (comp != NULL) {
14826         if (ctxt->comp != NULL)
14827 	    xmlXPathFreeCompExpr(ctxt->comp);
14828         ctxt->comp = comp;
14829     } else
14830 #endif
14831     {
14832 	xmlXPathCompileExpr(ctxt, 1);
14833         CHECK_ERROR;
14834 
14835         /* Check for trailing characters. */
14836         if (*ctxt->cur != 0)
14837             XP_ERROR(XPATH_EXPR_ERROR);
14838 
14839 	if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0))
14840 	    xmlXPathOptimizeExpression(ctxt->comp,
14841 		&ctxt->comp->steps[ctxt->comp->last]);
14842     }
14843 
14844     xmlXPathRunEval(ctxt, 0);
14845 }
14846 
14847 /**
14848  * xmlXPathEval:
14849  * @str:  the XPath expression
14850  * @ctx:  the XPath context
14851  *
14852  * Evaluate the XPath Location Path in the given context.
14853  *
14854  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14855  *         the caller has to free the object.
14856  */
14857 xmlXPathObjectPtr
xmlXPathEval(const xmlChar * str,xmlXPathContextPtr ctx)14858 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14859     xmlXPathParserContextPtr ctxt;
14860     xmlXPathObjectPtr res;
14861 
14862     CHECK_CTXT(ctx)
14863 
14864     xmlXPathInit();
14865 
14866     ctxt = xmlXPathNewParserContext(str, ctx);
14867     if (ctxt == NULL)
14868         return NULL;
14869     xmlXPathEvalExpr(ctxt);
14870 
14871     if (ctxt->error != XPATH_EXPRESSION_OK) {
14872 	res = NULL;
14873     } else {
14874 	res = valuePop(ctxt);
14875         if (res == NULL) {
14876             xmlGenericError(xmlGenericErrorContext,
14877                 "xmlXPathCompiledEval: No result on the stack.\n");
14878         } else if (ctxt->valueNr > 0) {
14879             xmlGenericError(xmlGenericErrorContext,
14880                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14881                 ctxt->valueNr);
14882         }
14883     }
14884 
14885     xmlXPathFreeParserContext(ctxt);
14886     return(res);
14887 }
14888 
14889 /**
14890  * xmlXPathSetContextNode:
14891  * @node: the node to to use as the context node
14892  * @ctx:  the XPath context
14893  *
14894  * Sets 'node' as the context node. The node must be in the same
14895  * document as that associated with the context.
14896  *
14897  * Returns -1 in case of error or 0 if successful
14898  */
14899 int
xmlXPathSetContextNode(xmlNodePtr node,xmlXPathContextPtr ctx)14900 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14901     if ((node == NULL) || (ctx == NULL))
14902         return(-1);
14903 
14904     if (node->doc == ctx->doc) {
14905         ctx->node = node;
14906 	return(0);
14907     }
14908     return(-1);
14909 }
14910 
14911 /**
14912  * xmlXPathNodeEval:
14913  * @node: the node to to use as the context node
14914  * @str:  the XPath expression
14915  * @ctx:  the XPath context
14916  *
14917  * Evaluate the XPath Location Path in the given context. The node 'node'
14918  * is set as the context node. The context node is not restored.
14919  *
14920  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14921  *         the caller has to free the object.
14922  */
14923 xmlXPathObjectPtr
xmlXPathNodeEval(xmlNodePtr node,const xmlChar * str,xmlXPathContextPtr ctx)14924 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14925     if (str == NULL)
14926         return(NULL);
14927     if (xmlXPathSetContextNode(node, ctx) < 0)
14928         return(NULL);
14929     return(xmlXPathEval(str, ctx));
14930 }
14931 
14932 /**
14933  * xmlXPathEvalExpression:
14934  * @str:  the XPath expression
14935  * @ctxt:  the XPath context
14936  *
14937  * Alias for xmlXPathEval().
14938  *
14939  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14940  *         the caller has to free the object.
14941  */
14942 xmlXPathObjectPtr
xmlXPathEvalExpression(const xmlChar * str,xmlXPathContextPtr ctxt)14943 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14944     return(xmlXPathEval(str, ctxt));
14945 }
14946 
14947 /************************************************************************
14948  *									*
14949  *	Extra functions not pertaining to the XPath spec		*
14950  *									*
14951  ************************************************************************/
14952 /**
14953  * xmlXPathEscapeUriFunction:
14954  * @ctxt:  the XPath Parser context
14955  * @nargs:  the number of arguments
14956  *
14957  * Implement the escape-uri() XPath function
14958  *    string escape-uri(string $str, bool $escape-reserved)
14959  *
14960  * This function applies the URI escaping rules defined in section 2 of [RFC
14961  * 2396] to the string supplied as $uri-part, which typically represents all
14962  * or part of a URI. The effect of the function is to replace any special
14963  * character in the string by an escape sequence of the form %xx%yy...,
14964  * where xxyy... is the hexadecimal representation of the octets used to
14965  * represent the character in UTF-8.
14966  *
14967  * The set of characters that are escaped depends on the setting of the
14968  * boolean argument $escape-reserved.
14969  *
14970  * If $escape-reserved is true, all characters are escaped other than lower
14971  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14972  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14973  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14974  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14975  * A-F).
14976  *
14977  * If $escape-reserved is false, the behavior differs in that characters
14978  * referred to in [RFC 2396] as reserved characters are not escaped. These
14979  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14980  *
14981  * [RFC 2396] does not define whether escaped URIs should use lower case or
14982  * upper case for hexadecimal digits. To ensure that escaped URIs can be
14983  * compared using string comparison functions, this function must always use
14984  * the upper-case letters A-F.
14985  *
14986  * Generally, $escape-reserved should be set to true when escaping a string
14987  * that is to form a single part of a URI, and to false when escaping an
14988  * entire URI or URI reference.
14989  *
14990  * In the case of non-ascii characters, the string is encoded according to
14991  * utf-8 and then converted according to RFC 2396.
14992  *
14993  * Examples
14994  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14995  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14996  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14997  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14998  *
14999  */
15000 static void
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt,int nargs)15001 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15002     xmlXPathObjectPtr str;
15003     int escape_reserved;
15004     xmlBufPtr target;
15005     xmlChar *cptr;
15006     xmlChar escape[4];
15007 
15008     CHECK_ARITY(2);
15009 
15010     escape_reserved = xmlXPathPopBoolean(ctxt);
15011 
15012     CAST_TO_STRING;
15013     str = valuePop(ctxt);
15014 
15015     target = xmlBufCreate();
15016 
15017     escape[0] = '%';
15018     escape[3] = 0;
15019 
15020     if (target) {
15021 	for (cptr = str->stringval; *cptr; cptr++) {
15022 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
15023 		(*cptr >= 'a' && *cptr <= 'z') ||
15024 		(*cptr >= '0' && *cptr <= '9') ||
15025 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
15026 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
15027 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15028 		(*cptr == '%' &&
15029 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15030 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15031 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
15032 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15033 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15034 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15035 		(!escape_reserved &&
15036 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15037 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15038 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15039 		  *cptr == ','))) {
15040 		xmlBufAdd(target, cptr, 1);
15041 	    } else {
15042 		if ((*cptr >> 4) < 10)
15043 		    escape[1] = '0' + (*cptr >> 4);
15044 		else
15045 		    escape[1] = 'A' - 10 + (*cptr >> 4);
15046 		if ((*cptr & 0xF) < 10)
15047 		    escape[2] = '0' + (*cptr & 0xF);
15048 		else
15049 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
15050 
15051 		xmlBufAdd(target, &escape[0], 3);
15052 	    }
15053 	}
15054     }
15055     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15056 	xmlBufContent(target)));
15057     xmlBufFree(target);
15058     xmlXPathReleaseObject(ctxt->context, str);
15059 }
15060 
15061 /**
15062  * xmlXPathRegisterAllFunctions:
15063  * @ctxt:  the XPath context
15064  *
15065  * Registers all default XPath functions in this context
15066  */
15067 void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)15068 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15069 {
15070     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15071                          xmlXPathBooleanFunction);
15072     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15073                          xmlXPathCeilingFunction);
15074     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15075                          xmlXPathCountFunction);
15076     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15077                          xmlXPathConcatFunction);
15078     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15079                          xmlXPathContainsFunction);
15080     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15081                          xmlXPathIdFunction);
15082     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15083                          xmlXPathFalseFunction);
15084     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15085                          xmlXPathFloorFunction);
15086     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15087                          xmlXPathLastFunction);
15088     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15089                          xmlXPathLangFunction);
15090     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15091                          xmlXPathLocalNameFunction);
15092     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15093                          xmlXPathNotFunction);
15094     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15095                          xmlXPathNameFunction);
15096     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15097                          xmlXPathNamespaceURIFunction);
15098     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15099                          xmlXPathNormalizeFunction);
15100     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15101                          xmlXPathNumberFunction);
15102     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15103                          xmlXPathPositionFunction);
15104     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15105                          xmlXPathRoundFunction);
15106     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15107                          xmlXPathStringFunction);
15108     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15109                          xmlXPathStringLengthFunction);
15110     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15111                          xmlXPathStartsWithFunction);
15112     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15113                          xmlXPathSubstringFunction);
15114     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15115                          xmlXPathSubstringBeforeFunction);
15116     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15117                          xmlXPathSubstringAfterFunction);
15118     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15119                          xmlXPathSumFunction);
15120     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15121                          xmlXPathTrueFunction);
15122     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15123                          xmlXPathTranslateFunction);
15124 
15125     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15126 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15127                          xmlXPathEscapeUriFunction);
15128 }
15129 
15130 #endif /* LIBXML_XPATH_ENABLED */
15131 #define bottom_xpath
15132 #include "elfgcchack.h"
15133