• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * xpath.c: XML Path Language implementation
3  *          XPath is a language for addressing parts of an XML document,
4  *          designed to be used by both XSLT and XPointer
5  *f
6  * Reference: W3C Recommendation 16 November 1999
7  *     http://www.w3.org/TR/1999/REC-xpath-19991116
8  * Public reference:
9  *     http://www.w3.org/TR/xpath
10  *
11  * See Copyright for the status of this software
12  *
13  * Author: daniel@veillard.com
14  *
15  */
16 
17 /* 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 NAN
481 #define NAN (0.0 / 0.0)
482 #endif
483 
484 #ifndef INFINITY
485 #define INFINITY HUGE_VAL
486 #endif
487 
488 double xmlXPathNAN = NAN;
489 double xmlXPathPINF = INFINITY;
490 double xmlXPathNINF = -INFINITY;
491 
492 /**
493  * xmlXPathInit:
494  *
495  * Initialize the XPath environment
496  *
497  * Does nothing but must be kept as public function.
498  */
499 void
xmlXPathInit(void)500 xmlXPathInit(void) {
501 }
502 
503 /**
504  * xmlXPathIsNaN:
505  * @val:  a double value
506  *
507  * Returns 1 if the value is a NaN, 0 otherwise
508  */
509 int
xmlXPathIsNaN(double val)510 xmlXPathIsNaN(double val) {
511 #ifdef isnan
512     return isnan(val);
513 #else
514     return !(val == val);
515 #endif
516 }
517 
518 /**
519  * xmlXPathIsInf:
520  * @val:  a double value
521  *
522  * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
523  */
524 int
xmlXPathIsInf(double val)525 xmlXPathIsInf(double val) {
526 #ifdef isinf
527     return isinf(val) ? (val > 0 ? 1 : -1) : 0;
528 #else
529     if (val >= HUGE_VAL)
530         return 1;
531     if (val <= -HUGE_VAL)
532         return -1;
533     return 0;
534 #endif
535 }
536 
537 #endif /* SCHEMAS or XPATH */
538 
539 #ifdef LIBXML_XPATH_ENABLED
540 
541 /*
542  * TODO: when compatibility allows remove all "fake node libxslt" strings
543  *       the test should just be name[0] = ' '
544  */
545 #ifdef DEBUG_XPATH_EXPRESSION
546 #define DEBUG_STEP
547 #define DEBUG_EXPR
548 #define DEBUG_EVAL_COUNTS
549 #endif
550 
551 static xmlNs xmlXPathXMLNamespaceStruct = {
552     NULL,
553     XML_NAMESPACE_DECL,
554     XML_XML_NAMESPACE,
555     BAD_CAST "xml",
556     NULL,
557     NULL
558 };
559 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
560 #ifndef LIBXML_THREAD_ENABLED
561 /*
562  * Optimizer is disabled only when threaded apps are detected while
563  * the library ain't compiled for thread safety.
564  */
565 static int xmlXPathDisableOptimizer = 0;
566 #endif
567 
568 /************************************************************************
569  *									*
570  *			Error handling routines				*
571  *									*
572  ************************************************************************/
573 
574 /**
575  * XP_ERRORNULL:
576  * @X:  the error code
577  *
578  * Macro to raise an XPath error and return NULL.
579  */
580 #define XP_ERRORNULL(X)							\
581     { xmlXPathErr(ctxt, X); return(NULL); }
582 
583 /*
584  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
585  */
586 static const char *xmlXPathErrorMessages[] = {
587     "Ok\n",
588     "Number encoding\n",
589     "Unfinished literal\n",
590     "Start of literal\n",
591     "Expected $ for variable reference\n",
592     "Undefined variable\n",
593     "Invalid predicate\n",
594     "Invalid expression\n",
595     "Missing closing curly brace\n",
596     "Unregistered function\n",
597     "Invalid operand\n",
598     "Invalid type\n",
599     "Invalid number of arguments\n",
600     "Invalid context size\n",
601     "Invalid context position\n",
602     "Memory allocation error\n",
603     "Syntax error\n",
604     "Resource error\n",
605     "Sub resource error\n",
606     "Undefined namespace prefix\n",
607     "Encoding error\n",
608     "Char out of XML range\n",
609     "Invalid or incomplete context\n",
610     "Stack usage error\n",
611     "Forbidden variable\n",
612     "?? Unknown error ??\n"	/* Must be last in the list! */
613 };
614 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
615 		   sizeof(xmlXPathErrorMessages[0])) - 1)
616 /**
617  * xmlXPathErrMemory:
618  * @ctxt:  an XPath context
619  * @extra:  extra informations
620  *
621  * Handle a redefinition of attribute error
622  */
623 static void
xmlXPathErrMemory(xmlXPathContextPtr ctxt,const char * extra)624 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
625 {
626     if (ctxt != NULL) {
627         if (extra) {
628             xmlChar buf[200];
629 
630             xmlStrPrintf(buf, 200,
631                          "Memory allocation failed : %s\n",
632                          extra);
633             ctxt->lastError.message = (char *) xmlStrdup(buf);
634         } else {
635             ctxt->lastError.message = (char *)
636 	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
637         }
638         ctxt->lastError.domain = XML_FROM_XPATH;
639         ctxt->lastError.code = XML_ERR_NO_MEMORY;
640 	if (ctxt->error != NULL)
641 	    ctxt->error(ctxt->userData, &ctxt->lastError);
642     } else {
643         if (extra)
644             __xmlRaiseError(NULL, NULL, NULL,
645                             NULL, NULL, XML_FROM_XPATH,
646                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
647                             extra, NULL, NULL, 0, 0,
648                             "Memory allocation failed : %s\n", extra);
649         else
650             __xmlRaiseError(NULL, NULL, NULL,
651                             NULL, NULL, XML_FROM_XPATH,
652                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
653                             NULL, NULL, NULL, 0, 0,
654                             "Memory allocation failed\n");
655     }
656 }
657 
658 /**
659  * xmlXPathPErrMemory:
660  * @ctxt:  an XPath parser context
661  * @extra:  extra informations
662  *
663  * Handle a redefinition of attribute error
664  */
665 static void
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt,const char * extra)666 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
667 {
668     if (ctxt == NULL)
669 	xmlXPathErrMemory(NULL, extra);
670     else {
671 	ctxt->error = XPATH_MEMORY_ERROR;
672 	xmlXPathErrMemory(ctxt->context, extra);
673     }
674 }
675 
676 /**
677  * xmlXPathErr:
678  * @ctxt:  a XPath parser context
679  * @error:  the error code
680  *
681  * Handle an XPath error
682  */
683 void
xmlXPathErr(xmlXPathParserContextPtr ctxt,int error)684 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
685 {
686     if ((error < 0) || (error > MAXERRNO))
687 	error = MAXERRNO;
688     if (ctxt == NULL) {
689 	__xmlRaiseError(NULL, NULL, NULL,
690 			NULL, NULL, XML_FROM_XPATH,
691 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
692 			XML_ERR_ERROR, NULL, 0,
693 			NULL, NULL, NULL, 0, 0,
694 			"%s", xmlXPathErrorMessages[error]);
695 	return;
696     }
697     ctxt->error = error;
698     if (ctxt->context == NULL) {
699 	__xmlRaiseError(NULL, NULL, NULL,
700 			NULL, NULL, XML_FROM_XPATH,
701 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
702 			XML_ERR_ERROR, NULL, 0,
703 			(const char *) ctxt->base, NULL, NULL,
704 			ctxt->cur - ctxt->base, 0,
705 			"%s", xmlXPathErrorMessages[error]);
706 	return;
707     }
708 
709     /* cleanup current last error */
710     xmlResetError(&ctxt->context->lastError);
711 
712     ctxt->context->lastError.domain = XML_FROM_XPATH;
713     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
714                            XPATH_EXPRESSION_OK;
715     ctxt->context->lastError.level = XML_ERR_ERROR;
716     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
717     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
718     ctxt->context->lastError.node = ctxt->context->debugNode;
719     if (ctxt->context->error != NULL) {
720 	ctxt->context->error(ctxt->context->userData,
721 	                     &ctxt->context->lastError);
722     } else {
723 	__xmlRaiseError(NULL, NULL, NULL,
724 			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
725 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
726 			XML_ERR_ERROR, NULL, 0,
727 			(const char *) ctxt->base, NULL, NULL,
728 			ctxt->cur - ctxt->base, 0,
729 			"%s", xmlXPathErrorMessages[error]);
730     }
731 
732 }
733 
734 /**
735  * xmlXPatherror:
736  * @ctxt:  the XPath Parser context
737  * @file:  the file name
738  * @line:  the line number
739  * @no:  the error number
740  *
741  * Formats an error message.
742  */
743 void
xmlXPatherror(xmlXPathParserContextPtr ctxt,const char * file ATTRIBUTE_UNUSED,int line ATTRIBUTE_UNUSED,int no)744 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
745               int line ATTRIBUTE_UNUSED, int no) {
746     xmlXPathErr(ctxt, no);
747 }
748 
749 /************************************************************************
750  *									*
751  *			Utilities					*
752  *									*
753  ************************************************************************/
754 
755 /**
756  * xsltPointerList:
757  *
758  * Pointer-list for various purposes.
759  */
760 typedef struct _xmlPointerList xmlPointerList;
761 typedef xmlPointerList *xmlPointerListPtr;
762 struct _xmlPointerList {
763     void **items;
764     int number;
765     int size;
766 };
767 /*
768 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
769 * and here, we should make the functions public.
770 */
771 static int
xmlPointerListAddSize(xmlPointerListPtr list,void * item,int initialSize)772 xmlPointerListAddSize(xmlPointerListPtr list,
773 		       void *item,
774 		       int initialSize)
775 {
776     if (list->items == NULL) {
777 	if (initialSize <= 0)
778 	    initialSize = 1;
779 	list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
780 	if (list->items == NULL) {
781 	    xmlXPathErrMemory(NULL,
782 		"xmlPointerListCreate: allocating item\n");
783 	    return(-1);
784 	}
785 	list->number = 0;
786 	list->size = initialSize;
787     } else if (list->size <= list->number) {
788         if (list->size > 50000000) {
789 	    xmlXPathErrMemory(NULL,
790 		"xmlPointerListAddSize: re-allocating item\n");
791             return(-1);
792         }
793 	list->size *= 2;
794 	list->items = (void **) xmlRealloc(list->items,
795 	    list->size * sizeof(void *));
796 	if (list->items == NULL) {
797 	    xmlXPathErrMemory(NULL,
798 		"xmlPointerListAddSize: re-allocating item\n");
799 	    list->size = 0;
800 	    return(-1);
801 	}
802     }
803     list->items[list->number++] = item;
804     return(0);
805 }
806 
807 /**
808  * xsltPointerListCreate:
809  *
810  * Creates an xsltPointerList structure.
811  *
812  * Returns a xsltPointerList structure or NULL in case of an error.
813  */
814 static xmlPointerListPtr
xmlPointerListCreate(int initialSize)815 xmlPointerListCreate(int initialSize)
816 {
817     xmlPointerListPtr ret;
818 
819     ret = xmlMalloc(sizeof(xmlPointerList));
820     if (ret == NULL) {
821 	xmlXPathErrMemory(NULL,
822 	    "xmlPointerListCreate: allocating item\n");
823 	return (NULL);
824     }
825     memset(ret, 0, sizeof(xmlPointerList));
826     if (initialSize > 0) {
827 	xmlPointerListAddSize(ret, NULL, initialSize);
828 	ret->number = 0;
829     }
830     return (ret);
831 }
832 
833 /**
834  * xsltPointerListFree:
835  *
836  * Frees the xsltPointerList structure. This does not free
837  * the content of the list.
838  */
839 static void
xmlPointerListFree(xmlPointerListPtr list)840 xmlPointerListFree(xmlPointerListPtr list)
841 {
842     if (list == NULL)
843 	return;
844     if (list->items != NULL)
845 	xmlFree(list->items);
846     xmlFree(list);
847 }
848 
849 /************************************************************************
850  *									*
851  *			Parser Types					*
852  *									*
853  ************************************************************************/
854 
855 /*
856  * Types are private:
857  */
858 
859 typedef enum {
860     XPATH_OP_END=0,
861     XPATH_OP_AND,
862     XPATH_OP_OR,
863     XPATH_OP_EQUAL,
864     XPATH_OP_CMP,
865     XPATH_OP_PLUS,
866     XPATH_OP_MULT,
867     XPATH_OP_UNION,
868     XPATH_OP_ROOT,
869     XPATH_OP_NODE,
870     XPATH_OP_RESET, /* 10 */
871     XPATH_OP_COLLECT,
872     XPATH_OP_VALUE, /* 12 */
873     XPATH_OP_VARIABLE,
874     XPATH_OP_FUNCTION,
875     XPATH_OP_ARG,
876     XPATH_OP_PREDICATE,
877     XPATH_OP_FILTER, /* 17 */
878     XPATH_OP_SORT /* 18 */
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_RESET:
1529 	     fprintf(output, "RESET"); break;
1530         case XPATH_OP_SORT:
1531 	     fprintf(output, "SORT"); break;
1532         case XPATH_OP_COLLECT: {
1533 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1534 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1535 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1536 	    const xmlChar *prefix = op->value4;
1537 	    const xmlChar *name = op->value5;
1538 
1539 	    fprintf(output, "COLLECT ");
1540 	    switch (axis) {
1541 		case AXIS_ANCESTOR:
1542 		    fprintf(output, " 'ancestors' "); break;
1543 		case AXIS_ANCESTOR_OR_SELF:
1544 		    fprintf(output, " 'ancestors-or-self' "); break;
1545 		case AXIS_ATTRIBUTE:
1546 		    fprintf(output, " 'attributes' "); break;
1547 		case AXIS_CHILD:
1548 		    fprintf(output, " 'child' "); break;
1549 		case AXIS_DESCENDANT:
1550 		    fprintf(output, " 'descendant' "); break;
1551 		case AXIS_DESCENDANT_OR_SELF:
1552 		    fprintf(output, " 'descendant-or-self' "); break;
1553 		case AXIS_FOLLOWING:
1554 		    fprintf(output, " 'following' "); break;
1555 		case AXIS_FOLLOWING_SIBLING:
1556 		    fprintf(output, " 'following-siblings' "); break;
1557 		case AXIS_NAMESPACE:
1558 		    fprintf(output, " 'namespace' "); break;
1559 		case AXIS_PARENT:
1560 		    fprintf(output, " 'parent' "); break;
1561 		case AXIS_PRECEDING:
1562 		    fprintf(output, " 'preceding' "); break;
1563 		case AXIS_PRECEDING_SIBLING:
1564 		    fprintf(output, " 'preceding-sibling' "); break;
1565 		case AXIS_SELF:
1566 		    fprintf(output, " 'self' "); break;
1567 	    }
1568 	    switch (test) {
1569                 case NODE_TEST_NONE:
1570 		    fprintf(output, "'none' "); break;
1571                 case NODE_TEST_TYPE:
1572 		    fprintf(output, "'type' "); break;
1573                 case NODE_TEST_PI:
1574 		    fprintf(output, "'PI' "); break;
1575                 case NODE_TEST_ALL:
1576 		    fprintf(output, "'all' "); break;
1577                 case NODE_TEST_NS:
1578 		    fprintf(output, "'namespace' "); break;
1579                 case NODE_TEST_NAME:
1580 		    fprintf(output, "'name' "); break;
1581 	    }
1582 	    switch (type) {
1583                 case NODE_TYPE_NODE:
1584 		    fprintf(output, "'node' "); break;
1585                 case NODE_TYPE_COMMENT:
1586 		    fprintf(output, "'comment' "); break;
1587                 case NODE_TYPE_TEXT:
1588 		    fprintf(output, "'text' "); break;
1589                 case NODE_TYPE_PI:
1590 		    fprintf(output, "'PI' "); break;
1591 	    }
1592 	    if (prefix != NULL)
1593 		fprintf(output, "%s:", prefix);
1594 	    if (name != NULL)
1595 		fprintf(output, "%s", (const char *) name);
1596 	    break;
1597 
1598         }
1599 	case XPATH_OP_VALUE: {
1600 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1601 
1602 	    fprintf(output, "ELEM ");
1603 	    xmlXPathDebugDumpObject(output, object, 0);
1604 	    goto finish;
1605 	}
1606 	case XPATH_OP_VARIABLE: {
1607 	    const xmlChar *prefix = op->value5;
1608 	    const xmlChar *name = op->value4;
1609 
1610 	    if (prefix != NULL)
1611 		fprintf(output, "VARIABLE %s:%s", prefix, name);
1612 	    else
1613 		fprintf(output, "VARIABLE %s", name);
1614 	    break;
1615 	}
1616 	case XPATH_OP_FUNCTION: {
1617 	    int nbargs = op->value;
1618 	    const xmlChar *prefix = op->value5;
1619 	    const xmlChar *name = op->value4;
1620 
1621 	    if (prefix != NULL)
1622 		fprintf(output, "FUNCTION %s:%s(%d args)",
1623 			prefix, name, nbargs);
1624 	    else
1625 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1626 	    break;
1627 	}
1628         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1629         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1630         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1631 #ifdef LIBXML_XPTR_ENABLED
1632         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1633 #endif
1634 	default:
1635         fprintf(output, "UNKNOWN %d\n", op->op); return;
1636     }
1637     fprintf(output, "\n");
1638 finish:
1639     if (op->ch1 >= 0)
1640 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1641     if (op->ch2 >= 0)
1642 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1643 }
1644 
1645 /**
1646  * xmlXPathDebugDumpCompExpr:
1647  * @output:  the FILE * for the output
1648  * @comp:  the precompiled XPath expression
1649  * @depth:  the indentation level.
1650  *
1651  * Dumps the tree of the compiled XPath expression.
1652  */
1653 void
xmlXPathDebugDumpCompExpr(FILE * output,xmlXPathCompExprPtr comp,int depth)1654 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1655 	                  int depth) {
1656     int i;
1657     char shift[100];
1658 
1659     if ((output == NULL) || (comp == NULL)) return;
1660 
1661     for (i = 0;((i < depth) && (i < 25));i++)
1662         shift[2 * i] = shift[2 * i + 1] = ' ';
1663     shift[2 * i] = shift[2 * i + 1] = 0;
1664 
1665     fprintf(output, "%s", shift);
1666 
1667 #ifdef XPATH_STREAMING
1668     if (comp->stream) {
1669         fprintf(output, "Streaming Expression\n");
1670     } else
1671 #endif
1672     {
1673         fprintf(output, "Compiled Expression : %d elements\n",
1674                 comp->nbStep);
1675         i = comp->last;
1676         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1677     }
1678 }
1679 
1680 #ifdef XP_DEBUG_OBJ_USAGE
1681 
1682 /*
1683 * XPath object usage related debugging variables.
1684 */
1685 static int xmlXPathDebugObjCounterUndefined = 0;
1686 static int xmlXPathDebugObjCounterNodeset = 0;
1687 static int xmlXPathDebugObjCounterBool = 0;
1688 static int xmlXPathDebugObjCounterNumber = 0;
1689 static int xmlXPathDebugObjCounterString = 0;
1690 static int xmlXPathDebugObjCounterPoint = 0;
1691 static int xmlXPathDebugObjCounterRange = 0;
1692 static int xmlXPathDebugObjCounterLocset = 0;
1693 static int xmlXPathDebugObjCounterUsers = 0;
1694 static int xmlXPathDebugObjCounterXSLTTree = 0;
1695 static int xmlXPathDebugObjCounterAll = 0;
1696 
1697 static int xmlXPathDebugObjTotalUndefined = 0;
1698 static int xmlXPathDebugObjTotalNodeset = 0;
1699 static int xmlXPathDebugObjTotalBool = 0;
1700 static int xmlXPathDebugObjTotalNumber = 0;
1701 static int xmlXPathDebugObjTotalString = 0;
1702 static int xmlXPathDebugObjTotalPoint = 0;
1703 static int xmlXPathDebugObjTotalRange = 0;
1704 static int xmlXPathDebugObjTotalLocset = 0;
1705 static int xmlXPathDebugObjTotalUsers = 0;
1706 static int xmlXPathDebugObjTotalXSLTTree = 0;
1707 static int xmlXPathDebugObjTotalAll = 0;
1708 
1709 static int xmlXPathDebugObjMaxUndefined = 0;
1710 static int xmlXPathDebugObjMaxNodeset = 0;
1711 static int xmlXPathDebugObjMaxBool = 0;
1712 static int xmlXPathDebugObjMaxNumber = 0;
1713 static int xmlXPathDebugObjMaxString = 0;
1714 static int xmlXPathDebugObjMaxPoint = 0;
1715 static int xmlXPathDebugObjMaxRange = 0;
1716 static int xmlXPathDebugObjMaxLocset = 0;
1717 static int xmlXPathDebugObjMaxUsers = 0;
1718 static int xmlXPathDebugObjMaxXSLTTree = 0;
1719 static int xmlXPathDebugObjMaxAll = 0;
1720 
1721 /* REVISIT TODO: Make this static when committing */
1722 static void
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)1723 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1724 {
1725     if (ctxt != NULL) {
1726 	if (ctxt->cache != NULL) {
1727 	    xmlXPathContextCachePtr cache =
1728 		(xmlXPathContextCachePtr) ctxt->cache;
1729 
1730 	    cache->dbgCachedAll = 0;
1731 	    cache->dbgCachedNodeset = 0;
1732 	    cache->dbgCachedString = 0;
1733 	    cache->dbgCachedBool = 0;
1734 	    cache->dbgCachedNumber = 0;
1735 	    cache->dbgCachedPoint = 0;
1736 	    cache->dbgCachedRange = 0;
1737 	    cache->dbgCachedLocset = 0;
1738 	    cache->dbgCachedUsers = 0;
1739 	    cache->dbgCachedXSLTTree = 0;
1740 	    cache->dbgCachedUndefined = 0;
1741 
1742 	    cache->dbgReusedAll = 0;
1743 	    cache->dbgReusedNodeset = 0;
1744 	    cache->dbgReusedString = 0;
1745 	    cache->dbgReusedBool = 0;
1746 	    cache->dbgReusedNumber = 0;
1747 	    cache->dbgReusedPoint = 0;
1748 	    cache->dbgReusedRange = 0;
1749 	    cache->dbgReusedLocset = 0;
1750 	    cache->dbgReusedUsers = 0;
1751 	    cache->dbgReusedXSLTTree = 0;
1752 	    cache->dbgReusedUndefined = 0;
1753 	}
1754     }
1755 
1756     xmlXPathDebugObjCounterUndefined = 0;
1757     xmlXPathDebugObjCounterNodeset = 0;
1758     xmlXPathDebugObjCounterBool = 0;
1759     xmlXPathDebugObjCounterNumber = 0;
1760     xmlXPathDebugObjCounterString = 0;
1761     xmlXPathDebugObjCounterPoint = 0;
1762     xmlXPathDebugObjCounterRange = 0;
1763     xmlXPathDebugObjCounterLocset = 0;
1764     xmlXPathDebugObjCounterUsers = 0;
1765     xmlXPathDebugObjCounterXSLTTree = 0;
1766     xmlXPathDebugObjCounterAll = 0;
1767 
1768     xmlXPathDebugObjTotalUndefined = 0;
1769     xmlXPathDebugObjTotalNodeset = 0;
1770     xmlXPathDebugObjTotalBool = 0;
1771     xmlXPathDebugObjTotalNumber = 0;
1772     xmlXPathDebugObjTotalString = 0;
1773     xmlXPathDebugObjTotalPoint = 0;
1774     xmlXPathDebugObjTotalRange = 0;
1775     xmlXPathDebugObjTotalLocset = 0;
1776     xmlXPathDebugObjTotalUsers = 0;
1777     xmlXPathDebugObjTotalXSLTTree = 0;
1778     xmlXPathDebugObjTotalAll = 0;
1779 
1780     xmlXPathDebugObjMaxUndefined = 0;
1781     xmlXPathDebugObjMaxNodeset = 0;
1782     xmlXPathDebugObjMaxBool = 0;
1783     xmlXPathDebugObjMaxNumber = 0;
1784     xmlXPathDebugObjMaxString = 0;
1785     xmlXPathDebugObjMaxPoint = 0;
1786     xmlXPathDebugObjMaxRange = 0;
1787     xmlXPathDebugObjMaxLocset = 0;
1788     xmlXPathDebugObjMaxUsers = 0;
1789     xmlXPathDebugObjMaxXSLTTree = 0;
1790     xmlXPathDebugObjMaxAll = 0;
1791 
1792 }
1793 
1794 static void
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,xmlXPathObjectType objType)1795 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1796 			      xmlXPathObjectType objType)
1797 {
1798     int isCached = 0;
1799 
1800     if (ctxt != NULL) {
1801 	if (ctxt->cache != NULL) {
1802 	    xmlXPathContextCachePtr cache =
1803 		(xmlXPathContextCachePtr) ctxt->cache;
1804 
1805 	    isCached = 1;
1806 
1807 	    cache->dbgReusedAll++;
1808 	    switch (objType) {
1809 		case XPATH_UNDEFINED:
1810 		    cache->dbgReusedUndefined++;
1811 		    break;
1812 		case XPATH_NODESET:
1813 		    cache->dbgReusedNodeset++;
1814 		    break;
1815 		case XPATH_BOOLEAN:
1816 		    cache->dbgReusedBool++;
1817 		    break;
1818 		case XPATH_NUMBER:
1819 		    cache->dbgReusedNumber++;
1820 		    break;
1821 		case XPATH_STRING:
1822 		    cache->dbgReusedString++;
1823 		    break;
1824 		case XPATH_POINT:
1825 		    cache->dbgReusedPoint++;
1826 		    break;
1827 		case XPATH_RANGE:
1828 		    cache->dbgReusedRange++;
1829 		    break;
1830 		case XPATH_LOCATIONSET:
1831 		    cache->dbgReusedLocset++;
1832 		    break;
1833 		case XPATH_USERS:
1834 		    cache->dbgReusedUsers++;
1835 		    break;
1836 		case XPATH_XSLT_TREE:
1837 		    cache->dbgReusedXSLTTree++;
1838 		    break;
1839 		default:
1840 		    break;
1841 	    }
1842 	}
1843     }
1844 
1845     switch (objType) {
1846 	case XPATH_UNDEFINED:
1847 	    if (! isCached)
1848 		xmlXPathDebugObjTotalUndefined++;
1849 	    xmlXPathDebugObjCounterUndefined++;
1850 	    if (xmlXPathDebugObjCounterUndefined >
1851 		xmlXPathDebugObjMaxUndefined)
1852 		xmlXPathDebugObjMaxUndefined =
1853 		    xmlXPathDebugObjCounterUndefined;
1854 	    break;
1855 	case XPATH_NODESET:
1856 	    if (! isCached)
1857 		xmlXPathDebugObjTotalNodeset++;
1858 	    xmlXPathDebugObjCounterNodeset++;
1859 	    if (xmlXPathDebugObjCounterNodeset >
1860 		xmlXPathDebugObjMaxNodeset)
1861 		xmlXPathDebugObjMaxNodeset =
1862 		    xmlXPathDebugObjCounterNodeset;
1863 	    break;
1864 	case XPATH_BOOLEAN:
1865 	    if (! isCached)
1866 		xmlXPathDebugObjTotalBool++;
1867 	    xmlXPathDebugObjCounterBool++;
1868 	    if (xmlXPathDebugObjCounterBool >
1869 		xmlXPathDebugObjMaxBool)
1870 		xmlXPathDebugObjMaxBool =
1871 		    xmlXPathDebugObjCounterBool;
1872 	    break;
1873 	case XPATH_NUMBER:
1874 	    if (! isCached)
1875 		xmlXPathDebugObjTotalNumber++;
1876 	    xmlXPathDebugObjCounterNumber++;
1877 	    if (xmlXPathDebugObjCounterNumber >
1878 		xmlXPathDebugObjMaxNumber)
1879 		xmlXPathDebugObjMaxNumber =
1880 		    xmlXPathDebugObjCounterNumber;
1881 	    break;
1882 	case XPATH_STRING:
1883 	    if (! isCached)
1884 		xmlXPathDebugObjTotalString++;
1885 	    xmlXPathDebugObjCounterString++;
1886 	    if (xmlXPathDebugObjCounterString >
1887 		xmlXPathDebugObjMaxString)
1888 		xmlXPathDebugObjMaxString =
1889 		    xmlXPathDebugObjCounterString;
1890 	    break;
1891 	case XPATH_POINT:
1892 	    if (! isCached)
1893 		xmlXPathDebugObjTotalPoint++;
1894 	    xmlXPathDebugObjCounterPoint++;
1895 	    if (xmlXPathDebugObjCounterPoint >
1896 		xmlXPathDebugObjMaxPoint)
1897 		xmlXPathDebugObjMaxPoint =
1898 		    xmlXPathDebugObjCounterPoint;
1899 	    break;
1900 	case XPATH_RANGE:
1901 	    if (! isCached)
1902 		xmlXPathDebugObjTotalRange++;
1903 	    xmlXPathDebugObjCounterRange++;
1904 	    if (xmlXPathDebugObjCounterRange >
1905 		xmlXPathDebugObjMaxRange)
1906 		xmlXPathDebugObjMaxRange =
1907 		    xmlXPathDebugObjCounterRange;
1908 	    break;
1909 	case XPATH_LOCATIONSET:
1910 	    if (! isCached)
1911 		xmlXPathDebugObjTotalLocset++;
1912 	    xmlXPathDebugObjCounterLocset++;
1913 	    if (xmlXPathDebugObjCounterLocset >
1914 		xmlXPathDebugObjMaxLocset)
1915 		xmlXPathDebugObjMaxLocset =
1916 		    xmlXPathDebugObjCounterLocset;
1917 	    break;
1918 	case XPATH_USERS:
1919 	    if (! isCached)
1920 		xmlXPathDebugObjTotalUsers++;
1921 	    xmlXPathDebugObjCounterUsers++;
1922 	    if (xmlXPathDebugObjCounterUsers >
1923 		xmlXPathDebugObjMaxUsers)
1924 		xmlXPathDebugObjMaxUsers =
1925 		    xmlXPathDebugObjCounterUsers;
1926 	    break;
1927 	case XPATH_XSLT_TREE:
1928 	    if (! isCached)
1929 		xmlXPathDebugObjTotalXSLTTree++;
1930 	    xmlXPathDebugObjCounterXSLTTree++;
1931 	    if (xmlXPathDebugObjCounterXSLTTree >
1932 		xmlXPathDebugObjMaxXSLTTree)
1933 		xmlXPathDebugObjMaxXSLTTree =
1934 		    xmlXPathDebugObjCounterXSLTTree;
1935 	    break;
1936 	default:
1937 	    break;
1938     }
1939     if (! isCached)
1940 	xmlXPathDebugObjTotalAll++;
1941     xmlXPathDebugObjCounterAll++;
1942     if (xmlXPathDebugObjCounterAll >
1943 	xmlXPathDebugObjMaxAll)
1944 	xmlXPathDebugObjMaxAll =
1945 	    xmlXPathDebugObjCounterAll;
1946 }
1947 
1948 static void
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,xmlXPathObjectType objType)1949 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1950 			      xmlXPathObjectType objType)
1951 {
1952     int isCached = 0;
1953 
1954     if (ctxt != NULL) {
1955 	if (ctxt->cache != NULL) {
1956 	    xmlXPathContextCachePtr cache =
1957 		(xmlXPathContextCachePtr) ctxt->cache;
1958 
1959 	    isCached = 1;
1960 
1961 	    cache->dbgCachedAll++;
1962 	    switch (objType) {
1963 		case XPATH_UNDEFINED:
1964 		    cache->dbgCachedUndefined++;
1965 		    break;
1966 		case XPATH_NODESET:
1967 		    cache->dbgCachedNodeset++;
1968 		    break;
1969 		case XPATH_BOOLEAN:
1970 		    cache->dbgCachedBool++;
1971 		    break;
1972 		case XPATH_NUMBER:
1973 		    cache->dbgCachedNumber++;
1974 		    break;
1975 		case XPATH_STRING:
1976 		    cache->dbgCachedString++;
1977 		    break;
1978 		case XPATH_POINT:
1979 		    cache->dbgCachedPoint++;
1980 		    break;
1981 		case XPATH_RANGE:
1982 		    cache->dbgCachedRange++;
1983 		    break;
1984 		case XPATH_LOCATIONSET:
1985 		    cache->dbgCachedLocset++;
1986 		    break;
1987 		case XPATH_USERS:
1988 		    cache->dbgCachedUsers++;
1989 		    break;
1990 		case XPATH_XSLT_TREE:
1991 		    cache->dbgCachedXSLTTree++;
1992 		    break;
1993 		default:
1994 		    break;
1995 	    }
1996 
1997 	}
1998     }
1999     switch (objType) {
2000 	case XPATH_UNDEFINED:
2001 	    xmlXPathDebugObjCounterUndefined--;
2002 	    break;
2003 	case XPATH_NODESET:
2004 	    xmlXPathDebugObjCounterNodeset--;
2005 	    break;
2006 	case XPATH_BOOLEAN:
2007 	    xmlXPathDebugObjCounterBool--;
2008 	    break;
2009 	case XPATH_NUMBER:
2010 	    xmlXPathDebugObjCounterNumber--;
2011 	    break;
2012 	case XPATH_STRING:
2013 	    xmlXPathDebugObjCounterString--;
2014 	    break;
2015 	case XPATH_POINT:
2016 	    xmlXPathDebugObjCounterPoint--;
2017 	    break;
2018 	case XPATH_RANGE:
2019 	    xmlXPathDebugObjCounterRange--;
2020 	    break;
2021 	case XPATH_LOCATIONSET:
2022 	    xmlXPathDebugObjCounterLocset--;
2023 	    break;
2024 	case XPATH_USERS:
2025 	    xmlXPathDebugObjCounterUsers--;
2026 	    break;
2027 	case XPATH_XSLT_TREE:
2028 	    xmlXPathDebugObjCounterXSLTTree--;
2029 	    break;
2030 	default:
2031 	    break;
2032     }
2033     xmlXPathDebugObjCounterAll--;
2034 }
2035 
2036 /* REVISIT TODO: Make this static when committing */
2037 static void
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)2038 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2039 {
2040     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2041 	reqXSLTTree, reqUndefined;
2042     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2043 	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2044     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2045 	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2046     int leftObjs = xmlXPathDebugObjCounterAll;
2047 
2048     reqAll = xmlXPathDebugObjTotalAll;
2049     reqNodeset = xmlXPathDebugObjTotalNodeset;
2050     reqString = xmlXPathDebugObjTotalString;
2051     reqBool = xmlXPathDebugObjTotalBool;
2052     reqNumber = xmlXPathDebugObjTotalNumber;
2053     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2054     reqUndefined = xmlXPathDebugObjTotalUndefined;
2055 
2056     printf("# XPath object usage:\n");
2057 
2058     if (ctxt != NULL) {
2059 	if (ctxt->cache != NULL) {
2060 	    xmlXPathContextCachePtr cache =
2061 		(xmlXPathContextCachePtr) ctxt->cache;
2062 
2063 	    reAll = cache->dbgReusedAll;
2064 	    reqAll += reAll;
2065 	    reNodeset = cache->dbgReusedNodeset;
2066 	    reqNodeset += reNodeset;
2067 	    reString = cache->dbgReusedString;
2068 	    reqString += reString;
2069 	    reBool = cache->dbgReusedBool;
2070 	    reqBool += reBool;
2071 	    reNumber = cache->dbgReusedNumber;
2072 	    reqNumber += reNumber;
2073 	    reXSLTTree = cache->dbgReusedXSLTTree;
2074 	    reqXSLTTree += reXSLTTree;
2075 	    reUndefined = cache->dbgReusedUndefined;
2076 	    reqUndefined += reUndefined;
2077 
2078 	    caAll = cache->dbgCachedAll;
2079 	    caBool = cache->dbgCachedBool;
2080 	    caNodeset = cache->dbgCachedNodeset;
2081 	    caString = cache->dbgCachedString;
2082 	    caNumber = cache->dbgCachedNumber;
2083 	    caXSLTTree = cache->dbgCachedXSLTTree;
2084 	    caUndefined = cache->dbgCachedUndefined;
2085 
2086 	    if (cache->nodesetObjs)
2087 		leftObjs -= cache->nodesetObjs->number;
2088 	    if (cache->stringObjs)
2089 		leftObjs -= cache->stringObjs->number;
2090 	    if (cache->booleanObjs)
2091 		leftObjs -= cache->booleanObjs->number;
2092 	    if (cache->numberObjs)
2093 		leftObjs -= cache->numberObjs->number;
2094 	    if (cache->miscObjs)
2095 		leftObjs -= cache->miscObjs->number;
2096 	}
2097     }
2098 
2099     printf("# all\n");
2100     printf("#   total  : %d\n", reqAll);
2101     printf("#   left  : %d\n", leftObjs);
2102     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2103     printf("#   reused : %d\n", reAll);
2104     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2105 
2106     printf("# node-sets\n");
2107     printf("#   total  : %d\n", reqNodeset);
2108     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2109     printf("#   reused : %d\n", reNodeset);
2110     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2111 
2112     printf("# strings\n");
2113     printf("#   total  : %d\n", reqString);
2114     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2115     printf("#   reused : %d\n", reString);
2116     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2117 
2118     printf("# booleans\n");
2119     printf("#   total  : %d\n", reqBool);
2120     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2121     printf("#   reused : %d\n", reBool);
2122     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2123 
2124     printf("# numbers\n");
2125     printf("#   total  : %d\n", reqNumber);
2126     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2127     printf("#   reused : %d\n", reNumber);
2128     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2129 
2130     printf("# XSLT result tree fragments\n");
2131     printf("#   total  : %d\n", reqXSLTTree);
2132     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2133     printf("#   reused : %d\n", reXSLTTree);
2134     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2135 
2136     printf("# undefined\n");
2137     printf("#   total  : %d\n", reqUndefined);
2138     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2139     printf("#   reused : %d\n", reUndefined);
2140     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2141 
2142 }
2143 
2144 #endif /* XP_DEBUG_OBJ_USAGE */
2145 
2146 #endif /* LIBXML_DEBUG_ENABLED */
2147 
2148 /************************************************************************
2149  *									*
2150  *			XPath object caching				*
2151  *									*
2152  ************************************************************************/
2153 
2154 /**
2155  * xmlXPathNewCache:
2156  *
2157  * Create a new object cache
2158  *
2159  * Returns the xmlXPathCache just allocated.
2160  */
2161 static xmlXPathContextCachePtr
xmlXPathNewCache(void)2162 xmlXPathNewCache(void)
2163 {
2164     xmlXPathContextCachePtr ret;
2165 
2166     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2167     if (ret == NULL) {
2168         xmlXPathErrMemory(NULL, "creating object cache\n");
2169 	return(NULL);
2170     }
2171     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2172     ret->maxNodeset = 100;
2173     ret->maxString = 100;
2174     ret->maxBoolean = 100;
2175     ret->maxNumber = 100;
2176     ret->maxMisc = 100;
2177     return(ret);
2178 }
2179 
2180 static void
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)2181 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2182 {
2183     int i;
2184     xmlXPathObjectPtr obj;
2185 
2186     if (list == NULL)
2187 	return;
2188 
2189     for (i = 0; i < list->number; i++) {
2190 	obj = list->items[i];
2191 	/*
2192 	* Note that it is already assured that we don't need to
2193 	* look out for namespace nodes in the node-set.
2194 	*/
2195 	if (obj->nodesetval != NULL) {
2196 	    if (obj->nodesetval->nodeTab != NULL)
2197 		xmlFree(obj->nodesetval->nodeTab);
2198 	    xmlFree(obj->nodesetval);
2199 	}
2200 	xmlFree(obj);
2201 #ifdef XP_DEBUG_OBJ_USAGE
2202 	xmlXPathDebugObjCounterAll--;
2203 #endif
2204     }
2205     xmlPointerListFree(list);
2206 }
2207 
2208 static void
xmlXPathFreeCache(xmlXPathContextCachePtr cache)2209 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2210 {
2211     if (cache == NULL)
2212 	return;
2213     if (cache->nodesetObjs)
2214 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2215     if (cache->stringObjs)
2216 	xmlXPathCacheFreeObjectList(cache->stringObjs);
2217     if (cache->booleanObjs)
2218 	xmlXPathCacheFreeObjectList(cache->booleanObjs);
2219     if (cache->numberObjs)
2220 	xmlXPathCacheFreeObjectList(cache->numberObjs);
2221     if (cache->miscObjs)
2222 	xmlXPathCacheFreeObjectList(cache->miscObjs);
2223     xmlFree(cache);
2224 }
2225 
2226 /**
2227  * xmlXPathContextSetCache:
2228  *
2229  * @ctxt:  the XPath context
2230  * @active: enables/disables (creates/frees) the cache
2231  * @value: a value with semantics dependant on @options
2232  * @options: options (currently only the value 0 is used)
2233  *
2234  * Creates/frees an object cache on the XPath context.
2235  * If activates XPath objects (xmlXPathObject) will be cached internally
2236  * to be reused.
2237  * @options:
2238  *   0: This will set the XPath object caching:
2239  *      @value:
2240  *        This will set the maximum number of XPath objects
2241  *        to be cached per slot
2242  *        There are 5 slots for: node-set, string, number, boolean, and
2243  *        misc objects. Use <0 for the default number (100).
2244  *   Other values for @options have currently no effect.
2245  *
2246  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2247  */
2248 int
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,int active,int value,int options)2249 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2250 			int active,
2251 			int value,
2252 			int options)
2253 {
2254     if (ctxt == NULL)
2255 	return(-1);
2256     if (active) {
2257 	xmlXPathContextCachePtr cache;
2258 
2259 	if (ctxt->cache == NULL) {
2260 	    ctxt->cache = xmlXPathNewCache();
2261 	    if (ctxt->cache == NULL)
2262 		return(-1);
2263 	}
2264 	cache = (xmlXPathContextCachePtr) ctxt->cache;
2265 	if (options == 0) {
2266 	    if (value < 0)
2267 		value = 100;
2268 	    cache->maxNodeset = value;
2269 	    cache->maxString = value;
2270 	    cache->maxNumber = value;
2271 	    cache->maxBoolean = value;
2272 	    cache->maxMisc = value;
2273 	}
2274     } else if (ctxt->cache != NULL) {
2275 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2276 	ctxt->cache = NULL;
2277     }
2278     return(0);
2279 }
2280 
2281 /**
2282  * xmlXPathCacheWrapNodeSet:
2283  * @ctxt: the XPath context
2284  * @val:  the NodePtr value
2285  *
2286  * This is the cached version of xmlXPathWrapNodeSet().
2287  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2288  *
2289  * Returns the created or reused object.
2290  */
2291 static xmlXPathObjectPtr
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt,xmlNodeSetPtr val)2292 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2293 {
2294     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2295 	xmlXPathContextCachePtr cache =
2296 	    (xmlXPathContextCachePtr) ctxt->cache;
2297 
2298 	if ((cache->miscObjs != NULL) &&
2299 	    (cache->miscObjs->number != 0))
2300 	{
2301 	    xmlXPathObjectPtr ret;
2302 
2303 	    ret = (xmlXPathObjectPtr)
2304 		cache->miscObjs->items[--cache->miscObjs->number];
2305 	    ret->type = XPATH_NODESET;
2306 	    ret->nodesetval = val;
2307 #ifdef XP_DEBUG_OBJ_USAGE
2308 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2309 #endif
2310 	    return(ret);
2311 	}
2312     }
2313 
2314     return(xmlXPathWrapNodeSet(val));
2315 
2316 }
2317 
2318 /**
2319  * xmlXPathCacheWrapString:
2320  * @ctxt: the XPath context
2321  * @val:  the xmlChar * value
2322  *
2323  * This is the cached version of xmlXPathWrapString().
2324  * Wraps the @val string into an XPath object.
2325  *
2326  * Returns the created or reused object.
2327  */
2328 static xmlXPathObjectPtr
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt,xmlChar * val)2329 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2330 {
2331     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2332 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2333 
2334 	if ((cache->stringObjs != NULL) &&
2335 	    (cache->stringObjs->number != 0))
2336 	{
2337 
2338 	    xmlXPathObjectPtr ret;
2339 
2340 	    ret = (xmlXPathObjectPtr)
2341 		cache->stringObjs->items[--cache->stringObjs->number];
2342 	    ret->type = XPATH_STRING;
2343 	    ret->stringval = val;
2344 #ifdef XP_DEBUG_OBJ_USAGE
2345 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2346 #endif
2347 	    return(ret);
2348 	} else if ((cache->miscObjs != NULL) &&
2349 	    (cache->miscObjs->number != 0))
2350 	{
2351 	    xmlXPathObjectPtr ret;
2352 	    /*
2353 	    * Fallback to misc-cache.
2354 	    */
2355 	    ret = (xmlXPathObjectPtr)
2356 		cache->miscObjs->items[--cache->miscObjs->number];
2357 
2358 	    ret->type = XPATH_STRING;
2359 	    ret->stringval = val;
2360 #ifdef XP_DEBUG_OBJ_USAGE
2361 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2362 #endif
2363 	    return(ret);
2364 	}
2365     }
2366     return(xmlXPathWrapString(val));
2367 }
2368 
2369 /**
2370  * xmlXPathCacheNewNodeSet:
2371  * @ctxt: the XPath context
2372  * @val:  the NodePtr value
2373  *
2374  * This is the cached version of xmlXPathNewNodeSet().
2375  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2376  * it with the single Node @val
2377  *
2378  * Returns the created or reused object.
2379  */
2380 static xmlXPathObjectPtr
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt,xmlNodePtr val)2381 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2382 {
2383     if ((ctxt != NULL) && (ctxt->cache)) {
2384 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2385 
2386 	if ((cache->nodesetObjs != NULL) &&
2387 	    (cache->nodesetObjs->number != 0))
2388 	{
2389 	    xmlXPathObjectPtr ret;
2390 	    /*
2391 	    * Use the nodset-cache.
2392 	    */
2393 	    ret = (xmlXPathObjectPtr)
2394 		cache->nodesetObjs->items[--cache->nodesetObjs->number];
2395 	    ret->type = XPATH_NODESET;
2396 	    ret->boolval = 0;
2397 	    if (val) {
2398 		if ((ret->nodesetval->nodeMax == 0) ||
2399 		    (val->type == XML_NAMESPACE_DECL))
2400 		{
2401 		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2402 		} else {
2403 		    ret->nodesetval->nodeTab[0] = val;
2404 		    ret->nodesetval->nodeNr = 1;
2405 		}
2406 	    }
2407 #ifdef XP_DEBUG_OBJ_USAGE
2408 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2409 #endif
2410 	    return(ret);
2411 	} else if ((cache->miscObjs != NULL) &&
2412 	    (cache->miscObjs->number != 0))
2413 	{
2414 	    xmlXPathObjectPtr ret;
2415 	    /*
2416 	    * Fallback to misc-cache.
2417 	    */
2418 
2419 	    ret = (xmlXPathObjectPtr)
2420 		cache->miscObjs->items[--cache->miscObjs->number];
2421 
2422 	    ret->type = XPATH_NODESET;
2423 	    ret->boolval = 0;
2424 	    ret->nodesetval = xmlXPathNodeSetCreate(val);
2425 	    if (ret->nodesetval == NULL) {
2426 		ctxt->lastError.domain = XML_FROM_XPATH;
2427 		ctxt->lastError.code = XML_ERR_NO_MEMORY;
2428 		return(NULL);
2429 	    }
2430 #ifdef XP_DEBUG_OBJ_USAGE
2431 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2432 #endif
2433 	    return(ret);
2434 	}
2435     }
2436     return(xmlXPathNewNodeSet(val));
2437 }
2438 
2439 /**
2440  * xmlXPathCacheNewCString:
2441  * @ctxt: the XPath context
2442  * @val:  the char * value
2443  *
2444  * This is the cached version of xmlXPathNewCString().
2445  * Acquire an xmlXPathObjectPtr of type string and of value @val
2446  *
2447  * Returns the created or reused object.
2448  */
2449 static xmlXPathObjectPtr
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt,const char * val)2450 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2451 {
2452     if ((ctxt != NULL) && (ctxt->cache)) {
2453 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2454 
2455 	if ((cache->stringObjs != NULL) &&
2456 	    (cache->stringObjs->number != 0))
2457 	{
2458 	    xmlXPathObjectPtr ret;
2459 
2460 	    ret = (xmlXPathObjectPtr)
2461 		cache->stringObjs->items[--cache->stringObjs->number];
2462 
2463 	    ret->type = XPATH_STRING;
2464 	    ret->stringval = xmlStrdup(BAD_CAST val);
2465 #ifdef XP_DEBUG_OBJ_USAGE
2466 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2467 #endif
2468 	    return(ret);
2469 	} else if ((cache->miscObjs != NULL) &&
2470 	    (cache->miscObjs->number != 0))
2471 	{
2472 	    xmlXPathObjectPtr ret;
2473 
2474 	    ret = (xmlXPathObjectPtr)
2475 		cache->miscObjs->items[--cache->miscObjs->number];
2476 
2477 	    ret->type = XPATH_STRING;
2478 	    ret->stringval = xmlStrdup(BAD_CAST val);
2479 #ifdef XP_DEBUG_OBJ_USAGE
2480 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2481 #endif
2482 	    return(ret);
2483 	}
2484     }
2485     return(xmlXPathNewCString(val));
2486 }
2487 
2488 /**
2489  * xmlXPathCacheNewString:
2490  * @ctxt: the XPath context
2491  * @val:  the xmlChar * value
2492  *
2493  * This is the cached version of xmlXPathNewString().
2494  * Acquire an xmlXPathObjectPtr of type string and of value @val
2495  *
2496  * Returns the created or reused object.
2497  */
2498 static xmlXPathObjectPtr
xmlXPathCacheNewString(xmlXPathContextPtr ctxt,const xmlChar * val)2499 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2500 {
2501     if ((ctxt != NULL) && (ctxt->cache)) {
2502 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2503 
2504 	if ((cache->stringObjs != NULL) &&
2505 	    (cache->stringObjs->number != 0))
2506 	{
2507 	    xmlXPathObjectPtr ret;
2508 
2509 	    ret = (xmlXPathObjectPtr)
2510 		cache->stringObjs->items[--cache->stringObjs->number];
2511 	    ret->type = XPATH_STRING;
2512 	    if (val != NULL)
2513 		ret->stringval = xmlStrdup(val);
2514 	    else
2515 		ret->stringval = xmlStrdup((const xmlChar *)"");
2516 #ifdef XP_DEBUG_OBJ_USAGE
2517 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2518 #endif
2519 	    return(ret);
2520 	} else if ((cache->miscObjs != NULL) &&
2521 	    (cache->miscObjs->number != 0))
2522 	{
2523 	    xmlXPathObjectPtr ret;
2524 
2525 	    ret = (xmlXPathObjectPtr)
2526 		cache->miscObjs->items[--cache->miscObjs->number];
2527 
2528 	    ret->type = XPATH_STRING;
2529 	    if (val != NULL)
2530 		ret->stringval = xmlStrdup(val);
2531 	    else
2532 		ret->stringval = xmlStrdup((const xmlChar *)"");
2533 #ifdef XP_DEBUG_OBJ_USAGE
2534 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2535 #endif
2536 	    return(ret);
2537 	}
2538     }
2539     return(xmlXPathNewString(val));
2540 }
2541 
2542 /**
2543  * xmlXPathCacheNewBoolean:
2544  * @ctxt: the XPath context
2545  * @val:  the boolean value
2546  *
2547  * This is the cached version of xmlXPathNewBoolean().
2548  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2549  *
2550  * Returns the created or reused object.
2551  */
2552 static xmlXPathObjectPtr
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt,int val)2553 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2554 {
2555     if ((ctxt != NULL) && (ctxt->cache)) {
2556 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2557 
2558 	if ((cache->booleanObjs != NULL) &&
2559 	    (cache->booleanObjs->number != 0))
2560 	{
2561 	    xmlXPathObjectPtr ret;
2562 
2563 	    ret = (xmlXPathObjectPtr)
2564 		cache->booleanObjs->items[--cache->booleanObjs->number];
2565 	    ret->type = XPATH_BOOLEAN;
2566 	    ret->boolval = (val != 0);
2567 #ifdef XP_DEBUG_OBJ_USAGE
2568 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2569 #endif
2570 	    return(ret);
2571 	} else if ((cache->miscObjs != NULL) &&
2572 	    (cache->miscObjs->number != 0))
2573 	{
2574 	    xmlXPathObjectPtr ret;
2575 
2576 	    ret = (xmlXPathObjectPtr)
2577 		cache->miscObjs->items[--cache->miscObjs->number];
2578 
2579 	    ret->type = XPATH_BOOLEAN;
2580 	    ret->boolval = (val != 0);
2581 #ifdef XP_DEBUG_OBJ_USAGE
2582 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2583 #endif
2584 	    return(ret);
2585 	}
2586     }
2587     return(xmlXPathNewBoolean(val));
2588 }
2589 
2590 /**
2591  * xmlXPathCacheNewFloat:
2592  * @ctxt: the XPath context
2593  * @val:  the double value
2594  *
2595  * This is the cached version of xmlXPathNewFloat().
2596  * Acquires an xmlXPathObjectPtr of type double and of value @val
2597  *
2598  * Returns the created or reused object.
2599  */
2600 static xmlXPathObjectPtr
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt,double val)2601 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2602 {
2603      if ((ctxt != NULL) && (ctxt->cache)) {
2604 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2605 
2606 	if ((cache->numberObjs != NULL) &&
2607 	    (cache->numberObjs->number != 0))
2608 	{
2609 	    xmlXPathObjectPtr ret;
2610 
2611 	    ret = (xmlXPathObjectPtr)
2612 		cache->numberObjs->items[--cache->numberObjs->number];
2613 	    ret->type = XPATH_NUMBER;
2614 	    ret->floatval = val;
2615 #ifdef XP_DEBUG_OBJ_USAGE
2616 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2617 #endif
2618 	    return(ret);
2619 	} else if ((cache->miscObjs != NULL) &&
2620 	    (cache->miscObjs->number != 0))
2621 	{
2622 	    xmlXPathObjectPtr ret;
2623 
2624 	    ret = (xmlXPathObjectPtr)
2625 		cache->miscObjs->items[--cache->miscObjs->number];
2626 
2627 	    ret->type = XPATH_NUMBER;
2628 	    ret->floatval = val;
2629 #ifdef XP_DEBUG_OBJ_USAGE
2630 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2631 #endif
2632 	    return(ret);
2633 	}
2634     }
2635     return(xmlXPathNewFloat(val));
2636 }
2637 
2638 /**
2639  * xmlXPathCacheConvertString:
2640  * @ctxt: the XPath context
2641  * @val:  an XPath object
2642  *
2643  * This is the cached version of xmlXPathConvertString().
2644  * Converts an existing object to its string() equivalent
2645  *
2646  * Returns a created or reused object, the old one is freed (cached)
2647  *         (or the operation is done directly on @val)
2648  */
2649 
2650 static xmlXPathObjectPtr
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2651 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2652     xmlChar *res = NULL;
2653 
2654     if (val == NULL)
2655 	return(xmlXPathCacheNewCString(ctxt, ""));
2656 
2657     switch (val->type) {
2658     case XPATH_UNDEFINED:
2659 #ifdef DEBUG_EXPR
2660 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2661 #endif
2662 	break;
2663     case XPATH_NODESET:
2664     case XPATH_XSLT_TREE:
2665 	res = xmlXPathCastNodeSetToString(val->nodesetval);
2666 	break;
2667     case XPATH_STRING:
2668 	return(val);
2669     case XPATH_BOOLEAN:
2670 	res = xmlXPathCastBooleanToString(val->boolval);
2671 	break;
2672     case XPATH_NUMBER:
2673 	res = xmlXPathCastNumberToString(val->floatval);
2674 	break;
2675     case XPATH_USERS:
2676     case XPATH_POINT:
2677     case XPATH_RANGE:
2678     case XPATH_LOCATIONSET:
2679 	TODO;
2680 	break;
2681     }
2682     xmlXPathReleaseObject(ctxt, val);
2683     if (res == NULL)
2684 	return(xmlXPathCacheNewCString(ctxt, ""));
2685     return(xmlXPathCacheWrapString(ctxt, res));
2686 }
2687 
2688 /**
2689  * xmlXPathCacheObjectCopy:
2690  * @ctxt: the XPath context
2691  * @val:  the original object
2692  *
2693  * This is the cached version of xmlXPathObjectCopy().
2694  * Acquire a copy of a given object
2695  *
2696  * Returns a created or reused created object.
2697  */
2698 static xmlXPathObjectPtr
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2699 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2700 {
2701     if (val == NULL)
2702 	return(NULL);
2703 
2704     if (XP_HAS_CACHE(ctxt)) {
2705 	switch (val->type) {
2706 	    case XPATH_NODESET:
2707 		return(xmlXPathCacheWrapNodeSet(ctxt,
2708 		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2709 	    case XPATH_STRING:
2710 		return(xmlXPathCacheNewString(ctxt, val->stringval));
2711 	    case XPATH_BOOLEAN:
2712 		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2713 	    case XPATH_NUMBER:
2714 		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2715 	    default:
2716 		break;
2717 	}
2718     }
2719     return(xmlXPathObjectCopy(val));
2720 }
2721 
2722 /**
2723  * xmlXPathCacheConvertBoolean:
2724  * @ctxt: the XPath context
2725  * @val:  an XPath object
2726  *
2727  * This is the cached version of xmlXPathConvertBoolean().
2728  * Converts an existing object to its boolean() equivalent
2729  *
2730  * Returns a created or reused object, the old one is freed (or the operation
2731  *         is done directly on @val)
2732  */
2733 static xmlXPathObjectPtr
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2734 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2735     xmlXPathObjectPtr ret;
2736 
2737     if (val == NULL)
2738 	return(xmlXPathCacheNewBoolean(ctxt, 0));
2739     if (val->type == XPATH_BOOLEAN)
2740 	return(val);
2741     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2742     xmlXPathReleaseObject(ctxt, val);
2743     return(ret);
2744 }
2745 
2746 /**
2747  * xmlXPathCacheConvertNumber:
2748  * @ctxt: the XPath context
2749  * @val:  an XPath object
2750  *
2751  * This is the cached version of xmlXPathConvertNumber().
2752  * Converts an existing object to its number() equivalent
2753  *
2754  * Returns a created or reused object, the old one is freed (or the operation
2755  *         is done directly on @val)
2756  */
2757 static xmlXPathObjectPtr
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2758 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2759     xmlXPathObjectPtr ret;
2760 
2761     if (val == NULL)
2762 	return(xmlXPathCacheNewFloat(ctxt, 0.0));
2763     if (val->type == XPATH_NUMBER)
2764 	return(val);
2765     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2766     xmlXPathReleaseObject(ctxt, val);
2767     return(ret);
2768 }
2769 
2770 /************************************************************************
2771  *									*
2772  *		Parser stacks related functions and macros		*
2773  *									*
2774  ************************************************************************/
2775 
2776 /**
2777  * xmlXPathSetFrame:
2778  * @ctxt: an XPath parser context
2779  *
2780  * Set the callee evaluation frame
2781  *
2782  * Returns the previous frame value to be restored once done
2783  */
2784 static int
xmlXPathSetFrame(xmlXPathParserContextPtr ctxt)2785 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2786     int ret;
2787 
2788     if (ctxt == NULL)
2789         return(0);
2790     ret = ctxt->valueFrame;
2791     ctxt->valueFrame = ctxt->valueNr;
2792     return(ret);
2793 }
2794 
2795 /**
2796  * xmlXPathPopFrame:
2797  * @ctxt: an XPath parser context
2798  * @frame: the previous frame value
2799  *
2800  * Remove the callee evaluation frame
2801  */
2802 static void
xmlXPathPopFrame(xmlXPathParserContextPtr ctxt,int frame)2803 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2804     if (ctxt == NULL)
2805         return;
2806     if (ctxt->valueNr < ctxt->valueFrame) {
2807         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2808     }
2809     ctxt->valueFrame = frame;
2810 }
2811 
2812 /**
2813  * valuePop:
2814  * @ctxt: an XPath evaluation context
2815  *
2816  * Pops the top XPath object from the value stack
2817  *
2818  * Returns the XPath object just removed
2819  */
2820 xmlXPathObjectPtr
valuePop(xmlXPathParserContextPtr ctxt)2821 valuePop(xmlXPathParserContextPtr ctxt)
2822 {
2823     xmlXPathObjectPtr ret;
2824 
2825     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2826         return (NULL);
2827 
2828     if (ctxt->valueNr <= ctxt->valueFrame) {
2829         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2830         return (NULL);
2831     }
2832 
2833     ctxt->valueNr--;
2834     if (ctxt->valueNr > 0)
2835         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2836     else
2837         ctxt->value = NULL;
2838     ret = ctxt->valueTab[ctxt->valueNr];
2839     ctxt->valueTab[ctxt->valueNr] = NULL;
2840     return (ret);
2841 }
2842 /**
2843  * valuePush:
2844  * @ctxt:  an XPath evaluation context
2845  * @value:  the XPath object
2846  *
2847  * Pushes a new XPath object on top of the value stack
2848  *
2849  * returns the number of items on the value stack
2850  */
2851 int
valuePush(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr value)2852 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2853 {
2854     if ((ctxt == NULL) || (value == NULL)) return(-1);
2855     if (ctxt->valueNr >= ctxt->valueMax) {
2856         xmlXPathObjectPtr *tmp;
2857 
2858         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2859             xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2860             ctxt->error = XPATH_MEMORY_ERROR;
2861             return (0);
2862         }
2863         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2864                                              2 * ctxt->valueMax *
2865                                              sizeof(ctxt->valueTab[0]));
2866         if (tmp == NULL) {
2867             xmlXPathErrMemory(NULL, "pushing value\n");
2868             ctxt->error = XPATH_MEMORY_ERROR;
2869             return (0);
2870         }
2871         ctxt->valueMax *= 2;
2872 	ctxt->valueTab = tmp;
2873     }
2874     ctxt->valueTab[ctxt->valueNr] = value;
2875     ctxt->value = value;
2876     return (ctxt->valueNr++);
2877 }
2878 
2879 /**
2880  * xmlXPathPopBoolean:
2881  * @ctxt:  an XPath parser context
2882  *
2883  * Pops a boolean from the stack, handling conversion if needed.
2884  * Check error with #xmlXPathCheckError.
2885  *
2886  * Returns the boolean
2887  */
2888 int
xmlXPathPopBoolean(xmlXPathParserContextPtr ctxt)2889 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2890     xmlXPathObjectPtr obj;
2891     int ret;
2892 
2893     obj = valuePop(ctxt);
2894     if (obj == NULL) {
2895 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2896 	return(0);
2897     }
2898     if (obj->type != XPATH_BOOLEAN)
2899 	ret = xmlXPathCastToBoolean(obj);
2900     else
2901         ret = obj->boolval;
2902     xmlXPathReleaseObject(ctxt->context, obj);
2903     return(ret);
2904 }
2905 
2906 /**
2907  * xmlXPathPopNumber:
2908  * @ctxt:  an XPath parser context
2909  *
2910  * Pops a number from the stack, handling conversion if needed.
2911  * Check error with #xmlXPathCheckError.
2912  *
2913  * Returns the number
2914  */
2915 double
xmlXPathPopNumber(xmlXPathParserContextPtr ctxt)2916 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2917     xmlXPathObjectPtr obj;
2918     double ret;
2919 
2920     obj = valuePop(ctxt);
2921     if (obj == NULL) {
2922 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2923 	return(0);
2924     }
2925     if (obj->type != XPATH_NUMBER)
2926 	ret = xmlXPathCastToNumber(obj);
2927     else
2928         ret = obj->floatval;
2929     xmlXPathReleaseObject(ctxt->context, obj);
2930     return(ret);
2931 }
2932 
2933 /**
2934  * xmlXPathPopString:
2935  * @ctxt:  an XPath parser context
2936  *
2937  * Pops a string from the stack, handling conversion if needed.
2938  * Check error with #xmlXPathCheckError.
2939  *
2940  * Returns the string
2941  */
2942 xmlChar *
xmlXPathPopString(xmlXPathParserContextPtr ctxt)2943 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2944     xmlXPathObjectPtr obj;
2945     xmlChar * ret;
2946 
2947     obj = valuePop(ctxt);
2948     if (obj == NULL) {
2949 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2950 	return(NULL);
2951     }
2952     ret = xmlXPathCastToString(obj);	/* this does required strdup */
2953     /* TODO: needs refactoring somewhere else */
2954     if (obj->stringval == ret)
2955 	obj->stringval = NULL;
2956     xmlXPathReleaseObject(ctxt->context, obj);
2957     return(ret);
2958 }
2959 
2960 /**
2961  * xmlXPathPopNodeSet:
2962  * @ctxt:  an XPath parser context
2963  *
2964  * Pops a node-set from the stack, handling conversion if needed.
2965  * Check error with #xmlXPathCheckError.
2966  *
2967  * Returns the node-set
2968  */
2969 xmlNodeSetPtr
xmlXPathPopNodeSet(xmlXPathParserContextPtr ctxt)2970 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2971     xmlXPathObjectPtr obj;
2972     xmlNodeSetPtr ret;
2973 
2974     if (ctxt == NULL) return(NULL);
2975     if (ctxt->value == NULL) {
2976 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2977 	return(NULL);
2978     }
2979     if (!xmlXPathStackIsNodeSet(ctxt)) {
2980 	xmlXPathSetTypeError(ctxt);
2981 	return(NULL);
2982     }
2983     obj = valuePop(ctxt);
2984     ret = obj->nodesetval;
2985 #if 0
2986     /* to fix memory leak of not clearing obj->user */
2987     if (obj->boolval && obj->user != NULL)
2988         xmlFreeNodeList((xmlNodePtr) obj->user);
2989 #endif
2990     obj->nodesetval = NULL;
2991     xmlXPathReleaseObject(ctxt->context, obj);
2992     return(ret);
2993 }
2994 
2995 /**
2996  * xmlXPathPopExternal:
2997  * @ctxt:  an XPath parser context
2998  *
2999  * Pops an external object from the stack, handling conversion if needed.
3000  * Check error with #xmlXPathCheckError.
3001  *
3002  * Returns the object
3003  */
3004 void *
xmlXPathPopExternal(xmlXPathParserContextPtr ctxt)3005 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3006     xmlXPathObjectPtr obj;
3007     void * ret;
3008 
3009     if ((ctxt == NULL) || (ctxt->value == NULL)) {
3010 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3011 	return(NULL);
3012     }
3013     if (ctxt->value->type != XPATH_USERS) {
3014 	xmlXPathSetTypeError(ctxt);
3015 	return(NULL);
3016     }
3017     obj = valuePop(ctxt);
3018     ret = obj->user;
3019     obj->user = NULL;
3020     xmlXPathReleaseObject(ctxt->context, obj);
3021     return(ret);
3022 }
3023 
3024 /*
3025  * Macros for accessing the content. Those should be used only by the parser,
3026  * and not exported.
3027  *
3028  * Dirty macros, i.e. one need to make assumption on the context to use them
3029  *
3030  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3031  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3032  *           in ISO-Latin or UTF-8.
3033  *           This should be used internally by the parser
3034  *           only to compare to ASCII values otherwise it would break when
3035  *           running with UTF-8 encoding.
3036  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3037  *           to compare on ASCII based substring.
3038  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3039  *           strings within the parser.
3040  *   CURRENT Returns the current char value, with the full decoding of
3041  *           UTF-8 if we are using this mode. It returns an int.
3042  *   NEXT    Skip to the next character, this does the proper decoding
3043  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3044  *           It returns the pointer to the current xmlChar.
3045  */
3046 
3047 #define CUR (*ctxt->cur)
3048 #define SKIP(val) ctxt->cur += (val)
3049 #define NXT(val) ctxt->cur[(val)]
3050 #define CUR_PTR ctxt->cur
3051 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3052 
3053 #define COPY_BUF(l,b,i,v)                                              \
3054     if (l == 1) b[i++] = (xmlChar) v;                                  \
3055     else i += xmlCopyChar(l,&b[i],v)
3056 
3057 #define NEXTL(l)  ctxt->cur += l
3058 
3059 #define SKIP_BLANKS							\
3060     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3061 
3062 #define CURRENT (*ctxt->cur)
3063 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3064 
3065 
3066 #ifndef DBL_DIG
3067 #define DBL_DIG 16
3068 #endif
3069 #ifndef DBL_EPSILON
3070 #define DBL_EPSILON 1E-9
3071 #endif
3072 
3073 #define UPPER_DOUBLE 1E9
3074 #define LOWER_DOUBLE 1E-5
3075 #define	LOWER_DOUBLE_EXP 5
3076 
3077 #define INTEGER_DIGITS DBL_DIG
3078 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3079 #define EXPONENT_DIGITS (3 + 2)
3080 
3081 /**
3082  * xmlXPathFormatNumber:
3083  * @number:     number to format
3084  * @buffer:     output buffer
3085  * @buffersize: size of output buffer
3086  *
3087  * Convert the number into a string representation.
3088  */
3089 static void
xmlXPathFormatNumber(double number,char buffer[],int buffersize)3090 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3091 {
3092     switch (xmlXPathIsInf(number)) {
3093     case 1:
3094 	if (buffersize > (int)sizeof("Infinity"))
3095 	    snprintf(buffer, buffersize, "Infinity");
3096 	break;
3097     case -1:
3098 	if (buffersize > (int)sizeof("-Infinity"))
3099 	    snprintf(buffer, buffersize, "-Infinity");
3100 	break;
3101     default:
3102 	if (xmlXPathIsNaN(number)) {
3103 	    if (buffersize > (int)sizeof("NaN"))
3104 		snprintf(buffer, buffersize, "NaN");
3105 	} else if (number == 0) {
3106             /* Omit sign for negative zero. */
3107 	    snprintf(buffer, buffersize, "0");
3108 	} else if ((number > INT_MIN) && (number < INT_MAX) &&
3109                    (number == (int) number)) {
3110 	    char work[30];
3111 	    char *ptr, *cur;
3112 	    int value = (int) number;
3113 
3114             ptr = &buffer[0];
3115 	    if (value == 0) {
3116 		*ptr++ = '0';
3117 	    } else {
3118 		snprintf(work, 29, "%d", value);
3119 		cur = &work[0];
3120 		while ((*cur) && (ptr - buffer < buffersize)) {
3121 		    *ptr++ = *cur++;
3122 		}
3123 	    }
3124 	    if (ptr - buffer < buffersize) {
3125 		*ptr = 0;
3126 	    } else if (buffersize > 0) {
3127 		ptr--;
3128 		*ptr = 0;
3129 	    }
3130 	} else {
3131 	    /*
3132 	      For the dimension of work,
3133 	          DBL_DIG is number of significant digits
3134 		  EXPONENT is only needed for "scientific notation"
3135 	          3 is sign, decimal point, and terminating zero
3136 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3137 	      Note that this dimension is slightly (a few characters)
3138 	      larger than actually necessary.
3139 	    */
3140 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3141 	    int integer_place, fraction_place;
3142 	    char *ptr;
3143 	    char *after_fraction;
3144 	    double absolute_value;
3145 	    int size;
3146 
3147 	    absolute_value = fabs(number);
3148 
3149 	    /*
3150 	     * First choose format - scientific or regular floating point.
3151 	     * In either case, result is in work, and after_fraction points
3152 	     * just past the fractional part.
3153 	    */
3154 	    if ( ((absolute_value > UPPER_DOUBLE) ||
3155 		  (absolute_value < LOWER_DOUBLE)) &&
3156 		 (absolute_value != 0.0) ) {
3157 		/* Use scientific notation */
3158 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3159 		fraction_place = DBL_DIG - 1;
3160 		size = snprintf(work, sizeof(work),"%*.*e",
3161 			 integer_place, fraction_place, number);
3162 		while ((size > 0) && (work[size] != 'e')) size--;
3163 
3164 	    }
3165 	    else {
3166 		/* Use regular notation */
3167 		if (absolute_value > 0.0) {
3168 		    integer_place = (int)log10(absolute_value);
3169 		    if (integer_place > 0)
3170 		        fraction_place = DBL_DIG - integer_place - 1;
3171 		    else
3172 		        fraction_place = DBL_DIG - integer_place;
3173 		} else {
3174 		    fraction_place = 1;
3175 		}
3176 		size = snprintf(work, sizeof(work), "%0.*f",
3177 				fraction_place, number);
3178 	    }
3179 
3180 	    /* Remove leading spaces sometimes inserted by snprintf */
3181 	    while (work[0] == ' ') {
3182 	        for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3183 		size--;
3184 	    }
3185 
3186 	    /* Remove fractional trailing zeroes */
3187 	    after_fraction = work + size;
3188 	    ptr = after_fraction;
3189 	    while (*(--ptr) == '0')
3190 		;
3191 	    if (*ptr != '.')
3192 	        ptr++;
3193 	    while ((*ptr++ = *after_fraction++) != 0);
3194 
3195 	    /* Finally copy result back to caller */
3196 	    size = strlen(work) + 1;
3197 	    if (size > buffersize) {
3198 		work[buffersize - 1] = 0;
3199 		size = buffersize;
3200 	    }
3201 	    memmove(buffer, work, size);
3202 	}
3203 	break;
3204     }
3205 }
3206 
3207 
3208 /************************************************************************
3209  *									*
3210  *			Routines to handle NodeSets			*
3211  *									*
3212  ************************************************************************/
3213 
3214 /**
3215  * xmlXPathOrderDocElems:
3216  * @doc:  an input document
3217  *
3218  * Call this routine to speed up XPath computation on static documents.
3219  * This stamps all the element nodes with the document order
3220  * Like for line information, the order is kept in the element->content
3221  * field, the value stored is actually - the node number (starting at -1)
3222  * to be able to differentiate from line numbers.
3223  *
3224  * Returns the number of elements found in the document or -1 in case
3225  *    of error.
3226  */
3227 long
xmlXPathOrderDocElems(xmlDocPtr doc)3228 xmlXPathOrderDocElems(xmlDocPtr doc) {
3229     ptrdiff_t count = 0;
3230     xmlNodePtr cur;
3231 
3232     if (doc == NULL)
3233 	return(-1);
3234     cur = doc->children;
3235     while (cur != NULL) {
3236 	if (cur->type == XML_ELEMENT_NODE) {
3237 	    cur->content = (void *) (-(++count));
3238 	    if (cur->children != NULL) {
3239 		cur = cur->children;
3240 		continue;
3241 	    }
3242 	}
3243 	if (cur->next != NULL) {
3244 	    cur = cur->next;
3245 	    continue;
3246 	}
3247 	do {
3248 	    cur = cur->parent;
3249 	    if (cur == NULL)
3250 		break;
3251 	    if (cur == (xmlNodePtr) doc) {
3252 		cur = NULL;
3253 		break;
3254 	    }
3255 	    if (cur->next != NULL) {
3256 		cur = cur->next;
3257 		break;
3258 	    }
3259 	} while (cur != NULL);
3260     }
3261     return((long) count);
3262 }
3263 
3264 /**
3265  * xmlXPathCmpNodes:
3266  * @node1:  the first node
3267  * @node2:  the second node
3268  *
3269  * Compare two nodes w.r.t document order
3270  *
3271  * Returns -2 in case of error 1 if first point < second point, 0 if
3272  *         it's the same node, -1 otherwise
3273  */
3274 int
xmlXPathCmpNodes(xmlNodePtr node1,xmlNodePtr node2)3275 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3276     int depth1, depth2;
3277     int attr1 = 0, attr2 = 0;
3278     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3279     xmlNodePtr cur, root;
3280 
3281     if ((node1 == NULL) || (node2 == NULL))
3282 	return(-2);
3283     /*
3284      * a couple of optimizations which will avoid computations in most cases
3285      */
3286     if (node1 == node2)		/* trivial case */
3287 	return(0);
3288     if (node1->type == XML_ATTRIBUTE_NODE) {
3289 	attr1 = 1;
3290 	attrNode1 = node1;
3291 	node1 = node1->parent;
3292     }
3293     if (node2->type == XML_ATTRIBUTE_NODE) {
3294 	attr2 = 1;
3295 	attrNode2 = node2;
3296 	node2 = node2->parent;
3297     }
3298     if (node1 == node2) {
3299 	if (attr1 == attr2) {
3300 	    /* not required, but we keep attributes in order */
3301 	    if (attr1 != 0) {
3302 	        cur = attrNode2->prev;
3303 		while (cur != NULL) {
3304 		    if (cur == attrNode1)
3305 		        return (1);
3306 		    cur = cur->prev;
3307 		}
3308 		return (-1);
3309 	    }
3310 	    return(0);
3311 	}
3312 	if (attr2 == 1)
3313 	    return(1);
3314 	return(-1);
3315     }
3316     if ((node1->type == XML_NAMESPACE_DECL) ||
3317         (node2->type == XML_NAMESPACE_DECL))
3318 	return(1);
3319     if (node1 == node2->prev)
3320 	return(1);
3321     if (node1 == node2->next)
3322 	return(-1);
3323 
3324     /*
3325      * Speedup using document order if availble.
3326      */
3327     if ((node1->type == XML_ELEMENT_NODE) &&
3328 	(node2->type == XML_ELEMENT_NODE) &&
3329 	(0 > (ptrdiff_t) node1->content) &&
3330 	(0 > (ptrdiff_t) node2->content) &&
3331 	(node1->doc == node2->doc)) {
3332 	ptrdiff_t l1, l2;
3333 
3334 	l1 = -((ptrdiff_t) node1->content);
3335 	l2 = -((ptrdiff_t) node2->content);
3336 	if (l1 < l2)
3337 	    return(1);
3338 	if (l1 > l2)
3339 	    return(-1);
3340     }
3341 
3342     /*
3343      * compute depth to root
3344      */
3345     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3346 	if (cur->parent == node1)
3347 	    return(1);
3348 	depth2++;
3349     }
3350     root = cur;
3351     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3352 	if (cur->parent == node2)
3353 	    return(-1);
3354 	depth1++;
3355     }
3356     /*
3357      * Distinct document (or distinct entities :-( ) case.
3358      */
3359     if (root != cur) {
3360 	return(-2);
3361     }
3362     /*
3363      * get the nearest common ancestor.
3364      */
3365     while (depth1 > depth2) {
3366 	depth1--;
3367 	node1 = node1->parent;
3368     }
3369     while (depth2 > depth1) {
3370 	depth2--;
3371 	node2 = node2->parent;
3372     }
3373     while (node1->parent != node2->parent) {
3374 	node1 = node1->parent;
3375 	node2 = node2->parent;
3376 	/* should not happen but just in case ... */
3377 	if ((node1 == NULL) || (node2 == NULL))
3378 	    return(-2);
3379     }
3380     /*
3381      * Find who's first.
3382      */
3383     if (node1 == node2->prev)
3384 	return(1);
3385     if (node1 == node2->next)
3386 	return(-1);
3387     /*
3388      * Speedup using document order if availble.
3389      */
3390     if ((node1->type == XML_ELEMENT_NODE) &&
3391 	(node2->type == XML_ELEMENT_NODE) &&
3392 	(0 > (ptrdiff_t) node1->content) &&
3393 	(0 > (ptrdiff_t) node2->content) &&
3394 	(node1->doc == node2->doc)) {
3395 	ptrdiff_t l1, l2;
3396 
3397 	l1 = -((ptrdiff_t) node1->content);
3398 	l2 = -((ptrdiff_t) node2->content);
3399 	if (l1 < l2)
3400 	    return(1);
3401 	if (l1 > l2)
3402 	    return(-1);
3403     }
3404 
3405     for (cur = node1->next;cur != NULL;cur = cur->next)
3406 	if (cur == node2)
3407 	    return(1);
3408     return(-1); /* assume there is no sibling list corruption */
3409 }
3410 
3411 /**
3412  * xmlXPathNodeSetSort:
3413  * @set:  the node set
3414  *
3415  * Sort the node set in document order
3416  */
3417 void
xmlXPathNodeSetSort(xmlNodeSetPtr set)3418 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3419 #ifndef WITH_TIM_SORT
3420     int i, j, incr, len;
3421     xmlNodePtr tmp;
3422 #endif
3423 
3424     if (set == NULL)
3425 	return;
3426 
3427 #ifndef WITH_TIM_SORT
3428     /*
3429      * Use the old Shell's sort implementation to sort the node-set
3430      * Timsort ought to be quite faster
3431      */
3432     len = set->nodeNr;
3433     for (incr = len / 2; incr > 0; incr /= 2) {
3434 	for (i = incr; i < len; i++) {
3435 	    j = i - incr;
3436 	    while (j >= 0) {
3437 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3438 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
3439 			set->nodeTab[j + incr]) == -1)
3440 #else
3441 		if (xmlXPathCmpNodes(set->nodeTab[j],
3442 			set->nodeTab[j + incr]) == -1)
3443 #endif
3444 		{
3445 		    tmp = set->nodeTab[j];
3446 		    set->nodeTab[j] = set->nodeTab[j + incr];
3447 		    set->nodeTab[j + incr] = tmp;
3448 		    j -= incr;
3449 		} else
3450 		    break;
3451 	    }
3452 	}
3453     }
3454 #else /* WITH_TIM_SORT */
3455     libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3456 #endif /* WITH_TIM_SORT */
3457 }
3458 
3459 #define XML_NODESET_DEFAULT	10
3460 /**
3461  * xmlXPathNodeSetDupNs:
3462  * @node:  the parent node of the namespace XPath node
3463  * @ns:  the libxml namespace declaration node.
3464  *
3465  * Namespace node in libxml don't match the XPath semantic. In a node set
3466  * the namespace nodes are duplicated and the next pointer is set to the
3467  * parent node in the XPath semantic.
3468  *
3469  * Returns the newly created object.
3470  */
3471 static xmlNodePtr
xmlXPathNodeSetDupNs(xmlNodePtr node,xmlNsPtr ns)3472 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3473     xmlNsPtr cur;
3474 
3475     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3476 	return(NULL);
3477     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3478 	return((xmlNodePtr) ns);
3479 
3480     /*
3481      * Allocate a new Namespace and fill the fields.
3482      */
3483     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3484     if (cur == NULL) {
3485         xmlXPathErrMemory(NULL, "duplicating namespace\n");
3486 	return(NULL);
3487     }
3488     memset(cur, 0, sizeof(xmlNs));
3489     cur->type = XML_NAMESPACE_DECL;
3490     if (ns->href != NULL)
3491 	cur->href = xmlStrdup(ns->href);
3492     if (ns->prefix != NULL)
3493 	cur->prefix = xmlStrdup(ns->prefix);
3494     cur->next = (xmlNsPtr) node;
3495     return((xmlNodePtr) cur);
3496 }
3497 
3498 /**
3499  * xmlXPathNodeSetFreeNs:
3500  * @ns:  the XPath namespace node found in a nodeset.
3501  *
3502  * Namespace nodes in libxml don't match the XPath semantic. In a node set
3503  * the namespace nodes are duplicated and the next pointer is set to the
3504  * parent node in the XPath semantic. Check if such a node needs to be freed
3505  */
3506 void
xmlXPathNodeSetFreeNs(xmlNsPtr ns)3507 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3508     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3509 	return;
3510 
3511     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3512 	if (ns->href != NULL)
3513 	    xmlFree((xmlChar *)ns->href);
3514 	if (ns->prefix != NULL)
3515 	    xmlFree((xmlChar *)ns->prefix);
3516 	xmlFree(ns);
3517     }
3518 }
3519 
3520 /**
3521  * xmlXPathNodeSetCreate:
3522  * @val:  an initial xmlNodePtr, or NULL
3523  *
3524  * Create a new xmlNodeSetPtr of type double and of value @val
3525  *
3526  * Returns the newly created object.
3527  */
3528 xmlNodeSetPtr
xmlXPathNodeSetCreate(xmlNodePtr val)3529 xmlXPathNodeSetCreate(xmlNodePtr val) {
3530     xmlNodeSetPtr ret;
3531 
3532     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3533     if (ret == NULL) {
3534         xmlXPathErrMemory(NULL, "creating nodeset\n");
3535 	return(NULL);
3536     }
3537     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3538     if (val != NULL) {
3539         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3540 					     sizeof(xmlNodePtr));
3541 	if (ret->nodeTab == NULL) {
3542 	    xmlXPathErrMemory(NULL, "creating nodeset\n");
3543 	    xmlFree(ret);
3544 	    return(NULL);
3545 	}
3546 	memset(ret->nodeTab, 0 ,
3547 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3548         ret->nodeMax = XML_NODESET_DEFAULT;
3549 	if (val->type == XML_NAMESPACE_DECL) {
3550 	    xmlNsPtr ns = (xmlNsPtr) val;
3551 
3552 	    ret->nodeTab[ret->nodeNr++] =
3553 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3554 	} else
3555 	    ret->nodeTab[ret->nodeNr++] = val;
3556     }
3557     return(ret);
3558 }
3559 
3560 /**
3561  * xmlXPathNodeSetCreateSize:
3562  * @size:  the initial size of the set
3563  *
3564  * Create a new xmlNodeSetPtr of type double and of value @val
3565  *
3566  * Returns the newly created object.
3567  */
3568 static xmlNodeSetPtr
xmlXPathNodeSetCreateSize(int size)3569 xmlXPathNodeSetCreateSize(int size) {
3570     xmlNodeSetPtr ret;
3571 
3572     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3573     if (ret == NULL) {
3574         xmlXPathErrMemory(NULL, "creating nodeset\n");
3575 	return(NULL);
3576     }
3577     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3578     if (size < XML_NODESET_DEFAULT)
3579 	size = XML_NODESET_DEFAULT;
3580     ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3581     if (ret->nodeTab == NULL) {
3582 	xmlXPathErrMemory(NULL, "creating nodeset\n");
3583 	xmlFree(ret);
3584 	return(NULL);
3585     }
3586     memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3587     ret->nodeMax = size;
3588     return(ret);
3589 }
3590 
3591 /**
3592  * xmlXPathNodeSetContains:
3593  * @cur:  the node-set
3594  * @val:  the node
3595  *
3596  * checks whether @cur contains @val
3597  *
3598  * Returns true (1) if @cur contains @val, false (0) otherwise
3599  */
3600 int
xmlXPathNodeSetContains(xmlNodeSetPtr cur,xmlNodePtr val)3601 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3602     int i;
3603 
3604     if ((cur == NULL) || (val == NULL)) return(0);
3605     if (val->type == XML_NAMESPACE_DECL) {
3606 	for (i = 0; i < cur->nodeNr; i++) {
3607 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3608 		xmlNsPtr ns1, ns2;
3609 
3610 		ns1 = (xmlNsPtr) val;
3611 		ns2 = (xmlNsPtr) cur->nodeTab[i];
3612 		if (ns1 == ns2)
3613 		    return(1);
3614 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3615 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
3616 		    return(1);
3617 	    }
3618 	}
3619     } else {
3620 	for (i = 0; i < cur->nodeNr; i++) {
3621 	    if (cur->nodeTab[i] == val)
3622 		return(1);
3623 	}
3624     }
3625     return(0);
3626 }
3627 
3628 /**
3629  * xmlXPathNodeSetAddNs:
3630  * @cur:  the initial node set
3631  * @node:  the hosting node
3632  * @ns:  a the namespace node
3633  *
3634  * add a new namespace node to an existing NodeSet
3635  *
3636  * Returns 0 in case of success and -1 in case of error
3637  */
3638 int
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur,xmlNodePtr node,xmlNsPtr ns)3639 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3640     int i;
3641 
3642 
3643     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3644         (ns->type != XML_NAMESPACE_DECL) ||
3645 	(node->type != XML_ELEMENT_NODE))
3646 	return(-1);
3647 
3648     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3649     /*
3650      * prevent duplicates
3651      */
3652     for (i = 0;i < cur->nodeNr;i++) {
3653         if ((cur->nodeTab[i] != NULL) &&
3654 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3655 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3656 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3657 	    return(0);
3658     }
3659 
3660     /*
3661      * grow the nodeTab if needed
3662      */
3663     if (cur->nodeMax == 0) {
3664         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3665 					     sizeof(xmlNodePtr));
3666 	if (cur->nodeTab == NULL) {
3667 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3668 	    return(-1);
3669 	}
3670 	memset(cur->nodeTab, 0 ,
3671 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3672         cur->nodeMax = XML_NODESET_DEFAULT;
3673     } else if (cur->nodeNr == cur->nodeMax) {
3674         xmlNodePtr *temp;
3675 
3676         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3677             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3678             return(-1);
3679         }
3680 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3681 				      sizeof(xmlNodePtr));
3682 	if (temp == NULL) {
3683 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3684 	    return(-1);
3685 	}
3686         cur->nodeMax *= 2;
3687 	cur->nodeTab = temp;
3688     }
3689     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3690     return(0);
3691 }
3692 
3693 /**
3694  * xmlXPathNodeSetAdd:
3695  * @cur:  the initial node set
3696  * @val:  a new xmlNodePtr
3697  *
3698  * add a new xmlNodePtr to an existing NodeSet
3699  *
3700  * Returns 0 in case of success, and -1 in case of error
3701  */
3702 int
xmlXPathNodeSetAdd(xmlNodeSetPtr cur,xmlNodePtr val)3703 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3704     int i;
3705 
3706     if ((cur == NULL) || (val == NULL)) return(-1);
3707 
3708     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3709     /*
3710      * prevent duplicates
3711      */
3712     for (i = 0;i < cur->nodeNr;i++)
3713         if (cur->nodeTab[i] == val) return(0);
3714 
3715     /*
3716      * grow the nodeTab if needed
3717      */
3718     if (cur->nodeMax == 0) {
3719         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3720 					     sizeof(xmlNodePtr));
3721 	if (cur->nodeTab == NULL) {
3722 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3723 	    return(-1);
3724 	}
3725 	memset(cur->nodeTab, 0 ,
3726 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3727         cur->nodeMax = XML_NODESET_DEFAULT;
3728     } else if (cur->nodeNr == cur->nodeMax) {
3729         xmlNodePtr *temp;
3730 
3731         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3732             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3733             return(-1);
3734         }
3735 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3736 				      sizeof(xmlNodePtr));
3737 	if (temp == NULL) {
3738 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3739 	    return(-1);
3740 	}
3741         cur->nodeMax *= 2;
3742 	cur->nodeTab = temp;
3743     }
3744     if (val->type == XML_NAMESPACE_DECL) {
3745 	xmlNsPtr ns = (xmlNsPtr) val;
3746 
3747 	cur->nodeTab[cur->nodeNr++] =
3748 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3749     } else
3750 	cur->nodeTab[cur->nodeNr++] = val;
3751     return(0);
3752 }
3753 
3754 /**
3755  * xmlXPathNodeSetAddUnique:
3756  * @cur:  the initial node set
3757  * @val:  a new xmlNodePtr
3758  *
3759  * add a new xmlNodePtr to an existing NodeSet, optimized version
3760  * when we are sure the node is not already in the set.
3761  *
3762  * Returns 0 in case of success and -1 in case of failure
3763  */
3764 int
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur,xmlNodePtr val)3765 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3766     if ((cur == NULL) || (val == NULL)) return(-1);
3767 
3768     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3769     /*
3770      * grow the nodeTab if needed
3771      */
3772     if (cur->nodeMax == 0) {
3773         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3774 					     sizeof(xmlNodePtr));
3775 	if (cur->nodeTab == NULL) {
3776 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3777 	    return(-1);
3778 	}
3779 	memset(cur->nodeTab, 0 ,
3780 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3781         cur->nodeMax = XML_NODESET_DEFAULT;
3782     } else if (cur->nodeNr == cur->nodeMax) {
3783         xmlNodePtr *temp;
3784 
3785         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3786             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3787             return(-1);
3788         }
3789 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3790 				      sizeof(xmlNodePtr));
3791 	if (temp == NULL) {
3792 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3793 	    return(-1);
3794 	}
3795 	cur->nodeTab = temp;
3796         cur->nodeMax *= 2;
3797     }
3798     if (val->type == XML_NAMESPACE_DECL) {
3799 	xmlNsPtr ns = (xmlNsPtr) val;
3800 
3801 	cur->nodeTab[cur->nodeNr++] =
3802 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3803     } else
3804 	cur->nodeTab[cur->nodeNr++] = val;
3805     return(0);
3806 }
3807 
3808 /**
3809  * xmlXPathNodeSetMerge:
3810  * @val1:  the first NodeSet or NULL
3811  * @val2:  the second NodeSet
3812  *
3813  * Merges two nodesets, all nodes from @val2 are added to @val1
3814  * if @val1 is NULL, a new set is created and copied from @val2
3815  *
3816  * Returns @val1 once extended or NULL in case of error.
3817  */
3818 xmlNodeSetPtr
xmlXPathNodeSetMerge(xmlNodeSetPtr val1,xmlNodeSetPtr val2)3819 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3820     int i, j, initNr, skip;
3821     xmlNodePtr n1, n2;
3822 
3823     if (val2 == NULL) return(val1);
3824     if (val1 == NULL) {
3825 	val1 = xmlXPathNodeSetCreate(NULL);
3826     if (val1 == NULL)
3827         return (NULL);
3828 #if 0
3829 	/*
3830 	* TODO: The optimization won't work in every case, since
3831 	*  those nasty namespace nodes need to be added with
3832 	*  xmlXPathNodeSetDupNs() to the set; thus a pure
3833 	*  memcpy is not possible.
3834 	*  If there was a flag on the nodesetval, indicating that
3835 	*  some temporary nodes are in, that would be helpfull.
3836 	*/
3837 	/*
3838 	* Optimization: Create an equally sized node-set
3839 	* and memcpy the content.
3840 	*/
3841 	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3842 	if (val1 == NULL)
3843 	    return(NULL);
3844 	if (val2->nodeNr != 0) {
3845 	    if (val2->nodeNr == 1)
3846 		*(val1->nodeTab) = *(val2->nodeTab);
3847 	    else {
3848 		memcpy(val1->nodeTab, val2->nodeTab,
3849 		    val2->nodeNr * sizeof(xmlNodePtr));
3850 	    }
3851 	    val1->nodeNr = val2->nodeNr;
3852 	}
3853 	return(val1);
3854 #endif
3855     }
3856 
3857     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3858     initNr = val1->nodeNr;
3859 
3860     for (i = 0;i < val2->nodeNr;i++) {
3861 	n2 = val2->nodeTab[i];
3862 	/*
3863 	 * check against duplicates
3864 	 */
3865 	skip = 0;
3866 	for (j = 0; j < initNr; j++) {
3867 	    n1 = val1->nodeTab[j];
3868 	    if (n1 == n2) {
3869 		skip = 1;
3870 		break;
3871 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3872 		       (n2->type == XML_NAMESPACE_DECL)) {
3873 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3874 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3875 			((xmlNsPtr) n2)->prefix)))
3876 		{
3877 		    skip = 1;
3878 		    break;
3879 		}
3880 	    }
3881 	}
3882 	if (skip)
3883 	    continue;
3884 
3885 	/*
3886 	 * grow the nodeTab if needed
3887 	 */
3888 	if (val1->nodeMax == 0) {
3889 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3890 						    sizeof(xmlNodePtr));
3891 	    if (val1->nodeTab == NULL) {
3892 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3893 		return(NULL);
3894 	    }
3895 	    memset(val1->nodeTab, 0 ,
3896 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3897 	    val1->nodeMax = XML_NODESET_DEFAULT;
3898 	} else if (val1->nodeNr == val1->nodeMax) {
3899 	    xmlNodePtr *temp;
3900 
3901             if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3902                 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3903                 return(NULL);
3904             }
3905 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3906 					     sizeof(xmlNodePtr));
3907 	    if (temp == NULL) {
3908 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3909 		return(NULL);
3910 	    }
3911 	    val1->nodeTab = temp;
3912 	    val1->nodeMax *= 2;
3913 	}
3914 	if (n2->type == XML_NAMESPACE_DECL) {
3915 	    xmlNsPtr ns = (xmlNsPtr) n2;
3916 
3917 	    val1->nodeTab[val1->nodeNr++] =
3918 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3919 	} else
3920 	    val1->nodeTab[val1->nodeNr++] = n2;
3921     }
3922 
3923     return(val1);
3924 }
3925 
3926 
3927 /**
3928  * xmlXPathNodeSetMergeAndClear:
3929  * @set1:  the first NodeSet or NULL
3930  * @set2:  the second NodeSet
3931  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3932  *
3933  * Merges two nodesets, all nodes from @set2 are added to @set1
3934  * if @set1 is NULL, a new set is created and copied from @set2.
3935  * Checks for duplicate nodes. Clears set2.
3936  *
3937  * Returns @set1 once extended or NULL in case of error.
3938  */
3939 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1,xmlNodeSetPtr set2,int hasNullEntries)3940 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3941 			     int hasNullEntries)
3942 {
3943     if ((set1 == NULL) && (hasNullEntries == 0)) {
3944 	/*
3945 	* Note that doing a memcpy of the list, namespace nodes are
3946 	* just assigned to set1, since set2 is cleared anyway.
3947 	*/
3948 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3949 	if (set1 == NULL)
3950 	    return(NULL);
3951 	if (set2->nodeNr != 0) {
3952 	    memcpy(set1->nodeTab, set2->nodeTab,
3953 		set2->nodeNr * sizeof(xmlNodePtr));
3954 	    set1->nodeNr = set2->nodeNr;
3955 	}
3956     } else {
3957 	int i, j, initNbSet1;
3958 	xmlNodePtr n1, n2;
3959 
3960 	if (set1 == NULL)
3961             set1 = xmlXPathNodeSetCreate(NULL);
3962         if (set1 == NULL)
3963             return (NULL);
3964 
3965 	initNbSet1 = set1->nodeNr;
3966 	for (i = 0;i < set2->nodeNr;i++) {
3967 	    n2 = set2->nodeTab[i];
3968 	    /*
3969 	    * Skip NULLed entries.
3970 	    */
3971 	    if (n2 == NULL)
3972 		continue;
3973 	    /*
3974 	    * Skip duplicates.
3975 	    */
3976 	    for (j = 0; j < initNbSet1; j++) {
3977 		n1 = set1->nodeTab[j];
3978 		if (n1 == n2) {
3979 		    goto skip_node;
3980 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
3981 		    (n2->type == XML_NAMESPACE_DECL))
3982 		{
3983 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3984 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
3985 			((xmlNsPtr) n2)->prefix)))
3986 		    {
3987 			/*
3988 			* Free the namespace node.
3989 			*/
3990 			set2->nodeTab[i] = NULL;
3991 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3992 			goto skip_node;
3993 		    }
3994 		}
3995 	    }
3996 	    /*
3997 	    * grow the nodeTab if needed
3998 	    */
3999 	    if (set1->nodeMax == 0) {
4000 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4001 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4002 		if (set1->nodeTab == NULL) {
4003 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4004 		    return(NULL);
4005 		}
4006 		memset(set1->nodeTab, 0,
4007 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4008 		set1->nodeMax = XML_NODESET_DEFAULT;
4009 	    } else if (set1->nodeNr >= set1->nodeMax) {
4010 		xmlNodePtr *temp;
4011 
4012                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4013                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4014                     return(NULL);
4015                 }
4016 		temp = (xmlNodePtr *) xmlRealloc(
4017 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4018 		if (temp == NULL) {
4019 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4020 		    return(NULL);
4021 		}
4022 		set1->nodeTab = temp;
4023 		set1->nodeMax *= 2;
4024 	    }
4025 	    set1->nodeTab[set1->nodeNr++] = n2;
4026 skip_node:
4027 	    {}
4028 	}
4029     }
4030     set2->nodeNr = 0;
4031     return(set1);
4032 }
4033 
4034 /**
4035  * xmlXPathNodeSetMergeAndClearNoDupls:
4036  * @set1:  the first NodeSet or NULL
4037  * @set2:  the second NodeSet
4038  * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4039  *
4040  * Merges two nodesets, all nodes from @set2 are added to @set1
4041  * if @set1 is NULL, a new set is created and copied from @set2.
4042  * Doesn't chack for duplicate nodes. Clears set2.
4043  *
4044  * Returns @set1 once extended or NULL in case of error.
4045  */
4046 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1,xmlNodeSetPtr set2,int hasNullEntries)4047 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4048 				    int hasNullEntries)
4049 {
4050     if (set2 == NULL)
4051 	return(set1);
4052     if ((set1 == NULL) && (hasNullEntries == 0)) {
4053 	/*
4054 	* Note that doing a memcpy of the list, namespace nodes are
4055 	* just assigned to set1, since set2 is cleared anyway.
4056 	*/
4057 	set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4058 	if (set1 == NULL)
4059 	    return(NULL);
4060 	if (set2->nodeNr != 0) {
4061 	    memcpy(set1->nodeTab, set2->nodeTab,
4062 		set2->nodeNr * sizeof(xmlNodePtr));
4063 	    set1->nodeNr = set2->nodeNr;
4064 	}
4065     } else {
4066 	int i;
4067 	xmlNodePtr n2;
4068 
4069 	if (set1 == NULL)
4070 	    set1 = xmlXPathNodeSetCreate(NULL);
4071         if (set1 == NULL)
4072             return (NULL);
4073 
4074 	for (i = 0;i < set2->nodeNr;i++) {
4075 	    n2 = set2->nodeTab[i];
4076 	    /*
4077 	    * Skip NULLed entries.
4078 	    */
4079 	    if (n2 == NULL)
4080 		continue;
4081 	    if (set1->nodeMax == 0) {
4082 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4083 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4084 		if (set1->nodeTab == NULL) {
4085 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4086 		    return(NULL);
4087 		}
4088 		memset(set1->nodeTab, 0,
4089 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4090 		set1->nodeMax = XML_NODESET_DEFAULT;
4091 	    } else if (set1->nodeNr >= set1->nodeMax) {
4092 		xmlNodePtr *temp;
4093 
4094                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4095                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4096                     return(NULL);
4097                 }
4098 		temp = (xmlNodePtr *) xmlRealloc(
4099 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4100 		if (temp == NULL) {
4101 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4102 		    return(NULL);
4103 		}
4104 		set1->nodeTab = temp;
4105 		set1->nodeMax *= 2;
4106 	    }
4107 	    set1->nodeTab[set1->nodeNr++] = n2;
4108 	}
4109     }
4110     set2->nodeNr = 0;
4111     return(set1);
4112 }
4113 
4114 /**
4115  * xmlXPathNodeSetDel:
4116  * @cur:  the initial node set
4117  * @val:  an xmlNodePtr
4118  *
4119  * Removes an xmlNodePtr from an existing NodeSet
4120  */
4121 void
xmlXPathNodeSetDel(xmlNodeSetPtr cur,xmlNodePtr val)4122 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4123     int i;
4124 
4125     if (cur == NULL) return;
4126     if (val == NULL) return;
4127 
4128     /*
4129      * find node in nodeTab
4130      */
4131     for (i = 0;i < cur->nodeNr;i++)
4132         if (cur->nodeTab[i] == val) break;
4133 
4134     if (i >= cur->nodeNr) {	/* not found */
4135 #ifdef DEBUG
4136         xmlGenericError(xmlGenericErrorContext,
4137 	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4138 		val->name);
4139 #endif
4140         return;
4141     }
4142     if ((cur->nodeTab[i] != NULL) &&
4143 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4144 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4145     cur->nodeNr--;
4146     for (;i < cur->nodeNr;i++)
4147         cur->nodeTab[i] = cur->nodeTab[i + 1];
4148     cur->nodeTab[cur->nodeNr] = NULL;
4149 }
4150 
4151 /**
4152  * xmlXPathNodeSetRemove:
4153  * @cur:  the initial node set
4154  * @val:  the index to remove
4155  *
4156  * Removes an entry from an existing NodeSet list.
4157  */
4158 void
xmlXPathNodeSetRemove(xmlNodeSetPtr cur,int val)4159 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4160     if (cur == NULL) return;
4161     if (val >= cur->nodeNr) return;
4162     if ((cur->nodeTab[val] != NULL) &&
4163 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4164 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4165     cur->nodeNr--;
4166     for (;val < cur->nodeNr;val++)
4167         cur->nodeTab[val] = cur->nodeTab[val + 1];
4168     cur->nodeTab[cur->nodeNr] = NULL;
4169 }
4170 
4171 /**
4172  * xmlXPathFreeNodeSet:
4173  * @obj:  the xmlNodeSetPtr to free
4174  *
4175  * Free the NodeSet compound (not the actual nodes !).
4176  */
4177 void
xmlXPathFreeNodeSet(xmlNodeSetPtr obj)4178 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4179     if (obj == NULL) return;
4180     if (obj->nodeTab != NULL) {
4181 	int i;
4182 
4183 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
4184 	for (i = 0;i < obj->nodeNr;i++)
4185 	    if ((obj->nodeTab[i] != NULL) &&
4186 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4187 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4188 	xmlFree(obj->nodeTab);
4189     }
4190     xmlFree(obj);
4191 }
4192 
4193 /**
4194  * xmlXPathNodeSetClearFromPos:
4195  * @set: the node set to be cleared
4196  * @pos: the start position to clear from
4197  *
4198  * Clears the list from temporary XPath objects (e.g. namespace nodes
4199  * are feed) starting with the entry at @pos, but does *not* free the list
4200  * itself. Sets the length of the list to @pos.
4201  */
4202 static void
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set,int pos,int hasNsNodes)4203 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4204 {
4205     if ((set == NULL) || (pos >= set->nodeNr))
4206 	return;
4207     else if ((hasNsNodes)) {
4208 	int i;
4209 	xmlNodePtr node;
4210 
4211 	for (i = pos; i < set->nodeNr; i++) {
4212 	    node = set->nodeTab[i];
4213 	    if ((node != NULL) &&
4214 		(node->type == XML_NAMESPACE_DECL))
4215 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4216 	}
4217     }
4218     set->nodeNr = pos;
4219 }
4220 
4221 /**
4222  * xmlXPathNodeSetClear:
4223  * @set:  the node set to clear
4224  *
4225  * Clears the list from all temporary XPath objects (e.g. namespace nodes
4226  * are feed), but does *not* free the list itself. Sets the length of the
4227  * list to 0.
4228  */
4229 static void
xmlXPathNodeSetClear(xmlNodeSetPtr set,int hasNsNodes)4230 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4231 {
4232     xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4233 }
4234 
4235 /**
4236  * xmlXPathNodeSetKeepLast:
4237  * @set: the node set to be cleared
4238  *
4239  * Move the last node to the first position and clear temporary XPath objects
4240  * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4241  * to 1.
4242  */
4243 static void
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)4244 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4245 {
4246     int i;
4247     xmlNodePtr node;
4248 
4249     if ((set == NULL) || (set->nodeNr <= 1))
4250 	return;
4251     for (i = 0; i < set->nodeNr - 1; i++) {
4252         node = set->nodeTab[i];
4253         if ((node != NULL) &&
4254             (node->type == XML_NAMESPACE_DECL))
4255             xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4256     }
4257     set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4258     set->nodeNr = 1;
4259 }
4260 
4261 /**
4262  * xmlXPathFreeValueTree:
4263  * @obj:  the xmlNodeSetPtr to free
4264  *
4265  * Free the NodeSet compound and the actual tree, this is different
4266  * from xmlXPathFreeNodeSet()
4267  */
4268 static void
xmlXPathFreeValueTree(xmlNodeSetPtr obj)4269 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4270     int i;
4271 
4272     if (obj == NULL) return;
4273 
4274     if (obj->nodeTab != NULL) {
4275 	for (i = 0;i < obj->nodeNr;i++) {
4276 	    if (obj->nodeTab[i] != NULL) {
4277 		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4278 		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4279 		} else {
4280 		    xmlFreeNodeList(obj->nodeTab[i]);
4281 		}
4282 	    }
4283 	}
4284 	xmlFree(obj->nodeTab);
4285     }
4286     xmlFree(obj);
4287 }
4288 
4289 #if defined(DEBUG) || defined(DEBUG_STEP)
4290 /**
4291  * xmlGenericErrorContextNodeSet:
4292  * @output:  a FILE * for the output
4293  * @obj:  the xmlNodeSetPtr to display
4294  *
4295  * Quick display of a NodeSet
4296  */
4297 void
xmlGenericErrorContextNodeSet(FILE * output,xmlNodeSetPtr obj)4298 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4299     int i;
4300 
4301     if (output == NULL) output = xmlGenericErrorContext;
4302     if (obj == NULL)  {
4303         fprintf(output, "NodeSet == NULL !\n");
4304 	return;
4305     }
4306     if (obj->nodeNr == 0) {
4307         fprintf(output, "NodeSet is empty\n");
4308 	return;
4309     }
4310     if (obj->nodeTab == NULL) {
4311 	fprintf(output, " nodeTab == NULL !\n");
4312 	return;
4313     }
4314     for (i = 0; i < obj->nodeNr; i++) {
4315         if (obj->nodeTab[i] == NULL) {
4316 	    fprintf(output, " NULL !\n");
4317 	    return;
4318         }
4319 	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4320 	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4321 	    fprintf(output, " /");
4322 	else if (obj->nodeTab[i]->name == NULL)
4323 	    fprintf(output, " noname!");
4324 	else fprintf(output, " %s", obj->nodeTab[i]->name);
4325     }
4326     fprintf(output, "\n");
4327 }
4328 #endif
4329 
4330 /**
4331  * xmlXPathNewNodeSet:
4332  * @val:  the NodePtr value
4333  *
4334  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4335  * it with the single Node @val
4336  *
4337  * Returns the newly created object.
4338  */
4339 xmlXPathObjectPtr
xmlXPathNewNodeSet(xmlNodePtr val)4340 xmlXPathNewNodeSet(xmlNodePtr val) {
4341     xmlXPathObjectPtr ret;
4342 
4343     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4344     if (ret == NULL) {
4345         xmlXPathErrMemory(NULL, "creating nodeset\n");
4346 	return(NULL);
4347     }
4348     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4349     ret->type = XPATH_NODESET;
4350     ret->boolval = 0;
4351     ret->nodesetval = xmlXPathNodeSetCreate(val);
4352     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4353 #ifdef XP_DEBUG_OBJ_USAGE
4354     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4355 #endif
4356     return(ret);
4357 }
4358 
4359 /**
4360  * xmlXPathNewValueTree:
4361  * @val:  the NodePtr value
4362  *
4363  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4364  * it with the tree root @val
4365  *
4366  * Returns the newly created object.
4367  */
4368 xmlXPathObjectPtr
xmlXPathNewValueTree(xmlNodePtr val)4369 xmlXPathNewValueTree(xmlNodePtr val) {
4370     xmlXPathObjectPtr ret;
4371 
4372     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4373     if (ret == NULL) {
4374         xmlXPathErrMemory(NULL, "creating result value tree\n");
4375 	return(NULL);
4376     }
4377     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4378     ret->type = XPATH_XSLT_TREE;
4379     ret->boolval = 0;
4380     ret->user = (void *) val;
4381     ret->nodesetval = xmlXPathNodeSetCreate(val);
4382 #ifdef XP_DEBUG_OBJ_USAGE
4383     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4384 #endif
4385     return(ret);
4386 }
4387 
4388 /**
4389  * xmlXPathNewNodeSetList:
4390  * @val:  an existing NodeSet
4391  *
4392  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4393  * it with the Nodeset @val
4394  *
4395  * Returns the newly created object.
4396  */
4397 xmlXPathObjectPtr
xmlXPathNewNodeSetList(xmlNodeSetPtr val)4398 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4399 {
4400     xmlXPathObjectPtr ret;
4401     int i;
4402 
4403     if (val == NULL)
4404         ret = NULL;
4405     else if (val->nodeTab == NULL)
4406         ret = xmlXPathNewNodeSet(NULL);
4407     else {
4408         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4409         if (ret) {
4410             for (i = 1; i < val->nodeNr; ++i) {
4411                 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4412 		    < 0) break;
4413 	    }
4414 	}
4415     }
4416 
4417     return (ret);
4418 }
4419 
4420 /**
4421  * xmlXPathWrapNodeSet:
4422  * @val:  the NodePtr value
4423  *
4424  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4425  *
4426  * Returns the newly created object.
4427  */
4428 xmlXPathObjectPtr
xmlXPathWrapNodeSet(xmlNodeSetPtr val)4429 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4430     xmlXPathObjectPtr ret;
4431 
4432     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4433     if (ret == NULL) {
4434         xmlXPathErrMemory(NULL, "creating node set object\n");
4435 	return(NULL);
4436     }
4437     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4438     ret->type = XPATH_NODESET;
4439     ret->nodesetval = val;
4440 #ifdef XP_DEBUG_OBJ_USAGE
4441     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4442 #endif
4443     return(ret);
4444 }
4445 
4446 /**
4447  * xmlXPathFreeNodeSetList:
4448  * @obj:  an existing NodeSetList object
4449  *
4450  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4451  * the list contrary to xmlXPathFreeObject().
4452  */
4453 void
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj)4454 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4455     if (obj == NULL) return;
4456 #ifdef XP_DEBUG_OBJ_USAGE
4457     xmlXPathDebugObjUsageReleased(NULL, obj->type);
4458 #endif
4459     xmlFree(obj);
4460 }
4461 
4462 /**
4463  * xmlXPathDifference:
4464  * @nodes1:  a node-set
4465  * @nodes2:  a node-set
4466  *
4467  * Implements the EXSLT - Sets difference() function:
4468  *    node-set set:difference (node-set, node-set)
4469  *
4470  * Returns the difference between the two node sets, or nodes1 if
4471  *         nodes2 is empty
4472  */
4473 xmlNodeSetPtr
xmlXPathDifference(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4474 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4475     xmlNodeSetPtr ret;
4476     int i, l1;
4477     xmlNodePtr cur;
4478 
4479     if (xmlXPathNodeSetIsEmpty(nodes2))
4480 	return(nodes1);
4481 
4482     ret = xmlXPathNodeSetCreate(NULL);
4483     if (xmlXPathNodeSetIsEmpty(nodes1))
4484 	return(ret);
4485 
4486     l1 = xmlXPathNodeSetGetLength(nodes1);
4487 
4488     for (i = 0; i < l1; i++) {
4489 	cur = xmlXPathNodeSetItem(nodes1, i);
4490 	if (!xmlXPathNodeSetContains(nodes2, cur)) {
4491 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4492 	        break;
4493 	}
4494     }
4495     return(ret);
4496 }
4497 
4498 /**
4499  * xmlXPathIntersection:
4500  * @nodes1:  a node-set
4501  * @nodes2:  a node-set
4502  *
4503  * Implements the EXSLT - Sets intersection() function:
4504  *    node-set set:intersection (node-set, node-set)
4505  *
4506  * Returns a node set comprising the nodes that are within both the
4507  *         node sets passed as arguments
4508  */
4509 xmlNodeSetPtr
xmlXPathIntersection(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4510 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4511     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4512     int i, l1;
4513     xmlNodePtr cur;
4514 
4515     if (ret == NULL)
4516         return(ret);
4517     if (xmlXPathNodeSetIsEmpty(nodes1))
4518 	return(ret);
4519     if (xmlXPathNodeSetIsEmpty(nodes2))
4520 	return(ret);
4521 
4522     l1 = xmlXPathNodeSetGetLength(nodes1);
4523 
4524     for (i = 0; i < l1; i++) {
4525 	cur = xmlXPathNodeSetItem(nodes1, i);
4526 	if (xmlXPathNodeSetContains(nodes2, cur)) {
4527 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4528 	        break;
4529 	}
4530     }
4531     return(ret);
4532 }
4533 
4534 /**
4535  * xmlXPathDistinctSorted:
4536  * @nodes:  a node-set, sorted by document order
4537  *
4538  * Implements the EXSLT - Sets distinct() function:
4539  *    node-set set:distinct (node-set)
4540  *
4541  * Returns a subset of the nodes contained in @nodes, or @nodes if
4542  *         it is empty
4543  */
4544 xmlNodeSetPtr
xmlXPathDistinctSorted(xmlNodeSetPtr nodes)4545 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4546     xmlNodeSetPtr ret;
4547     xmlHashTablePtr hash;
4548     int i, l;
4549     xmlChar * strval;
4550     xmlNodePtr cur;
4551 
4552     if (xmlXPathNodeSetIsEmpty(nodes))
4553 	return(nodes);
4554 
4555     ret = xmlXPathNodeSetCreate(NULL);
4556     if (ret == NULL)
4557         return(ret);
4558     l = xmlXPathNodeSetGetLength(nodes);
4559     hash = xmlHashCreate (l);
4560     for (i = 0; i < l; i++) {
4561 	cur = xmlXPathNodeSetItem(nodes, i);
4562 	strval = xmlXPathCastNodeToString(cur);
4563 	if (xmlHashLookup(hash, strval) == NULL) {
4564 	    xmlHashAddEntry(hash, strval, strval);
4565 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4566 	        break;
4567 	} else {
4568 	    xmlFree(strval);
4569 	}
4570     }
4571     xmlHashFree(hash, xmlHashDefaultDeallocator);
4572     return(ret);
4573 }
4574 
4575 /**
4576  * xmlXPathDistinct:
4577  * @nodes:  a node-set
4578  *
4579  * Implements the EXSLT - Sets distinct() function:
4580  *    node-set set:distinct (node-set)
4581  * @nodes is sorted by document order, then #exslSetsDistinctSorted
4582  * is called with the sorted node-set
4583  *
4584  * Returns a subset of the nodes contained in @nodes, or @nodes if
4585  *         it is empty
4586  */
4587 xmlNodeSetPtr
xmlXPathDistinct(xmlNodeSetPtr nodes)4588 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4589     if (xmlXPathNodeSetIsEmpty(nodes))
4590 	return(nodes);
4591 
4592     xmlXPathNodeSetSort(nodes);
4593     return(xmlXPathDistinctSorted(nodes));
4594 }
4595 
4596 /**
4597  * xmlXPathHasSameNodes:
4598  * @nodes1:  a node-set
4599  * @nodes2:  a node-set
4600  *
4601  * Implements the EXSLT - Sets has-same-nodes function:
4602  *    boolean set:has-same-node(node-set, node-set)
4603  *
4604  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4605  *         otherwise
4606  */
4607 int
xmlXPathHasSameNodes(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4608 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4609     int i, l;
4610     xmlNodePtr cur;
4611 
4612     if (xmlXPathNodeSetIsEmpty(nodes1) ||
4613 	xmlXPathNodeSetIsEmpty(nodes2))
4614 	return(0);
4615 
4616     l = xmlXPathNodeSetGetLength(nodes1);
4617     for (i = 0; i < l; i++) {
4618 	cur = xmlXPathNodeSetItem(nodes1, i);
4619 	if (xmlXPathNodeSetContains(nodes2, cur))
4620 	    return(1);
4621     }
4622     return(0);
4623 }
4624 
4625 /**
4626  * xmlXPathNodeLeadingSorted:
4627  * @nodes: a node-set, sorted by document order
4628  * @node: a node
4629  *
4630  * Implements the EXSLT - Sets leading() function:
4631  *    node-set set:leading (node-set, node-set)
4632  *
4633  * Returns the nodes in @nodes that precede @node in document order,
4634  *         @nodes if @node is NULL or an empty node-set if @nodes
4635  *         doesn't contain @node
4636  */
4637 xmlNodeSetPtr
xmlXPathNodeLeadingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4638 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4639     int i, l;
4640     xmlNodePtr cur;
4641     xmlNodeSetPtr ret;
4642 
4643     if (node == NULL)
4644 	return(nodes);
4645 
4646     ret = xmlXPathNodeSetCreate(NULL);
4647     if (ret == NULL)
4648         return(ret);
4649     if (xmlXPathNodeSetIsEmpty(nodes) ||
4650 	(!xmlXPathNodeSetContains(nodes, node)))
4651 	return(ret);
4652 
4653     l = xmlXPathNodeSetGetLength(nodes);
4654     for (i = 0; i < l; i++) {
4655 	cur = xmlXPathNodeSetItem(nodes, i);
4656 	if (cur == node)
4657 	    break;
4658 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4659 	    break;
4660     }
4661     return(ret);
4662 }
4663 
4664 /**
4665  * xmlXPathNodeLeading:
4666  * @nodes:  a node-set
4667  * @node:  a node
4668  *
4669  * Implements the EXSLT - Sets leading() function:
4670  *    node-set set:leading (node-set, node-set)
4671  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4672  * is called.
4673  *
4674  * Returns the nodes in @nodes that precede @node in document order,
4675  *         @nodes if @node is NULL or an empty node-set if @nodes
4676  *         doesn't contain @node
4677  */
4678 xmlNodeSetPtr
xmlXPathNodeLeading(xmlNodeSetPtr nodes,xmlNodePtr node)4679 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4680     xmlXPathNodeSetSort(nodes);
4681     return(xmlXPathNodeLeadingSorted(nodes, node));
4682 }
4683 
4684 /**
4685  * xmlXPathLeadingSorted:
4686  * @nodes1:  a node-set, sorted by document order
4687  * @nodes2:  a node-set, sorted by document order
4688  *
4689  * Implements the EXSLT - Sets leading() function:
4690  *    node-set set:leading (node-set, node-set)
4691  *
4692  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4693  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4694  *         an empty node-set if @nodes1 doesn't contain @nodes2
4695  */
4696 xmlNodeSetPtr
xmlXPathLeadingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4697 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4698     if (xmlXPathNodeSetIsEmpty(nodes2))
4699 	return(nodes1);
4700     return(xmlXPathNodeLeadingSorted(nodes1,
4701 				     xmlXPathNodeSetItem(nodes2, 1)));
4702 }
4703 
4704 /**
4705  * xmlXPathLeading:
4706  * @nodes1:  a node-set
4707  * @nodes2:  a node-set
4708  *
4709  * Implements the EXSLT - Sets leading() function:
4710  *    node-set set:leading (node-set, node-set)
4711  * @nodes1 and @nodes2 are sorted by document order, then
4712  * #exslSetsLeadingSorted is called.
4713  *
4714  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4715  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4716  *         an empty node-set if @nodes1 doesn't contain @nodes2
4717  */
4718 xmlNodeSetPtr
xmlXPathLeading(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4719 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4720     if (xmlXPathNodeSetIsEmpty(nodes2))
4721 	return(nodes1);
4722     if (xmlXPathNodeSetIsEmpty(nodes1))
4723 	return(xmlXPathNodeSetCreate(NULL));
4724     xmlXPathNodeSetSort(nodes1);
4725     xmlXPathNodeSetSort(nodes2);
4726     return(xmlXPathNodeLeadingSorted(nodes1,
4727 				     xmlXPathNodeSetItem(nodes2, 1)));
4728 }
4729 
4730 /**
4731  * xmlXPathNodeTrailingSorted:
4732  * @nodes: a node-set, sorted by document order
4733  * @node: a node
4734  *
4735  * Implements the EXSLT - Sets trailing() function:
4736  *    node-set set:trailing (node-set, node-set)
4737  *
4738  * Returns the nodes in @nodes that follow @node in document order,
4739  *         @nodes if @node is NULL or an empty node-set if @nodes
4740  *         doesn't contain @node
4741  */
4742 xmlNodeSetPtr
xmlXPathNodeTrailingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4743 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4744     int i, l;
4745     xmlNodePtr cur;
4746     xmlNodeSetPtr ret;
4747 
4748     if (node == NULL)
4749 	return(nodes);
4750 
4751     ret = xmlXPathNodeSetCreate(NULL);
4752     if (ret == NULL)
4753         return(ret);
4754     if (xmlXPathNodeSetIsEmpty(nodes) ||
4755 	(!xmlXPathNodeSetContains(nodes, node)))
4756 	return(ret);
4757 
4758     l = xmlXPathNodeSetGetLength(nodes);
4759     for (i = l - 1; i >= 0; i--) {
4760 	cur = xmlXPathNodeSetItem(nodes, i);
4761 	if (cur == node)
4762 	    break;
4763 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4764 	    break;
4765     }
4766     xmlXPathNodeSetSort(ret);	/* bug 413451 */
4767     return(ret);
4768 }
4769 
4770 /**
4771  * xmlXPathNodeTrailing:
4772  * @nodes:  a node-set
4773  * @node:  a node
4774  *
4775  * Implements the EXSLT - Sets trailing() function:
4776  *    node-set set:trailing (node-set, node-set)
4777  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4778  * is called.
4779  *
4780  * Returns the nodes in @nodes that follow @node in document order,
4781  *         @nodes if @node is NULL or an empty node-set if @nodes
4782  *         doesn't contain @node
4783  */
4784 xmlNodeSetPtr
xmlXPathNodeTrailing(xmlNodeSetPtr nodes,xmlNodePtr node)4785 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4786     xmlXPathNodeSetSort(nodes);
4787     return(xmlXPathNodeTrailingSorted(nodes, node));
4788 }
4789 
4790 /**
4791  * xmlXPathTrailingSorted:
4792  * @nodes1:  a node-set, sorted by document order
4793  * @nodes2:  a node-set, sorted by document order
4794  *
4795  * Implements the EXSLT - Sets trailing() function:
4796  *    node-set set:trailing (node-set, node-set)
4797  *
4798  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4799  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4800  *         an empty node-set if @nodes1 doesn't contain @nodes2
4801  */
4802 xmlNodeSetPtr
xmlXPathTrailingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4803 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4804     if (xmlXPathNodeSetIsEmpty(nodes2))
4805 	return(nodes1);
4806     return(xmlXPathNodeTrailingSorted(nodes1,
4807 				      xmlXPathNodeSetItem(nodes2, 0)));
4808 }
4809 
4810 /**
4811  * xmlXPathTrailing:
4812  * @nodes1:  a node-set
4813  * @nodes2:  a node-set
4814  *
4815  * Implements the EXSLT - Sets trailing() function:
4816  *    node-set set:trailing (node-set, node-set)
4817  * @nodes1 and @nodes2 are sorted by document order, then
4818  * #xmlXPathTrailingSorted is called.
4819  *
4820  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4821  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4822  *         an empty node-set if @nodes1 doesn't contain @nodes2
4823  */
4824 xmlNodeSetPtr
xmlXPathTrailing(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4825 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4826     if (xmlXPathNodeSetIsEmpty(nodes2))
4827 	return(nodes1);
4828     if (xmlXPathNodeSetIsEmpty(nodes1))
4829 	return(xmlXPathNodeSetCreate(NULL));
4830     xmlXPathNodeSetSort(nodes1);
4831     xmlXPathNodeSetSort(nodes2);
4832     return(xmlXPathNodeTrailingSorted(nodes1,
4833 				      xmlXPathNodeSetItem(nodes2, 0)));
4834 }
4835 
4836 /************************************************************************
4837  *									*
4838  *		Routines to handle extra functions			*
4839  *									*
4840  ************************************************************************/
4841 
4842 /**
4843  * xmlXPathRegisterFunc:
4844  * @ctxt:  the XPath context
4845  * @name:  the function name
4846  * @f:  the function implementation or NULL
4847  *
4848  * Register a new function. If @f is NULL it unregisters the function
4849  *
4850  * Returns 0 in case of success, -1 in case of error
4851  */
4852 int
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathFunction f)4853 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4854 		     xmlXPathFunction f) {
4855     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4856 }
4857 
4858 /**
4859  * xmlXPathRegisterFuncNS:
4860  * @ctxt:  the XPath context
4861  * @name:  the function name
4862  * @ns_uri:  the function namespace URI
4863  * @f:  the function implementation or NULL
4864  *
4865  * Register a new function. If @f is NULL it unregisters the function
4866  *
4867  * Returns 0 in case of success, -1 in case of error
4868  */
4869 int
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathFunction f)4870 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4871 		       const xmlChar *ns_uri, xmlXPathFunction f) {
4872     if (ctxt == NULL)
4873 	return(-1);
4874     if (name == NULL)
4875 	return(-1);
4876 
4877     if (ctxt->funcHash == NULL)
4878 	ctxt->funcHash = xmlHashCreate(0);
4879     if (ctxt->funcHash == NULL)
4880 	return(-1);
4881     if (f == NULL)
4882         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4883 XML_IGNORE_PEDANTIC_WARNINGS
4884     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4885 XML_POP_WARNINGS
4886 }
4887 
4888 /**
4889  * xmlXPathRegisterFuncLookup:
4890  * @ctxt:  the XPath context
4891  * @f:  the lookup function
4892  * @funcCtxt:  the lookup data
4893  *
4894  * Registers an external mechanism to do function lookup.
4895  */
4896 void
xmlXPathRegisterFuncLookup(xmlXPathContextPtr ctxt,xmlXPathFuncLookupFunc f,void * funcCtxt)4897 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4898 			    xmlXPathFuncLookupFunc f,
4899 			    void *funcCtxt) {
4900     if (ctxt == NULL)
4901 	return;
4902     ctxt->funcLookupFunc = f;
4903     ctxt->funcLookupData = funcCtxt;
4904 }
4905 
4906 /**
4907  * xmlXPathFunctionLookup:
4908  * @ctxt:  the XPath context
4909  * @name:  the function name
4910  *
4911  * Search in the Function array of the context for the given
4912  * function.
4913  *
4914  * Returns the xmlXPathFunction or NULL if not found
4915  */
4916 xmlXPathFunction
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt,const xmlChar * name)4917 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4918     if (ctxt == NULL)
4919 	return (NULL);
4920 
4921     if (ctxt->funcLookupFunc != NULL) {
4922 	xmlXPathFunction ret;
4923 	xmlXPathFuncLookupFunc f;
4924 
4925 	f = ctxt->funcLookupFunc;
4926 	ret = f(ctxt->funcLookupData, name, NULL);
4927 	if (ret != NULL)
4928 	    return(ret);
4929     }
4930     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4931 }
4932 
4933 /**
4934  * xmlXPathFunctionLookupNS:
4935  * @ctxt:  the XPath context
4936  * @name:  the function name
4937  * @ns_uri:  the function namespace URI
4938  *
4939  * Search in the Function array of the context for the given
4940  * function.
4941  *
4942  * Returns the xmlXPathFunction or NULL if not found
4943  */
4944 xmlXPathFunction
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4945 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4946 			 const xmlChar *ns_uri) {
4947     xmlXPathFunction ret;
4948 
4949     if (ctxt == NULL)
4950 	return(NULL);
4951     if (name == NULL)
4952 	return(NULL);
4953 
4954     if (ctxt->funcLookupFunc != NULL) {
4955 	xmlXPathFuncLookupFunc f;
4956 
4957 	f = ctxt->funcLookupFunc;
4958 	ret = f(ctxt->funcLookupData, name, ns_uri);
4959 	if (ret != NULL)
4960 	    return(ret);
4961     }
4962 
4963     if (ctxt->funcHash == NULL)
4964 	return(NULL);
4965 
4966 XML_IGNORE_PEDANTIC_WARNINGS
4967     ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4968 XML_POP_WARNINGS
4969     return(ret);
4970 }
4971 
4972 /**
4973  * xmlXPathRegisteredFuncsCleanup:
4974  * @ctxt:  the XPath context
4975  *
4976  * Cleanup the XPath context data associated to registered functions
4977  */
4978 void
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt)4979 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4980     if (ctxt == NULL)
4981 	return;
4982 
4983     xmlHashFree(ctxt->funcHash, NULL);
4984     ctxt->funcHash = NULL;
4985 }
4986 
4987 /************************************************************************
4988  *									*
4989  *			Routines to handle Variables			*
4990  *									*
4991  ************************************************************************/
4992 
4993 /**
4994  * xmlXPathRegisterVariable:
4995  * @ctxt:  the XPath context
4996  * @name:  the variable name
4997  * @value:  the variable value or NULL
4998  *
4999  * Register a new variable value. If @value is NULL it unregisters
5000  * the variable
5001  *
5002  * Returns 0 in case of success, -1 in case of error
5003  */
5004 int
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathObjectPtr value)5005 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
5006 			 xmlXPathObjectPtr value) {
5007     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
5008 }
5009 
5010 /**
5011  * xmlXPathRegisterVariableNS:
5012  * @ctxt:  the XPath context
5013  * @name:  the variable name
5014  * @ns_uri:  the variable namespace URI
5015  * @value:  the variable value or NULL
5016  *
5017  * Register a new variable value. If @value is NULL it unregisters
5018  * the variable
5019  *
5020  * Returns 0 in case of success, -1 in case of error
5021  */
5022 int
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathObjectPtr value)5023 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5024 			   const xmlChar *ns_uri,
5025 			   xmlXPathObjectPtr value) {
5026     if (ctxt == NULL)
5027 	return(-1);
5028     if (name == NULL)
5029 	return(-1);
5030 
5031     if (ctxt->varHash == NULL)
5032 	ctxt->varHash = xmlHashCreate(0);
5033     if (ctxt->varHash == NULL)
5034 	return(-1);
5035     if (value == NULL)
5036         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5037 	                           xmlXPathFreeObjectEntry));
5038     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5039 			       (void *) value, xmlXPathFreeObjectEntry));
5040 }
5041 
5042 /**
5043  * xmlXPathRegisterVariableLookup:
5044  * @ctxt:  the XPath context
5045  * @f:  the lookup function
5046  * @data:  the lookup data
5047  *
5048  * register an external mechanism to do variable lookup
5049  */
5050 void
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,xmlXPathVariableLookupFunc f,void * data)5051 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5052 	 xmlXPathVariableLookupFunc f, void *data) {
5053     if (ctxt == NULL)
5054 	return;
5055     ctxt->varLookupFunc = f;
5056     ctxt->varLookupData = data;
5057 }
5058 
5059 /**
5060  * xmlXPathVariableLookup:
5061  * @ctxt:  the XPath context
5062  * @name:  the variable name
5063  *
5064  * Search in the Variable array of the context for the given
5065  * variable value.
5066  *
5067  * Returns a copy of the value or NULL if not found
5068  */
5069 xmlXPathObjectPtr
xmlXPathVariableLookup(xmlXPathContextPtr ctxt,const xmlChar * name)5070 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5071     if (ctxt == NULL)
5072 	return(NULL);
5073 
5074     if (ctxt->varLookupFunc != NULL) {
5075 	xmlXPathObjectPtr ret;
5076 
5077 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5078 	        (ctxt->varLookupData, name, NULL);
5079 	return(ret);
5080     }
5081     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5082 }
5083 
5084 /**
5085  * xmlXPathVariableLookupNS:
5086  * @ctxt:  the XPath context
5087  * @name:  the variable name
5088  * @ns_uri:  the variable namespace URI
5089  *
5090  * Search in the Variable array of the context for the given
5091  * variable value.
5092  *
5093  * Returns the a copy of the value or NULL if not found
5094  */
5095 xmlXPathObjectPtr
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)5096 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5097 			 const xmlChar *ns_uri) {
5098     if (ctxt == NULL)
5099 	return(NULL);
5100 
5101     if (ctxt->varLookupFunc != NULL) {
5102 	xmlXPathObjectPtr ret;
5103 
5104 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5105 	        (ctxt->varLookupData, name, ns_uri);
5106 	if (ret != NULL) return(ret);
5107     }
5108 
5109     if (ctxt->varHash == NULL)
5110 	return(NULL);
5111     if (name == NULL)
5112 	return(NULL);
5113 
5114     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5115 		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5116 }
5117 
5118 /**
5119  * xmlXPathRegisteredVariablesCleanup:
5120  * @ctxt:  the XPath context
5121  *
5122  * Cleanup the XPath context data associated to registered variables
5123  */
5124 void
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt)5125 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5126     if (ctxt == NULL)
5127 	return;
5128 
5129     xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5130     ctxt->varHash = NULL;
5131 }
5132 
5133 /**
5134  * xmlXPathRegisterNs:
5135  * @ctxt:  the XPath context
5136  * @prefix:  the namespace prefix cannot be NULL or empty string
5137  * @ns_uri:  the namespace name
5138  *
5139  * Register a new namespace. If @ns_uri is NULL it unregisters
5140  * the namespace
5141  *
5142  * Returns 0 in case of success, -1 in case of error
5143  */
5144 int
xmlXPathRegisterNs(xmlXPathContextPtr ctxt,const xmlChar * prefix,const xmlChar * ns_uri)5145 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5146 			   const xmlChar *ns_uri) {
5147     if (ctxt == NULL)
5148 	return(-1);
5149     if (prefix == NULL)
5150 	return(-1);
5151     if (prefix[0] == 0)
5152 	return(-1);
5153 
5154     if (ctxt->nsHash == NULL)
5155 	ctxt->nsHash = xmlHashCreate(10);
5156     if (ctxt->nsHash == NULL)
5157 	return(-1);
5158     if (ns_uri == NULL)
5159         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5160 	                          xmlHashDefaultDeallocator));
5161     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5162 			      xmlHashDefaultDeallocator));
5163 }
5164 
5165 /**
5166  * xmlXPathNsLookup:
5167  * @ctxt:  the XPath context
5168  * @prefix:  the namespace prefix value
5169  *
5170  * Search in the namespace declaration array of the context for the given
5171  * namespace name associated to the given prefix
5172  *
5173  * Returns the value or NULL if not found
5174  */
5175 const xmlChar *
xmlXPathNsLookup(xmlXPathContextPtr ctxt,const xmlChar * prefix)5176 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5177     if (ctxt == NULL)
5178 	return(NULL);
5179     if (prefix == NULL)
5180 	return(NULL);
5181 
5182 #ifdef XML_XML_NAMESPACE
5183     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5184 	return(XML_XML_NAMESPACE);
5185 #endif
5186 
5187     if (ctxt->namespaces != NULL) {
5188 	int i;
5189 
5190 	for (i = 0;i < ctxt->nsNr;i++) {
5191 	    if ((ctxt->namespaces[i] != NULL) &&
5192 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5193 		return(ctxt->namespaces[i]->href);
5194 	}
5195     }
5196 
5197     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5198 }
5199 
5200 /**
5201  * xmlXPathRegisteredNsCleanup:
5202  * @ctxt:  the XPath context
5203  *
5204  * Cleanup the XPath context data associated to registered variables
5205  */
5206 void
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt)5207 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5208     if (ctxt == NULL)
5209 	return;
5210 
5211     xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5212     ctxt->nsHash = NULL;
5213 }
5214 
5215 /************************************************************************
5216  *									*
5217  *			Routines to handle Values			*
5218  *									*
5219  ************************************************************************/
5220 
5221 /* Allocations are terrible, one needs to optimize all this !!! */
5222 
5223 /**
5224  * xmlXPathNewFloat:
5225  * @val:  the double value
5226  *
5227  * Create a new xmlXPathObjectPtr of type double and of value @val
5228  *
5229  * Returns the newly created object.
5230  */
5231 xmlXPathObjectPtr
xmlXPathNewFloat(double val)5232 xmlXPathNewFloat(double val) {
5233     xmlXPathObjectPtr ret;
5234 
5235     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5236     if (ret == NULL) {
5237         xmlXPathErrMemory(NULL, "creating float object\n");
5238 	return(NULL);
5239     }
5240     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5241     ret->type = XPATH_NUMBER;
5242     ret->floatval = val;
5243 #ifdef XP_DEBUG_OBJ_USAGE
5244     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5245 #endif
5246     return(ret);
5247 }
5248 
5249 /**
5250  * xmlXPathNewBoolean:
5251  * @val:  the boolean value
5252  *
5253  * Create a new xmlXPathObjectPtr of type boolean and of value @val
5254  *
5255  * Returns the newly created object.
5256  */
5257 xmlXPathObjectPtr
xmlXPathNewBoolean(int val)5258 xmlXPathNewBoolean(int val) {
5259     xmlXPathObjectPtr ret;
5260 
5261     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5262     if (ret == NULL) {
5263         xmlXPathErrMemory(NULL, "creating boolean object\n");
5264 	return(NULL);
5265     }
5266     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5267     ret->type = XPATH_BOOLEAN;
5268     ret->boolval = (val != 0);
5269 #ifdef XP_DEBUG_OBJ_USAGE
5270     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5271 #endif
5272     return(ret);
5273 }
5274 
5275 /**
5276  * xmlXPathNewString:
5277  * @val:  the xmlChar * value
5278  *
5279  * Create a new xmlXPathObjectPtr of type string and of value @val
5280  *
5281  * Returns the newly created object.
5282  */
5283 xmlXPathObjectPtr
xmlXPathNewString(const xmlChar * val)5284 xmlXPathNewString(const xmlChar *val) {
5285     xmlXPathObjectPtr ret;
5286 
5287     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5288     if (ret == NULL) {
5289         xmlXPathErrMemory(NULL, "creating string object\n");
5290 	return(NULL);
5291     }
5292     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5293     ret->type = XPATH_STRING;
5294     if (val != NULL)
5295 	ret->stringval = xmlStrdup(val);
5296     else
5297 	ret->stringval = xmlStrdup((const xmlChar *)"");
5298 #ifdef XP_DEBUG_OBJ_USAGE
5299     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5300 #endif
5301     return(ret);
5302 }
5303 
5304 /**
5305  * xmlXPathWrapString:
5306  * @val:  the xmlChar * value
5307  *
5308  * Wraps the @val string into an XPath object.
5309  *
5310  * Returns the newly created object.
5311  */
5312 xmlXPathObjectPtr
xmlXPathWrapString(xmlChar * val)5313 xmlXPathWrapString (xmlChar *val) {
5314     xmlXPathObjectPtr ret;
5315 
5316     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5317     if (ret == NULL) {
5318         xmlXPathErrMemory(NULL, "creating string object\n");
5319 	return(NULL);
5320     }
5321     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5322     ret->type = XPATH_STRING;
5323     ret->stringval = val;
5324 #ifdef XP_DEBUG_OBJ_USAGE
5325     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5326 #endif
5327     return(ret);
5328 }
5329 
5330 /**
5331  * xmlXPathNewCString:
5332  * @val:  the char * value
5333  *
5334  * Create a new xmlXPathObjectPtr of type string and of value @val
5335  *
5336  * Returns the newly created object.
5337  */
5338 xmlXPathObjectPtr
xmlXPathNewCString(const char * val)5339 xmlXPathNewCString(const char *val) {
5340     xmlXPathObjectPtr ret;
5341 
5342     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5343     if (ret == NULL) {
5344         xmlXPathErrMemory(NULL, "creating string object\n");
5345 	return(NULL);
5346     }
5347     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5348     ret->type = XPATH_STRING;
5349     ret->stringval = xmlStrdup(BAD_CAST val);
5350 #ifdef XP_DEBUG_OBJ_USAGE
5351     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5352 #endif
5353     return(ret);
5354 }
5355 
5356 /**
5357  * xmlXPathWrapCString:
5358  * @val:  the char * value
5359  *
5360  * Wraps a string into an XPath object.
5361  *
5362  * Returns the newly created object.
5363  */
5364 xmlXPathObjectPtr
xmlXPathWrapCString(char * val)5365 xmlXPathWrapCString (char * val) {
5366     return(xmlXPathWrapString((xmlChar *)(val)));
5367 }
5368 
5369 /**
5370  * xmlXPathWrapExternal:
5371  * @val:  the user data
5372  *
5373  * Wraps the @val data into an XPath object.
5374  *
5375  * Returns the newly created object.
5376  */
5377 xmlXPathObjectPtr
xmlXPathWrapExternal(void * val)5378 xmlXPathWrapExternal (void *val) {
5379     xmlXPathObjectPtr ret;
5380 
5381     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5382     if (ret == NULL) {
5383         xmlXPathErrMemory(NULL, "creating user object\n");
5384 	return(NULL);
5385     }
5386     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5387     ret->type = XPATH_USERS;
5388     ret->user = val;
5389 #ifdef XP_DEBUG_OBJ_USAGE
5390     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5391 #endif
5392     return(ret);
5393 }
5394 
5395 /**
5396  * xmlXPathObjectCopy:
5397  * @val:  the original object
5398  *
5399  * allocate a new copy of a given object
5400  *
5401  * Returns the newly created object.
5402  */
5403 xmlXPathObjectPtr
xmlXPathObjectCopy(xmlXPathObjectPtr val)5404 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5405     xmlXPathObjectPtr ret;
5406 
5407     if (val == NULL)
5408 	return(NULL);
5409 
5410     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5411     if (ret == NULL) {
5412         xmlXPathErrMemory(NULL, "copying object\n");
5413 	return(NULL);
5414     }
5415     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5416 #ifdef XP_DEBUG_OBJ_USAGE
5417     xmlXPathDebugObjUsageRequested(NULL, val->type);
5418 #endif
5419     switch (val->type) {
5420 	case XPATH_BOOLEAN:
5421 	case XPATH_NUMBER:
5422 	case XPATH_POINT:
5423 	case XPATH_RANGE:
5424 	    break;
5425 	case XPATH_STRING:
5426 	    ret->stringval = xmlStrdup(val->stringval);
5427 	    break;
5428 	case XPATH_XSLT_TREE:
5429 #if 0
5430 /*
5431   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5432   this previous handling is no longer correct, and can cause some serious
5433   problems (ref. bug 145547)
5434 */
5435 	    if ((val->nodesetval != NULL) &&
5436 		(val->nodesetval->nodeTab != NULL)) {
5437 		xmlNodePtr cur, tmp;
5438 		xmlDocPtr top;
5439 
5440 		ret->boolval = 1;
5441 		top =  xmlNewDoc(NULL);
5442 		top->name = (char *)
5443 		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
5444 		ret->user = top;
5445 		if (top != NULL) {
5446 		    top->doc = top;
5447 		    cur = val->nodesetval->nodeTab[0]->children;
5448 		    while (cur != NULL) {
5449 			tmp = xmlDocCopyNode(cur, top, 1);
5450 			xmlAddChild((xmlNodePtr) top, tmp);
5451 			cur = cur->next;
5452 		    }
5453 		}
5454 
5455 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5456 	    } else
5457 		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5458 	    /* Deallocate the copied tree value */
5459 	    break;
5460 #endif
5461 	case XPATH_NODESET:
5462 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5463 	    /* Do not deallocate the copied tree value */
5464 	    ret->boolval = 0;
5465 	    break;
5466 	case XPATH_LOCATIONSET:
5467 #ifdef LIBXML_XPTR_ENABLED
5468 	{
5469 	    xmlLocationSetPtr loc = val->user;
5470 	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5471 	    break;
5472 	}
5473 #endif
5474         case XPATH_USERS:
5475 	    ret->user = val->user;
5476 	    break;
5477         case XPATH_UNDEFINED:
5478 	    xmlGenericError(xmlGenericErrorContext,
5479 		    "xmlXPathObjectCopy: unsupported type %d\n",
5480 		    val->type);
5481 	    break;
5482     }
5483     return(ret);
5484 }
5485 
5486 /**
5487  * xmlXPathFreeObject:
5488  * @obj:  the object to free
5489  *
5490  * Free up an xmlXPathObjectPtr object.
5491  */
5492 void
xmlXPathFreeObject(xmlXPathObjectPtr obj)5493 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5494     if (obj == NULL) return;
5495     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5496 	if (obj->boolval) {
5497 #if 0
5498 	    if (obj->user != NULL) {
5499                 xmlXPathFreeNodeSet(obj->nodesetval);
5500 		xmlFreeNodeList((xmlNodePtr) obj->user);
5501 	    } else
5502 #endif
5503 	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5504 	    if (obj->nodesetval != NULL)
5505 		xmlXPathFreeValueTree(obj->nodesetval);
5506 	} else {
5507 	    if (obj->nodesetval != NULL)
5508 		xmlXPathFreeNodeSet(obj->nodesetval);
5509 	}
5510 #ifdef LIBXML_XPTR_ENABLED
5511     } else if (obj->type == XPATH_LOCATIONSET) {
5512 	if (obj->user != NULL)
5513 	    xmlXPtrFreeLocationSet(obj->user);
5514 #endif
5515     } else if (obj->type == XPATH_STRING) {
5516 	if (obj->stringval != NULL)
5517 	    xmlFree(obj->stringval);
5518     }
5519 #ifdef XP_DEBUG_OBJ_USAGE
5520     xmlXPathDebugObjUsageReleased(NULL, obj->type);
5521 #endif
5522     xmlFree(obj);
5523 }
5524 
5525 static void
xmlXPathFreeObjectEntry(void * obj,const xmlChar * name ATTRIBUTE_UNUSED)5526 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5527     xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5528 }
5529 
5530 /**
5531  * xmlXPathReleaseObject:
5532  * @obj:  the xmlXPathObjectPtr to free or to cache
5533  *
5534  * Depending on the state of the cache this frees the given
5535  * XPath object or stores it in the cache.
5536  */
5537 static void
xmlXPathReleaseObject(xmlXPathContextPtr ctxt,xmlXPathObjectPtr obj)5538 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5539 {
5540 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5541 	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5542     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5543 
5544 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5545 
5546     if (obj == NULL)
5547 	return;
5548     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5549 	 xmlXPathFreeObject(obj);
5550     } else {
5551 	xmlXPathContextCachePtr cache =
5552 	    (xmlXPathContextCachePtr) ctxt->cache;
5553 
5554 	switch (obj->type) {
5555 	    case XPATH_NODESET:
5556 	    case XPATH_XSLT_TREE:
5557 		if (obj->nodesetval != NULL) {
5558 		    if (obj->boolval) {
5559 			/*
5560 			* It looks like the @boolval is used for
5561 			* evaluation if this an XSLT Result Tree Fragment.
5562 			* TODO: Check if this assumption is correct.
5563 			*/
5564 			obj->type = XPATH_XSLT_TREE; /* just for debugging */
5565 			xmlXPathFreeValueTree(obj->nodesetval);
5566 			obj->nodesetval = NULL;
5567 		    } else if ((obj->nodesetval->nodeMax <= 40) &&
5568 			(XP_CACHE_WANTS(cache->nodesetObjs,
5569 					cache->maxNodeset)))
5570 		    {
5571 			XP_CACHE_ADD(cache->nodesetObjs, obj);
5572 			goto obj_cached;
5573 		    } else {
5574 			xmlXPathFreeNodeSet(obj->nodesetval);
5575 			obj->nodesetval = NULL;
5576 		    }
5577 		}
5578 		break;
5579 	    case XPATH_STRING:
5580 		if (obj->stringval != NULL)
5581 		    xmlFree(obj->stringval);
5582 
5583 		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5584 		    XP_CACHE_ADD(cache->stringObjs, obj);
5585 		    goto obj_cached;
5586 		}
5587 		break;
5588 	    case XPATH_BOOLEAN:
5589 		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5590 		    XP_CACHE_ADD(cache->booleanObjs, obj);
5591 		    goto obj_cached;
5592 		}
5593 		break;
5594 	    case XPATH_NUMBER:
5595 		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5596 		    XP_CACHE_ADD(cache->numberObjs, obj);
5597 		    goto obj_cached;
5598 		}
5599 		break;
5600 #ifdef LIBXML_XPTR_ENABLED
5601 	    case XPATH_LOCATIONSET:
5602 		if (obj->user != NULL) {
5603 		    xmlXPtrFreeLocationSet(obj->user);
5604 		}
5605 		goto free_obj;
5606 #endif
5607 	    default:
5608 		goto free_obj;
5609 	}
5610 
5611 	/*
5612 	* Fallback to adding to the misc-objects slot.
5613 	*/
5614 	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5615 	    XP_CACHE_ADD(cache->miscObjs, obj);
5616 	} else
5617 	    goto free_obj;
5618 
5619 obj_cached:
5620 
5621 #ifdef XP_DEBUG_OBJ_USAGE
5622 	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5623 #endif
5624 
5625 	if (obj->nodesetval != NULL) {
5626 	    xmlNodeSetPtr tmpset = obj->nodesetval;
5627 
5628 	    /*
5629 	    * TODO: Due to those nasty ns-nodes, we need to traverse
5630 	    *  the list and free the ns-nodes.
5631 	    * URGENT TODO: Check if it's actually slowing things down.
5632 	    *  Maybe we shouldn't try to preserve the list.
5633 	    */
5634 	    if (tmpset->nodeNr > 1) {
5635 		int i;
5636 		xmlNodePtr node;
5637 
5638 		for (i = 0; i < tmpset->nodeNr; i++) {
5639 		    node = tmpset->nodeTab[i];
5640 		    if ((node != NULL) &&
5641 			(node->type == XML_NAMESPACE_DECL))
5642 		    {
5643 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5644 		    }
5645 		}
5646 	    } else if (tmpset->nodeNr == 1) {
5647 		if ((tmpset->nodeTab[0] != NULL) &&
5648 		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5649 		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5650 	    }
5651 	    tmpset->nodeNr = 0;
5652 	    memset(obj, 0, sizeof(xmlXPathObject));
5653 	    obj->nodesetval = tmpset;
5654 	} else
5655 	    memset(obj, 0, sizeof(xmlXPathObject));
5656 
5657 	return;
5658 
5659 free_obj:
5660 	/*
5661 	* Cache is full; free the object.
5662 	*/
5663 	if (obj->nodesetval != NULL)
5664 	    xmlXPathFreeNodeSet(obj->nodesetval);
5665 #ifdef XP_DEBUG_OBJ_USAGE
5666 	xmlXPathDebugObjUsageReleased(NULL, obj->type);
5667 #endif
5668 	xmlFree(obj);
5669     }
5670     return;
5671 }
5672 
5673 
5674 /************************************************************************
5675  *									*
5676  *			Type Casting Routines				*
5677  *									*
5678  ************************************************************************/
5679 
5680 /**
5681  * xmlXPathCastBooleanToString:
5682  * @val:  a boolean
5683  *
5684  * Converts a boolean to its string value.
5685  *
5686  * Returns a newly allocated string.
5687  */
5688 xmlChar *
xmlXPathCastBooleanToString(int val)5689 xmlXPathCastBooleanToString (int val) {
5690     xmlChar *ret;
5691     if (val)
5692 	ret = xmlStrdup((const xmlChar *) "true");
5693     else
5694 	ret = xmlStrdup((const xmlChar *) "false");
5695     return(ret);
5696 }
5697 
5698 /**
5699  * xmlXPathCastNumberToString:
5700  * @val:  a number
5701  *
5702  * Converts a number to its string value.
5703  *
5704  * Returns a newly allocated string.
5705  */
5706 xmlChar *
xmlXPathCastNumberToString(double val)5707 xmlXPathCastNumberToString (double val) {
5708     xmlChar *ret;
5709     switch (xmlXPathIsInf(val)) {
5710     case 1:
5711 	ret = xmlStrdup((const xmlChar *) "Infinity");
5712 	break;
5713     case -1:
5714 	ret = xmlStrdup((const xmlChar *) "-Infinity");
5715 	break;
5716     default:
5717 	if (xmlXPathIsNaN(val)) {
5718 	    ret = xmlStrdup((const xmlChar *) "NaN");
5719 	} else if (val == 0) {
5720             /* Omit sign for negative zero. */
5721 	    ret = xmlStrdup((const xmlChar *) "0");
5722 	} else {
5723 	    /* could be improved */
5724 	    char buf[100];
5725 	    xmlXPathFormatNumber(val, buf, 99);
5726 	    buf[99] = 0;
5727 	    ret = xmlStrdup((const xmlChar *) buf);
5728 	}
5729     }
5730     return(ret);
5731 }
5732 
5733 /**
5734  * xmlXPathCastNodeToString:
5735  * @node:  a node
5736  *
5737  * Converts a node to its string value.
5738  *
5739  * Returns a newly allocated string.
5740  */
5741 xmlChar *
xmlXPathCastNodeToString(xmlNodePtr node)5742 xmlXPathCastNodeToString (xmlNodePtr node) {
5743 xmlChar *ret;
5744     if ((ret = xmlNodeGetContent(node)) == NULL)
5745 	ret = xmlStrdup((const xmlChar *) "");
5746     return(ret);
5747 }
5748 
5749 /**
5750  * xmlXPathCastNodeSetToString:
5751  * @ns:  a node-set
5752  *
5753  * Converts a node-set to its string value.
5754  *
5755  * Returns a newly allocated string.
5756  */
5757 xmlChar *
xmlXPathCastNodeSetToString(xmlNodeSetPtr ns)5758 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5759     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5760 	return(xmlStrdup((const xmlChar *) ""));
5761 
5762     if (ns->nodeNr > 1)
5763 	xmlXPathNodeSetSort(ns);
5764     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5765 }
5766 
5767 /**
5768  * xmlXPathCastToString:
5769  * @val:  an XPath object
5770  *
5771  * Converts an existing object to its string() equivalent
5772  *
5773  * Returns the allocated string value of the object, NULL in case of error.
5774  *         It's up to the caller to free the string memory with xmlFree().
5775  */
5776 xmlChar *
xmlXPathCastToString(xmlXPathObjectPtr val)5777 xmlXPathCastToString(xmlXPathObjectPtr val) {
5778     xmlChar *ret = NULL;
5779 
5780     if (val == NULL)
5781 	return(xmlStrdup((const xmlChar *) ""));
5782     switch (val->type) {
5783 	case XPATH_UNDEFINED:
5784 #ifdef DEBUG_EXPR
5785 	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5786 #endif
5787 	    ret = xmlStrdup((const xmlChar *) "");
5788 	    break;
5789         case XPATH_NODESET:
5790         case XPATH_XSLT_TREE:
5791 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
5792 	    break;
5793 	case XPATH_STRING:
5794 	    return(xmlStrdup(val->stringval));
5795         case XPATH_BOOLEAN:
5796 	    ret = xmlXPathCastBooleanToString(val->boolval);
5797 	    break;
5798 	case XPATH_NUMBER: {
5799 	    ret = xmlXPathCastNumberToString(val->floatval);
5800 	    break;
5801 	}
5802 	case XPATH_USERS:
5803 	case XPATH_POINT:
5804 	case XPATH_RANGE:
5805 	case XPATH_LOCATIONSET:
5806 	    TODO
5807 	    ret = xmlStrdup((const xmlChar *) "");
5808 	    break;
5809     }
5810     return(ret);
5811 }
5812 
5813 /**
5814  * xmlXPathConvertString:
5815  * @val:  an XPath object
5816  *
5817  * Converts an existing object to its string() equivalent
5818  *
5819  * Returns the new object, the old one is freed (or the operation
5820  *         is done directly on @val)
5821  */
5822 xmlXPathObjectPtr
xmlXPathConvertString(xmlXPathObjectPtr val)5823 xmlXPathConvertString(xmlXPathObjectPtr val) {
5824     xmlChar *res = NULL;
5825 
5826     if (val == NULL)
5827 	return(xmlXPathNewCString(""));
5828 
5829     switch (val->type) {
5830     case XPATH_UNDEFINED:
5831 #ifdef DEBUG_EXPR
5832 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5833 #endif
5834 	break;
5835     case XPATH_NODESET:
5836     case XPATH_XSLT_TREE:
5837 	res = xmlXPathCastNodeSetToString(val->nodesetval);
5838 	break;
5839     case XPATH_STRING:
5840 	return(val);
5841     case XPATH_BOOLEAN:
5842 	res = xmlXPathCastBooleanToString(val->boolval);
5843 	break;
5844     case XPATH_NUMBER:
5845 	res = xmlXPathCastNumberToString(val->floatval);
5846 	break;
5847     case XPATH_USERS:
5848     case XPATH_POINT:
5849     case XPATH_RANGE:
5850     case XPATH_LOCATIONSET:
5851 	TODO;
5852 	break;
5853     }
5854     xmlXPathFreeObject(val);
5855     if (res == NULL)
5856 	return(xmlXPathNewCString(""));
5857     return(xmlXPathWrapString(res));
5858 }
5859 
5860 /**
5861  * xmlXPathCastBooleanToNumber:
5862  * @val:  a boolean
5863  *
5864  * Converts a boolean to its number value
5865  *
5866  * Returns the number value
5867  */
5868 double
xmlXPathCastBooleanToNumber(int val)5869 xmlXPathCastBooleanToNumber(int val) {
5870     if (val)
5871 	return(1.0);
5872     return(0.0);
5873 }
5874 
5875 /**
5876  * xmlXPathCastStringToNumber:
5877  * @val:  a string
5878  *
5879  * Converts a string to its number value
5880  *
5881  * Returns the number value
5882  */
5883 double
xmlXPathCastStringToNumber(const xmlChar * val)5884 xmlXPathCastStringToNumber(const xmlChar * val) {
5885     return(xmlXPathStringEvalNumber(val));
5886 }
5887 
5888 /**
5889  * xmlXPathCastNodeToNumber:
5890  * @node:  a node
5891  *
5892  * Converts a node to its number value
5893  *
5894  * Returns the number value
5895  */
5896 double
xmlXPathCastNodeToNumber(xmlNodePtr node)5897 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5898     xmlChar *strval;
5899     double ret;
5900 
5901     if (node == NULL)
5902 	return(NAN);
5903     strval = xmlXPathCastNodeToString(node);
5904     if (strval == NULL)
5905 	return(NAN);
5906     ret = xmlXPathCastStringToNumber(strval);
5907     xmlFree(strval);
5908 
5909     return(ret);
5910 }
5911 
5912 /**
5913  * xmlXPathCastNodeSetToNumber:
5914  * @ns:  a node-set
5915  *
5916  * Converts a node-set to its number value
5917  *
5918  * Returns the number value
5919  */
5920 double
xmlXPathCastNodeSetToNumber(xmlNodeSetPtr ns)5921 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5922     xmlChar *str;
5923     double ret;
5924 
5925     if (ns == NULL)
5926 	return(NAN);
5927     str = xmlXPathCastNodeSetToString(ns);
5928     ret = xmlXPathCastStringToNumber(str);
5929     xmlFree(str);
5930     return(ret);
5931 }
5932 
5933 /**
5934  * xmlXPathCastToNumber:
5935  * @val:  an XPath object
5936  *
5937  * Converts an XPath object to its number value
5938  *
5939  * Returns the number value
5940  */
5941 double
xmlXPathCastToNumber(xmlXPathObjectPtr val)5942 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5943     double ret = 0.0;
5944 
5945     if (val == NULL)
5946 	return(NAN);
5947     switch (val->type) {
5948     case XPATH_UNDEFINED:
5949 #ifdef DEGUB_EXPR
5950 	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5951 #endif
5952 	ret = NAN;
5953 	break;
5954     case XPATH_NODESET:
5955     case XPATH_XSLT_TREE:
5956 	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5957 	break;
5958     case XPATH_STRING:
5959 	ret = xmlXPathCastStringToNumber(val->stringval);
5960 	break;
5961     case XPATH_NUMBER:
5962 	ret = val->floatval;
5963 	break;
5964     case XPATH_BOOLEAN:
5965 	ret = xmlXPathCastBooleanToNumber(val->boolval);
5966 	break;
5967     case XPATH_USERS:
5968     case XPATH_POINT:
5969     case XPATH_RANGE:
5970     case XPATH_LOCATIONSET:
5971 	TODO;
5972 	ret = NAN;
5973 	break;
5974     }
5975     return(ret);
5976 }
5977 
5978 /**
5979  * xmlXPathConvertNumber:
5980  * @val:  an XPath object
5981  *
5982  * Converts an existing object to its number() equivalent
5983  *
5984  * Returns the new object, the old one is freed (or the operation
5985  *         is done directly on @val)
5986  */
5987 xmlXPathObjectPtr
xmlXPathConvertNumber(xmlXPathObjectPtr val)5988 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5989     xmlXPathObjectPtr ret;
5990 
5991     if (val == NULL)
5992 	return(xmlXPathNewFloat(0.0));
5993     if (val->type == XPATH_NUMBER)
5994 	return(val);
5995     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5996     xmlXPathFreeObject(val);
5997     return(ret);
5998 }
5999 
6000 /**
6001  * xmlXPathCastNumberToBoolean:
6002  * @val:  a number
6003  *
6004  * Converts a number to its boolean value
6005  *
6006  * Returns the boolean value
6007  */
6008 int
xmlXPathCastNumberToBoolean(double val)6009 xmlXPathCastNumberToBoolean (double val) {
6010      if (xmlXPathIsNaN(val) || (val == 0.0))
6011 	 return(0);
6012      return(1);
6013 }
6014 
6015 /**
6016  * xmlXPathCastStringToBoolean:
6017  * @val:  a string
6018  *
6019  * Converts a string to its boolean value
6020  *
6021  * Returns the boolean value
6022  */
6023 int
xmlXPathCastStringToBoolean(const xmlChar * val)6024 xmlXPathCastStringToBoolean (const xmlChar *val) {
6025     if ((val == NULL) || (xmlStrlen(val) == 0))
6026 	return(0);
6027     return(1);
6028 }
6029 
6030 /**
6031  * xmlXPathCastNodeSetToBoolean:
6032  * @ns:  a node-set
6033  *
6034  * Converts a node-set to its boolean value
6035  *
6036  * Returns the boolean value
6037  */
6038 int
xmlXPathCastNodeSetToBoolean(xmlNodeSetPtr ns)6039 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6040     if ((ns == NULL) || (ns->nodeNr == 0))
6041 	return(0);
6042     return(1);
6043 }
6044 
6045 /**
6046  * xmlXPathCastToBoolean:
6047  * @val:  an XPath object
6048  *
6049  * Converts an XPath object to its boolean value
6050  *
6051  * Returns the boolean value
6052  */
6053 int
xmlXPathCastToBoolean(xmlXPathObjectPtr val)6054 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6055     int ret = 0;
6056 
6057     if (val == NULL)
6058 	return(0);
6059     switch (val->type) {
6060     case XPATH_UNDEFINED:
6061 #ifdef DEBUG_EXPR
6062 	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6063 #endif
6064 	ret = 0;
6065 	break;
6066     case XPATH_NODESET:
6067     case XPATH_XSLT_TREE:
6068 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6069 	break;
6070     case XPATH_STRING:
6071 	ret = xmlXPathCastStringToBoolean(val->stringval);
6072 	break;
6073     case XPATH_NUMBER:
6074 	ret = xmlXPathCastNumberToBoolean(val->floatval);
6075 	break;
6076     case XPATH_BOOLEAN:
6077 	ret = val->boolval;
6078 	break;
6079     case XPATH_USERS:
6080     case XPATH_POINT:
6081     case XPATH_RANGE:
6082     case XPATH_LOCATIONSET:
6083 	TODO;
6084 	ret = 0;
6085 	break;
6086     }
6087     return(ret);
6088 }
6089 
6090 
6091 /**
6092  * xmlXPathConvertBoolean:
6093  * @val:  an XPath object
6094  *
6095  * Converts an existing object to its boolean() equivalent
6096  *
6097  * Returns the new object, the old one is freed (or the operation
6098  *         is done directly on @val)
6099  */
6100 xmlXPathObjectPtr
xmlXPathConvertBoolean(xmlXPathObjectPtr val)6101 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6102     xmlXPathObjectPtr ret;
6103 
6104     if (val == NULL)
6105 	return(xmlXPathNewBoolean(0));
6106     if (val->type == XPATH_BOOLEAN)
6107 	return(val);
6108     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6109     xmlXPathFreeObject(val);
6110     return(ret);
6111 }
6112 
6113 /************************************************************************
6114  *									*
6115  *		Routines to handle XPath contexts			*
6116  *									*
6117  ************************************************************************/
6118 
6119 /**
6120  * xmlXPathNewContext:
6121  * @doc:  the XML document
6122  *
6123  * Create a new xmlXPathContext
6124  *
6125  * Returns the xmlXPathContext just allocated. The caller will need to free it.
6126  */
6127 xmlXPathContextPtr
xmlXPathNewContext(xmlDocPtr doc)6128 xmlXPathNewContext(xmlDocPtr doc) {
6129     xmlXPathContextPtr ret;
6130 
6131     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6132     if (ret == NULL) {
6133         xmlXPathErrMemory(NULL, "creating context\n");
6134 	return(NULL);
6135     }
6136     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6137     ret->doc = doc;
6138     ret->node = NULL;
6139 
6140     ret->varHash = NULL;
6141 
6142     ret->nb_types = 0;
6143     ret->max_types = 0;
6144     ret->types = NULL;
6145 
6146     ret->funcHash = xmlHashCreate(0);
6147 
6148     ret->nb_axis = 0;
6149     ret->max_axis = 0;
6150     ret->axis = NULL;
6151 
6152     ret->nsHash = NULL;
6153     ret->user = NULL;
6154 
6155     ret->contextSize = -1;
6156     ret->proximityPosition = -1;
6157 
6158 #ifdef XP_DEFAULT_CACHE_ON
6159     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6160 	xmlXPathFreeContext(ret);
6161 	return(NULL);
6162     }
6163 #endif
6164 
6165     xmlXPathRegisterAllFunctions(ret);
6166 
6167     return(ret);
6168 }
6169 
6170 /**
6171  * xmlXPathFreeContext:
6172  * @ctxt:  the context to free
6173  *
6174  * Free up an xmlXPathContext
6175  */
6176 void
xmlXPathFreeContext(xmlXPathContextPtr ctxt)6177 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6178     if (ctxt == NULL) return;
6179 
6180     if (ctxt->cache != NULL)
6181 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6182     xmlXPathRegisteredNsCleanup(ctxt);
6183     xmlXPathRegisteredFuncsCleanup(ctxt);
6184     xmlXPathRegisteredVariablesCleanup(ctxt);
6185     xmlResetError(&ctxt->lastError);
6186     xmlFree(ctxt);
6187 }
6188 
6189 /************************************************************************
6190  *									*
6191  *		Routines to handle XPath parser contexts		*
6192  *									*
6193  ************************************************************************/
6194 
6195 #define CHECK_CTXT(ctxt)						\
6196     if (ctxt == NULL) {						\
6197 	__xmlRaiseError(NULL, NULL, NULL,				\
6198 		NULL, NULL, XML_FROM_XPATH,				\
6199 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6200 		__FILE__, __LINE__,					\
6201 		NULL, NULL, NULL, 0, 0,					\
6202 		"NULL context pointer\n");				\
6203 	return(NULL);							\
6204     }									\
6205 
6206 #define CHECK_CTXT_NEG(ctxt)						\
6207     if (ctxt == NULL) {						\
6208 	__xmlRaiseError(NULL, NULL, NULL,				\
6209 		NULL, NULL, XML_FROM_XPATH,				\
6210 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6211 		__FILE__, __LINE__,					\
6212 		NULL, NULL, NULL, 0, 0,					\
6213 		"NULL context pointer\n");				\
6214 	return(-1);							\
6215     }									\
6216 
6217 
6218 #define CHECK_CONTEXT(ctxt)						\
6219     if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
6220         (ctxt->doc->children == NULL)) {				\
6221 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
6222 	return(NULL);							\
6223     }
6224 
6225 
6226 /**
6227  * xmlXPathNewParserContext:
6228  * @str:  the XPath expression
6229  * @ctxt:  the XPath context
6230  *
6231  * Create a new xmlXPathParserContext
6232  *
6233  * Returns the xmlXPathParserContext just allocated.
6234  */
6235 xmlXPathParserContextPtr
xmlXPathNewParserContext(const xmlChar * str,xmlXPathContextPtr ctxt)6236 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6237     xmlXPathParserContextPtr ret;
6238 
6239     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6240     if (ret == NULL) {
6241         xmlXPathErrMemory(ctxt, "creating parser context\n");
6242 	return(NULL);
6243     }
6244     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6245     ret->cur = ret->base = str;
6246     ret->context = ctxt;
6247 
6248     ret->comp = xmlXPathNewCompExpr();
6249     if (ret->comp == NULL) {
6250 	xmlFree(ret->valueTab);
6251 	xmlFree(ret);
6252 	return(NULL);
6253     }
6254     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6255         ret->comp->dict = ctxt->dict;
6256 	xmlDictReference(ret->comp->dict);
6257     }
6258 
6259     return(ret);
6260 }
6261 
6262 /**
6263  * xmlXPathCompParserContext:
6264  * @comp:  the XPath compiled expression
6265  * @ctxt:  the XPath context
6266  *
6267  * Create a new xmlXPathParserContext when processing a compiled expression
6268  *
6269  * Returns the xmlXPathParserContext just allocated.
6270  */
6271 static xmlXPathParserContextPtr
xmlXPathCompParserContext(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)6272 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6273     xmlXPathParserContextPtr ret;
6274 
6275     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6276     if (ret == NULL) {
6277         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6278 	return(NULL);
6279     }
6280     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6281 
6282     /* Allocate the value stack */
6283     ret->valueTab = (xmlXPathObjectPtr *)
6284                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6285     if (ret->valueTab == NULL) {
6286 	xmlFree(ret);
6287 	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6288 	return(NULL);
6289     }
6290     ret->valueNr = 0;
6291     ret->valueMax = 10;
6292     ret->value = NULL;
6293     ret->valueFrame = 0;
6294 
6295     ret->context = ctxt;
6296     ret->comp = comp;
6297 
6298     return(ret);
6299 }
6300 
6301 /**
6302  * xmlXPathFreeParserContext:
6303  * @ctxt:  the context to free
6304  *
6305  * Free up an xmlXPathParserContext
6306  */
6307 void
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt)6308 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6309     int i;
6310 
6311     if (ctxt->valueTab != NULL) {
6312         for (i = 0; i < ctxt->valueNr; i++) {
6313             if (ctxt->context)
6314                 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6315             else
6316                 xmlXPathFreeObject(ctxt->valueTab[i]);
6317         }
6318         xmlFree(ctxt->valueTab);
6319     }
6320     if (ctxt->comp != NULL) {
6321 #ifdef XPATH_STREAMING
6322 	if (ctxt->comp->stream != NULL) {
6323 	    xmlFreePatternList(ctxt->comp->stream);
6324 	    ctxt->comp->stream = NULL;
6325 	}
6326 #endif
6327 	xmlXPathFreeCompExpr(ctxt->comp);
6328     }
6329     xmlFree(ctxt);
6330 }
6331 
6332 /************************************************************************
6333  *									*
6334  *		The implicit core function library			*
6335  *									*
6336  ************************************************************************/
6337 
6338 /**
6339  * xmlXPathNodeValHash:
6340  * @node:  a node pointer
6341  *
6342  * Function computing the beginning of the string value of the node,
6343  * used to speed up comparisons
6344  *
6345  * Returns an int usable as a hash
6346  */
6347 static unsigned int
xmlXPathNodeValHash(xmlNodePtr node)6348 xmlXPathNodeValHash(xmlNodePtr node) {
6349     int len = 2;
6350     const xmlChar * string = NULL;
6351     xmlNodePtr tmp = NULL;
6352     unsigned int ret = 0;
6353 
6354     if (node == NULL)
6355 	return(0);
6356 
6357     if (node->type == XML_DOCUMENT_NODE) {
6358 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
6359 	if (tmp == NULL)
6360 	    node = node->children;
6361 	else
6362 	    node = tmp;
6363 
6364 	if (node == NULL)
6365 	    return(0);
6366     }
6367 
6368     switch (node->type) {
6369 	case XML_COMMENT_NODE:
6370 	case XML_PI_NODE:
6371 	case XML_CDATA_SECTION_NODE:
6372 	case XML_TEXT_NODE:
6373 	    string = node->content;
6374 	    if (string == NULL)
6375 		return(0);
6376 	    if (string[0] == 0)
6377 		return(0);
6378 	    return(((unsigned int) string[0]) +
6379 		   (((unsigned int) string[1]) << 8));
6380 	case XML_NAMESPACE_DECL:
6381 	    string = ((xmlNsPtr)node)->href;
6382 	    if (string == NULL)
6383 		return(0);
6384 	    if (string[0] == 0)
6385 		return(0);
6386 	    return(((unsigned int) string[0]) +
6387 		   (((unsigned int) string[1]) << 8));
6388 	case XML_ATTRIBUTE_NODE:
6389 	    tmp = ((xmlAttrPtr) node)->children;
6390 	    break;
6391 	case XML_ELEMENT_NODE:
6392 	    tmp = node->children;
6393 	    break;
6394 	default:
6395 	    return(0);
6396     }
6397     while (tmp != NULL) {
6398 	switch (tmp->type) {
6399 	    case XML_CDATA_SECTION_NODE:
6400 	    case XML_TEXT_NODE:
6401 		string = tmp->content;
6402 		break;
6403 	    default:
6404                 string = NULL;
6405 		break;
6406 	}
6407 	if ((string != NULL) && (string[0] != 0)) {
6408 	    if (len == 1) {
6409 		return(ret + (((unsigned int) string[0]) << 8));
6410 	    }
6411 	    if (string[1] == 0) {
6412 		len = 1;
6413 		ret = (unsigned int) string[0];
6414 	    } else {
6415 		return(((unsigned int) string[0]) +
6416 		       (((unsigned int) string[1]) << 8));
6417 	    }
6418 	}
6419 	/*
6420 	 * Skip to next node
6421 	 */
6422 	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6423 	    if (tmp->children->type != XML_ENTITY_DECL) {
6424 		tmp = tmp->children;
6425 		continue;
6426 	    }
6427 	}
6428 	if (tmp == node)
6429 	    break;
6430 
6431 	if (tmp->next != NULL) {
6432 	    tmp = tmp->next;
6433 	    continue;
6434 	}
6435 
6436 	do {
6437 	    tmp = tmp->parent;
6438 	    if (tmp == NULL)
6439 		break;
6440 	    if (tmp == node) {
6441 		tmp = NULL;
6442 		break;
6443 	    }
6444 	    if (tmp->next != NULL) {
6445 		tmp = tmp->next;
6446 		break;
6447 	    }
6448 	} while (tmp != NULL);
6449     }
6450     return(ret);
6451 }
6452 
6453 /**
6454  * xmlXPathStringHash:
6455  * @string:  a string
6456  *
6457  * Function computing the beginning of the string value of the node,
6458  * used to speed up comparisons
6459  *
6460  * Returns an int usable as a hash
6461  */
6462 static unsigned int
xmlXPathStringHash(const xmlChar * string)6463 xmlXPathStringHash(const xmlChar * string) {
6464     if (string == NULL)
6465 	return((unsigned int) 0);
6466     if (string[0] == 0)
6467 	return(0);
6468     return(((unsigned int) string[0]) +
6469 	   (((unsigned int) string[1]) << 8));
6470 }
6471 
6472 /**
6473  * xmlXPathCompareNodeSetFloat:
6474  * @ctxt:  the XPath Parser context
6475  * @inf:  less than (1) or greater than (0)
6476  * @strict:  is the comparison strict
6477  * @arg:  the node set
6478  * @f:  the value
6479  *
6480  * Implement the compare operation between a nodeset and a number
6481  *     @ns < @val    (1, 1, ...
6482  *     @ns <= @val   (1, 0, ...
6483  *     @ns > @val    (0, 1, ...
6484  *     @ns >= @val   (0, 0, ...
6485  *
6486  * If one object to be compared is a node-set and the other is a number,
6487  * then the comparison will be true if and only if there is a node in the
6488  * node-set such that the result of performing the comparison on the number
6489  * to be compared and on the result of converting the string-value of that
6490  * node to a number using the number function is true.
6491  *
6492  * Returns 0 or 1 depending on the results of the test.
6493  */
6494 static int
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr f)6495 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6496 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6497     int i, ret = 0;
6498     xmlNodeSetPtr ns;
6499     xmlChar *str2;
6500 
6501     if ((f == NULL) || (arg == NULL) ||
6502 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6503 	xmlXPathReleaseObject(ctxt->context, arg);
6504 	xmlXPathReleaseObject(ctxt->context, f);
6505         return(0);
6506     }
6507     ns = arg->nodesetval;
6508     if (ns != NULL) {
6509 	for (i = 0;i < ns->nodeNr;i++) {
6510 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6511 	     if (str2 != NULL) {
6512 		 valuePush(ctxt,
6513 			   xmlXPathCacheNewString(ctxt->context, str2));
6514 		 xmlFree(str2);
6515 		 xmlXPathNumberFunction(ctxt, 1);
6516 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6517 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6518 		 if (ret)
6519 		     break;
6520 	     }
6521 	}
6522     }
6523     xmlXPathReleaseObject(ctxt->context, arg);
6524     xmlXPathReleaseObject(ctxt->context, f);
6525     return(ret);
6526 }
6527 
6528 /**
6529  * xmlXPathCompareNodeSetString:
6530  * @ctxt:  the XPath Parser context
6531  * @inf:  less than (1) or greater than (0)
6532  * @strict:  is the comparison strict
6533  * @arg:  the node set
6534  * @s:  the value
6535  *
6536  * Implement the compare operation between a nodeset and a string
6537  *     @ns < @val    (1, 1, ...
6538  *     @ns <= @val   (1, 0, ...
6539  *     @ns > @val    (0, 1, ...
6540  *     @ns >= @val   (0, 0, ...
6541  *
6542  * If one object to be compared is a node-set and the other is a string,
6543  * then the comparison will be true if and only if there is a node in
6544  * the node-set such that the result of performing the comparison on the
6545  * string-value of the node and the other string is true.
6546  *
6547  * Returns 0 or 1 depending on the results of the test.
6548  */
6549 static int
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr s)6550 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6551 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6552     int i, ret = 0;
6553     xmlNodeSetPtr ns;
6554     xmlChar *str2;
6555 
6556     if ((s == NULL) || (arg == NULL) ||
6557 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6558 	xmlXPathReleaseObject(ctxt->context, arg);
6559 	xmlXPathReleaseObject(ctxt->context, s);
6560         return(0);
6561     }
6562     ns = arg->nodesetval;
6563     if (ns != NULL) {
6564 	for (i = 0;i < ns->nodeNr;i++) {
6565 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6566 	     if (str2 != NULL) {
6567 		 valuePush(ctxt,
6568 			   xmlXPathCacheNewString(ctxt->context, str2));
6569 		 xmlFree(str2);
6570 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6571 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6572 		 if (ret)
6573 		     break;
6574 	     }
6575 	}
6576     }
6577     xmlXPathReleaseObject(ctxt->context, arg);
6578     xmlXPathReleaseObject(ctxt->context, s);
6579     return(ret);
6580 }
6581 
6582 /**
6583  * xmlXPathCompareNodeSets:
6584  * @inf:  less than (1) or greater than (0)
6585  * @strict:  is the comparison strict
6586  * @arg1:  the first node set object
6587  * @arg2:  the second node set object
6588  *
6589  * Implement the compare operation on nodesets:
6590  *
6591  * If both objects to be compared are node-sets, then the comparison
6592  * will be true if and only if there is a node in the first node-set
6593  * and a node in the second node-set such that the result of performing
6594  * the comparison on the string-values of the two nodes is true.
6595  * ....
6596  * When neither object to be compared is a node-set and the operator
6597  * is <=, <, >= or >, then the objects are compared by converting both
6598  * objects to numbers and comparing the numbers according to IEEE 754.
6599  * ....
6600  * The number function converts its argument to a number as follows:
6601  *  - a string that consists of optional whitespace followed by an
6602  *    optional minus sign followed by a Number followed by whitespace
6603  *    is converted to the IEEE 754 number that is nearest (according
6604  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6605  *    represented by the string; any other string is converted to NaN
6606  *
6607  * Conclusion all nodes need to be converted first to their string value
6608  * and then the comparison must be done when possible
6609  */
6610 static int
xmlXPathCompareNodeSets(int inf,int strict,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6611 xmlXPathCompareNodeSets(int inf, int strict,
6612 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6613     int i, j, init = 0;
6614     double val1;
6615     double *values2;
6616     int ret = 0;
6617     xmlNodeSetPtr ns1;
6618     xmlNodeSetPtr ns2;
6619 
6620     if ((arg1 == NULL) ||
6621 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6622 	xmlXPathFreeObject(arg2);
6623         return(0);
6624     }
6625     if ((arg2 == NULL) ||
6626 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6627 	xmlXPathFreeObject(arg1);
6628 	xmlXPathFreeObject(arg2);
6629         return(0);
6630     }
6631 
6632     ns1 = arg1->nodesetval;
6633     ns2 = arg2->nodesetval;
6634 
6635     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6636 	xmlXPathFreeObject(arg1);
6637 	xmlXPathFreeObject(arg2);
6638 	return(0);
6639     }
6640     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6641 	xmlXPathFreeObject(arg1);
6642 	xmlXPathFreeObject(arg2);
6643 	return(0);
6644     }
6645 
6646     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6647     if (values2 == NULL) {
6648         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6649 	xmlXPathFreeObject(arg1);
6650 	xmlXPathFreeObject(arg2);
6651 	return(0);
6652     }
6653     for (i = 0;i < ns1->nodeNr;i++) {
6654 	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6655 	if (xmlXPathIsNaN(val1))
6656 	    continue;
6657 	for (j = 0;j < ns2->nodeNr;j++) {
6658 	    if (init == 0) {
6659 		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6660 	    }
6661 	    if (xmlXPathIsNaN(values2[j]))
6662 		continue;
6663 	    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 	    else if (!inf && !strict)
6670 		ret = (val1 >= values2[j]);
6671 	    if (ret)
6672 		break;
6673 	}
6674 	if (ret)
6675 	    break;
6676 	init = 1;
6677     }
6678     xmlFree(values2);
6679     xmlXPathFreeObject(arg1);
6680     xmlXPathFreeObject(arg2);
6681     return(ret);
6682 }
6683 
6684 /**
6685  * xmlXPathCompareNodeSetValue:
6686  * @ctxt:  the XPath Parser context
6687  * @inf:  less than (1) or greater than (0)
6688  * @strict:  is the comparison strict
6689  * @arg:  the node set
6690  * @val:  the value
6691  *
6692  * Implement the compare operation between a nodeset and a value
6693  *     @ns < @val    (1, 1, ...
6694  *     @ns <= @val   (1, 0, ...
6695  *     @ns > @val    (0, 1, ...
6696  *     @ns >= @val   (0, 0, ...
6697  *
6698  * If one object to be compared is a node-set and the other is a boolean,
6699  * then the comparison will be true if and only if the result of performing
6700  * the comparison on the boolean and on the result of converting
6701  * the node-set to a boolean using the boolean function is true.
6702  *
6703  * Returns 0 or 1 depending on the results of the test.
6704  */
6705 static int
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr val)6706 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6707 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6708     if ((val == NULL) || (arg == NULL) ||
6709 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6710         return(0);
6711 
6712     switch(val->type) {
6713         case XPATH_NUMBER:
6714 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6715         case XPATH_NODESET:
6716         case XPATH_XSLT_TREE:
6717 	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6718         case XPATH_STRING:
6719 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6720         case XPATH_BOOLEAN:
6721 	    valuePush(ctxt, arg);
6722 	    xmlXPathBooleanFunction(ctxt, 1);
6723 	    valuePush(ctxt, val);
6724 	    return(xmlXPathCompareValues(ctxt, inf, strict));
6725 	default:
6726             xmlGenericError(xmlGenericErrorContext,
6727                     "xmlXPathCompareNodeSetValue: Can't compare node set "
6728                     "and object of type %d\n",
6729                     val->type);
6730             xmlXPathReleaseObject(ctxt->context, arg);
6731             xmlXPathReleaseObject(ctxt->context, val);
6732             XP_ERROR0(XPATH_INVALID_TYPE);
6733     }
6734     return(0);
6735 }
6736 
6737 /**
6738  * xmlXPathEqualNodeSetString:
6739  * @arg:  the nodeset object argument
6740  * @str:  the string to compare to.
6741  * @neq:  flag to show whether for '=' (0) or '!=' (1)
6742  *
6743  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6744  * If one object to be compared is a node-set and the other is a string,
6745  * then the comparison will be true if and only if there is a node in
6746  * the node-set such that the result of performing the comparison on the
6747  * string-value of the node and the other string is true.
6748  *
6749  * Returns 0 or 1 depending on the results of the test.
6750  */
6751 static int
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg,const xmlChar * str,int neq)6752 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6753 {
6754     int i;
6755     xmlNodeSetPtr ns;
6756     xmlChar *str2;
6757     unsigned int hash;
6758 
6759     if ((str == NULL) || (arg == NULL) ||
6760         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6761         return (0);
6762     ns = arg->nodesetval;
6763     /*
6764      * A NULL nodeset compared with a string is always false
6765      * (since there is no node equal, and no node not equal)
6766      */
6767     if ((ns == NULL) || (ns->nodeNr <= 0) )
6768         return (0);
6769     hash = xmlXPathStringHash(str);
6770     for (i = 0; i < ns->nodeNr; i++) {
6771         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6772             str2 = xmlNodeGetContent(ns->nodeTab[i]);
6773             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6774                 xmlFree(str2);
6775 		if (neq)
6776 		    continue;
6777                 return (1);
6778 	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6779 		if (neq)
6780 		    continue;
6781                 return (1);
6782             } else if (neq) {
6783 		if (str2 != NULL)
6784 		    xmlFree(str2);
6785 		return (1);
6786 	    }
6787             if (str2 != NULL)
6788                 xmlFree(str2);
6789         } else if (neq)
6790 	    return (1);
6791     }
6792     return (0);
6793 }
6794 
6795 /**
6796  * xmlXPathEqualNodeSetFloat:
6797  * @arg:  the nodeset object argument
6798  * @f:  the float to compare to
6799  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6800  *
6801  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6802  * If one object to be compared is a node-set and the other is a number,
6803  * then the comparison will be true if and only if there is a node in
6804  * the node-set such that the result of performing the comparison on the
6805  * number to be compared and on the result of converting the string-value
6806  * of that node to a number using the number function is true.
6807  *
6808  * Returns 0 or 1 depending on the results of the test.
6809  */
6810 static int
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,double f,int neq)6811 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6812     xmlXPathObjectPtr arg, double f, int neq) {
6813   int i, ret=0;
6814   xmlNodeSetPtr ns;
6815   xmlChar *str2;
6816   xmlXPathObjectPtr val;
6817   double v;
6818 
6819     if ((arg == NULL) ||
6820 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6821         return(0);
6822 
6823     ns = arg->nodesetval;
6824     if (ns != NULL) {
6825 	for (i=0;i<ns->nodeNr;i++) {
6826 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6827 	    if (str2 != NULL) {
6828 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6829 		xmlFree(str2);
6830 		xmlXPathNumberFunction(ctxt, 1);
6831 		val = valuePop(ctxt);
6832 		v = val->floatval;
6833 		xmlXPathReleaseObject(ctxt->context, val);
6834 		if (!xmlXPathIsNaN(v)) {
6835 		    if ((!neq) && (v==f)) {
6836 			ret = 1;
6837 			break;
6838 		    } else if ((neq) && (v!=f)) {
6839 			ret = 1;
6840 			break;
6841 		    }
6842 		} else {	/* NaN is unequal to any value */
6843 		    if (neq)
6844 			ret = 1;
6845 		}
6846 	    }
6847 	}
6848     }
6849 
6850     return(ret);
6851 }
6852 
6853 
6854 /**
6855  * xmlXPathEqualNodeSets:
6856  * @arg1:  first nodeset object argument
6857  * @arg2:  second nodeset object argument
6858  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6859  *
6860  * Implement the equal / not equal operation on XPath nodesets:
6861  * @arg1 == @arg2  or  @arg1 != @arg2
6862  * If both objects to be compared are node-sets, then the comparison
6863  * will be true if and only if there is a node in the first node-set and
6864  * a node in the second node-set such that the result of performing the
6865  * comparison on the string-values of the two nodes is true.
6866  *
6867  * (needless to say, this is a costly operation)
6868  *
6869  * Returns 0 or 1 depending on the results of the test.
6870  */
6871 static int
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2,int neq)6872 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6873     int i, j;
6874     unsigned int *hashs1;
6875     unsigned int *hashs2;
6876     xmlChar **values1;
6877     xmlChar **values2;
6878     int ret = 0;
6879     xmlNodeSetPtr ns1;
6880     xmlNodeSetPtr ns2;
6881 
6882     if ((arg1 == NULL) ||
6883 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6884         return(0);
6885     if ((arg2 == NULL) ||
6886 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6887         return(0);
6888 
6889     ns1 = arg1->nodesetval;
6890     ns2 = arg2->nodesetval;
6891 
6892     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6893 	return(0);
6894     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6895 	return(0);
6896 
6897     /*
6898      * for equal, check if there is a node pertaining to both sets
6899      */
6900     if (neq == 0)
6901 	for (i = 0;i < ns1->nodeNr;i++)
6902 	    for (j = 0;j < ns2->nodeNr;j++)
6903 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
6904 		    return(1);
6905 
6906     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6907     if (values1 == NULL) {
6908         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6909 	return(0);
6910     }
6911     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6912     if (hashs1 == NULL) {
6913         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6914 	xmlFree(values1);
6915 	return(0);
6916     }
6917     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6918     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6919     if (values2 == NULL) {
6920         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6921 	xmlFree(hashs1);
6922 	xmlFree(values1);
6923 	return(0);
6924     }
6925     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6926     if (hashs2 == NULL) {
6927         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6928 	xmlFree(hashs1);
6929 	xmlFree(values1);
6930 	xmlFree(values2);
6931 	return(0);
6932     }
6933     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6934     for (i = 0;i < ns1->nodeNr;i++) {
6935 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6936 	for (j = 0;j < ns2->nodeNr;j++) {
6937 	    if (i == 0)
6938 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6939 	    if (hashs1[i] != hashs2[j]) {
6940 		if (neq) {
6941 		    ret = 1;
6942 		    break;
6943 		}
6944 	    }
6945 	    else {
6946 		if (values1[i] == NULL)
6947 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6948 		if (values2[j] == NULL)
6949 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6950 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6951 		if (ret)
6952 		    break;
6953 	    }
6954 	}
6955 	if (ret)
6956 	    break;
6957     }
6958     for (i = 0;i < ns1->nodeNr;i++)
6959 	if (values1[i] != NULL)
6960 	    xmlFree(values1[i]);
6961     for (j = 0;j < ns2->nodeNr;j++)
6962 	if (values2[j] != NULL)
6963 	    xmlFree(values2[j]);
6964     xmlFree(values1);
6965     xmlFree(values2);
6966     xmlFree(hashs1);
6967     xmlFree(hashs2);
6968     return(ret);
6969 }
6970 
6971 static int
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6972 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6973   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6974     int ret = 0;
6975     /*
6976      *At this point we are assured neither arg1 nor arg2
6977      *is a nodeset, so we can just pick the appropriate routine.
6978      */
6979     switch (arg1->type) {
6980         case XPATH_UNDEFINED:
6981 #ifdef DEBUG_EXPR
6982 	    xmlGenericError(xmlGenericErrorContext,
6983 		    "Equal: undefined\n");
6984 #endif
6985 	    break;
6986         case XPATH_BOOLEAN:
6987 	    switch (arg2->type) {
6988 	        case XPATH_UNDEFINED:
6989 #ifdef DEBUG_EXPR
6990 		    xmlGenericError(xmlGenericErrorContext,
6991 			    "Equal: undefined\n");
6992 #endif
6993 		    break;
6994 		case XPATH_BOOLEAN:
6995 #ifdef DEBUG_EXPR
6996 		    xmlGenericError(xmlGenericErrorContext,
6997 			    "Equal: %d boolean %d \n",
6998 			    arg1->boolval, arg2->boolval);
6999 #endif
7000 		    ret = (arg1->boolval == arg2->boolval);
7001 		    break;
7002 		case XPATH_NUMBER:
7003 		    ret = (arg1->boolval ==
7004 			   xmlXPathCastNumberToBoolean(arg2->floatval));
7005 		    break;
7006 		case XPATH_STRING:
7007 		    if ((arg2->stringval == NULL) ||
7008 			(arg2->stringval[0] == 0)) ret = 0;
7009 		    else
7010 			ret = 1;
7011 		    ret = (arg1->boolval == ret);
7012 		    break;
7013 		case XPATH_USERS:
7014 		case XPATH_POINT:
7015 		case XPATH_RANGE:
7016 		case XPATH_LOCATIONSET:
7017 		    TODO
7018 		    break;
7019 		case XPATH_NODESET:
7020 		case XPATH_XSLT_TREE:
7021 		    break;
7022 	    }
7023 	    break;
7024         case XPATH_NUMBER:
7025 	    switch (arg2->type) {
7026 	        case XPATH_UNDEFINED:
7027 #ifdef DEBUG_EXPR
7028 		    xmlGenericError(xmlGenericErrorContext,
7029 			    "Equal: undefined\n");
7030 #endif
7031 		    break;
7032 		case XPATH_BOOLEAN:
7033 		    ret = (arg2->boolval==
7034 			   xmlXPathCastNumberToBoolean(arg1->floatval));
7035 		    break;
7036 		case XPATH_STRING:
7037 		    valuePush(ctxt, arg2);
7038 		    xmlXPathNumberFunction(ctxt, 1);
7039 		    arg2 = valuePop(ctxt);
7040                     /* Falls through. */
7041 		case XPATH_NUMBER:
7042 		    /* Hand check NaN and Infinity equalities */
7043 		    if (xmlXPathIsNaN(arg1->floatval) ||
7044 			    xmlXPathIsNaN(arg2->floatval)) {
7045 		        ret = 0;
7046 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7047 		        if (xmlXPathIsInf(arg2->floatval) == 1)
7048 			    ret = 1;
7049 			else
7050 			    ret = 0;
7051 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7052 			if (xmlXPathIsInf(arg2->floatval) == -1)
7053 			    ret = 1;
7054 			else
7055 			    ret = 0;
7056 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7057 			if (xmlXPathIsInf(arg1->floatval) == 1)
7058 			    ret = 1;
7059 			else
7060 			    ret = 0;
7061 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7062 			if (xmlXPathIsInf(arg1->floatval) == -1)
7063 			    ret = 1;
7064 			else
7065 			    ret = 0;
7066 		    } else {
7067 		        ret = (arg1->floatval == arg2->floatval);
7068 		    }
7069 		    break;
7070 		case XPATH_USERS:
7071 		case XPATH_POINT:
7072 		case XPATH_RANGE:
7073 		case XPATH_LOCATIONSET:
7074 		    TODO
7075 		    break;
7076 		case XPATH_NODESET:
7077 		case XPATH_XSLT_TREE:
7078 		    break;
7079 	    }
7080 	    break;
7081         case XPATH_STRING:
7082 	    switch (arg2->type) {
7083 	        case XPATH_UNDEFINED:
7084 #ifdef DEBUG_EXPR
7085 		    xmlGenericError(xmlGenericErrorContext,
7086 			    "Equal: undefined\n");
7087 #endif
7088 		    break;
7089 		case XPATH_BOOLEAN:
7090 		    if ((arg1->stringval == NULL) ||
7091 			(arg1->stringval[0] == 0)) ret = 0;
7092 		    else
7093 			ret = 1;
7094 		    ret = (arg2->boolval == ret);
7095 		    break;
7096 		case XPATH_STRING:
7097 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7098 		    break;
7099 		case XPATH_NUMBER:
7100 		    valuePush(ctxt, arg1);
7101 		    xmlXPathNumberFunction(ctxt, 1);
7102 		    arg1 = valuePop(ctxt);
7103 		    /* Hand check NaN and Infinity equalities */
7104 		    if (xmlXPathIsNaN(arg1->floatval) ||
7105 			    xmlXPathIsNaN(arg2->floatval)) {
7106 		        ret = 0;
7107 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7108 			if (xmlXPathIsInf(arg2->floatval) == 1)
7109 			    ret = 1;
7110 			else
7111 			    ret = 0;
7112 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7113 			if (xmlXPathIsInf(arg2->floatval) == -1)
7114 			    ret = 1;
7115 			else
7116 			    ret = 0;
7117 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7118 			if (xmlXPathIsInf(arg1->floatval) == 1)
7119 			    ret = 1;
7120 			else
7121 			    ret = 0;
7122 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7123 			if (xmlXPathIsInf(arg1->floatval) == -1)
7124 			    ret = 1;
7125 			else
7126 			    ret = 0;
7127 		    } else {
7128 		        ret = (arg1->floatval == arg2->floatval);
7129 		    }
7130 		    break;
7131 		case XPATH_USERS:
7132 		case XPATH_POINT:
7133 		case XPATH_RANGE:
7134 		case XPATH_LOCATIONSET:
7135 		    TODO
7136 		    break;
7137 		case XPATH_NODESET:
7138 		case XPATH_XSLT_TREE:
7139 		    break;
7140 	    }
7141 	    break;
7142         case XPATH_USERS:
7143 	case XPATH_POINT:
7144 	case XPATH_RANGE:
7145 	case XPATH_LOCATIONSET:
7146 	    TODO
7147 	    break;
7148 	case XPATH_NODESET:
7149 	case XPATH_XSLT_TREE:
7150 	    break;
7151     }
7152     xmlXPathReleaseObject(ctxt->context, arg1);
7153     xmlXPathReleaseObject(ctxt->context, arg2);
7154     return(ret);
7155 }
7156 
7157 /**
7158  * xmlXPathEqualValues:
7159  * @ctxt:  the XPath Parser context
7160  *
7161  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7162  *
7163  * Returns 0 or 1 depending on the results of the test.
7164  */
7165 int
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt)7166 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7167     xmlXPathObjectPtr arg1, arg2, argtmp;
7168     int ret = 0;
7169 
7170     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7171     arg2 = valuePop(ctxt);
7172     arg1 = valuePop(ctxt);
7173     if ((arg1 == NULL) || (arg2 == NULL)) {
7174 	if (arg1 != NULL)
7175 	    xmlXPathReleaseObject(ctxt->context, arg1);
7176 	else
7177 	    xmlXPathReleaseObject(ctxt->context, arg2);
7178 	XP_ERROR0(XPATH_INVALID_OPERAND);
7179     }
7180 
7181     if (arg1 == arg2) {
7182 #ifdef DEBUG_EXPR
7183         xmlGenericError(xmlGenericErrorContext,
7184 		"Equal: by pointer\n");
7185 #endif
7186 	xmlXPathFreeObject(arg1);
7187         return(1);
7188     }
7189 
7190     /*
7191      *If either argument is a nodeset, it's a 'special case'
7192      */
7193     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7194       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7195 	/*
7196 	 *Hack it to assure arg1 is the nodeset
7197 	 */
7198 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7199 		argtmp = arg2;
7200 		arg2 = arg1;
7201 		arg1 = argtmp;
7202 	}
7203 	switch (arg2->type) {
7204 	    case XPATH_UNDEFINED:
7205 #ifdef DEBUG_EXPR
7206 		xmlGenericError(xmlGenericErrorContext,
7207 			"Equal: undefined\n");
7208 #endif
7209 		break;
7210 	    case XPATH_NODESET:
7211 	    case XPATH_XSLT_TREE:
7212 		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7213 		break;
7214 	    case XPATH_BOOLEAN:
7215 		if ((arg1->nodesetval == NULL) ||
7216 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7217 		else
7218 		    ret = 1;
7219 		ret = (ret == arg2->boolval);
7220 		break;
7221 	    case XPATH_NUMBER:
7222 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7223 		break;
7224 	    case XPATH_STRING:
7225 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7226 		break;
7227 	    case XPATH_USERS:
7228 	    case XPATH_POINT:
7229 	    case XPATH_RANGE:
7230 	    case XPATH_LOCATIONSET:
7231 		TODO
7232 		break;
7233 	}
7234 	xmlXPathReleaseObject(ctxt->context, arg1);
7235 	xmlXPathReleaseObject(ctxt->context, arg2);
7236 	return(ret);
7237     }
7238 
7239     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7240 }
7241 
7242 /**
7243  * xmlXPathNotEqualValues:
7244  * @ctxt:  the XPath Parser context
7245  *
7246  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7247  *
7248  * Returns 0 or 1 depending on the results of the test.
7249  */
7250 int
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt)7251 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7252     xmlXPathObjectPtr arg1, arg2, argtmp;
7253     int ret = 0;
7254 
7255     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7256     arg2 = valuePop(ctxt);
7257     arg1 = valuePop(ctxt);
7258     if ((arg1 == NULL) || (arg2 == NULL)) {
7259 	if (arg1 != NULL)
7260 	    xmlXPathReleaseObject(ctxt->context, arg1);
7261 	else
7262 	    xmlXPathReleaseObject(ctxt->context, arg2);
7263 	XP_ERROR0(XPATH_INVALID_OPERAND);
7264     }
7265 
7266     if (arg1 == arg2) {
7267 #ifdef DEBUG_EXPR
7268         xmlGenericError(xmlGenericErrorContext,
7269 		"NotEqual: by pointer\n");
7270 #endif
7271 	xmlXPathReleaseObject(ctxt->context, arg1);
7272         return(0);
7273     }
7274 
7275     /*
7276      *If either argument is a nodeset, it's a 'special case'
7277      */
7278     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7279       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7280 	/*
7281 	 *Hack it to assure arg1 is the nodeset
7282 	 */
7283 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7284 		argtmp = arg2;
7285 		arg2 = arg1;
7286 		arg1 = argtmp;
7287 	}
7288 	switch (arg2->type) {
7289 	    case XPATH_UNDEFINED:
7290 #ifdef DEBUG_EXPR
7291 		xmlGenericError(xmlGenericErrorContext,
7292 			"NotEqual: undefined\n");
7293 #endif
7294 		break;
7295 	    case XPATH_NODESET:
7296 	    case XPATH_XSLT_TREE:
7297 		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7298 		break;
7299 	    case XPATH_BOOLEAN:
7300 		if ((arg1->nodesetval == NULL) ||
7301 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7302 		else
7303 		    ret = 1;
7304 		ret = (ret != arg2->boolval);
7305 		break;
7306 	    case XPATH_NUMBER:
7307 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7308 		break;
7309 	    case XPATH_STRING:
7310 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7311 		break;
7312 	    case XPATH_USERS:
7313 	    case XPATH_POINT:
7314 	    case XPATH_RANGE:
7315 	    case XPATH_LOCATIONSET:
7316 		TODO
7317 		break;
7318 	}
7319 	xmlXPathReleaseObject(ctxt->context, arg1);
7320 	xmlXPathReleaseObject(ctxt->context, arg2);
7321 	return(ret);
7322     }
7323 
7324     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7325 }
7326 
7327 /**
7328  * xmlXPathCompareValues:
7329  * @ctxt:  the XPath Parser context
7330  * @inf:  less than (1) or greater than (0)
7331  * @strict:  is the comparison strict
7332  *
7333  * Implement the compare operation on XPath objects:
7334  *     @arg1 < @arg2    (1, 1, ...
7335  *     @arg1 <= @arg2   (1, 0, ...
7336  *     @arg1 > @arg2    (0, 1, ...
7337  *     @arg1 >= @arg2   (0, 0, ...
7338  *
7339  * When neither object to be compared is a node-set and the operator is
7340  * <=, <, >=, >, then the objects are compared by converted both objects
7341  * to numbers and comparing the numbers according to IEEE 754. The <
7342  * comparison will be true if and only if the first number is less than the
7343  * second number. The <= comparison will be true if and only if the first
7344  * number is less than or equal to the second number. The > comparison
7345  * will be true if and only if the first number is greater than the second
7346  * number. The >= comparison will be true if and only if the first number
7347  * is greater than or equal to the second number.
7348  *
7349  * Returns 1 if the comparison succeeded, 0 if it failed
7350  */
7351 int
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt,int inf,int strict)7352 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7353     int ret = 0, arg1i = 0, arg2i = 0;
7354     xmlXPathObjectPtr arg1, arg2;
7355 
7356     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7357     arg2 = valuePop(ctxt);
7358     arg1 = valuePop(ctxt);
7359     if ((arg1 == NULL) || (arg2 == NULL)) {
7360 	if (arg1 != NULL)
7361 	    xmlXPathReleaseObject(ctxt->context, arg1);
7362 	else
7363 	    xmlXPathReleaseObject(ctxt->context, arg2);
7364 	XP_ERROR0(XPATH_INVALID_OPERAND);
7365     }
7366 
7367     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7368       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7369 	/*
7370 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7371 	 * are not freed from within this routine; they will be freed from the
7372 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7373 	 */
7374 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7375 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7376 	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7377 	} else {
7378 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7379 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7380 			                          arg1, arg2);
7381 	    } else {
7382 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7383 			                          arg2, arg1);
7384 	    }
7385 	}
7386 	return(ret);
7387     }
7388 
7389     if (arg1->type != XPATH_NUMBER) {
7390 	valuePush(ctxt, arg1);
7391 	xmlXPathNumberFunction(ctxt, 1);
7392 	arg1 = valuePop(ctxt);
7393     }
7394     if (arg1->type != XPATH_NUMBER) {
7395 	xmlXPathFreeObject(arg1);
7396 	xmlXPathFreeObject(arg2);
7397 	XP_ERROR0(XPATH_INVALID_OPERAND);
7398     }
7399     if (arg2->type != XPATH_NUMBER) {
7400 	valuePush(ctxt, arg2);
7401 	xmlXPathNumberFunction(ctxt, 1);
7402 	arg2 = valuePop(ctxt);
7403     }
7404     if (arg2->type != XPATH_NUMBER) {
7405 	xmlXPathReleaseObject(ctxt->context, arg1);
7406 	xmlXPathReleaseObject(ctxt->context, arg2);
7407 	XP_ERROR0(XPATH_INVALID_OPERAND);
7408     }
7409     /*
7410      * Add tests for infinity and nan
7411      * => feedback on 3.4 for Inf and NaN
7412      */
7413     /* Hand check NaN and Infinity comparisons */
7414     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7415 	ret=0;
7416     } else {
7417 	arg1i=xmlXPathIsInf(arg1->floatval);
7418 	arg2i=xmlXPathIsInf(arg2->floatval);
7419 	if (inf && strict) {
7420 	    if ((arg1i == -1 && arg2i != -1) ||
7421 		(arg2i == 1 && arg1i != 1)) {
7422 		ret = 1;
7423 	    } else if (arg1i == 0 && arg2i == 0) {
7424 		ret = (arg1->floatval < arg2->floatval);
7425 	    } else {
7426 		ret = 0;
7427 	    }
7428 	}
7429 	else if (inf && !strict) {
7430 	    if (arg1i == -1 || arg2i == 1) {
7431 		ret = 1;
7432 	    } else if (arg1i == 0 && arg2i == 0) {
7433 		ret = (arg1->floatval <= arg2->floatval);
7434 	    } else {
7435 		ret = 0;
7436 	    }
7437 	}
7438 	else if (!inf && strict) {
7439 	    if ((arg1i == 1 && arg2i != 1) ||
7440 		(arg2i == -1 && arg1i != -1)) {
7441 		ret = 1;
7442 	    } else if (arg1i == 0 && arg2i == 0) {
7443 		ret = (arg1->floatval > arg2->floatval);
7444 	    } else {
7445 		ret = 0;
7446 	    }
7447 	}
7448 	else if (!inf && !strict) {
7449 	    if (arg1i == 1 || arg2i == -1) {
7450 		ret = 1;
7451 	    } else if (arg1i == 0 && arg2i == 0) {
7452 		ret = (arg1->floatval >= arg2->floatval);
7453 	    } else {
7454 		ret = 0;
7455 	    }
7456 	}
7457     }
7458     xmlXPathReleaseObject(ctxt->context, arg1);
7459     xmlXPathReleaseObject(ctxt->context, arg2);
7460     return(ret);
7461 }
7462 
7463 /**
7464  * xmlXPathValueFlipSign:
7465  * @ctxt:  the XPath Parser context
7466  *
7467  * Implement the unary - operation on an XPath object
7468  * The numeric operators convert their operands to numbers as if
7469  * by calling the number function.
7470  */
7471 void
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt)7472 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7473     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7474     CAST_TO_NUMBER;
7475     CHECK_TYPE(XPATH_NUMBER);
7476     ctxt->value->floatval = -ctxt->value->floatval;
7477 }
7478 
7479 /**
7480  * xmlXPathAddValues:
7481  * @ctxt:  the XPath Parser context
7482  *
7483  * Implement the add operation on XPath objects:
7484  * The numeric operators convert their operands to numbers as if
7485  * by calling the number function.
7486  */
7487 void
xmlXPathAddValues(xmlXPathParserContextPtr ctxt)7488 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7489     xmlXPathObjectPtr arg;
7490     double val;
7491 
7492     arg = valuePop(ctxt);
7493     if (arg == NULL)
7494 	XP_ERROR(XPATH_INVALID_OPERAND);
7495     val = xmlXPathCastToNumber(arg);
7496     xmlXPathReleaseObject(ctxt->context, arg);
7497     CAST_TO_NUMBER;
7498     CHECK_TYPE(XPATH_NUMBER);
7499     ctxt->value->floatval += val;
7500 }
7501 
7502 /**
7503  * xmlXPathSubValues:
7504  * @ctxt:  the XPath Parser context
7505  *
7506  * Implement the subtraction operation on XPath objects:
7507  * The numeric operators convert their operands to numbers as if
7508  * by calling the number function.
7509  */
7510 void
xmlXPathSubValues(xmlXPathParserContextPtr ctxt)7511 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7512     xmlXPathObjectPtr arg;
7513     double val;
7514 
7515     arg = valuePop(ctxt);
7516     if (arg == NULL)
7517 	XP_ERROR(XPATH_INVALID_OPERAND);
7518     val = xmlXPathCastToNumber(arg);
7519     xmlXPathReleaseObject(ctxt->context, arg);
7520     CAST_TO_NUMBER;
7521     CHECK_TYPE(XPATH_NUMBER);
7522     ctxt->value->floatval -= val;
7523 }
7524 
7525 /**
7526  * xmlXPathMultValues:
7527  * @ctxt:  the XPath Parser context
7528  *
7529  * Implement the multiply operation on XPath objects:
7530  * The numeric operators convert their operands to numbers as if
7531  * by calling the number function.
7532  */
7533 void
xmlXPathMultValues(xmlXPathParserContextPtr ctxt)7534 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7535     xmlXPathObjectPtr arg;
7536     double val;
7537 
7538     arg = valuePop(ctxt);
7539     if (arg == NULL)
7540 	XP_ERROR(XPATH_INVALID_OPERAND);
7541     val = xmlXPathCastToNumber(arg);
7542     xmlXPathReleaseObject(ctxt->context, arg);
7543     CAST_TO_NUMBER;
7544     CHECK_TYPE(XPATH_NUMBER);
7545     ctxt->value->floatval *= val;
7546 }
7547 
7548 /**
7549  * xmlXPathDivValues:
7550  * @ctxt:  the XPath Parser context
7551  *
7552  * Implement the div operation on XPath objects @arg1 / @arg2:
7553  * The numeric operators convert their operands to numbers as if
7554  * by calling the number function.
7555  */
7556 void
xmlXPathDivValues(xmlXPathParserContextPtr ctxt)7557 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7558     xmlXPathObjectPtr arg;
7559     double val;
7560 
7561     arg = valuePop(ctxt);
7562     if (arg == NULL)
7563 	XP_ERROR(XPATH_INVALID_OPERAND);
7564     val = xmlXPathCastToNumber(arg);
7565     xmlXPathReleaseObject(ctxt->context, arg);
7566     CAST_TO_NUMBER;
7567     CHECK_TYPE(XPATH_NUMBER);
7568     ctxt->value->floatval /= val;
7569 }
7570 
7571 /**
7572  * xmlXPathModValues:
7573  * @ctxt:  the XPath Parser context
7574  *
7575  * Implement the mod operation on XPath objects: @arg1 / @arg2
7576  * The numeric operators convert their operands to numbers as if
7577  * by calling the number function.
7578  */
7579 void
xmlXPathModValues(xmlXPathParserContextPtr ctxt)7580 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7581     xmlXPathObjectPtr arg;
7582     double arg1, arg2;
7583 
7584     arg = valuePop(ctxt);
7585     if (arg == NULL)
7586 	XP_ERROR(XPATH_INVALID_OPERAND);
7587     arg2 = xmlXPathCastToNumber(arg);
7588     xmlXPathReleaseObject(ctxt->context, arg);
7589     CAST_TO_NUMBER;
7590     CHECK_TYPE(XPATH_NUMBER);
7591     arg1 = ctxt->value->floatval;
7592     if (arg2 == 0)
7593 	ctxt->value->floatval = NAN;
7594     else {
7595 	ctxt->value->floatval = fmod(arg1, arg2);
7596     }
7597 }
7598 
7599 /************************************************************************
7600  *									*
7601  *		The traversal functions					*
7602  *									*
7603  ************************************************************************/
7604 
7605 /*
7606  * A traversal function enumerates nodes along an axis.
7607  * Initially it must be called with NULL, and it indicates
7608  * termination on the axis by returning NULL.
7609  */
7610 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7611                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7612 
7613 /*
7614  * xmlXPathTraversalFunctionExt:
7615  * A traversal function enumerates nodes along an axis.
7616  * Initially it must be called with NULL, and it indicates
7617  * termination on the axis by returning NULL.
7618  * The context node of the traversal is specified via @contextNode.
7619  */
7620 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7621                     (xmlNodePtr cur, xmlNodePtr contextNode);
7622 
7623 /*
7624  * xmlXPathNodeSetMergeFunction:
7625  * Used for merging node sets in xmlXPathCollectAndTest().
7626  */
7627 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7628 		    (xmlNodeSetPtr, xmlNodeSetPtr, int);
7629 
7630 
7631 /**
7632  * xmlXPathNextSelf:
7633  * @ctxt:  the XPath Parser context
7634  * @cur:  the current node in the traversal
7635  *
7636  * Traversal function for the "self" direction
7637  * The self axis contains just the context node itself
7638  *
7639  * Returns the next element following that axis
7640  */
7641 xmlNodePtr
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7642 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7643     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7644     if (cur == NULL)
7645         return(ctxt->context->node);
7646     return(NULL);
7647 }
7648 
7649 /**
7650  * xmlXPathNextChild:
7651  * @ctxt:  the XPath Parser context
7652  * @cur:  the current node in the traversal
7653  *
7654  * Traversal function for the "child" direction
7655  * The child axis contains the children of the context node in document order.
7656  *
7657  * Returns the next element following that axis
7658  */
7659 xmlNodePtr
xmlXPathNextChild(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7660 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7661     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7662     if (cur == NULL) {
7663 	if (ctxt->context->node == NULL) return(NULL);
7664 	switch (ctxt->context->node->type) {
7665             case XML_ELEMENT_NODE:
7666             case XML_TEXT_NODE:
7667             case XML_CDATA_SECTION_NODE:
7668             case XML_ENTITY_REF_NODE:
7669             case XML_ENTITY_NODE:
7670             case XML_PI_NODE:
7671             case XML_COMMENT_NODE:
7672             case XML_NOTATION_NODE:
7673             case XML_DTD_NODE:
7674 		return(ctxt->context->node->children);
7675             case XML_DOCUMENT_NODE:
7676             case XML_DOCUMENT_TYPE_NODE:
7677             case XML_DOCUMENT_FRAG_NODE:
7678             case XML_HTML_DOCUMENT_NODE:
7679 #ifdef LIBXML_DOCB_ENABLED
7680 	    case XML_DOCB_DOCUMENT_NODE:
7681 #endif
7682 		return(((xmlDocPtr) ctxt->context->node)->children);
7683 	    case XML_ELEMENT_DECL:
7684 	    case XML_ATTRIBUTE_DECL:
7685 	    case XML_ENTITY_DECL:
7686             case XML_ATTRIBUTE_NODE:
7687 	    case XML_NAMESPACE_DECL:
7688 	    case XML_XINCLUDE_START:
7689 	    case XML_XINCLUDE_END:
7690 		return(NULL);
7691 	}
7692 	return(NULL);
7693     }
7694     if ((cur->type == XML_DOCUMENT_NODE) ||
7695         (cur->type == XML_HTML_DOCUMENT_NODE))
7696 	return(NULL);
7697     return(cur->next);
7698 }
7699 
7700 /**
7701  * xmlXPathNextChildElement:
7702  * @ctxt:  the XPath Parser context
7703  * @cur:  the current node in the traversal
7704  *
7705  * Traversal function for the "child" direction and nodes of type element.
7706  * The child axis contains the children of the context node in document order.
7707  *
7708  * Returns the next element following that axis
7709  */
7710 static xmlNodePtr
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7711 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7712     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7713     if (cur == NULL) {
7714 	cur = ctxt->context->node;
7715 	if (cur == NULL) return(NULL);
7716 	/*
7717 	* Get the first element child.
7718 	*/
7719 	switch (cur->type) {
7720             case XML_ELEMENT_NODE:
7721 	    case XML_DOCUMENT_FRAG_NODE:
7722 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7723             case XML_ENTITY_NODE:
7724 		cur = cur->children;
7725 		if (cur != NULL) {
7726 		    if (cur->type == XML_ELEMENT_NODE)
7727 			return(cur);
7728 		    do {
7729 			cur = cur->next;
7730 		    } while ((cur != NULL) &&
7731 			(cur->type != XML_ELEMENT_NODE));
7732 		    return(cur);
7733 		}
7734 		return(NULL);
7735             case XML_DOCUMENT_NODE:
7736             case XML_HTML_DOCUMENT_NODE:
7737 #ifdef LIBXML_DOCB_ENABLED
7738 	    case XML_DOCB_DOCUMENT_NODE:
7739 #endif
7740 		return(xmlDocGetRootElement((xmlDocPtr) cur));
7741 	    default:
7742 		return(NULL);
7743 	}
7744 	return(NULL);
7745     }
7746     /*
7747     * Get the next sibling element node.
7748     */
7749     switch (cur->type) {
7750 	case XML_ELEMENT_NODE:
7751 	case XML_TEXT_NODE:
7752 	case XML_ENTITY_REF_NODE:
7753 	case XML_ENTITY_NODE:
7754 	case XML_CDATA_SECTION_NODE:
7755 	case XML_PI_NODE:
7756 	case XML_COMMENT_NODE:
7757 	case XML_XINCLUDE_END:
7758 	    break;
7759 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7760 	default:
7761 	    return(NULL);
7762     }
7763     if (cur->next != NULL) {
7764 	if (cur->next->type == XML_ELEMENT_NODE)
7765 	    return(cur->next);
7766 	cur = cur->next;
7767 	do {
7768 	    cur = cur->next;
7769 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7770 	return(cur);
7771     }
7772     return(NULL);
7773 }
7774 
7775 #if 0
7776 /**
7777  * xmlXPathNextDescendantOrSelfElemParent:
7778  * @ctxt:  the XPath Parser context
7779  * @cur:  the current node in the traversal
7780  *
7781  * Traversal function for the "descendant-or-self" axis.
7782  * Additionally it returns only nodes which can be parents of
7783  * element nodes.
7784  *
7785  *
7786  * Returns the next element following that axis
7787  */
7788 static xmlNodePtr
7789 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7790 				       xmlNodePtr contextNode)
7791 {
7792     if (cur == NULL) {
7793 	if (contextNode == NULL)
7794 	    return(NULL);
7795 	switch (contextNode->type) {
7796 	    case XML_ELEMENT_NODE:
7797 	    case XML_XINCLUDE_START:
7798 	    case XML_DOCUMENT_FRAG_NODE:
7799 	    case XML_DOCUMENT_NODE:
7800 #ifdef LIBXML_DOCB_ENABLED
7801 	    case XML_DOCB_DOCUMENT_NODE:
7802 #endif
7803 	    case XML_HTML_DOCUMENT_NODE:
7804 		return(contextNode);
7805 	    default:
7806 		return(NULL);
7807 	}
7808 	return(NULL);
7809     } else {
7810 	xmlNodePtr start = cur;
7811 
7812 	while (cur != NULL) {
7813 	    switch (cur->type) {
7814 		case XML_ELEMENT_NODE:
7815 		/* TODO: OK to have XInclude here? */
7816 		case XML_XINCLUDE_START:
7817 		case XML_DOCUMENT_FRAG_NODE:
7818 		    if (cur != start)
7819 			return(cur);
7820 		    if (cur->children != NULL) {
7821 			cur = cur->children;
7822 			continue;
7823 		    }
7824 		    break;
7825 		/* Not sure if we need those here. */
7826 		case XML_DOCUMENT_NODE:
7827 #ifdef LIBXML_DOCB_ENABLED
7828 		case XML_DOCB_DOCUMENT_NODE:
7829 #endif
7830 		case XML_HTML_DOCUMENT_NODE:
7831 		    if (cur != start)
7832 			return(cur);
7833 		    return(xmlDocGetRootElement((xmlDocPtr) cur));
7834 		default:
7835 		    break;
7836 	    }
7837 
7838 next_sibling:
7839 	    if ((cur == NULL) || (cur == contextNode))
7840 		return(NULL);
7841 	    if (cur->next != NULL) {
7842 		cur = cur->next;
7843 	    } else {
7844 		cur = cur->parent;
7845 		goto next_sibling;
7846 	    }
7847 	}
7848     }
7849     return(NULL);
7850 }
7851 #endif
7852 
7853 /**
7854  * xmlXPathNextDescendant:
7855  * @ctxt:  the XPath Parser context
7856  * @cur:  the current node in the traversal
7857  *
7858  * Traversal function for the "descendant" direction
7859  * the descendant axis contains the descendants of the context node in document
7860  * order; a descendant is a child or a child of a child and so on.
7861  *
7862  * Returns the next element following that axis
7863  */
7864 xmlNodePtr
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7865 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7866     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7867     if (cur == NULL) {
7868 	if (ctxt->context->node == NULL)
7869 	    return(NULL);
7870 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7871 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7872 	    return(NULL);
7873 
7874         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7875 	    return(ctxt->context->doc->children);
7876         return(ctxt->context->node->children);
7877     }
7878 
7879     if (cur->type == XML_NAMESPACE_DECL)
7880         return(NULL);
7881     if (cur->children != NULL) {
7882 	/*
7883 	 * Do not descend on entities declarations
7884 	 */
7885 	if (cur->children->type != XML_ENTITY_DECL) {
7886 	    cur = cur->children;
7887 	    /*
7888 	     * Skip DTDs
7889 	     */
7890 	    if (cur->type != XML_DTD_NODE)
7891 		return(cur);
7892 	}
7893     }
7894 
7895     if (cur == ctxt->context->node) return(NULL);
7896 
7897     while (cur->next != NULL) {
7898 	cur = cur->next;
7899 	if ((cur->type != XML_ENTITY_DECL) &&
7900 	    (cur->type != XML_DTD_NODE))
7901 	    return(cur);
7902     }
7903 
7904     do {
7905         cur = cur->parent;
7906 	if (cur == NULL) break;
7907 	if (cur == ctxt->context->node) return(NULL);
7908 	if (cur->next != NULL) {
7909 	    cur = cur->next;
7910 	    return(cur);
7911 	}
7912     } while (cur != NULL);
7913     return(cur);
7914 }
7915 
7916 /**
7917  * xmlXPathNextDescendantOrSelf:
7918  * @ctxt:  the XPath Parser context
7919  * @cur:  the current node in the traversal
7920  *
7921  * Traversal function for the "descendant-or-self" direction
7922  * the descendant-or-self axis contains the context node and the descendants
7923  * of the context node in document order; thus the context node is the first
7924  * node on the axis, and the first child of the context node is the second node
7925  * on the axis
7926  *
7927  * Returns the next element following that axis
7928  */
7929 xmlNodePtr
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7930 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7931     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7932     if (cur == NULL)
7933         return(ctxt->context->node);
7934 
7935     if (ctxt->context->node == NULL)
7936         return(NULL);
7937     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7938         (ctxt->context->node->type == XML_NAMESPACE_DECL))
7939         return(NULL);
7940 
7941     return(xmlXPathNextDescendant(ctxt, cur));
7942 }
7943 
7944 /**
7945  * xmlXPathNextParent:
7946  * @ctxt:  the XPath Parser context
7947  * @cur:  the current node in the traversal
7948  *
7949  * Traversal function for the "parent" direction
7950  * The parent axis contains the parent of the context node, if there is one.
7951  *
7952  * Returns the next element following that axis
7953  */
7954 xmlNodePtr
xmlXPathNextParent(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7955 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7956     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7957     /*
7958      * the parent of an attribute or namespace node is the element
7959      * to which the attribute or namespace node is attached
7960      * Namespace handling !!!
7961      */
7962     if (cur == NULL) {
7963 	if (ctxt->context->node == NULL) return(NULL);
7964 	switch (ctxt->context->node->type) {
7965             case XML_ELEMENT_NODE:
7966             case XML_TEXT_NODE:
7967             case XML_CDATA_SECTION_NODE:
7968             case XML_ENTITY_REF_NODE:
7969             case XML_ENTITY_NODE:
7970             case XML_PI_NODE:
7971             case XML_COMMENT_NODE:
7972             case XML_NOTATION_NODE:
7973             case XML_DTD_NODE:
7974 	    case XML_ELEMENT_DECL:
7975 	    case XML_ATTRIBUTE_DECL:
7976 	    case XML_XINCLUDE_START:
7977 	    case XML_XINCLUDE_END:
7978 	    case XML_ENTITY_DECL:
7979 		if (ctxt->context->node->parent == NULL)
7980 		    return((xmlNodePtr) ctxt->context->doc);
7981 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7982 		    ((ctxt->context->node->parent->name[0] == ' ') ||
7983 		     (xmlStrEqual(ctxt->context->node->parent->name,
7984 				 BAD_CAST "fake node libxslt"))))
7985 		    return(NULL);
7986 		return(ctxt->context->node->parent);
7987             case XML_ATTRIBUTE_NODE: {
7988 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7989 
7990 		return(att->parent);
7991 	    }
7992             case XML_DOCUMENT_NODE:
7993             case XML_DOCUMENT_TYPE_NODE:
7994             case XML_DOCUMENT_FRAG_NODE:
7995             case XML_HTML_DOCUMENT_NODE:
7996 #ifdef LIBXML_DOCB_ENABLED
7997 	    case XML_DOCB_DOCUMENT_NODE:
7998 #endif
7999                 return(NULL);
8000 	    case XML_NAMESPACE_DECL: {
8001 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8002 
8003 		if ((ns->next != NULL) &&
8004 		    (ns->next->type != XML_NAMESPACE_DECL))
8005 		    return((xmlNodePtr) ns->next);
8006                 return(NULL);
8007 	    }
8008 	}
8009     }
8010     return(NULL);
8011 }
8012 
8013 /**
8014  * xmlXPathNextAncestor:
8015  * @ctxt:  the XPath Parser context
8016  * @cur:  the current node in the traversal
8017  *
8018  * Traversal function for the "ancestor" direction
8019  * the ancestor axis contains the ancestors of the context node; the ancestors
8020  * of the context node consist of the parent of context node and the parent's
8021  * parent and so on; the nodes are ordered in reverse document order; thus the
8022  * parent is the first node on the axis, and the parent's parent is the second
8023  * node on the axis
8024  *
8025  * Returns the next element following that axis
8026  */
8027 xmlNodePtr
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8028 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8029     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8030     /*
8031      * the parent of an attribute or namespace node is the element
8032      * to which the attribute or namespace node is attached
8033      * !!!!!!!!!!!!!
8034      */
8035     if (cur == NULL) {
8036 	if (ctxt->context->node == NULL) return(NULL);
8037 	switch (ctxt->context->node->type) {
8038             case XML_ELEMENT_NODE:
8039             case XML_TEXT_NODE:
8040             case XML_CDATA_SECTION_NODE:
8041             case XML_ENTITY_REF_NODE:
8042             case XML_ENTITY_NODE:
8043             case XML_PI_NODE:
8044             case XML_COMMENT_NODE:
8045 	    case XML_DTD_NODE:
8046 	    case XML_ELEMENT_DECL:
8047 	    case XML_ATTRIBUTE_DECL:
8048 	    case XML_ENTITY_DECL:
8049             case XML_NOTATION_NODE:
8050 	    case XML_XINCLUDE_START:
8051 	    case XML_XINCLUDE_END:
8052 		if (ctxt->context->node->parent == NULL)
8053 		    return((xmlNodePtr) ctxt->context->doc);
8054 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8055 		    ((ctxt->context->node->parent->name[0] == ' ') ||
8056 		     (xmlStrEqual(ctxt->context->node->parent->name,
8057 				 BAD_CAST "fake node libxslt"))))
8058 		    return(NULL);
8059 		return(ctxt->context->node->parent);
8060             case XML_ATTRIBUTE_NODE: {
8061 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8062 
8063 		return(tmp->parent);
8064 	    }
8065             case XML_DOCUMENT_NODE:
8066             case XML_DOCUMENT_TYPE_NODE:
8067             case XML_DOCUMENT_FRAG_NODE:
8068             case XML_HTML_DOCUMENT_NODE:
8069 #ifdef LIBXML_DOCB_ENABLED
8070 	    case XML_DOCB_DOCUMENT_NODE:
8071 #endif
8072                 return(NULL);
8073 	    case XML_NAMESPACE_DECL: {
8074 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8075 
8076 		if ((ns->next != NULL) &&
8077 		    (ns->next->type != XML_NAMESPACE_DECL))
8078 		    return((xmlNodePtr) ns->next);
8079 		/* Bad, how did that namespace end up here ? */
8080                 return(NULL);
8081 	    }
8082 	}
8083 	return(NULL);
8084     }
8085     if (cur == ctxt->context->doc->children)
8086 	return((xmlNodePtr) ctxt->context->doc);
8087     if (cur == (xmlNodePtr) ctxt->context->doc)
8088 	return(NULL);
8089     switch (cur->type) {
8090 	case XML_ELEMENT_NODE:
8091 	case XML_TEXT_NODE:
8092 	case XML_CDATA_SECTION_NODE:
8093 	case XML_ENTITY_REF_NODE:
8094 	case XML_ENTITY_NODE:
8095 	case XML_PI_NODE:
8096 	case XML_COMMENT_NODE:
8097 	case XML_NOTATION_NODE:
8098 	case XML_DTD_NODE:
8099         case XML_ELEMENT_DECL:
8100         case XML_ATTRIBUTE_DECL:
8101         case XML_ENTITY_DECL:
8102 	case XML_XINCLUDE_START:
8103 	case XML_XINCLUDE_END:
8104 	    if (cur->parent == NULL)
8105 		return(NULL);
8106 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
8107 		((cur->parent->name[0] == ' ') ||
8108 		 (xmlStrEqual(cur->parent->name,
8109 			      BAD_CAST "fake node libxslt"))))
8110 		return(NULL);
8111 	    return(cur->parent);
8112 	case XML_ATTRIBUTE_NODE: {
8113 	    xmlAttrPtr att = (xmlAttrPtr) cur;
8114 
8115 	    return(att->parent);
8116 	}
8117 	case XML_NAMESPACE_DECL: {
8118 	    xmlNsPtr ns = (xmlNsPtr) cur;
8119 
8120 	    if ((ns->next != NULL) &&
8121 	        (ns->next->type != XML_NAMESPACE_DECL))
8122 	        return((xmlNodePtr) ns->next);
8123 	    /* Bad, how did that namespace end up here ? */
8124             return(NULL);
8125 	}
8126 	case XML_DOCUMENT_NODE:
8127 	case XML_DOCUMENT_TYPE_NODE:
8128 	case XML_DOCUMENT_FRAG_NODE:
8129 	case XML_HTML_DOCUMENT_NODE:
8130 #ifdef LIBXML_DOCB_ENABLED
8131 	case XML_DOCB_DOCUMENT_NODE:
8132 #endif
8133 	    return(NULL);
8134     }
8135     return(NULL);
8136 }
8137 
8138 /**
8139  * xmlXPathNextAncestorOrSelf:
8140  * @ctxt:  the XPath Parser context
8141  * @cur:  the current node in the traversal
8142  *
8143  * Traversal function for the "ancestor-or-self" direction
8144  * he ancestor-or-self axis contains the context node and ancestors of
8145  * the context node in reverse document order; thus the context node is
8146  * the first node on the axis, and the context node's parent the second;
8147  * parent here is defined the same as with the parent axis.
8148  *
8149  * Returns the next element following that axis
8150  */
8151 xmlNodePtr
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8152 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8153     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8154     if (cur == NULL)
8155         return(ctxt->context->node);
8156     return(xmlXPathNextAncestor(ctxt, cur));
8157 }
8158 
8159 /**
8160  * xmlXPathNextFollowingSibling:
8161  * @ctxt:  the XPath Parser context
8162  * @cur:  the current node in the traversal
8163  *
8164  * Traversal function for the "following-sibling" direction
8165  * The following-sibling axis contains the following siblings of the context
8166  * node in document order.
8167  *
8168  * Returns the next element following that axis
8169  */
8170 xmlNodePtr
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8171 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8172     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8173     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8174 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8175 	return(NULL);
8176     if (cur == (xmlNodePtr) ctxt->context->doc)
8177         return(NULL);
8178     if (cur == NULL)
8179         return(ctxt->context->node->next);
8180     return(cur->next);
8181 }
8182 
8183 /**
8184  * xmlXPathNextPrecedingSibling:
8185  * @ctxt:  the XPath Parser context
8186  * @cur:  the current node in the traversal
8187  *
8188  * Traversal function for the "preceding-sibling" direction
8189  * The preceding-sibling axis contains the preceding siblings of the context
8190  * node in reverse document order; the first preceding sibling is first on the
8191  * axis; the sibling preceding that node is the second on the axis and so on.
8192  *
8193  * Returns the next element following that axis
8194  */
8195 xmlNodePtr
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8196 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8197     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8198     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8199 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8200 	return(NULL);
8201     if (cur == (xmlNodePtr) ctxt->context->doc)
8202         return(NULL);
8203     if (cur == NULL)
8204         return(ctxt->context->node->prev);
8205     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8206 	cur = cur->prev;
8207 	if (cur == NULL)
8208 	    return(ctxt->context->node->prev);
8209     }
8210     return(cur->prev);
8211 }
8212 
8213 /**
8214  * xmlXPathNextFollowing:
8215  * @ctxt:  the XPath Parser context
8216  * @cur:  the current node in the traversal
8217  *
8218  * Traversal function for the "following" direction
8219  * The following axis contains all nodes in the same document as the context
8220  * node that are after the context node in document order, excluding any
8221  * descendants and excluding attribute nodes and namespace nodes; the nodes
8222  * are ordered in document order
8223  *
8224  * Returns the next element following that axis
8225  */
8226 xmlNodePtr
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8227 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8228     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8229     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8230         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8231         return(cur->children);
8232 
8233     if (cur == NULL) {
8234         cur = ctxt->context->node;
8235         if (cur->type == XML_ATTRIBUTE_NODE) {
8236             cur = cur->parent;
8237         } else if (cur->type == XML_NAMESPACE_DECL) {
8238             xmlNsPtr ns = (xmlNsPtr) cur;
8239 
8240             if ((ns->next == NULL) ||
8241                 (ns->next->type == XML_NAMESPACE_DECL))
8242                 return (NULL);
8243             cur = (xmlNodePtr) ns->next;
8244         }
8245     }
8246     if (cur == NULL) return(NULL) ; /* ERROR */
8247     if (cur->next != NULL) return(cur->next) ;
8248     do {
8249         cur = cur->parent;
8250         if (cur == NULL) break;
8251         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8252         if (cur->next != NULL) return(cur->next);
8253     } while (cur != NULL);
8254     return(cur);
8255 }
8256 
8257 /*
8258  * xmlXPathIsAncestor:
8259  * @ancestor:  the ancestor node
8260  * @node:  the current node
8261  *
8262  * Check that @ancestor is a @node's ancestor
8263  *
8264  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8265  */
8266 static int
xmlXPathIsAncestor(xmlNodePtr ancestor,xmlNodePtr node)8267 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8268     if ((ancestor == NULL) || (node == NULL)) return(0);
8269     if (node->type == XML_NAMESPACE_DECL)
8270         return(0);
8271     if (ancestor->type == XML_NAMESPACE_DECL)
8272         return(0);
8273     /* nodes need to be in the same document */
8274     if (ancestor->doc != node->doc) return(0);
8275     /* avoid searching if ancestor or node is the root node */
8276     if (ancestor == (xmlNodePtr) node->doc) return(1);
8277     if (node == (xmlNodePtr) ancestor->doc) return(0);
8278     while (node->parent != NULL) {
8279         if (node->parent == ancestor)
8280             return(1);
8281 	node = node->parent;
8282     }
8283     return(0);
8284 }
8285 
8286 /**
8287  * xmlXPathNextPreceding:
8288  * @ctxt:  the XPath Parser context
8289  * @cur:  the current node in the traversal
8290  *
8291  * Traversal function for the "preceding" direction
8292  * the preceding axis contains all nodes in the same document as the context
8293  * node that are before the context node in document order, excluding any
8294  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8295  * ordered in reverse document order
8296  *
8297  * Returns the next element following that axis
8298  */
8299 xmlNodePtr
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8300 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8301 {
8302     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8303     if (cur == NULL) {
8304         cur = ctxt->context->node;
8305         if (cur->type == XML_ATTRIBUTE_NODE) {
8306             cur = cur->parent;
8307         } else if (cur->type == XML_NAMESPACE_DECL) {
8308             xmlNsPtr ns = (xmlNsPtr) cur;
8309 
8310             if ((ns->next == NULL) ||
8311                 (ns->next->type == XML_NAMESPACE_DECL))
8312                 return (NULL);
8313             cur = (xmlNodePtr) ns->next;
8314         }
8315     }
8316     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8317 	return (NULL);
8318     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8319 	cur = cur->prev;
8320     do {
8321         if (cur->prev != NULL) {
8322             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8323             return (cur);
8324         }
8325 
8326         cur = cur->parent;
8327         if (cur == NULL)
8328             return (NULL);
8329         if (cur == ctxt->context->doc->children)
8330             return (NULL);
8331     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8332     return (cur);
8333 }
8334 
8335 /**
8336  * xmlXPathNextPrecedingInternal:
8337  * @ctxt:  the XPath Parser context
8338  * @cur:  the current node in the traversal
8339  *
8340  * Traversal function for the "preceding" direction
8341  * the preceding axis contains all nodes in the same document as the context
8342  * node that are before the context node in document order, excluding any
8343  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8344  * ordered in reverse document order
8345  * This is a faster implementation but internal only since it requires a
8346  * state kept in the parser context: ctxt->ancestor.
8347  *
8348  * Returns the next element following that axis
8349  */
8350 static xmlNodePtr
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8351 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8352                               xmlNodePtr cur)
8353 {
8354     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8355     if (cur == NULL) {
8356         cur = ctxt->context->node;
8357         if (cur == NULL)
8358             return (NULL);
8359         if (cur->type == XML_ATTRIBUTE_NODE) {
8360             cur = cur->parent;
8361         } else if (cur->type == XML_NAMESPACE_DECL) {
8362             xmlNsPtr ns = (xmlNsPtr) cur;
8363 
8364             if ((ns->next == NULL) ||
8365                 (ns->next->type == XML_NAMESPACE_DECL))
8366                 return (NULL);
8367             cur = (xmlNodePtr) ns->next;
8368         }
8369         ctxt->ancestor = cur->parent;
8370     }
8371     if (cur->type == XML_NAMESPACE_DECL)
8372         return(NULL);
8373     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8374 	cur = cur->prev;
8375     while (cur->prev == NULL) {
8376         cur = cur->parent;
8377         if (cur == NULL)
8378             return (NULL);
8379         if (cur == ctxt->context->doc->children)
8380             return (NULL);
8381         if (cur != ctxt->ancestor)
8382             return (cur);
8383         ctxt->ancestor = cur->parent;
8384     }
8385     cur = cur->prev;
8386     while (cur->last != NULL)
8387         cur = cur->last;
8388     return (cur);
8389 }
8390 
8391 /**
8392  * xmlXPathNextNamespace:
8393  * @ctxt:  the XPath Parser context
8394  * @cur:  the current attribute in the traversal
8395  *
8396  * Traversal function for the "namespace" direction
8397  * the namespace axis contains the namespace nodes of the context node;
8398  * the order of nodes on this axis is implementation-defined; the axis will
8399  * be empty unless the context node is an element
8400  *
8401  * We keep the XML namespace node at the end of the list.
8402  *
8403  * Returns the next element following that axis
8404  */
8405 xmlNodePtr
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8406 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8407     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8408     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8409     if (cur == NULL) {
8410         if (ctxt->context->tmpNsList != NULL)
8411 	    xmlFree(ctxt->context->tmpNsList);
8412 	ctxt->context->tmpNsList =
8413 	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8414 	ctxt->context->tmpNsNr = 0;
8415 	if (ctxt->context->tmpNsList != NULL) {
8416 	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8417 		ctxt->context->tmpNsNr++;
8418 	    }
8419 	}
8420 	return((xmlNodePtr) xmlXPathXMLNamespace);
8421     }
8422     if (ctxt->context->tmpNsNr > 0) {
8423 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8424     } else {
8425 	if (ctxt->context->tmpNsList != NULL)
8426 	    xmlFree(ctxt->context->tmpNsList);
8427 	ctxt->context->tmpNsList = NULL;
8428 	return(NULL);
8429     }
8430 }
8431 
8432 /**
8433  * xmlXPathNextAttribute:
8434  * @ctxt:  the XPath Parser context
8435  * @cur:  the current attribute in the traversal
8436  *
8437  * Traversal function for the "attribute" direction
8438  * TODO: support DTD inherited default attributes
8439  *
8440  * Returns the next element following that axis
8441  */
8442 xmlNodePtr
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8443 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8444     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8445     if (ctxt->context->node == NULL)
8446 	return(NULL);
8447     if (ctxt->context->node->type != XML_ELEMENT_NODE)
8448 	return(NULL);
8449     if (cur == NULL) {
8450         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8451 	    return(NULL);
8452         return((xmlNodePtr)ctxt->context->node->properties);
8453     }
8454     return((xmlNodePtr)cur->next);
8455 }
8456 
8457 /************************************************************************
8458  *									*
8459  *		NodeTest Functions					*
8460  *									*
8461  ************************************************************************/
8462 
8463 #define IS_FUNCTION			200
8464 
8465 
8466 /************************************************************************
8467  *									*
8468  *		Implicit tree core function library			*
8469  *									*
8470  ************************************************************************/
8471 
8472 /**
8473  * xmlXPathRoot:
8474  * @ctxt:  the XPath Parser context
8475  *
8476  * Initialize the context to the root of the document
8477  */
8478 void
xmlXPathRoot(xmlXPathParserContextPtr ctxt)8479 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8480     if ((ctxt == NULL) || (ctxt->context == NULL))
8481 	return;
8482     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8483     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8484 	ctxt->context->node));
8485 }
8486 
8487 /************************************************************************
8488  *									*
8489  *		The explicit core function library			*
8490  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
8491  *									*
8492  ************************************************************************/
8493 
8494 
8495 /**
8496  * xmlXPathLastFunction:
8497  * @ctxt:  the XPath Parser context
8498  * @nargs:  the number of arguments
8499  *
8500  * Implement the last() XPath function
8501  *    number last()
8502  * The last function returns the number of nodes in the context node list.
8503  */
8504 void
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt,int nargs)8505 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8506     CHECK_ARITY(0);
8507     if (ctxt->context->contextSize >= 0) {
8508 	valuePush(ctxt,
8509 	    xmlXPathCacheNewFloat(ctxt->context,
8510 		(double) ctxt->context->contextSize));
8511 #ifdef DEBUG_EXPR
8512 	xmlGenericError(xmlGenericErrorContext,
8513 		"last() : %d\n", ctxt->context->contextSize);
8514 #endif
8515     } else {
8516 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8517     }
8518 }
8519 
8520 /**
8521  * xmlXPathPositionFunction:
8522  * @ctxt:  the XPath Parser context
8523  * @nargs:  the number of arguments
8524  *
8525  * Implement the position() XPath function
8526  *    number position()
8527  * The position function returns the position of the context node in the
8528  * context node list. The first position is 1, and so the last position
8529  * will be equal to last().
8530  */
8531 void
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt,int nargs)8532 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8533     CHECK_ARITY(0);
8534     if (ctxt->context->proximityPosition >= 0) {
8535 	valuePush(ctxt,
8536 	      xmlXPathCacheNewFloat(ctxt->context,
8537 		(double) ctxt->context->proximityPosition));
8538 #ifdef DEBUG_EXPR
8539 	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8540 		ctxt->context->proximityPosition);
8541 #endif
8542     } else {
8543 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8544     }
8545 }
8546 
8547 /**
8548  * xmlXPathCountFunction:
8549  * @ctxt:  the XPath Parser context
8550  * @nargs:  the number of arguments
8551  *
8552  * Implement the count() XPath function
8553  *    number count(node-set)
8554  */
8555 void
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt,int nargs)8556 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8557     xmlXPathObjectPtr cur;
8558 
8559     CHECK_ARITY(1);
8560     if ((ctxt->value == NULL) ||
8561 	((ctxt->value->type != XPATH_NODESET) &&
8562 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8563 	XP_ERROR(XPATH_INVALID_TYPE);
8564     cur = valuePop(ctxt);
8565 
8566     if ((cur == NULL) || (cur->nodesetval == NULL))
8567 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8568     else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8569 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8570 	    (double) cur->nodesetval->nodeNr));
8571     } else {
8572 	if ((cur->nodesetval->nodeNr != 1) ||
8573 	    (cur->nodesetval->nodeTab == NULL)) {
8574 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8575 	} else {
8576 	    xmlNodePtr tmp;
8577 	    int i = 0;
8578 
8579 	    tmp = cur->nodesetval->nodeTab[0];
8580 	    if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
8581 		tmp = tmp->children;
8582 		while (tmp != NULL) {
8583 		    tmp = tmp->next;
8584 		    i++;
8585 		}
8586 	    }
8587 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8588 	}
8589     }
8590     xmlXPathReleaseObject(ctxt->context, cur);
8591 }
8592 
8593 /**
8594  * xmlXPathGetElementsByIds:
8595  * @doc:  the document
8596  * @ids:  a whitespace separated list of IDs
8597  *
8598  * Selects elements by their unique ID.
8599  *
8600  * Returns a node-set of selected elements.
8601  */
8602 static xmlNodeSetPtr
xmlXPathGetElementsByIds(xmlDocPtr doc,const xmlChar * ids)8603 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8604     xmlNodeSetPtr ret;
8605     const xmlChar *cur = ids;
8606     xmlChar *ID;
8607     xmlAttrPtr attr;
8608     xmlNodePtr elem = NULL;
8609 
8610     if (ids == NULL) return(NULL);
8611 
8612     ret = xmlXPathNodeSetCreate(NULL);
8613     if (ret == NULL)
8614         return(ret);
8615 
8616     while (IS_BLANK_CH(*cur)) cur++;
8617     while (*cur != 0) {
8618 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8619 	    cur++;
8620 
8621         ID = xmlStrndup(ids, cur - ids);
8622 	if (ID != NULL) {
8623 	    /*
8624 	     * We used to check the fact that the value passed
8625 	     * was an NCName, but this generated much troubles for
8626 	     * me and Aleksey Sanin, people blatantly violated that
8627 	     * constaint, like Visa3D spec.
8628 	     * if (xmlValidateNCName(ID, 1) == 0)
8629 	     */
8630 	    attr = xmlGetID(doc, ID);
8631 	    if (attr != NULL) {
8632 		if (attr->type == XML_ATTRIBUTE_NODE)
8633 		    elem = attr->parent;
8634 		else if (attr->type == XML_ELEMENT_NODE)
8635 		    elem = (xmlNodePtr) attr;
8636 		else
8637 		    elem = NULL;
8638 		if (elem != NULL)
8639 		    xmlXPathNodeSetAdd(ret, elem);
8640 	    }
8641 	    xmlFree(ID);
8642 	}
8643 
8644 	while (IS_BLANK_CH(*cur)) cur++;
8645 	ids = cur;
8646     }
8647     return(ret);
8648 }
8649 
8650 /**
8651  * xmlXPathIdFunction:
8652  * @ctxt:  the XPath Parser context
8653  * @nargs:  the number of arguments
8654  *
8655  * Implement the id() XPath function
8656  *    node-set id(object)
8657  * The id function selects elements by their unique ID
8658  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8659  * then the result is the union of the result of applying id to the
8660  * string value of each of the nodes in the argument node-set. When the
8661  * argument to id is of any other type, the argument is converted to a
8662  * string as if by a call to the string function; the string is split
8663  * into a whitespace-separated list of tokens (whitespace is any sequence
8664  * of characters matching the production S); the result is a node-set
8665  * containing the elements in the same document as the context node that
8666  * have a unique ID equal to any of the tokens in the list.
8667  */
8668 void
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt,int nargs)8669 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8670     xmlChar *tokens;
8671     xmlNodeSetPtr ret;
8672     xmlXPathObjectPtr obj;
8673 
8674     CHECK_ARITY(1);
8675     obj = valuePop(ctxt);
8676     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8677     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8678 	xmlNodeSetPtr ns;
8679 	int i;
8680 
8681 	ret = xmlXPathNodeSetCreate(NULL);
8682         /*
8683          * FIXME -- in an out-of-memory condition this will behave badly.
8684          * The solution is not clear -- we already popped an item from
8685          * ctxt, so the object is in a corrupt state.
8686          */
8687 
8688 	if (obj->nodesetval != NULL) {
8689 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8690 		tokens =
8691 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8692 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8693 		ret = xmlXPathNodeSetMerge(ret, ns);
8694 		xmlXPathFreeNodeSet(ns);
8695 		if (tokens != NULL)
8696 		    xmlFree(tokens);
8697 	    }
8698 	}
8699 	xmlXPathReleaseObject(ctxt->context, obj);
8700 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8701 	return;
8702     }
8703     obj = xmlXPathCacheConvertString(ctxt->context, obj);
8704     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8705     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8706     xmlXPathReleaseObject(ctxt->context, obj);
8707     return;
8708 }
8709 
8710 /**
8711  * xmlXPathLocalNameFunction:
8712  * @ctxt:  the XPath Parser context
8713  * @nargs:  the number of arguments
8714  *
8715  * Implement the local-name() XPath function
8716  *    string local-name(node-set?)
8717  * The local-name function returns a string containing the local part
8718  * of the name of the node in the argument node-set that is first in
8719  * document order. If the node-set is empty or the first node has no
8720  * name, an empty string is returned. If the argument is omitted it
8721  * defaults to the context node.
8722  */
8723 void
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8724 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8725     xmlXPathObjectPtr cur;
8726 
8727     if (ctxt == NULL) return;
8728 
8729     if (nargs == 0) {
8730 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8731 	    ctxt->context->node));
8732 	nargs = 1;
8733     }
8734 
8735     CHECK_ARITY(1);
8736     if ((ctxt->value == NULL) ||
8737 	((ctxt->value->type != XPATH_NODESET) &&
8738 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8739 	XP_ERROR(XPATH_INVALID_TYPE);
8740     cur = valuePop(ctxt);
8741 
8742     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8743 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8744     } else {
8745 	int i = 0; /* Should be first in document order !!!!! */
8746 	switch (cur->nodesetval->nodeTab[i]->type) {
8747 	case XML_ELEMENT_NODE:
8748 	case XML_ATTRIBUTE_NODE:
8749 	case XML_PI_NODE:
8750 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8751 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8752 	    else
8753 		valuePush(ctxt,
8754 		      xmlXPathCacheNewString(ctxt->context,
8755 			cur->nodesetval->nodeTab[i]->name));
8756 	    break;
8757 	case XML_NAMESPACE_DECL:
8758 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8759 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8760 	    break;
8761 	default:
8762 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8763 	}
8764     }
8765     xmlXPathReleaseObject(ctxt->context, cur);
8766 }
8767 
8768 /**
8769  * xmlXPathNamespaceURIFunction:
8770  * @ctxt:  the XPath Parser context
8771  * @nargs:  the number of arguments
8772  *
8773  * Implement the namespace-uri() XPath function
8774  *    string namespace-uri(node-set?)
8775  * The namespace-uri function returns a string containing the
8776  * namespace URI of the expanded name of the node in the argument
8777  * node-set that is first in document order. If the node-set is empty,
8778  * the first node has no name, or the expanded name has no namespace
8779  * URI, an empty string is returned. If the argument is omitted it
8780  * defaults to the context node.
8781  */
8782 void
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt,int nargs)8783 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8784     xmlXPathObjectPtr cur;
8785 
8786     if (ctxt == NULL) return;
8787 
8788     if (nargs == 0) {
8789 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8790 	    ctxt->context->node));
8791 	nargs = 1;
8792     }
8793     CHECK_ARITY(1);
8794     if ((ctxt->value == NULL) ||
8795 	((ctxt->value->type != XPATH_NODESET) &&
8796 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8797 	XP_ERROR(XPATH_INVALID_TYPE);
8798     cur = valuePop(ctxt);
8799 
8800     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8801 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8802     } else {
8803 	int i = 0; /* Should be first in document order !!!!! */
8804 	switch (cur->nodesetval->nodeTab[i]->type) {
8805 	case XML_ELEMENT_NODE:
8806 	case XML_ATTRIBUTE_NODE:
8807 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
8808 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8809 	    else
8810 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8811 			  cur->nodesetval->nodeTab[i]->ns->href));
8812 	    break;
8813 	default:
8814 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8815 	}
8816     }
8817     xmlXPathReleaseObject(ctxt->context, cur);
8818 }
8819 
8820 /**
8821  * xmlXPathNameFunction:
8822  * @ctxt:  the XPath Parser context
8823  * @nargs:  the number of arguments
8824  *
8825  * Implement the name() XPath function
8826  *    string name(node-set?)
8827  * The name function returns a string containing a QName representing
8828  * the name of the node in the argument node-set that is first in document
8829  * order. The QName must represent the name with respect to the namespace
8830  * declarations in effect on the node whose name is being represented.
8831  * Typically, this will be the form in which the name occurred in the XML
8832  * source. This need not be the case if there are namespace declarations
8833  * in effect on the node that associate multiple prefixes with the same
8834  * namespace. However, an implementation may include information about
8835  * the original prefix in its representation of nodes; in this case, an
8836  * implementation can ensure that the returned string is always the same
8837  * as the QName used in the XML source. If the argument it omitted it
8838  * defaults to the context node.
8839  * Libxml keep the original prefix so the "real qualified name" used is
8840  * returned.
8841  */
8842 static void
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8843 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8844 {
8845     xmlXPathObjectPtr cur;
8846 
8847     if (nargs == 0) {
8848 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8849 	    ctxt->context->node));
8850         nargs = 1;
8851     }
8852 
8853     CHECK_ARITY(1);
8854     if ((ctxt->value == NULL) ||
8855         ((ctxt->value->type != XPATH_NODESET) &&
8856          (ctxt->value->type != XPATH_XSLT_TREE)))
8857         XP_ERROR(XPATH_INVALID_TYPE);
8858     cur = valuePop(ctxt);
8859 
8860     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8861         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8862     } else {
8863         int i = 0;              /* Should be first in document order !!!!! */
8864 
8865         switch (cur->nodesetval->nodeTab[i]->type) {
8866             case XML_ELEMENT_NODE:
8867             case XML_ATTRIBUTE_NODE:
8868 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8869 		    valuePush(ctxt,
8870 			xmlXPathCacheNewCString(ctxt->context, ""));
8871 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8872                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8873 		    valuePush(ctxt,
8874 		        xmlXPathCacheNewString(ctxt->context,
8875 			    cur->nodesetval->nodeTab[i]->name));
8876 		} else {
8877 		    xmlChar *fullname;
8878 
8879 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8880 				     cur->nodesetval->nodeTab[i]->ns->prefix,
8881 				     NULL, 0);
8882 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
8883 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8884 		    if (fullname == NULL) {
8885 			XP_ERROR(XPATH_MEMORY_ERROR);
8886 		    }
8887 		    valuePush(ctxt, xmlXPathCacheWrapString(
8888 			ctxt->context, fullname));
8889                 }
8890                 break;
8891             default:
8892 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8893 		    cur->nodesetval->nodeTab[i]));
8894                 xmlXPathLocalNameFunction(ctxt, 1);
8895         }
8896     }
8897     xmlXPathReleaseObject(ctxt->context, cur);
8898 }
8899 
8900 
8901 /**
8902  * xmlXPathStringFunction:
8903  * @ctxt:  the XPath Parser context
8904  * @nargs:  the number of arguments
8905  *
8906  * Implement the string() XPath function
8907  *    string string(object?)
8908  * The string function converts an object to a string as follows:
8909  *    - A node-set is converted to a string by returning the value of
8910  *      the node in the node-set that is first in document order.
8911  *      If the node-set is empty, an empty string is returned.
8912  *    - A number is converted to a string as follows
8913  *      + NaN is converted to the string NaN
8914  *      + positive zero is converted to the string 0
8915  *      + negative zero is converted to the string 0
8916  *      + positive infinity is converted to the string Infinity
8917  *      + negative infinity is converted to the string -Infinity
8918  *      + if the number is an integer, the number is represented in
8919  *        decimal form as a Number with no decimal point and no leading
8920  *        zeros, preceded by a minus sign (-) if the number is negative
8921  *      + otherwise, the number is represented in decimal form as a
8922  *        Number including a decimal point with at least one digit
8923  *        before the decimal point and at least one digit after the
8924  *        decimal point, preceded by a minus sign (-) if the number
8925  *        is negative; there must be no leading zeros before the decimal
8926  *        point apart possibly from the one required digit immediately
8927  *        before the decimal point; beyond the one required digit
8928  *        after the decimal point there must be as many, but only as
8929  *        many, more digits as are needed to uniquely distinguish the
8930  *        number from all other IEEE 754 numeric values.
8931  *    - The boolean false value is converted to the string false.
8932  *      The boolean true value is converted to the string true.
8933  *
8934  * If the argument is omitted, it defaults to a node-set with the
8935  * context node as its only member.
8936  */
8937 void
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt,int nargs)8938 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8939     xmlXPathObjectPtr cur;
8940 
8941     if (ctxt == NULL) return;
8942     if (nargs == 0) {
8943     valuePush(ctxt,
8944 	xmlXPathCacheWrapString(ctxt->context,
8945 	    xmlXPathCastNodeToString(ctxt->context->node)));
8946 	return;
8947     }
8948 
8949     CHECK_ARITY(1);
8950     cur = valuePop(ctxt);
8951     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8952     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8953 }
8954 
8955 /**
8956  * xmlXPathStringLengthFunction:
8957  * @ctxt:  the XPath Parser context
8958  * @nargs:  the number of arguments
8959  *
8960  * Implement the string-length() XPath function
8961  *    number string-length(string?)
8962  * The string-length returns the number of characters in the string
8963  * (see [3.6 Strings]). If the argument is omitted, it defaults to
8964  * the context node converted to a string, in other words the value
8965  * of the context node.
8966  */
8967 void
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt,int nargs)8968 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8969     xmlXPathObjectPtr cur;
8970 
8971     if (nargs == 0) {
8972         if ((ctxt == NULL) || (ctxt->context == NULL))
8973 	    return;
8974 	if (ctxt->context->node == NULL) {
8975 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8976 	} else {
8977 	    xmlChar *content;
8978 
8979 	    content = xmlXPathCastNodeToString(ctxt->context->node);
8980 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8981 		xmlUTF8Strlen(content)));
8982 	    xmlFree(content);
8983 	}
8984 	return;
8985     }
8986     CHECK_ARITY(1);
8987     CAST_TO_STRING;
8988     CHECK_TYPE(XPATH_STRING);
8989     cur = valuePop(ctxt);
8990     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8991 	xmlUTF8Strlen(cur->stringval)));
8992     xmlXPathReleaseObject(ctxt->context, cur);
8993 }
8994 
8995 /**
8996  * xmlXPathConcatFunction:
8997  * @ctxt:  the XPath Parser context
8998  * @nargs:  the number of arguments
8999  *
9000  * Implement the concat() XPath function
9001  *    string concat(string, string, string*)
9002  * The concat function returns the concatenation of its arguments.
9003  */
9004 void
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt,int nargs)9005 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9006     xmlXPathObjectPtr cur, newobj;
9007     xmlChar *tmp;
9008 
9009     if (ctxt == NULL) return;
9010     if (nargs < 2) {
9011 	CHECK_ARITY(2);
9012     }
9013 
9014     CAST_TO_STRING;
9015     cur = valuePop(ctxt);
9016     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
9017 	xmlXPathReleaseObject(ctxt->context, cur);
9018 	return;
9019     }
9020     nargs--;
9021 
9022     while (nargs > 0) {
9023 	CAST_TO_STRING;
9024 	newobj = valuePop(ctxt);
9025 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
9026 	    xmlXPathReleaseObject(ctxt->context, newobj);
9027 	    xmlXPathReleaseObject(ctxt->context, cur);
9028 	    XP_ERROR(XPATH_INVALID_TYPE);
9029 	}
9030 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
9031 	newobj->stringval = cur->stringval;
9032 	cur->stringval = tmp;
9033 	xmlXPathReleaseObject(ctxt->context, newobj);
9034 	nargs--;
9035     }
9036     valuePush(ctxt, cur);
9037 }
9038 
9039 /**
9040  * xmlXPathContainsFunction:
9041  * @ctxt:  the XPath Parser context
9042  * @nargs:  the number of arguments
9043  *
9044  * Implement the contains() XPath function
9045  *    boolean contains(string, string)
9046  * The contains function returns true if the first argument string
9047  * contains the second argument string, and otherwise returns false.
9048  */
9049 void
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt,int nargs)9050 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9051     xmlXPathObjectPtr hay, needle;
9052 
9053     CHECK_ARITY(2);
9054     CAST_TO_STRING;
9055     CHECK_TYPE(XPATH_STRING);
9056     needle = valuePop(ctxt);
9057     CAST_TO_STRING;
9058     hay = valuePop(ctxt);
9059 
9060     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9061 	xmlXPathReleaseObject(ctxt->context, hay);
9062 	xmlXPathReleaseObject(ctxt->context, needle);
9063 	XP_ERROR(XPATH_INVALID_TYPE);
9064     }
9065     if (xmlStrstr(hay->stringval, needle->stringval))
9066 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9067     else
9068 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9069     xmlXPathReleaseObject(ctxt->context, hay);
9070     xmlXPathReleaseObject(ctxt->context, needle);
9071 }
9072 
9073 /**
9074  * xmlXPathStartsWithFunction:
9075  * @ctxt:  the XPath Parser context
9076  * @nargs:  the number of arguments
9077  *
9078  * Implement the starts-with() XPath function
9079  *    boolean starts-with(string, string)
9080  * The starts-with function returns true if the first argument string
9081  * starts with the second argument string, and otherwise returns false.
9082  */
9083 void
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt,int nargs)9084 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9085     xmlXPathObjectPtr hay, needle;
9086     int n;
9087 
9088     CHECK_ARITY(2);
9089     CAST_TO_STRING;
9090     CHECK_TYPE(XPATH_STRING);
9091     needle = valuePop(ctxt);
9092     CAST_TO_STRING;
9093     hay = valuePop(ctxt);
9094 
9095     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9096 	xmlXPathReleaseObject(ctxt->context, hay);
9097 	xmlXPathReleaseObject(ctxt->context, needle);
9098 	XP_ERROR(XPATH_INVALID_TYPE);
9099     }
9100     n = xmlStrlen(needle->stringval);
9101     if (xmlStrncmp(hay->stringval, needle->stringval, n))
9102         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9103     else
9104         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9105     xmlXPathReleaseObject(ctxt->context, hay);
9106     xmlXPathReleaseObject(ctxt->context, needle);
9107 }
9108 
9109 /**
9110  * xmlXPathSubstringFunction:
9111  * @ctxt:  the XPath Parser context
9112  * @nargs:  the number of arguments
9113  *
9114  * Implement the substring() XPath function
9115  *    string substring(string, number, number?)
9116  * The substring function returns the substring of the first argument
9117  * starting at the position specified in the second argument with
9118  * length specified in the third argument. For example,
9119  * substring("12345",2,3) returns "234". If the third argument is not
9120  * specified, it returns the substring starting at the position specified
9121  * in the second argument and continuing to the end of the string. For
9122  * example, substring("12345",2) returns "2345".  More precisely, each
9123  * character in the string (see [3.6 Strings]) is considered to have a
9124  * numeric position: the position of the first character is 1, the position
9125  * of the second character is 2 and so on. The returned substring contains
9126  * those characters for which the position of the character is greater than
9127  * or equal to the second argument and, if the third argument is specified,
9128  * less than the sum of the second and third arguments; the comparisons
9129  * and addition used for the above follow the standard IEEE 754 rules. Thus:
9130  *  - substring("12345", 1.5, 2.6) returns "234"
9131  *  - substring("12345", 0, 3) returns "12"
9132  *  - substring("12345", 0 div 0, 3) returns ""
9133  *  - substring("12345", 1, 0 div 0) returns ""
9134  *  - substring("12345", -42, 1 div 0) returns "12345"
9135  *  - substring("12345", -1 div 0, 1 div 0) returns ""
9136  */
9137 void
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt,int nargs)9138 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9139     xmlXPathObjectPtr str, start, len;
9140     double le=0, in;
9141     int i, l, m;
9142     xmlChar *ret;
9143 
9144     if (nargs < 2) {
9145 	CHECK_ARITY(2);
9146     }
9147     if (nargs > 3) {
9148 	CHECK_ARITY(3);
9149     }
9150     /*
9151      * take care of possible last (position) argument
9152     */
9153     if (nargs == 3) {
9154 	CAST_TO_NUMBER;
9155 	CHECK_TYPE(XPATH_NUMBER);
9156 	len = valuePop(ctxt);
9157 	le = len->floatval;
9158 	xmlXPathReleaseObject(ctxt->context, len);
9159     }
9160 
9161     CAST_TO_NUMBER;
9162     CHECK_TYPE(XPATH_NUMBER);
9163     start = valuePop(ctxt);
9164     in = start->floatval;
9165     xmlXPathReleaseObject(ctxt->context, start);
9166     CAST_TO_STRING;
9167     CHECK_TYPE(XPATH_STRING);
9168     str = valuePop(ctxt);
9169     m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9170 
9171     /*
9172      * If last pos not present, calculate last position
9173     */
9174     if (nargs != 3) {
9175 	le = (double)m;
9176 	if (in < 1.0)
9177 	    in = 1.0;
9178     }
9179 
9180     /* Need to check for the special cases where either
9181      * the index is NaN, the length is NaN, or both
9182      * arguments are infinity (relying on Inf + -Inf = NaN)
9183      */
9184     if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9185         /*
9186          * To meet the requirements of the spec, the arguments
9187 	 * must be converted to integer format before
9188 	 * initial index calculations are done
9189          *
9190          * First we go to integer form, rounding up
9191 	 * and checking for special cases
9192          */
9193         i = (int) in;
9194         if (((double)i)+0.5 <= in) i++;
9195 
9196 	if (xmlXPathIsInf(le) == 1) {
9197 	    l = m;
9198 	    if (i < 1)
9199 		i = 1;
9200 	}
9201 	else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9202 	    l = 0;
9203 	else {
9204 	    l = (int) le;
9205 	    if (((double)l)+0.5 <= le) l++;
9206 	}
9207 
9208 	/* Now we normalize inidices */
9209         i -= 1;
9210         l += i;
9211         if (i < 0)
9212             i = 0;
9213         if (l > m)
9214             l = m;
9215 
9216         /* number of chars to copy */
9217         l -= i;
9218 
9219         ret = xmlUTF8Strsub(str->stringval, i, l);
9220     }
9221     else {
9222         ret = NULL;
9223     }
9224     if (ret == NULL)
9225 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9226     else {
9227 	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9228 	xmlFree(ret);
9229     }
9230     xmlXPathReleaseObject(ctxt->context, str);
9231 }
9232 
9233 /**
9234  * xmlXPathSubstringBeforeFunction:
9235  * @ctxt:  the XPath Parser context
9236  * @nargs:  the number of arguments
9237  *
9238  * Implement the substring-before() XPath function
9239  *    string substring-before(string, string)
9240  * The substring-before function returns the substring of the first
9241  * argument string that precedes the first occurrence of the second
9242  * argument string in the first argument string, or the empty string
9243  * if the first argument string does not contain the second argument
9244  * string. For example, substring-before("1999/04/01","/") returns 1999.
9245  */
9246 void
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt,int nargs)9247 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9248   xmlXPathObjectPtr str;
9249   xmlXPathObjectPtr find;
9250   xmlBufPtr target;
9251   const xmlChar *point;
9252   int offset;
9253 
9254   CHECK_ARITY(2);
9255   CAST_TO_STRING;
9256   find = valuePop(ctxt);
9257   CAST_TO_STRING;
9258   str = valuePop(ctxt);
9259 
9260   target = xmlBufCreate();
9261   if (target) {
9262     point = xmlStrstr(str->stringval, find->stringval);
9263     if (point) {
9264       offset = (int)(point - str->stringval);
9265       xmlBufAdd(target, str->stringval, offset);
9266     }
9267     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9268 	xmlBufContent(target)));
9269     xmlBufFree(target);
9270   }
9271   xmlXPathReleaseObject(ctxt->context, str);
9272   xmlXPathReleaseObject(ctxt->context, find);
9273 }
9274 
9275 /**
9276  * xmlXPathSubstringAfterFunction:
9277  * @ctxt:  the XPath Parser context
9278  * @nargs:  the number of arguments
9279  *
9280  * Implement the substring-after() XPath function
9281  *    string substring-after(string, string)
9282  * The substring-after function returns the substring of the first
9283  * argument string that follows the first occurrence of the second
9284  * argument string in the first argument string, or the empty stringi
9285  * if the first argument string does not contain the second argument
9286  * string. For example, substring-after("1999/04/01","/") returns 04/01,
9287  * and substring-after("1999/04/01","19") returns 99/04/01.
9288  */
9289 void
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt,int nargs)9290 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9291   xmlXPathObjectPtr str;
9292   xmlXPathObjectPtr find;
9293   xmlBufPtr target;
9294   const xmlChar *point;
9295   int offset;
9296 
9297   CHECK_ARITY(2);
9298   CAST_TO_STRING;
9299   find = valuePop(ctxt);
9300   CAST_TO_STRING;
9301   str = valuePop(ctxt);
9302 
9303   target = xmlBufCreate();
9304   if (target) {
9305     point = xmlStrstr(str->stringval, find->stringval);
9306     if (point) {
9307       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9308       xmlBufAdd(target, &str->stringval[offset],
9309 		   xmlStrlen(str->stringval) - offset);
9310     }
9311     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9312 	xmlBufContent(target)));
9313     xmlBufFree(target);
9314   }
9315   xmlXPathReleaseObject(ctxt->context, str);
9316   xmlXPathReleaseObject(ctxt->context, find);
9317 }
9318 
9319 /**
9320  * xmlXPathNormalizeFunction:
9321  * @ctxt:  the XPath Parser context
9322  * @nargs:  the number of arguments
9323  *
9324  * Implement the normalize-space() XPath function
9325  *    string normalize-space(string?)
9326  * The normalize-space function returns the argument string with white
9327  * space normalized by stripping leading and trailing whitespace
9328  * and replacing sequences of whitespace characters by a single
9329  * space. Whitespace characters are the same allowed by the S production
9330  * in XML. If the argument is omitted, it defaults to the context
9331  * node converted to a string, in other words the value of the context node.
9332  */
9333 void
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt,int nargs)9334 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9335   xmlXPathObjectPtr obj = NULL;
9336   xmlChar *source = NULL;
9337   xmlBufPtr target;
9338   xmlChar blank;
9339 
9340   if (ctxt == NULL) return;
9341   if (nargs == 0) {
9342     /* Use current context node */
9343       valuePush(ctxt,
9344 	  xmlXPathCacheWrapString(ctxt->context,
9345 	    xmlXPathCastNodeToString(ctxt->context->node)));
9346     nargs = 1;
9347   }
9348 
9349   CHECK_ARITY(1);
9350   CAST_TO_STRING;
9351   CHECK_TYPE(XPATH_STRING);
9352   obj = valuePop(ctxt);
9353   source = obj->stringval;
9354 
9355   target = xmlBufCreate();
9356   if (target && source) {
9357 
9358     /* Skip leading whitespaces */
9359     while (IS_BLANK_CH(*source))
9360       source++;
9361 
9362     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9363     blank = 0;
9364     while (*source) {
9365       if (IS_BLANK_CH(*source)) {
9366 	blank = 0x20;
9367       } else {
9368 	if (blank) {
9369 	  xmlBufAdd(target, &blank, 1);
9370 	  blank = 0;
9371 	}
9372 	xmlBufAdd(target, source, 1);
9373       }
9374       source++;
9375     }
9376     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9377 	xmlBufContent(target)));
9378     xmlBufFree(target);
9379   }
9380   xmlXPathReleaseObject(ctxt->context, obj);
9381 }
9382 
9383 /**
9384  * xmlXPathTranslateFunction:
9385  * @ctxt:  the XPath Parser context
9386  * @nargs:  the number of arguments
9387  *
9388  * Implement the translate() XPath function
9389  *    string translate(string, string, string)
9390  * The translate function returns the first argument string with
9391  * occurrences of characters in the second argument string replaced
9392  * by the character at the corresponding position in the third argument
9393  * string. For example, translate("bar","abc","ABC") returns the string
9394  * BAr. If there is a character in the second argument string with no
9395  * character at a corresponding position in the third argument string
9396  * (because the second argument string is longer than the third argument
9397  * string), then occurrences of that character in the first argument
9398  * string are removed. For example, translate("--aaa--","abc-","ABC")
9399  * returns "AAA". If a character occurs more than once in second
9400  * argument string, then the first occurrence determines the replacement
9401  * character. If the third argument string is longer than the second
9402  * argument string, then excess characters are ignored.
9403  */
9404 void
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt,int nargs)9405 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9406     xmlXPathObjectPtr str;
9407     xmlXPathObjectPtr from;
9408     xmlXPathObjectPtr to;
9409     xmlBufPtr target;
9410     int offset, max;
9411     xmlChar ch;
9412     const xmlChar *point;
9413     xmlChar *cptr;
9414 
9415     CHECK_ARITY(3);
9416 
9417     CAST_TO_STRING;
9418     to = valuePop(ctxt);
9419     CAST_TO_STRING;
9420     from = valuePop(ctxt);
9421     CAST_TO_STRING;
9422     str = valuePop(ctxt);
9423 
9424     target = xmlBufCreate();
9425     if (target) {
9426 	max = xmlUTF8Strlen(to->stringval);
9427 	for (cptr = str->stringval; (ch=*cptr); ) {
9428 	    offset = xmlUTF8Strloc(from->stringval, cptr);
9429 	    if (offset >= 0) {
9430 		if (offset < max) {
9431 		    point = xmlUTF8Strpos(to->stringval, offset);
9432 		    if (point)
9433 			xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9434 		}
9435 	    } else
9436 		xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9437 
9438 	    /* Step to next character in input */
9439 	    cptr++;
9440 	    if ( ch & 0x80 ) {
9441 		/* if not simple ascii, verify proper format */
9442 		if ( (ch & 0xc0) != 0xc0 ) {
9443 		    xmlGenericError(xmlGenericErrorContext,
9444 			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
9445                     /* not asserting an XPath error is probably better */
9446 		    break;
9447 		}
9448 		/* then skip over remaining bytes for this char */
9449 		while ( (ch <<= 1) & 0x80 )
9450 		    if ( (*cptr++ & 0xc0) != 0x80 ) {
9451 			xmlGenericError(xmlGenericErrorContext,
9452 			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9453                         /* not asserting an XPath error is probably better */
9454 			break;
9455 		    }
9456 		if (ch & 0x80) /* must have had error encountered */
9457 		    break;
9458 	    }
9459 	}
9460     }
9461     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9462 	xmlBufContent(target)));
9463     xmlBufFree(target);
9464     xmlXPathReleaseObject(ctxt->context, str);
9465     xmlXPathReleaseObject(ctxt->context, from);
9466     xmlXPathReleaseObject(ctxt->context, to);
9467 }
9468 
9469 /**
9470  * xmlXPathBooleanFunction:
9471  * @ctxt:  the XPath Parser context
9472  * @nargs:  the number of arguments
9473  *
9474  * Implement the boolean() XPath function
9475  *    boolean boolean(object)
9476  * The boolean function converts its argument to a boolean as follows:
9477  *    - a number is true if and only if it is neither positive or
9478  *      negative zero nor NaN
9479  *    - a node-set is true if and only if it is non-empty
9480  *    - a string is true if and only if its length is non-zero
9481  */
9482 void
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt,int nargs)9483 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9484     xmlXPathObjectPtr cur;
9485 
9486     CHECK_ARITY(1);
9487     cur = valuePop(ctxt);
9488     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9489     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9490     valuePush(ctxt, cur);
9491 }
9492 
9493 /**
9494  * xmlXPathNotFunction:
9495  * @ctxt:  the XPath Parser context
9496  * @nargs:  the number of arguments
9497  *
9498  * Implement the not() XPath function
9499  *    boolean not(boolean)
9500  * The not function returns true if its argument is false,
9501  * and false otherwise.
9502  */
9503 void
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt,int nargs)9504 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9505     CHECK_ARITY(1);
9506     CAST_TO_BOOLEAN;
9507     CHECK_TYPE(XPATH_BOOLEAN);
9508     ctxt->value->boolval = ! ctxt->value->boolval;
9509 }
9510 
9511 /**
9512  * xmlXPathTrueFunction:
9513  * @ctxt:  the XPath Parser context
9514  * @nargs:  the number of arguments
9515  *
9516  * Implement the true() XPath function
9517  *    boolean true()
9518  */
9519 void
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt,int nargs)9520 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9521     CHECK_ARITY(0);
9522     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9523 }
9524 
9525 /**
9526  * xmlXPathFalseFunction:
9527  * @ctxt:  the XPath Parser context
9528  * @nargs:  the number of arguments
9529  *
9530  * Implement the false() XPath function
9531  *    boolean false()
9532  */
9533 void
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt,int nargs)9534 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9535     CHECK_ARITY(0);
9536     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9537 }
9538 
9539 /**
9540  * xmlXPathLangFunction:
9541  * @ctxt:  the XPath Parser context
9542  * @nargs:  the number of arguments
9543  *
9544  * Implement the lang() XPath function
9545  *    boolean lang(string)
9546  * The lang function returns true or false depending on whether the
9547  * language of the context node as specified by xml:lang attributes
9548  * is the same as or is a sublanguage of the language specified by
9549  * the argument string. The language of the context node is determined
9550  * by the value of the xml:lang attribute on the context node, or, if
9551  * the context node has no xml:lang attribute, by the value of the
9552  * xml:lang attribute on the nearest ancestor of the context node that
9553  * has an xml:lang attribute. If there is no such attribute, then lang
9554  * returns false. If there is such an attribute, then lang returns
9555  * true if the attribute value is equal to the argument ignoring case,
9556  * or if there is some suffix starting with - such that the attribute
9557  * value is equal to the argument ignoring that suffix of the attribute
9558  * value and ignoring case.
9559  */
9560 void
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt,int nargs)9561 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9562     xmlXPathObjectPtr val = NULL;
9563     const xmlChar *theLang = NULL;
9564     const xmlChar *lang;
9565     int ret = 0;
9566     int i;
9567 
9568     CHECK_ARITY(1);
9569     CAST_TO_STRING;
9570     CHECK_TYPE(XPATH_STRING);
9571     val = valuePop(ctxt);
9572     lang = val->stringval;
9573     theLang = xmlNodeGetLang(ctxt->context->node);
9574     if ((theLang != NULL) && (lang != NULL)) {
9575         for (i = 0;lang[i] != 0;i++)
9576 	    if (toupper(lang[i]) != toupper(theLang[i]))
9577 	        goto not_equal;
9578 	if ((theLang[i] == 0) || (theLang[i] == '-'))
9579 	    ret = 1;
9580     }
9581 not_equal:
9582     if (theLang != NULL)
9583 	xmlFree((void *)theLang);
9584 
9585     xmlXPathReleaseObject(ctxt->context, val);
9586     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9587 }
9588 
9589 /**
9590  * xmlXPathNumberFunction:
9591  * @ctxt:  the XPath Parser context
9592  * @nargs:  the number of arguments
9593  *
9594  * Implement the number() XPath function
9595  *    number number(object?)
9596  */
9597 void
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt,int nargs)9598 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9599     xmlXPathObjectPtr cur;
9600     double res;
9601 
9602     if (ctxt == NULL) return;
9603     if (nargs == 0) {
9604 	if (ctxt->context->node == NULL) {
9605 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9606 	} else {
9607 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9608 
9609 	    res = xmlXPathStringEvalNumber(content);
9610 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9611 	    xmlFree(content);
9612 	}
9613 	return;
9614     }
9615 
9616     CHECK_ARITY(1);
9617     cur = valuePop(ctxt);
9618     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9619 }
9620 
9621 /**
9622  * xmlXPathSumFunction:
9623  * @ctxt:  the XPath Parser context
9624  * @nargs:  the number of arguments
9625  *
9626  * Implement the sum() XPath function
9627  *    number sum(node-set)
9628  * The sum function returns the sum of the values of the nodes in
9629  * the argument node-set.
9630  */
9631 void
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt,int nargs)9632 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9633     xmlXPathObjectPtr cur;
9634     int i;
9635     double res = 0.0;
9636 
9637     CHECK_ARITY(1);
9638     if ((ctxt->value == NULL) ||
9639 	((ctxt->value->type != XPATH_NODESET) &&
9640 	 (ctxt->value->type != XPATH_XSLT_TREE)))
9641 	XP_ERROR(XPATH_INVALID_TYPE);
9642     cur = valuePop(ctxt);
9643 
9644     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9645 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9646 	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9647 	}
9648     }
9649     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9650     xmlXPathReleaseObject(ctxt->context, cur);
9651 }
9652 
9653 /**
9654  * xmlXPathFloorFunction:
9655  * @ctxt:  the XPath Parser context
9656  * @nargs:  the number of arguments
9657  *
9658  * Implement the floor() XPath function
9659  *    number floor(number)
9660  * The floor function returns the largest (closest to positive infinity)
9661  * number that is not greater than the argument and that is an integer.
9662  */
9663 void
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt,int nargs)9664 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9665     CHECK_ARITY(1);
9666     CAST_TO_NUMBER;
9667     CHECK_TYPE(XPATH_NUMBER);
9668 
9669     ctxt->value->floatval = floor(ctxt->value->floatval);
9670 }
9671 
9672 /**
9673  * xmlXPathCeilingFunction:
9674  * @ctxt:  the XPath Parser context
9675  * @nargs:  the number of arguments
9676  *
9677  * Implement the ceiling() XPath function
9678  *    number ceiling(number)
9679  * The ceiling function returns the smallest (closest to negative infinity)
9680  * number that is not less than the argument and that is an integer.
9681  */
9682 void
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt,int nargs)9683 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9684     CHECK_ARITY(1);
9685     CAST_TO_NUMBER;
9686     CHECK_TYPE(XPATH_NUMBER);
9687 
9688     ctxt->value->floatval = ceil(ctxt->value->floatval);
9689 }
9690 
9691 /**
9692  * xmlXPathRoundFunction:
9693  * @ctxt:  the XPath Parser context
9694  * @nargs:  the number of arguments
9695  *
9696  * Implement the round() XPath function
9697  *    number round(number)
9698  * The round function returns the number that is closest to the
9699  * argument and that is an integer. If there are two such numbers,
9700  * then the one that is closest to positive infinity is returned.
9701  */
9702 void
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt,int nargs)9703 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9704     double f;
9705 
9706     CHECK_ARITY(1);
9707     CAST_TO_NUMBER;
9708     CHECK_TYPE(XPATH_NUMBER);
9709 
9710     f = ctxt->value->floatval;
9711 
9712     if ((f >= -0.5) && (f < 0.5)) {
9713         /* Handles negative zero. */
9714         ctxt->value->floatval *= 0.0;
9715     }
9716     else {
9717         double rounded = floor(f);
9718         if (f - rounded >= 0.5)
9719             rounded += 1.0;
9720         ctxt->value->floatval = rounded;
9721     }
9722 }
9723 
9724 /************************************************************************
9725  *									*
9726  *			The Parser					*
9727  *									*
9728  ************************************************************************/
9729 
9730 /*
9731  * a few forward declarations since we use a recursive call based
9732  * implementation.
9733  */
9734 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9735 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9736 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9737 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9738 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9739 	                                  int qualified);
9740 
9741 /**
9742  * xmlXPathCurrentChar:
9743  * @ctxt:  the XPath parser context
9744  * @cur:  pointer to the beginning of the char
9745  * @len:  pointer to the length of the char read
9746  *
9747  * The current char value, if using UTF-8 this may actually span multiple
9748  * bytes in the input buffer.
9749  *
9750  * Returns the current char value and its length
9751  */
9752 
9753 static int
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt,int * len)9754 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9755     unsigned char c;
9756     unsigned int val;
9757     const xmlChar *cur;
9758 
9759     if (ctxt == NULL)
9760 	return(0);
9761     cur = ctxt->cur;
9762 
9763     /*
9764      * We are supposed to handle UTF8, check it's valid
9765      * From rfc2044: encoding of the Unicode values on UTF-8:
9766      *
9767      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9768      * 0000 0000-0000 007F   0xxxxxxx
9769      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9770      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9771      *
9772      * Check for the 0x110000 limit too
9773      */
9774     c = *cur;
9775     if (c & 0x80) {
9776 	if ((cur[1] & 0xc0) != 0x80)
9777 	    goto encoding_error;
9778 	if ((c & 0xe0) == 0xe0) {
9779 
9780 	    if ((cur[2] & 0xc0) != 0x80)
9781 		goto encoding_error;
9782 	    if ((c & 0xf0) == 0xf0) {
9783 		if (((c & 0xf8) != 0xf0) ||
9784 		    ((cur[3] & 0xc0) != 0x80))
9785 		    goto encoding_error;
9786 		/* 4-byte code */
9787 		*len = 4;
9788 		val = (cur[0] & 0x7) << 18;
9789 		val |= (cur[1] & 0x3f) << 12;
9790 		val |= (cur[2] & 0x3f) << 6;
9791 		val |= cur[3] & 0x3f;
9792 	    } else {
9793 	      /* 3-byte code */
9794 		*len = 3;
9795 		val = (cur[0] & 0xf) << 12;
9796 		val |= (cur[1] & 0x3f) << 6;
9797 		val |= cur[2] & 0x3f;
9798 	    }
9799 	} else {
9800 	  /* 2-byte code */
9801 	    *len = 2;
9802 	    val = (cur[0] & 0x1f) << 6;
9803 	    val |= cur[1] & 0x3f;
9804 	}
9805 	if (!IS_CHAR(val)) {
9806 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9807 	}
9808 	return(val);
9809     } else {
9810 	/* 1-byte code */
9811 	*len = 1;
9812 	return((int) *cur);
9813     }
9814 encoding_error:
9815     /*
9816      * If we detect an UTF8 error that probably means that the
9817      * input encoding didn't get properly advertised in the
9818      * declaration header. Report the error and switch the encoding
9819      * to ISO-Latin-1 (if you don't like this policy, just declare the
9820      * encoding !)
9821      */
9822     *len = 0;
9823     XP_ERROR0(XPATH_ENCODING_ERROR);
9824 }
9825 
9826 /**
9827  * xmlXPathParseNCName:
9828  * @ctxt:  the XPath Parser context
9829  *
9830  * parse an XML namespace non qualified name.
9831  *
9832  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9833  *
9834  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9835  *                       CombiningChar | Extender
9836  *
9837  * Returns the namespace name or NULL
9838  */
9839 
9840 xmlChar *
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt)9841 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9842     const xmlChar *in;
9843     xmlChar *ret;
9844     int count = 0;
9845 
9846     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9847     /*
9848      * Accelerator for simple ASCII names
9849      */
9850     in = ctxt->cur;
9851     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9852 	((*in >= 0x41) && (*in <= 0x5A)) ||
9853 	(*in == '_')) {
9854 	in++;
9855 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9856 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9857 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9858 	       (*in == '_') || (*in == '.') ||
9859 	       (*in == '-'))
9860 	    in++;
9861 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9862             (*in == '[') || (*in == ']') || (*in == ':') ||
9863             (*in == '@') || (*in == '*')) {
9864 	    count = in - ctxt->cur;
9865 	    if (count == 0)
9866 		return(NULL);
9867 	    ret = xmlStrndup(ctxt->cur, count);
9868 	    ctxt->cur = in;
9869 	    return(ret);
9870 	}
9871     }
9872     return(xmlXPathParseNameComplex(ctxt, 0));
9873 }
9874 
9875 
9876 /**
9877  * xmlXPathParseQName:
9878  * @ctxt:  the XPath Parser context
9879  * @prefix:  a xmlChar **
9880  *
9881  * parse an XML qualified name
9882  *
9883  * [NS 5] QName ::= (Prefix ':')? LocalPart
9884  *
9885  * [NS 6] Prefix ::= NCName
9886  *
9887  * [NS 7] LocalPart ::= NCName
9888  *
9889  * Returns the function returns the local part, and prefix is updated
9890  *   to get the Prefix if any.
9891  */
9892 
9893 static xmlChar *
xmlXPathParseQName(xmlXPathParserContextPtr ctxt,xmlChar ** prefix)9894 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9895     xmlChar *ret = NULL;
9896 
9897     *prefix = NULL;
9898     ret = xmlXPathParseNCName(ctxt);
9899     if (ret && CUR == ':') {
9900         *prefix = ret;
9901 	NEXT;
9902 	ret = xmlXPathParseNCName(ctxt);
9903     }
9904     return(ret);
9905 }
9906 
9907 /**
9908  * xmlXPathParseName:
9909  * @ctxt:  the XPath Parser context
9910  *
9911  * parse an XML name
9912  *
9913  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9914  *                  CombiningChar | Extender
9915  *
9916  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9917  *
9918  * Returns the namespace name or NULL
9919  */
9920 
9921 xmlChar *
xmlXPathParseName(xmlXPathParserContextPtr ctxt)9922 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9923     const xmlChar *in;
9924     xmlChar *ret;
9925     size_t count = 0;
9926 
9927     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9928     /*
9929      * Accelerator for simple ASCII names
9930      */
9931     in = ctxt->cur;
9932     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9933 	((*in >= 0x41) && (*in <= 0x5A)) ||
9934 	(*in == '_') || (*in == ':')) {
9935 	in++;
9936 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9937 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9938 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9939 	       (*in == '_') || (*in == '-') ||
9940 	       (*in == ':') || (*in == '.'))
9941 	    in++;
9942 	if ((*in > 0) && (*in < 0x80)) {
9943 	    count = in - ctxt->cur;
9944             if (count > XML_MAX_NAME_LENGTH) {
9945                 ctxt->cur = in;
9946                 XP_ERRORNULL(XPATH_EXPR_ERROR);
9947             }
9948 	    ret = xmlStrndup(ctxt->cur, count);
9949 	    ctxt->cur = in;
9950 	    return(ret);
9951 	}
9952     }
9953     return(xmlXPathParseNameComplex(ctxt, 1));
9954 }
9955 
9956 static xmlChar *
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,int qualified)9957 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9958     xmlChar buf[XML_MAX_NAMELEN + 5];
9959     int len = 0, l;
9960     int c;
9961 
9962     /*
9963      * Handler for more complex cases
9964      */
9965     c = CUR_CHAR(l);
9966     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9967         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9968         (c == '*') || /* accelerators */
9969 	(!IS_LETTER(c) && (c != '_') &&
9970          ((!qualified) || (c != ':')))) {
9971 	return(NULL);
9972     }
9973 
9974     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9975 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9976             (c == '.') || (c == '-') ||
9977 	    (c == '_') || ((qualified) && (c == ':')) ||
9978 	    (IS_COMBINING(c)) ||
9979 	    (IS_EXTENDER(c)))) {
9980 	COPY_BUF(l,buf,len,c);
9981 	NEXTL(l);
9982 	c = CUR_CHAR(l);
9983 	if (len >= XML_MAX_NAMELEN) {
9984 	    /*
9985 	     * Okay someone managed to make a huge name, so he's ready to pay
9986 	     * for the processing speed.
9987 	     */
9988 	    xmlChar *buffer;
9989 	    int max = len * 2;
9990 
9991             if (len > XML_MAX_NAME_LENGTH) {
9992                 XP_ERRORNULL(XPATH_EXPR_ERROR);
9993             }
9994 	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9995 	    if (buffer == NULL) {
9996 		XP_ERRORNULL(XPATH_MEMORY_ERROR);
9997 	    }
9998 	    memcpy(buffer, buf, len);
9999 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10000 		   (c == '.') || (c == '-') ||
10001 		   (c == '_') || ((qualified) && (c == ':')) ||
10002 		   (IS_COMBINING(c)) ||
10003 		   (IS_EXTENDER(c))) {
10004 		if (len + 10 > max) {
10005                     if (max > XML_MAX_NAME_LENGTH) {
10006                         XP_ERRORNULL(XPATH_EXPR_ERROR);
10007                     }
10008 		    max *= 2;
10009 		    buffer = (xmlChar *) xmlRealloc(buffer,
10010 			                            max * sizeof(xmlChar));
10011 		    if (buffer == NULL) {
10012 			XP_ERRORNULL(XPATH_MEMORY_ERROR);
10013 		    }
10014 		}
10015 		COPY_BUF(l,buffer,len,c);
10016 		NEXTL(l);
10017 		c = CUR_CHAR(l);
10018 	    }
10019 	    buffer[len] = 0;
10020 	    return(buffer);
10021 	}
10022     }
10023     if (len == 0)
10024 	return(NULL);
10025     return(xmlStrndup(buf, len));
10026 }
10027 
10028 #define MAX_FRAC 20
10029 
10030 /**
10031  * xmlXPathStringEvalNumber:
10032  * @str:  A string to scan
10033  *
10034  *  [30a]  Float  ::= Number ('e' Digits?)?
10035  *
10036  *  [30]   Number ::=   Digits ('.' Digits?)?
10037  *                    | '.' Digits
10038  *  [31]   Digits ::=   [0-9]+
10039  *
10040  * Compile a Number in the string
10041  * In complement of the Number expression, this function also handles
10042  * negative values : '-' Number.
10043  *
10044  * Returns the double value.
10045  */
10046 double
xmlXPathStringEvalNumber(const xmlChar * str)10047 xmlXPathStringEvalNumber(const xmlChar *str) {
10048     const xmlChar *cur = str;
10049     double ret;
10050     int ok = 0;
10051     int isneg = 0;
10052     int exponent = 0;
10053     int is_exponent_negative = 0;
10054 #ifdef __GNUC__
10055     unsigned long tmp = 0;
10056     double temp;
10057 #endif
10058     if (cur == NULL) return(0);
10059     while (IS_BLANK_CH(*cur)) cur++;
10060     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10061         return(NAN);
10062     }
10063     if (*cur == '-') {
10064 	isneg = 1;
10065 	cur++;
10066     }
10067 
10068 #ifdef __GNUC__
10069     /*
10070      * tmp/temp is a workaround against a gcc compiler bug
10071      * http://veillard.com/gcc.bug
10072      */
10073     ret = 0;
10074     while ((*cur >= '0') && (*cur <= '9')) {
10075 	ret = ret * 10;
10076 	tmp = (*cur - '0');
10077 	ok = 1;
10078 	cur++;
10079 	temp = (double) tmp;
10080 	ret = ret + temp;
10081     }
10082 #else
10083     ret = 0;
10084     while ((*cur >= '0') && (*cur <= '9')) {
10085 	ret = ret * 10 + (*cur - '0');
10086 	ok = 1;
10087 	cur++;
10088     }
10089 #endif
10090 
10091     if (*cur == '.') {
10092 	int v, frac = 0, max;
10093 	double fraction = 0;
10094 
10095         cur++;
10096 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10097 	    return(NAN);
10098 	}
10099         while (*cur == '0') {
10100 	    frac = frac + 1;
10101 	    cur++;
10102         }
10103         max = frac + MAX_FRAC;
10104 	while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10105 	    v = (*cur - '0');
10106 	    fraction = fraction * 10 + v;
10107 	    frac = frac + 1;
10108 	    cur++;
10109 	}
10110 	fraction /= pow(10.0, frac);
10111 	ret = ret + fraction;
10112 	while ((*cur >= '0') && (*cur <= '9'))
10113 	    cur++;
10114     }
10115     if ((*cur == 'e') || (*cur == 'E')) {
10116       cur++;
10117       if (*cur == '-') {
10118 	is_exponent_negative = 1;
10119 	cur++;
10120       } else if (*cur == '+') {
10121         cur++;
10122       }
10123       while ((*cur >= '0') && (*cur <= '9')) {
10124         if (exponent < 1000000)
10125 	  exponent = exponent * 10 + (*cur - '0');
10126 	cur++;
10127       }
10128     }
10129     while (IS_BLANK_CH(*cur)) cur++;
10130     if (*cur != 0) return(NAN);
10131     if (isneg) ret = -ret;
10132     if (is_exponent_negative) exponent = -exponent;
10133     ret *= pow(10.0, (double)exponent);
10134     return(ret);
10135 }
10136 
10137 /**
10138  * xmlXPathCompNumber:
10139  * @ctxt:  the XPath Parser context
10140  *
10141  *  [30]   Number ::=   Digits ('.' Digits?)?
10142  *                    | '.' Digits
10143  *  [31]   Digits ::=   [0-9]+
10144  *
10145  * Compile a Number, then push it on the stack
10146  *
10147  */
10148 static void
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)10149 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10150 {
10151     double ret = 0.0;
10152     int ok = 0;
10153     int exponent = 0;
10154     int is_exponent_negative = 0;
10155 #ifdef __GNUC__
10156     unsigned long tmp = 0;
10157     double temp;
10158 #endif
10159 
10160     CHECK_ERROR;
10161     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10162         XP_ERROR(XPATH_NUMBER_ERROR);
10163     }
10164 #ifdef __GNUC__
10165     /*
10166      * tmp/temp is a workaround against a gcc compiler bug
10167      * http://veillard.com/gcc.bug
10168      */
10169     ret = 0;
10170     while ((CUR >= '0') && (CUR <= '9')) {
10171 	ret = ret * 10;
10172 	tmp = (CUR - '0');
10173         ok = 1;
10174         NEXT;
10175 	temp = (double) tmp;
10176 	ret = ret + temp;
10177     }
10178 #else
10179     ret = 0;
10180     while ((CUR >= '0') && (CUR <= '9')) {
10181 	ret = ret * 10 + (CUR - '0');
10182 	ok = 1;
10183 	NEXT;
10184     }
10185 #endif
10186     if (CUR == '.') {
10187 	int v, frac = 0, max;
10188 	double fraction = 0;
10189 
10190         NEXT;
10191         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10192             XP_ERROR(XPATH_NUMBER_ERROR);
10193         }
10194         while (CUR == '0') {
10195             frac = frac + 1;
10196             NEXT;
10197         }
10198         max = frac + MAX_FRAC;
10199         while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10200 	    v = (CUR - '0');
10201 	    fraction = fraction * 10 + v;
10202 	    frac = frac + 1;
10203             NEXT;
10204         }
10205         fraction /= pow(10.0, frac);
10206         ret = ret + fraction;
10207         while ((CUR >= '0') && (CUR <= '9'))
10208             NEXT;
10209     }
10210     if ((CUR == 'e') || (CUR == 'E')) {
10211         NEXT;
10212         if (CUR == '-') {
10213             is_exponent_negative = 1;
10214             NEXT;
10215         } else if (CUR == '+') {
10216 	    NEXT;
10217 	}
10218         while ((CUR >= '0') && (CUR <= '9')) {
10219             if (exponent < 1000000)
10220                 exponent = exponent * 10 + (CUR - '0');
10221             NEXT;
10222         }
10223         if (is_exponent_negative)
10224             exponent = -exponent;
10225         ret *= pow(10.0, (double) exponent);
10226     }
10227     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10228                    xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10229 }
10230 
10231 /**
10232  * xmlXPathParseLiteral:
10233  * @ctxt:  the XPath Parser context
10234  *
10235  * Parse a Literal
10236  *
10237  *  [29]   Literal ::=   '"' [^"]* '"'
10238  *                    | "'" [^']* "'"
10239  *
10240  * Returns the value found or NULL in case of error
10241  */
10242 static xmlChar *
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt)10243 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10244     const xmlChar *q;
10245     xmlChar *ret = NULL;
10246 
10247     if (CUR == '"') {
10248         NEXT;
10249 	q = CUR_PTR;
10250 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10251 	    NEXT;
10252 	if (!IS_CHAR_CH(CUR)) {
10253 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10254 	} else {
10255 	    ret = xmlStrndup(q, CUR_PTR - q);
10256 	    NEXT;
10257         }
10258     } else if (CUR == '\'') {
10259         NEXT;
10260 	q = CUR_PTR;
10261 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10262 	    NEXT;
10263 	if (!IS_CHAR_CH(CUR)) {
10264 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10265 	} else {
10266 	    ret = xmlStrndup(q, CUR_PTR - q);
10267 	    NEXT;
10268         }
10269     } else {
10270 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10271     }
10272     return(ret);
10273 }
10274 
10275 /**
10276  * xmlXPathCompLiteral:
10277  * @ctxt:  the XPath Parser context
10278  *
10279  * Parse a Literal and push it on the stack.
10280  *
10281  *  [29]   Literal ::=   '"' [^"]* '"'
10282  *                    | "'" [^']* "'"
10283  *
10284  * TODO: xmlXPathCompLiteral memory allocation could be improved.
10285  */
10286 static void
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt)10287 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10288     const xmlChar *q;
10289     xmlChar *ret = NULL;
10290 
10291     if (CUR == '"') {
10292         NEXT;
10293 	q = CUR_PTR;
10294 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10295 	    NEXT;
10296 	if (!IS_CHAR_CH(CUR)) {
10297 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10298 	} else {
10299 	    ret = xmlStrndup(q, CUR_PTR - q);
10300 	    NEXT;
10301         }
10302     } else if (CUR == '\'') {
10303         NEXT;
10304 	q = CUR_PTR;
10305 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10306 	    NEXT;
10307 	if (!IS_CHAR_CH(CUR)) {
10308 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10309 	} else {
10310 	    ret = xmlStrndup(q, CUR_PTR - q);
10311 	    NEXT;
10312         }
10313     } else {
10314 	XP_ERROR(XPATH_START_LITERAL_ERROR);
10315     }
10316     if (ret == NULL) return;
10317     PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10318 	           xmlXPathCacheNewString(ctxt->context, ret), NULL);
10319     xmlFree(ret);
10320 }
10321 
10322 /**
10323  * xmlXPathCompVariableReference:
10324  * @ctxt:  the XPath Parser context
10325  *
10326  * Parse a VariableReference, evaluate it and push it on the stack.
10327  *
10328  * The variable bindings consist of a mapping from variable names
10329  * to variable values. The value of a variable is an object, which can be
10330  * of any of the types that are possible for the value of an expression,
10331  * and may also be of additional types not specified here.
10332  *
10333  * Early evaluation is possible since:
10334  * The variable bindings [...] used to evaluate a subexpression are
10335  * always the same as those used to evaluate the containing expression.
10336  *
10337  *  [36]   VariableReference ::=   '$' QName
10338  */
10339 static void
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt)10340 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10341     xmlChar *name;
10342     xmlChar *prefix;
10343 
10344     SKIP_BLANKS;
10345     if (CUR != '$') {
10346 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10347     }
10348     NEXT;
10349     name = xmlXPathParseQName(ctxt, &prefix);
10350     if (name == NULL) {
10351         xmlFree(prefix);
10352 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10353     }
10354     ctxt->comp->last = -1;
10355     PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10356 	           name, prefix);
10357     SKIP_BLANKS;
10358     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10359 	XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10360     }
10361 }
10362 
10363 /**
10364  * xmlXPathIsNodeType:
10365  * @name:  a name string
10366  *
10367  * Is the name given a NodeType one.
10368  *
10369  *  [38]   NodeType ::=   'comment'
10370  *                    | 'text'
10371  *                    | 'processing-instruction'
10372  *                    | 'node'
10373  *
10374  * Returns 1 if true 0 otherwise
10375  */
10376 int
xmlXPathIsNodeType(const xmlChar * name)10377 xmlXPathIsNodeType(const xmlChar *name) {
10378     if (name == NULL)
10379 	return(0);
10380 
10381     if (xmlStrEqual(name, BAD_CAST "node"))
10382 	return(1);
10383     if (xmlStrEqual(name, BAD_CAST "text"))
10384 	return(1);
10385     if (xmlStrEqual(name, BAD_CAST "comment"))
10386 	return(1);
10387     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10388 	return(1);
10389     return(0);
10390 }
10391 
10392 /**
10393  * xmlXPathCompFunctionCall:
10394  * @ctxt:  the XPath Parser context
10395  *
10396  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10397  *  [17]   Argument ::=   Expr
10398  *
10399  * Compile a function call, the evaluation of all arguments are
10400  * pushed on the stack
10401  */
10402 static void
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt)10403 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10404     xmlChar *name;
10405     xmlChar *prefix;
10406     int nbargs = 0;
10407     int sort = 1;
10408 
10409     name = xmlXPathParseQName(ctxt, &prefix);
10410     if (name == NULL) {
10411 	xmlFree(prefix);
10412 	XP_ERROR(XPATH_EXPR_ERROR);
10413     }
10414     SKIP_BLANKS;
10415 #ifdef DEBUG_EXPR
10416     if (prefix == NULL)
10417 	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10418 			name);
10419     else
10420 	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10421 			prefix, name);
10422 #endif
10423 
10424     if (CUR != '(') {
10425 	xmlFree(name);
10426 	xmlFree(prefix);
10427 	XP_ERROR(XPATH_EXPR_ERROR);
10428     }
10429     NEXT;
10430     SKIP_BLANKS;
10431 
10432     /*
10433     * Optimization for count(): we don't need the node-set to be sorted.
10434     */
10435     if ((prefix == NULL) && (name[0] == 'c') &&
10436 	xmlStrEqual(name, BAD_CAST "count"))
10437     {
10438 	sort = 0;
10439     }
10440     ctxt->comp->last = -1;
10441     if (CUR != ')') {
10442 	while (CUR != 0) {
10443 	    int op1 = ctxt->comp->last;
10444 	    ctxt->comp->last = -1;
10445 	    xmlXPathCompileExpr(ctxt, sort);
10446 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
10447 		xmlFree(name);
10448 		xmlFree(prefix);
10449 		return;
10450 	    }
10451 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10452 	    nbargs++;
10453 	    if (CUR == ')') break;
10454 	    if (CUR != ',') {
10455 		xmlFree(name);
10456 		xmlFree(prefix);
10457 		XP_ERROR(XPATH_EXPR_ERROR);
10458 	    }
10459 	    NEXT;
10460 	    SKIP_BLANKS;
10461 	}
10462     }
10463     PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10464 	           name, prefix);
10465     NEXT;
10466     SKIP_BLANKS;
10467 }
10468 
10469 /**
10470  * xmlXPathCompPrimaryExpr:
10471  * @ctxt:  the XPath Parser context
10472  *
10473  *  [15]   PrimaryExpr ::=   VariableReference
10474  *                | '(' Expr ')'
10475  *                | Literal
10476  *                | Number
10477  *                | FunctionCall
10478  *
10479  * Compile a primary expression.
10480  */
10481 static void
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt)10482 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10483     SKIP_BLANKS;
10484     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10485     else if (CUR == '(') {
10486 	NEXT;
10487 	SKIP_BLANKS;
10488 	xmlXPathCompileExpr(ctxt, 1);
10489 	CHECK_ERROR;
10490 	if (CUR != ')') {
10491 	    XP_ERROR(XPATH_EXPR_ERROR);
10492 	}
10493 	NEXT;
10494 	SKIP_BLANKS;
10495     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10496 	xmlXPathCompNumber(ctxt);
10497     } else if ((CUR == '\'') || (CUR == '"')) {
10498 	xmlXPathCompLiteral(ctxt);
10499     } else {
10500 	xmlXPathCompFunctionCall(ctxt);
10501     }
10502     SKIP_BLANKS;
10503 }
10504 
10505 /**
10506  * xmlXPathCompFilterExpr:
10507  * @ctxt:  the XPath Parser context
10508  *
10509  *  [20]   FilterExpr ::=   PrimaryExpr
10510  *               | FilterExpr Predicate
10511  *
10512  * Compile a filter expression.
10513  * Square brackets are used to filter expressions in the same way that
10514  * they are used in location paths. It is an error if the expression to
10515  * be filtered does not evaluate to a node-set. The context node list
10516  * used for evaluating the expression in square brackets is the node-set
10517  * to be filtered listed in document order.
10518  */
10519 
10520 static void
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt)10521 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10522     xmlXPathCompPrimaryExpr(ctxt);
10523     CHECK_ERROR;
10524     SKIP_BLANKS;
10525 
10526     while (CUR == '[') {
10527 	xmlXPathCompPredicate(ctxt, 1);
10528 	SKIP_BLANKS;
10529     }
10530 
10531 
10532 }
10533 
10534 /**
10535  * xmlXPathScanName:
10536  * @ctxt:  the XPath Parser context
10537  *
10538  * Trickery: parse an XML name but without consuming the input flow
10539  * Needed to avoid insanity in the parser state.
10540  *
10541  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10542  *                  CombiningChar | Extender
10543  *
10544  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10545  *
10546  * [6] Names ::= Name (S Name)*
10547  *
10548  * Returns the Name parsed or NULL
10549  */
10550 
10551 static xmlChar *
xmlXPathScanName(xmlXPathParserContextPtr ctxt)10552 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10553     int len = 0, l;
10554     int c;
10555     const xmlChar *cur;
10556     xmlChar *ret;
10557 
10558     cur = ctxt->cur;
10559 
10560     c = CUR_CHAR(l);
10561     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10562 	(!IS_LETTER(c) && (c != '_') &&
10563          (c != ':'))) {
10564 	return(NULL);
10565     }
10566 
10567     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10568 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10569             (c == '.') || (c == '-') ||
10570 	    (c == '_') || (c == ':') ||
10571 	    (IS_COMBINING(c)) ||
10572 	    (IS_EXTENDER(c)))) {
10573 	len += l;
10574 	NEXTL(l);
10575 	c = CUR_CHAR(l);
10576     }
10577     ret = xmlStrndup(cur, ctxt->cur - cur);
10578     ctxt->cur = cur;
10579     return(ret);
10580 }
10581 
10582 /**
10583  * xmlXPathCompPathExpr:
10584  * @ctxt:  the XPath Parser context
10585  *
10586  *  [19]   PathExpr ::=   LocationPath
10587  *               | FilterExpr
10588  *               | FilterExpr '/' RelativeLocationPath
10589  *               | FilterExpr '//' RelativeLocationPath
10590  *
10591  * Compile a path expression.
10592  * The / operator and // operators combine an arbitrary expression
10593  * and a relative location path. It is an error if the expression
10594  * does not evaluate to a node-set.
10595  * The / operator does composition in the same way as when / is
10596  * used in a location path. As in location paths, // is short for
10597  * /descendant-or-self::node()/.
10598  */
10599 
10600 static void
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt)10601 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10602     int lc = 1;           /* Should we branch to LocationPath ?         */
10603     xmlChar *name = NULL; /* we may have to preparse a name to find out */
10604 
10605     SKIP_BLANKS;
10606     if ((CUR == '$') || (CUR == '(') ||
10607 	(IS_ASCII_DIGIT(CUR)) ||
10608         (CUR == '\'') || (CUR == '"') ||
10609 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10610 	lc = 0;
10611     } else if (CUR == '*') {
10612 	/* relative or absolute location path */
10613 	lc = 1;
10614     } else if (CUR == '/') {
10615 	/* relative or absolute location path */
10616 	lc = 1;
10617     } else if (CUR == '@') {
10618 	/* relative abbreviated attribute location path */
10619 	lc = 1;
10620     } else if (CUR == '.') {
10621 	/* relative abbreviated attribute location path */
10622 	lc = 1;
10623     } else {
10624 	/*
10625 	 * Problem is finding if we have a name here whether it's:
10626 	 *   - a nodetype
10627 	 *   - a function call in which case it's followed by '('
10628 	 *   - an axis in which case it's followed by ':'
10629 	 *   - a element name
10630 	 * We do an a priori analysis here rather than having to
10631 	 * maintain parsed token content through the recursive function
10632 	 * calls. This looks uglier but makes the code easier to
10633 	 * read/write/debug.
10634 	 */
10635 	SKIP_BLANKS;
10636 	name = xmlXPathScanName(ctxt);
10637 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10638 #ifdef DEBUG_STEP
10639 	    xmlGenericError(xmlGenericErrorContext,
10640 		    "PathExpr: Axis\n");
10641 #endif
10642 	    lc = 1;
10643 	    xmlFree(name);
10644 	} else if (name != NULL) {
10645 	    int len =xmlStrlen(name);
10646 
10647 
10648 	    while (NXT(len) != 0) {
10649 		if (NXT(len) == '/') {
10650 		    /* element name */
10651 #ifdef DEBUG_STEP
10652 		    xmlGenericError(xmlGenericErrorContext,
10653 			    "PathExpr: AbbrRelLocation\n");
10654 #endif
10655 		    lc = 1;
10656 		    break;
10657 		} else if (IS_BLANK_CH(NXT(len))) {
10658 		    /* ignore blanks */
10659 		    ;
10660 		} else if (NXT(len) == ':') {
10661 #ifdef DEBUG_STEP
10662 		    xmlGenericError(xmlGenericErrorContext,
10663 			    "PathExpr: AbbrRelLocation\n");
10664 #endif
10665 		    lc = 1;
10666 		    break;
10667 		} else if ((NXT(len) == '(')) {
10668 		    /* Node Type or Function */
10669 		    if (xmlXPathIsNodeType(name)) {
10670 #ifdef DEBUG_STEP
10671 		        xmlGenericError(xmlGenericErrorContext,
10672 				"PathExpr: Type search\n");
10673 #endif
10674 			lc = 1;
10675 #ifdef LIBXML_XPTR_ENABLED
10676                     } else if (ctxt->xptr &&
10677                                xmlStrEqual(name, BAD_CAST "range-to")) {
10678                         lc = 1;
10679 #endif
10680 		    } else {
10681 #ifdef DEBUG_STEP
10682 		        xmlGenericError(xmlGenericErrorContext,
10683 				"PathExpr: function call\n");
10684 #endif
10685 			lc = 0;
10686 		    }
10687                     break;
10688 		} else if ((NXT(len) == '[')) {
10689 		    /* element name */
10690 #ifdef DEBUG_STEP
10691 		    xmlGenericError(xmlGenericErrorContext,
10692 			    "PathExpr: AbbrRelLocation\n");
10693 #endif
10694 		    lc = 1;
10695 		    break;
10696 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10697 			   (NXT(len) == '=')) {
10698 		    lc = 1;
10699 		    break;
10700 		} else {
10701 		    lc = 1;
10702 		    break;
10703 		}
10704 		len++;
10705 	    }
10706 	    if (NXT(len) == 0) {
10707 #ifdef DEBUG_STEP
10708 		xmlGenericError(xmlGenericErrorContext,
10709 			"PathExpr: AbbrRelLocation\n");
10710 #endif
10711 		/* element name */
10712 		lc = 1;
10713 	    }
10714 	    xmlFree(name);
10715 	} else {
10716 	    /* make sure all cases are covered explicitly */
10717 	    XP_ERROR(XPATH_EXPR_ERROR);
10718 	}
10719     }
10720 
10721     if (lc) {
10722 	if (CUR == '/') {
10723 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10724 	} else {
10725 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10726 	}
10727 	xmlXPathCompLocationPath(ctxt);
10728     } else {
10729 	xmlXPathCompFilterExpr(ctxt);
10730 	CHECK_ERROR;
10731 	if ((CUR == '/') && (NXT(1) == '/')) {
10732 	    SKIP(2);
10733 	    SKIP_BLANKS;
10734 
10735 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10736 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10737 	    PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10738 
10739 	    xmlXPathCompRelativeLocationPath(ctxt);
10740 	} else if (CUR == '/') {
10741 	    xmlXPathCompRelativeLocationPath(ctxt);
10742 	}
10743     }
10744     SKIP_BLANKS;
10745 }
10746 
10747 /**
10748  * xmlXPathCompUnionExpr:
10749  * @ctxt:  the XPath Parser context
10750  *
10751  *  [18]   UnionExpr ::=   PathExpr
10752  *               | UnionExpr '|' PathExpr
10753  *
10754  * Compile an union expression.
10755  */
10756 
10757 static void
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt)10758 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10759     xmlXPathCompPathExpr(ctxt);
10760     CHECK_ERROR;
10761     SKIP_BLANKS;
10762     while (CUR == '|') {
10763 	int op1 = ctxt->comp->last;
10764 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10765 
10766 	NEXT;
10767 	SKIP_BLANKS;
10768 	xmlXPathCompPathExpr(ctxt);
10769 
10770 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10771 
10772 	SKIP_BLANKS;
10773     }
10774 }
10775 
10776 /**
10777  * xmlXPathCompUnaryExpr:
10778  * @ctxt:  the XPath Parser context
10779  *
10780  *  [27]   UnaryExpr ::=   UnionExpr
10781  *                   | '-' UnaryExpr
10782  *
10783  * Compile an unary expression.
10784  */
10785 
10786 static void
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt)10787 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10788     int minus = 0;
10789     int found = 0;
10790 
10791     SKIP_BLANKS;
10792     while (CUR == '-') {
10793         minus = 1 - minus;
10794 	found = 1;
10795 	NEXT;
10796 	SKIP_BLANKS;
10797     }
10798 
10799     xmlXPathCompUnionExpr(ctxt);
10800     CHECK_ERROR;
10801     if (found) {
10802 	if (minus)
10803 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10804 	else
10805 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10806     }
10807 }
10808 
10809 /**
10810  * xmlXPathCompMultiplicativeExpr:
10811  * @ctxt:  the XPath Parser context
10812  *
10813  *  [26]   MultiplicativeExpr ::=   UnaryExpr
10814  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10815  *                   | MultiplicativeExpr 'div' UnaryExpr
10816  *                   | MultiplicativeExpr 'mod' UnaryExpr
10817  *  [34]   MultiplyOperator ::=   '*'
10818  *
10819  * Compile an Additive expression.
10820  */
10821 
10822 static void
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt)10823 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10824     xmlXPathCompUnaryExpr(ctxt);
10825     CHECK_ERROR;
10826     SKIP_BLANKS;
10827     while ((CUR == '*') ||
10828            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10829            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10830 	int op = -1;
10831 	int op1 = ctxt->comp->last;
10832 
10833         if (CUR == '*') {
10834 	    op = 0;
10835 	    NEXT;
10836 	} else if (CUR == 'd') {
10837 	    op = 1;
10838 	    SKIP(3);
10839 	} else if (CUR == 'm') {
10840 	    op = 2;
10841 	    SKIP(3);
10842 	}
10843 	SKIP_BLANKS;
10844         xmlXPathCompUnaryExpr(ctxt);
10845 	CHECK_ERROR;
10846 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10847 	SKIP_BLANKS;
10848     }
10849 }
10850 
10851 /**
10852  * xmlXPathCompAdditiveExpr:
10853  * @ctxt:  the XPath Parser context
10854  *
10855  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10856  *                   | AdditiveExpr '+' MultiplicativeExpr
10857  *                   | AdditiveExpr '-' MultiplicativeExpr
10858  *
10859  * Compile an Additive expression.
10860  */
10861 
10862 static void
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt)10863 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10864 
10865     xmlXPathCompMultiplicativeExpr(ctxt);
10866     CHECK_ERROR;
10867     SKIP_BLANKS;
10868     while ((CUR == '+') || (CUR == '-')) {
10869 	int plus;
10870 	int op1 = ctxt->comp->last;
10871 
10872         if (CUR == '+') plus = 1;
10873 	else plus = 0;
10874 	NEXT;
10875 	SKIP_BLANKS;
10876         xmlXPathCompMultiplicativeExpr(ctxt);
10877 	CHECK_ERROR;
10878 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10879 	SKIP_BLANKS;
10880     }
10881 }
10882 
10883 /**
10884  * xmlXPathCompRelationalExpr:
10885  * @ctxt:  the XPath Parser context
10886  *
10887  *  [24]   RelationalExpr ::=   AdditiveExpr
10888  *                 | RelationalExpr '<' AdditiveExpr
10889  *                 | RelationalExpr '>' AdditiveExpr
10890  *                 | RelationalExpr '<=' AdditiveExpr
10891  *                 | RelationalExpr '>=' AdditiveExpr
10892  *
10893  *  A <= B > C is allowed ? Answer from James, yes with
10894  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10895  *  which is basically what got implemented.
10896  *
10897  * Compile a Relational expression, then push the result
10898  * on the stack
10899  */
10900 
10901 static void
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt)10902 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10903     xmlXPathCompAdditiveExpr(ctxt);
10904     CHECK_ERROR;
10905     SKIP_BLANKS;
10906     while ((CUR == '<') ||
10907            (CUR == '>') ||
10908            ((CUR == '<') && (NXT(1) == '=')) ||
10909            ((CUR == '>') && (NXT(1) == '='))) {
10910 	int inf, strict;
10911 	int op1 = ctxt->comp->last;
10912 
10913         if (CUR == '<') inf = 1;
10914 	else inf = 0;
10915 	if (NXT(1) == '=') strict = 0;
10916 	else strict = 1;
10917 	NEXT;
10918 	if (!strict) NEXT;
10919 	SKIP_BLANKS;
10920         xmlXPathCompAdditiveExpr(ctxt);
10921 	CHECK_ERROR;
10922 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10923 	SKIP_BLANKS;
10924     }
10925 }
10926 
10927 /**
10928  * xmlXPathCompEqualityExpr:
10929  * @ctxt:  the XPath Parser context
10930  *
10931  *  [23]   EqualityExpr ::=   RelationalExpr
10932  *                 | EqualityExpr '=' RelationalExpr
10933  *                 | EqualityExpr '!=' RelationalExpr
10934  *
10935  *  A != B != C is allowed ? Answer from James, yes with
10936  *  (RelationalExpr = RelationalExpr) = RelationalExpr
10937  *  (RelationalExpr != RelationalExpr) != RelationalExpr
10938  *  which is basically what got implemented.
10939  *
10940  * Compile an Equality expression.
10941  *
10942  */
10943 static void
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt)10944 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10945     xmlXPathCompRelationalExpr(ctxt);
10946     CHECK_ERROR;
10947     SKIP_BLANKS;
10948     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10949 	int eq;
10950 	int op1 = ctxt->comp->last;
10951 
10952         if (CUR == '=') eq = 1;
10953 	else eq = 0;
10954 	NEXT;
10955 	if (!eq) NEXT;
10956 	SKIP_BLANKS;
10957         xmlXPathCompRelationalExpr(ctxt);
10958 	CHECK_ERROR;
10959 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10960 	SKIP_BLANKS;
10961     }
10962 }
10963 
10964 /**
10965  * xmlXPathCompAndExpr:
10966  * @ctxt:  the XPath Parser context
10967  *
10968  *  [22]   AndExpr ::=   EqualityExpr
10969  *                 | AndExpr 'and' EqualityExpr
10970  *
10971  * Compile an AND expression.
10972  *
10973  */
10974 static void
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt)10975 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10976     xmlXPathCompEqualityExpr(ctxt);
10977     CHECK_ERROR;
10978     SKIP_BLANKS;
10979     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10980 	int op1 = ctxt->comp->last;
10981         SKIP(3);
10982 	SKIP_BLANKS;
10983         xmlXPathCompEqualityExpr(ctxt);
10984 	CHECK_ERROR;
10985 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10986 	SKIP_BLANKS;
10987     }
10988 }
10989 
10990 /**
10991  * xmlXPathCompileExpr:
10992  * @ctxt:  the XPath Parser context
10993  *
10994  *  [14]   Expr ::=   OrExpr
10995  *  [21]   OrExpr ::=   AndExpr
10996  *                 | OrExpr 'or' AndExpr
10997  *
10998  * Parse and compile an expression
10999  */
11000 static void
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt,int sort)11001 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
11002     xmlXPathCompAndExpr(ctxt);
11003     CHECK_ERROR;
11004     SKIP_BLANKS;
11005     while ((CUR == 'o') && (NXT(1) == 'r')) {
11006 	int op1 = ctxt->comp->last;
11007         SKIP(2);
11008 	SKIP_BLANKS;
11009         xmlXPathCompAndExpr(ctxt);
11010 	CHECK_ERROR;
11011 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
11012 	SKIP_BLANKS;
11013     }
11014     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
11015 	/* more ops could be optimized too */
11016 	/*
11017 	* This is the main place to eliminate sorting for
11018 	* operations which don't require a sorted node-set.
11019 	* E.g. count().
11020 	*/
11021 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11022     }
11023 }
11024 
11025 /**
11026  * xmlXPathCompPredicate:
11027  * @ctxt:  the XPath Parser context
11028  * @filter:  act as a filter
11029  *
11030  *  [8]   Predicate ::=   '[' PredicateExpr ']'
11031  *  [9]   PredicateExpr ::=   Expr
11032  *
11033  * Compile a predicate expression
11034  */
11035 static void
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt,int filter)11036 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11037     int op1 = ctxt->comp->last;
11038 
11039     SKIP_BLANKS;
11040     if (CUR != '[') {
11041 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11042     }
11043     NEXT;
11044     SKIP_BLANKS;
11045 
11046     ctxt->comp->last = -1;
11047     /*
11048     * This call to xmlXPathCompileExpr() will deactivate sorting
11049     * of the predicate result.
11050     * TODO: Sorting is still activated for filters, since I'm not
11051     *  sure if needed. Normally sorting should not be needed, since
11052     *  a filter can only diminish the number of items in a sequence,
11053     *  but won't change its order; so if the initial sequence is sorted,
11054     *  subsequent sorting is not needed.
11055     */
11056     if (! filter)
11057 	xmlXPathCompileExpr(ctxt, 0);
11058     else
11059 	xmlXPathCompileExpr(ctxt, 1);
11060     CHECK_ERROR;
11061 
11062     if (CUR != ']') {
11063 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11064     }
11065 
11066     if (filter)
11067 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11068     else
11069 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11070 
11071     NEXT;
11072     SKIP_BLANKS;
11073 }
11074 
11075 /**
11076  * xmlXPathCompNodeTest:
11077  * @ctxt:  the XPath Parser context
11078  * @test:  pointer to a xmlXPathTestVal
11079  * @type:  pointer to a xmlXPathTypeVal
11080  * @prefix:  placeholder for a possible name prefix
11081  *
11082  * [7] NodeTest ::=   NameTest
11083  *		    | NodeType '(' ')'
11084  *		    | 'processing-instruction' '(' Literal ')'
11085  *
11086  * [37] NameTest ::=  '*'
11087  *		    | NCName ':' '*'
11088  *		    | QName
11089  * [38] NodeType ::= 'comment'
11090  *		   | 'text'
11091  *		   | 'processing-instruction'
11092  *		   | 'node'
11093  *
11094  * Returns the name found and updates @test, @type and @prefix appropriately
11095  */
11096 static xmlChar *
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt,xmlXPathTestVal * test,xmlXPathTypeVal * type,const xmlChar ** prefix,xmlChar * name)11097 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11098 	             xmlXPathTypeVal *type, const xmlChar **prefix,
11099 		     xmlChar *name) {
11100     int blanks;
11101 
11102     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11103 	STRANGE;
11104 	return(NULL);
11105     }
11106     *type = (xmlXPathTypeVal) 0;
11107     *test = (xmlXPathTestVal) 0;
11108     *prefix = NULL;
11109     SKIP_BLANKS;
11110 
11111     if ((name == NULL) && (CUR == '*')) {
11112 	/*
11113 	 * All elements
11114 	 */
11115 	NEXT;
11116 	*test = NODE_TEST_ALL;
11117 	return(NULL);
11118     }
11119 
11120     if (name == NULL)
11121 	name = xmlXPathParseNCName(ctxt);
11122     if (name == NULL) {
11123 	XP_ERRORNULL(XPATH_EXPR_ERROR);
11124     }
11125 
11126     blanks = IS_BLANK_CH(CUR);
11127     SKIP_BLANKS;
11128     if (CUR == '(') {
11129 	NEXT;
11130 	/*
11131 	 * NodeType or PI search
11132 	 */
11133 	if (xmlStrEqual(name, BAD_CAST "comment"))
11134 	    *type = NODE_TYPE_COMMENT;
11135 	else if (xmlStrEqual(name, BAD_CAST "node"))
11136 	    *type = NODE_TYPE_NODE;
11137 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11138 	    *type = NODE_TYPE_PI;
11139 	else if (xmlStrEqual(name, BAD_CAST "text"))
11140 	    *type = NODE_TYPE_TEXT;
11141 	else {
11142 	    if (name != NULL)
11143 		xmlFree(name);
11144 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11145 	}
11146 
11147 	*test = NODE_TEST_TYPE;
11148 
11149 	SKIP_BLANKS;
11150 	if (*type == NODE_TYPE_PI) {
11151 	    /*
11152 	     * Specific case: search a PI by name.
11153 	     */
11154 	    if (name != NULL)
11155 		xmlFree(name);
11156 	    name = NULL;
11157 	    if (CUR != ')') {
11158 		name = xmlXPathParseLiteral(ctxt);
11159 		CHECK_ERROR NULL;
11160 		*test = NODE_TEST_PI;
11161 		SKIP_BLANKS;
11162 	    }
11163 	}
11164 	if (CUR != ')') {
11165 	    if (name != NULL)
11166 		xmlFree(name);
11167 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11168 	}
11169 	NEXT;
11170 	return(name);
11171     }
11172     *test = NODE_TEST_NAME;
11173     if ((!blanks) && (CUR == ':')) {
11174 	NEXT;
11175 
11176 	/*
11177 	 * Since currently the parser context don't have a
11178 	 * namespace list associated:
11179 	 * The namespace name for this prefix can be computed
11180 	 * only at evaluation time. The compilation is done
11181 	 * outside of any context.
11182 	 */
11183 #if 0
11184 	*prefix = xmlXPathNsLookup(ctxt->context, name);
11185 	if (name != NULL)
11186 	    xmlFree(name);
11187 	if (*prefix == NULL) {
11188 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11189 	}
11190 #else
11191 	*prefix = name;
11192 #endif
11193 
11194 	if (CUR == '*') {
11195 	    /*
11196 	     * All elements
11197 	     */
11198 	    NEXT;
11199 	    *test = NODE_TEST_ALL;
11200 	    return(NULL);
11201 	}
11202 
11203 	name = xmlXPathParseNCName(ctxt);
11204 	if (name == NULL) {
11205 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11206 	}
11207     }
11208     return(name);
11209 }
11210 
11211 /**
11212  * xmlXPathIsAxisName:
11213  * @name:  a preparsed name token
11214  *
11215  * [6] AxisName ::=   'ancestor'
11216  *                  | 'ancestor-or-self'
11217  *                  | 'attribute'
11218  *                  | 'child'
11219  *                  | 'descendant'
11220  *                  | 'descendant-or-self'
11221  *                  | 'following'
11222  *                  | 'following-sibling'
11223  *                  | 'namespace'
11224  *                  | 'parent'
11225  *                  | 'preceding'
11226  *                  | 'preceding-sibling'
11227  *                  | 'self'
11228  *
11229  * Returns the axis or 0
11230  */
11231 static xmlXPathAxisVal
xmlXPathIsAxisName(const xmlChar * name)11232 xmlXPathIsAxisName(const xmlChar *name) {
11233     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11234     switch (name[0]) {
11235 	case 'a':
11236 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
11237 		ret = AXIS_ANCESTOR;
11238 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11239 		ret = AXIS_ANCESTOR_OR_SELF;
11240 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
11241 		ret = AXIS_ATTRIBUTE;
11242 	    break;
11243 	case 'c':
11244 	    if (xmlStrEqual(name, BAD_CAST "child"))
11245 		ret = AXIS_CHILD;
11246 	    break;
11247 	case 'd':
11248 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
11249 		ret = AXIS_DESCENDANT;
11250 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11251 		ret = AXIS_DESCENDANT_OR_SELF;
11252 	    break;
11253 	case 'f':
11254 	    if (xmlStrEqual(name, BAD_CAST "following"))
11255 		ret = AXIS_FOLLOWING;
11256 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11257 		ret = AXIS_FOLLOWING_SIBLING;
11258 	    break;
11259 	case 'n':
11260 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
11261 		ret = AXIS_NAMESPACE;
11262 	    break;
11263 	case 'p':
11264 	    if (xmlStrEqual(name, BAD_CAST "parent"))
11265 		ret = AXIS_PARENT;
11266 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
11267 		ret = AXIS_PRECEDING;
11268 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11269 		ret = AXIS_PRECEDING_SIBLING;
11270 	    break;
11271 	case 's':
11272 	    if (xmlStrEqual(name, BAD_CAST "self"))
11273 		ret = AXIS_SELF;
11274 	    break;
11275     }
11276     return(ret);
11277 }
11278 
11279 /**
11280  * xmlXPathCompStep:
11281  * @ctxt:  the XPath Parser context
11282  *
11283  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11284  *                  | AbbreviatedStep
11285  *
11286  * [12] AbbreviatedStep ::=   '.' | '..'
11287  *
11288  * [5] AxisSpecifier ::= AxisName '::'
11289  *                  | AbbreviatedAxisSpecifier
11290  *
11291  * [13] AbbreviatedAxisSpecifier ::= '@'?
11292  *
11293  * Modified for XPtr range support as:
11294  *
11295  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11296  *                     | AbbreviatedStep
11297  *                     | 'range-to' '(' Expr ')' Predicate*
11298  *
11299  * Compile one step in a Location Path
11300  * A location step of . is short for self::node(). This is
11301  * particularly useful in conjunction with //. For example, the
11302  * location path .//para is short for
11303  * self::node()/descendant-or-self::node()/child::para
11304  * and so will select all para descendant elements of the context
11305  * node.
11306  * Similarly, a location step of .. is short for parent::node().
11307  * For example, ../title is short for parent::node()/child::title
11308  * and so will select the title children of the parent of the context
11309  * node.
11310  */
11311 static void
xmlXPathCompStep(xmlXPathParserContextPtr ctxt)11312 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11313 #ifdef LIBXML_XPTR_ENABLED
11314     int rangeto = 0;
11315     int op2 = -1;
11316 #endif
11317 
11318     SKIP_BLANKS;
11319     if ((CUR == '.') && (NXT(1) == '.')) {
11320 	SKIP(2);
11321 	SKIP_BLANKS;
11322 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11323 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11324     } else if (CUR == '.') {
11325 	NEXT;
11326 	SKIP_BLANKS;
11327     } else {
11328 	xmlChar *name = NULL;
11329 	const xmlChar *prefix = NULL;
11330 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
11331 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11332 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11333 	int op1;
11334 
11335 	/*
11336 	 * The modification needed for XPointer change to the production
11337 	 */
11338 #ifdef LIBXML_XPTR_ENABLED
11339 	if (ctxt->xptr) {
11340 	    name = xmlXPathParseNCName(ctxt);
11341 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11342                 op2 = ctxt->comp->last;
11343 		xmlFree(name);
11344 		SKIP_BLANKS;
11345 		if (CUR != '(') {
11346 		    XP_ERROR(XPATH_EXPR_ERROR);
11347 		}
11348 		NEXT;
11349 		SKIP_BLANKS;
11350 
11351 		xmlXPathCompileExpr(ctxt, 1);
11352 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11353 		CHECK_ERROR;
11354 
11355 		SKIP_BLANKS;
11356 		if (CUR != ')') {
11357 		    XP_ERROR(XPATH_EXPR_ERROR);
11358 		}
11359 		NEXT;
11360 		rangeto = 1;
11361 		goto eval_predicates;
11362 	    }
11363 	}
11364 #endif
11365 	if (CUR == '*') {
11366 	    axis = AXIS_CHILD;
11367 	} else {
11368 	    if (name == NULL)
11369 		name = xmlXPathParseNCName(ctxt);
11370 	    if (name != NULL) {
11371 		axis = xmlXPathIsAxisName(name);
11372 		if (axis != 0) {
11373 		    SKIP_BLANKS;
11374 		    if ((CUR == ':') && (NXT(1) == ':')) {
11375 			SKIP(2);
11376 			xmlFree(name);
11377 			name = NULL;
11378 		    } else {
11379 			/* an element name can conflict with an axis one :-\ */
11380 			axis = AXIS_CHILD;
11381 		    }
11382 		} else {
11383 		    axis = AXIS_CHILD;
11384 		}
11385 	    } else if (CUR == '@') {
11386 		NEXT;
11387 		axis = AXIS_ATTRIBUTE;
11388 	    } else {
11389 		axis = AXIS_CHILD;
11390 	    }
11391 	}
11392 
11393         if (ctxt->error != XPATH_EXPRESSION_OK) {
11394             xmlFree(name);
11395             return;
11396         }
11397 
11398 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11399 	if (test == 0)
11400 	    return;
11401 
11402         if ((prefix != NULL) && (ctxt->context != NULL) &&
11403 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11404 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11405 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11406 	    }
11407 	}
11408 #ifdef DEBUG_STEP
11409 	xmlGenericError(xmlGenericErrorContext,
11410 		"Basis : computing new set\n");
11411 #endif
11412 
11413 #ifdef DEBUG_STEP
11414 	xmlGenericError(xmlGenericErrorContext, "Basis : ");
11415 	if (ctxt->value == NULL)
11416 	    xmlGenericError(xmlGenericErrorContext, "no value\n");
11417 	else if (ctxt->value->nodesetval == NULL)
11418 	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
11419 	else
11420 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11421 #endif
11422 
11423 #ifdef LIBXML_XPTR_ENABLED
11424 eval_predicates:
11425 #endif
11426 	op1 = ctxt->comp->last;
11427 	ctxt->comp->last = -1;
11428 
11429 	SKIP_BLANKS;
11430 	while (CUR == '[') {
11431 	    xmlXPathCompPredicate(ctxt, 0);
11432 	}
11433 
11434 #ifdef LIBXML_XPTR_ENABLED
11435 	if (rangeto) {
11436 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11437 	} else
11438 #endif
11439 	    PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11440 			   test, type, (void *)prefix, (void *)name);
11441 
11442     }
11443 #ifdef DEBUG_STEP
11444     xmlGenericError(xmlGenericErrorContext, "Step : ");
11445     if (ctxt->value == NULL)
11446 	xmlGenericError(xmlGenericErrorContext, "no value\n");
11447     else if (ctxt->value->nodesetval == NULL)
11448 	xmlGenericError(xmlGenericErrorContext, "Empty\n");
11449     else
11450 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11451 		ctxt->value->nodesetval);
11452 #endif
11453 }
11454 
11455 /**
11456  * xmlXPathCompRelativeLocationPath:
11457  * @ctxt:  the XPath Parser context
11458  *
11459  *  [3]   RelativeLocationPath ::=   Step
11460  *                     | RelativeLocationPath '/' Step
11461  *                     | AbbreviatedRelativeLocationPath
11462  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11463  *
11464  * Compile a relative location path.
11465  */
11466 static void
xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt)11467 xmlXPathCompRelativeLocationPath
11468 (xmlXPathParserContextPtr ctxt) {
11469     SKIP_BLANKS;
11470     if ((CUR == '/') && (NXT(1) == '/')) {
11471 	SKIP(2);
11472 	SKIP_BLANKS;
11473 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11474 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11475     } else if (CUR == '/') {
11476 	    NEXT;
11477 	SKIP_BLANKS;
11478     }
11479     xmlXPathCompStep(ctxt);
11480     CHECK_ERROR;
11481     SKIP_BLANKS;
11482     while (CUR == '/') {
11483 	if ((CUR == '/') && (NXT(1) == '/')) {
11484 	    SKIP(2);
11485 	    SKIP_BLANKS;
11486 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11487 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11488 	    xmlXPathCompStep(ctxt);
11489 	} else if (CUR == '/') {
11490 	    NEXT;
11491 	    SKIP_BLANKS;
11492 	    xmlXPathCompStep(ctxt);
11493 	}
11494 	SKIP_BLANKS;
11495     }
11496 }
11497 
11498 /**
11499  * xmlXPathCompLocationPath:
11500  * @ctxt:  the XPath Parser context
11501  *
11502  *  [1]   LocationPath ::=   RelativeLocationPath
11503  *                     | AbsoluteLocationPath
11504  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11505  *                     | AbbreviatedAbsoluteLocationPath
11506  *  [10]   AbbreviatedAbsoluteLocationPath ::=
11507  *                           '//' RelativeLocationPath
11508  *
11509  * Compile a location path
11510  *
11511  * // is short for /descendant-or-self::node()/. For example,
11512  * //para is short for /descendant-or-self::node()/child::para and
11513  * so will select any para element in the document (even a para element
11514  * that is a document element will be selected by //para since the
11515  * document element node is a child of the root node); div//para is
11516  * short for div/descendant-or-self::node()/child::para and so will
11517  * select all para descendants of div children.
11518  */
11519 static void
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt)11520 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11521     SKIP_BLANKS;
11522     if (CUR != '/') {
11523         xmlXPathCompRelativeLocationPath(ctxt);
11524     } else {
11525 	while (CUR == '/') {
11526 	    if ((CUR == '/') && (NXT(1) == '/')) {
11527 		SKIP(2);
11528 		SKIP_BLANKS;
11529 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11530 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11531 		xmlXPathCompRelativeLocationPath(ctxt);
11532 	    } else if (CUR == '/') {
11533 		NEXT;
11534 		SKIP_BLANKS;
11535 		if ((CUR != 0 ) &&
11536 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11537 		     (CUR == '@') || (CUR == '*')))
11538 		    xmlXPathCompRelativeLocationPath(ctxt);
11539 	    }
11540 	    CHECK_ERROR;
11541 	}
11542     }
11543 }
11544 
11545 /************************************************************************
11546  *									*
11547  *		XPath precompiled expression evaluation			*
11548  *									*
11549  ************************************************************************/
11550 
11551 static int
11552 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11553 
11554 #ifdef DEBUG_STEP
11555 static void
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,int nbNodes)11556 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11557 			  int nbNodes)
11558 {
11559     xmlGenericError(xmlGenericErrorContext, "new step : ");
11560     switch (op->value) {
11561         case AXIS_ANCESTOR:
11562             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11563             break;
11564         case AXIS_ANCESTOR_OR_SELF:
11565             xmlGenericError(xmlGenericErrorContext,
11566                             "axis 'ancestors-or-self' ");
11567             break;
11568         case AXIS_ATTRIBUTE:
11569             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11570             break;
11571         case AXIS_CHILD:
11572             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11573             break;
11574         case AXIS_DESCENDANT:
11575             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11576             break;
11577         case AXIS_DESCENDANT_OR_SELF:
11578             xmlGenericError(xmlGenericErrorContext,
11579                             "axis 'descendant-or-self' ");
11580             break;
11581         case AXIS_FOLLOWING:
11582             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11583             break;
11584         case AXIS_FOLLOWING_SIBLING:
11585             xmlGenericError(xmlGenericErrorContext,
11586                             "axis 'following-siblings' ");
11587             break;
11588         case AXIS_NAMESPACE:
11589             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11590             break;
11591         case AXIS_PARENT:
11592             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11593             break;
11594         case AXIS_PRECEDING:
11595             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11596             break;
11597         case AXIS_PRECEDING_SIBLING:
11598             xmlGenericError(xmlGenericErrorContext,
11599                             "axis 'preceding-sibling' ");
11600             break;
11601         case AXIS_SELF:
11602             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11603             break;
11604     }
11605     xmlGenericError(xmlGenericErrorContext,
11606 	" context contains %d nodes\n", nbNodes);
11607     switch (op->value2) {
11608         case NODE_TEST_NONE:
11609             xmlGenericError(xmlGenericErrorContext,
11610                             "           searching for none !!!\n");
11611             break;
11612         case NODE_TEST_TYPE:
11613             xmlGenericError(xmlGenericErrorContext,
11614                             "           searching for type %d\n", op->value3);
11615             break;
11616         case NODE_TEST_PI:
11617             xmlGenericError(xmlGenericErrorContext,
11618                             "           searching for PI !!!\n");
11619             break;
11620         case NODE_TEST_ALL:
11621             xmlGenericError(xmlGenericErrorContext,
11622                             "           searching for *\n");
11623             break;
11624         case NODE_TEST_NS:
11625             xmlGenericError(xmlGenericErrorContext,
11626                             "           searching for namespace %s\n",
11627                             op->value5);
11628             break;
11629         case NODE_TEST_NAME:
11630             xmlGenericError(xmlGenericErrorContext,
11631                             "           searching for name %s\n", op->value5);
11632             if (op->value4)
11633                 xmlGenericError(xmlGenericErrorContext,
11634                                 "           with namespace %s\n", op->value4);
11635             break;
11636     }
11637     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11638 }
11639 #endif /* DEBUG_STEP */
11640 
11641 static int
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int contextSize,int hasNsNodes)11642 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11643 			    xmlXPathStepOpPtr op,
11644 			    xmlNodeSetPtr set,
11645 			    int contextSize,
11646 			    int hasNsNodes)
11647 {
11648     if (op->ch1 != -1) {
11649 	xmlXPathCompExprPtr comp = ctxt->comp;
11650 	/*
11651 	* Process inner predicates first.
11652 	*/
11653 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11654 	    /*
11655 	    * TODO: raise an internal error.
11656 	    */
11657 	}
11658 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11659 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11660 	CHECK_ERROR0;
11661 	if (contextSize <= 0)
11662 	    return(0);
11663     }
11664     if (op->ch2 != -1) {
11665 	xmlXPathContextPtr xpctxt = ctxt->context;
11666 	xmlNodePtr contextNode, oldContextNode;
11667 	xmlDocPtr oldContextDoc;
11668 	int i, res, contextPos = 0, newContextSize;
11669 	xmlXPathStepOpPtr exprOp;
11670 	xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11671 
11672 #ifdef LIBXML_XPTR_ENABLED
11673 	/*
11674 	* URGENT TODO: Check the following:
11675 	*  We don't expect location sets if evaluating prediates, right?
11676 	*  Only filters should expect location sets, right?
11677 	*/
11678 #endif
11679 	/*
11680 	* SPEC XPath 1.0:
11681 	*  "For each node in the node-set to be filtered, the
11682 	*  PredicateExpr is evaluated with that node as the
11683 	*  context node, with the number of nodes in the
11684 	*  node-set as the context size, and with the proximity
11685 	*  position of the node in the node-set with respect to
11686 	*  the axis as the context position;"
11687 	* @oldset is the node-set" to be filtered.
11688 	*
11689 	* SPEC XPath 1.0:
11690 	*  "only predicates change the context position and
11691 	*  context size (see [2.4 Predicates])."
11692 	* Example:
11693 	*   node-set  context pos
11694 	*    nA         1
11695 	*    nB         2
11696 	*    nC         3
11697 	*   After applying predicate [position() > 1] :
11698 	*   node-set  context pos
11699 	*    nB         1
11700 	*    nC         2
11701 	*/
11702 	oldContextNode = xpctxt->node;
11703 	oldContextDoc = xpctxt->doc;
11704 	/*
11705 	* Get the expression of this predicate.
11706 	*/
11707 	exprOp = &ctxt->comp->steps[op->ch2];
11708 	newContextSize = 0;
11709 	for (i = 0; i < set->nodeNr; i++) {
11710 	    if (set->nodeTab[i] == NULL)
11711 		continue;
11712 
11713 	    contextNode = set->nodeTab[i];
11714 	    xpctxt->node = contextNode;
11715 	    xpctxt->contextSize = contextSize;
11716 	    xpctxt->proximityPosition = ++contextPos;
11717 
11718 	    /*
11719 	    * Also set the xpath document in case things like
11720 	    * key() are evaluated in the predicate.
11721 	    */
11722 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11723 		(contextNode->doc != NULL))
11724 		xpctxt->doc = contextNode->doc;
11725 	    /*
11726 	    * Evaluate the predicate expression with 1 context node
11727 	    * at a time; this node is packaged into a node set; this
11728 	    * node set is handed over to the evaluation mechanism.
11729 	    */
11730 	    if (contextObj == NULL)
11731 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11732 	    else {
11733 		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11734 		    contextNode) < 0) {
11735 		    ctxt->error = XPATH_MEMORY_ERROR;
11736 		    goto evaluation_exit;
11737 		}
11738 	    }
11739 
11740 	    valuePush(ctxt, contextObj);
11741 
11742 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11743 
11744 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11745 		xmlXPathNodeSetClear(set, hasNsNodes);
11746 		newContextSize = 0;
11747 		goto evaluation_exit;
11748 	    }
11749 
11750 	    if (res != 0) {
11751 		newContextSize++;
11752 	    } else {
11753 		/*
11754 		* Remove the entry from the initial node set.
11755 		*/
11756 		set->nodeTab[i] = NULL;
11757 		if (contextNode->type == XML_NAMESPACE_DECL)
11758 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11759 	    }
11760 	    if (ctxt->value == contextObj) {
11761 		/*
11762 		* Don't free the temporary XPath object holding the
11763 		* context node, in order to avoid massive recreation
11764 		* inside this loop.
11765 		*/
11766 		valuePop(ctxt);
11767 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11768 	    } else {
11769 		/*
11770 		* TODO: The object was lost in the evaluation machinery.
11771 		*  Can this happen? Maybe in internal-error cases.
11772 		*/
11773 		contextObj = NULL;
11774 	    }
11775 	}
11776 
11777 	if (contextObj != NULL) {
11778 	    if (ctxt->value == contextObj)
11779 		valuePop(ctxt);
11780 	    xmlXPathReleaseObject(xpctxt, contextObj);
11781 	}
11782 evaluation_exit:
11783 	if (exprRes != NULL)
11784 	    xmlXPathReleaseObject(ctxt->context, exprRes);
11785 	/*
11786 	* Reset/invalidate the context.
11787 	*/
11788 	xpctxt->node = oldContextNode;
11789 	xpctxt->doc = oldContextDoc;
11790 	xpctxt->contextSize = -1;
11791 	xpctxt->proximityPosition = -1;
11792 	return(newContextSize);
11793     }
11794     return(contextSize);
11795 }
11796 
11797 static int
xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int contextSize,int minPos,int maxPos,int hasNsNodes)11798 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11799 				      xmlXPathStepOpPtr op,
11800 				      xmlNodeSetPtr set,
11801 				      int contextSize,
11802 				      int minPos,
11803 				      int maxPos,
11804 				      int hasNsNodes)
11805 {
11806     if (op->ch1 != -1) {
11807 	xmlXPathCompExprPtr comp = ctxt->comp;
11808 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11809 	    /*
11810 	    * TODO: raise an internal error.
11811 	    */
11812 	}
11813 	contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11814 	    &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11815 	CHECK_ERROR0;
11816 	if (contextSize <= 0)
11817 	    return(0);
11818     }
11819     /*
11820     * Check if the node set contains a sufficient number of nodes for
11821     * the requested range.
11822     */
11823     if (contextSize < minPos) {
11824 	xmlXPathNodeSetClear(set, hasNsNodes);
11825 	return(0);
11826     }
11827     if (op->ch2 == -1) {
11828 	/*
11829 	* TODO: Can this ever happen?
11830 	*/
11831 	return (contextSize);
11832     } else {
11833 	xmlDocPtr oldContextDoc;
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 	/*
11855 	* Get the expression of this predicate.
11856 	*/
11857 	exprOp = &ctxt->comp->steps[op->ch2];
11858 	for (i = 0; i < set->nodeNr; i++) {
11859             xmlXPathObjectPtr tmp;
11860 
11861 	    if (set->nodeTab[i] == NULL)
11862 		continue;
11863 
11864 	    contextNode = set->nodeTab[i];
11865 	    xpctxt->node = contextNode;
11866 	    xpctxt->contextSize = contextSize;
11867 	    xpctxt->proximityPosition = ++contextPos;
11868 
11869 	    /*
11870 	    * Initialize the new set.
11871 	    * Also set the xpath document in case things like
11872 	    * key() evaluation are attempted on the predicate
11873 	    */
11874 	    if ((contextNode->type != XML_NAMESPACE_DECL) &&
11875 		(contextNode->doc != NULL))
11876 		xpctxt->doc = contextNode->doc;
11877 	    /*
11878 	    * Evaluate the predicate expression with 1 context node
11879 	    * at a time; this node is packaged into a node set; this
11880 	    * node set is handed over to the evaluation mechanism.
11881 	    */
11882 	    if (contextObj == NULL)
11883 		contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11884 	    else {
11885 		if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11886 		    contextNode) < 0) {
11887 		    ctxt->error = XPATH_MEMORY_ERROR;
11888 		    goto evaluation_exit;
11889 		}
11890 	    }
11891 
11892 	    valuePush(ctxt, contextObj);
11893             frame = xmlXPathSetFrame(ctxt);
11894 	    res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11895             xmlXPathPopFrame(ctxt, frame);
11896             tmp = valuePop(ctxt);
11897 
11898 	    if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11899                 while (tmp != contextObj) {
11900                     /*
11901                      * Free up the result
11902                      * then pop off contextObj, which will be freed later
11903                      */
11904                     xmlXPathReleaseObject(xpctxt, tmp);
11905                     tmp = valuePop(ctxt);
11906                 }
11907 		goto evaluation_error;
11908 	    }
11909             /* push the result back onto the stack */
11910             valuePush(ctxt, tmp);
11911 
11912 	    if (res)
11913 		pos++;
11914 
11915 	    if (res && (pos >= minPos) && (pos <= maxPos)) {
11916 		/*
11917 		* Fits in the requested range.
11918 		*/
11919 		newContextSize++;
11920 		if (minPos == maxPos) {
11921 		    /*
11922 		    * Only 1 node was requested.
11923 		    */
11924 		    if (contextNode->type == XML_NAMESPACE_DECL) {
11925 			/*
11926 			* As always: take care of those nasty
11927 			* namespace nodes.
11928 			*/
11929 			set->nodeTab[i] = NULL;
11930 		    }
11931 		    xmlXPathNodeSetClear(set, hasNsNodes);
11932 		    set->nodeNr = 1;
11933 		    set->nodeTab[0] = contextNode;
11934 		    goto evaluation_exit;
11935 		}
11936 		if (pos == maxPos) {
11937 		    /*
11938 		    * We are done.
11939 		    */
11940 		    xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11941 		    goto evaluation_exit;
11942 		}
11943 	    } else {
11944 		/*
11945 		* Remove the entry from the initial node set.
11946 		*/
11947 		set->nodeTab[i] = NULL;
11948 		if (contextNode->type == XML_NAMESPACE_DECL)
11949 		    xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11950 	    }
11951 	    if (exprRes != NULL) {
11952 		xmlXPathReleaseObject(ctxt->context, exprRes);
11953 		exprRes = NULL;
11954 	    }
11955 	    if (ctxt->value == contextObj) {
11956 		/*
11957 		* Don't free the temporary XPath object holding the
11958 		* context node, in order to avoid massive recreation
11959 		* inside this loop.
11960 		*/
11961 		valuePop(ctxt);
11962 		xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11963 	    } else {
11964 		/*
11965 		* The object was lost in the evaluation machinery.
11966 		* Can this happen? Maybe in case of internal-errors.
11967 		*/
11968 		contextObj = NULL;
11969 	    }
11970 	}
11971 	goto evaluation_exit;
11972 
11973 evaluation_error:
11974 	xmlXPathNodeSetClear(set, hasNsNodes);
11975 	newContextSize = 0;
11976 
11977 evaluation_exit:
11978 	if (contextObj != NULL) {
11979 	    if (ctxt->value == contextObj)
11980 		valuePop(ctxt);
11981 	    xmlXPathReleaseObject(xpctxt, contextObj);
11982 	}
11983 	if (exprRes != NULL)
11984 	    xmlXPathReleaseObject(ctxt->context, exprRes);
11985 	/*
11986 	* Reset/invalidate the context.
11987 	*/
11988 	xpctxt->node = oldContextNode;
11989 	xpctxt->doc = oldContextDoc;
11990 	xpctxt->contextSize = -1;
11991 	xpctxt->proximityPosition = -1;
11992 	return(newContextSize);
11993     }
11994     return(contextSize);
11995 }
11996 
11997 static int
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int * maxPos)11998 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11999 			    xmlXPathStepOpPtr op,
12000 			    int *maxPos)
12001 {
12002 
12003     xmlXPathStepOpPtr exprOp;
12004 
12005     /*
12006     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12007     */
12008 
12009     /*
12010     * If not -1, then ch1 will point to:
12011     * 1) For predicates (XPATH_OP_PREDICATE):
12012     *    - an inner predicate operator
12013     * 2) For filters (XPATH_OP_FILTER):
12014     *    - an inner filter operater OR
12015     *    - an expression selecting the node set.
12016     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
12017     */
12018     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12019 	return(0);
12020 
12021     if (op->ch2 != -1) {
12022 	exprOp = &ctxt->comp->steps[op->ch2];
12023     } else
12024 	return(0);
12025 
12026     if ((exprOp != NULL) &&
12027 	(exprOp->op == XPATH_OP_VALUE) &&
12028 	(exprOp->value4 != NULL) &&
12029 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12030     {
12031         double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12032 
12033 	/*
12034 	* We have a "[n]" predicate here.
12035 	* TODO: Unfortunately this simplistic test here is not
12036 	* able to detect a position() predicate in compound
12037 	* expressions like "[@attr = 'a" and position() = 1],
12038 	* and even not the usage of position() in
12039 	* "[position() = 1]"; thus - obviously - a position-range,
12040 	* like it "[position() < 5]", is also not detected.
12041 	* Maybe we could rewrite the AST to ease the optimization.
12042 	*/
12043 
12044         if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
12045 	    *maxPos = (int) floatval;
12046             if (floatval == (double) *maxPos)
12047                 return(1);
12048         }
12049     }
12050     return(0);
12051 }
12052 
12053 static int
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first,xmlNodePtr * last,int toBool)12054 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12055                            xmlXPathStepOpPtr op,
12056 			   xmlNodePtr * first, xmlNodePtr * last,
12057 			   int toBool)
12058 {
12059 
12060 #define XP_TEST_HIT \
12061     if (hasAxisRange != 0) { \
12062 	if (++pos == maxPos) { \
12063 	    if (addNode(seq, cur) < 0) \
12064 	        ctxt->error = XPATH_MEMORY_ERROR; \
12065 	    goto axis_range_end; } \
12066     } else { \
12067 	if (addNode(seq, cur) < 0) \
12068 	    ctxt->error = XPATH_MEMORY_ERROR; \
12069 	if (breakOnFirstHit) goto first_hit; }
12070 
12071 #define XP_TEST_HIT_NS \
12072     if (hasAxisRange != 0) { \
12073 	if (++pos == maxPos) { \
12074 	    hasNsNodes = 1; \
12075 	    if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12076 	        ctxt->error = XPATH_MEMORY_ERROR; \
12077 	goto axis_range_end; } \
12078     } else { \
12079 	hasNsNodes = 1; \
12080 	if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12081 	    ctxt->error = XPATH_MEMORY_ERROR; \
12082 	if (breakOnFirstHit) goto first_hit; }
12083 
12084     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12085     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12086     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12087     const xmlChar *prefix = op->value4;
12088     const xmlChar *name = op->value5;
12089     const xmlChar *URI = NULL;
12090 
12091 #ifdef DEBUG_STEP
12092     int nbMatches = 0, prevMatches = 0;
12093 #endif
12094     int total = 0, hasNsNodes = 0;
12095     /* The popped object holding the context nodes */
12096     xmlXPathObjectPtr obj;
12097     /* The set of context nodes for the node tests */
12098     xmlNodeSetPtr contextSeq;
12099     int contextIdx;
12100     xmlNodePtr contextNode;
12101     /* The final resulting node set wrt to all context nodes */
12102     xmlNodeSetPtr outSeq;
12103     /*
12104     * The temporary resulting node set wrt 1 context node.
12105     * Used to feed predicate evaluation.
12106     */
12107     xmlNodeSetPtr seq;
12108     xmlNodePtr cur;
12109     /* First predicate operator */
12110     xmlXPathStepOpPtr predOp;
12111     int maxPos; /* The requested position() (when a "[n]" predicate) */
12112     int hasPredicateRange, hasAxisRange, pos, size, newSize;
12113     int breakOnFirstHit;
12114 
12115     xmlXPathTraversalFunction next = NULL;
12116     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12117     xmlXPathNodeSetMergeFunction mergeAndClear;
12118     xmlNodePtr oldContextNode;
12119     xmlXPathContextPtr xpctxt = ctxt->context;
12120 
12121 
12122     CHECK_TYPE0(XPATH_NODESET);
12123     obj = valuePop(ctxt);
12124     /*
12125     * Setup namespaces.
12126     */
12127     if (prefix != NULL) {
12128         URI = xmlXPathNsLookup(xpctxt, prefix);
12129         if (URI == NULL) {
12130 	    xmlXPathReleaseObject(xpctxt, obj);
12131             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12132 	}
12133     }
12134     /*
12135     * Setup axis.
12136     *
12137     * MAYBE FUTURE TODO: merging optimizations:
12138     * - If the nodes to be traversed wrt to the initial nodes and
12139     *   the current axis cannot overlap, then we could avoid searching
12140     *   for duplicates during the merge.
12141     *   But the question is how/when to evaluate if they cannot overlap.
12142     *   Example: if we know that for two initial nodes, the one is
12143     *   not in the ancestor-or-self axis of the other, then we could safely
12144     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12145     *   the descendant-or-self axis.
12146     */
12147     mergeAndClear = xmlXPathNodeSetMergeAndClear;
12148     switch (axis) {
12149         case AXIS_ANCESTOR:
12150             first = NULL;
12151             next = xmlXPathNextAncestor;
12152             break;
12153         case AXIS_ANCESTOR_OR_SELF:
12154             first = NULL;
12155             next = xmlXPathNextAncestorOrSelf;
12156             break;
12157         case AXIS_ATTRIBUTE:
12158             first = NULL;
12159 	    last = NULL;
12160             next = xmlXPathNextAttribute;
12161 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12162             break;
12163         case AXIS_CHILD:
12164 	    last = NULL;
12165 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12166 		(type == NODE_TYPE_NODE))
12167 	    {
12168 		/*
12169 		* Optimization if an element node type is 'element'.
12170 		*/
12171 		next = xmlXPathNextChildElement;
12172 	    } else
12173 		next = xmlXPathNextChild;
12174 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12175             break;
12176         case AXIS_DESCENDANT:
12177 	    last = NULL;
12178             next = xmlXPathNextDescendant;
12179             break;
12180         case AXIS_DESCENDANT_OR_SELF:
12181 	    last = NULL;
12182             next = xmlXPathNextDescendantOrSelf;
12183             break;
12184         case AXIS_FOLLOWING:
12185 	    last = NULL;
12186             next = xmlXPathNextFollowing;
12187             break;
12188         case AXIS_FOLLOWING_SIBLING:
12189 	    last = NULL;
12190             next = xmlXPathNextFollowingSibling;
12191             break;
12192         case AXIS_NAMESPACE:
12193             first = NULL;
12194 	    last = NULL;
12195             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12196 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12197             break;
12198         case AXIS_PARENT:
12199             first = NULL;
12200             next = xmlXPathNextParent;
12201             break;
12202         case AXIS_PRECEDING:
12203             first = NULL;
12204             next = xmlXPathNextPrecedingInternal;
12205             break;
12206         case AXIS_PRECEDING_SIBLING:
12207             first = NULL;
12208             next = xmlXPathNextPrecedingSibling;
12209             break;
12210         case AXIS_SELF:
12211             first = NULL;
12212 	    last = NULL;
12213             next = xmlXPathNextSelf;
12214 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12215             break;
12216     }
12217 
12218 #ifdef DEBUG_STEP
12219     xmlXPathDebugDumpStepAxis(op,
12220 	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12221 #endif
12222 
12223     if (next == NULL) {
12224 	xmlXPathReleaseObject(xpctxt, obj);
12225         return(0);
12226     }
12227     contextSeq = obj->nodesetval;
12228     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12229 	xmlXPathReleaseObject(xpctxt, obj);
12230         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12231         return(0);
12232     }
12233     /*
12234     * Predicate optimization ---------------------------------------------
12235     * If this step has a last predicate, which contains a position(),
12236     * then we'll optimize (although not exactly "position()", but only
12237     * the  short-hand form, i.e., "[n]".
12238     *
12239     * Example - expression "/foo[parent::bar][1]":
12240     *
12241     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12242     *   ROOT                               -- op->ch1
12243     *   PREDICATE                          -- op->ch2 (predOp)
12244     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12245     *       SORT
12246     *         COLLECT  'parent' 'name' 'node' bar
12247     *           NODE
12248     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12249     *
12250     */
12251     maxPos = 0;
12252     predOp = NULL;
12253     hasPredicateRange = 0;
12254     hasAxisRange = 0;
12255     if (op->ch2 != -1) {
12256 	/*
12257 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
12258 	*/
12259 	predOp = &ctxt->comp->steps[op->ch2];
12260 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12261 	    if (predOp->ch1 != -1) {
12262 		/*
12263 		* Use the next inner predicate operator.
12264 		*/
12265 		predOp = &ctxt->comp->steps[predOp->ch1];
12266 		hasPredicateRange = 1;
12267 	    } else {
12268 		/*
12269 		* There's no other predicate than the [n] predicate.
12270 		*/
12271 		predOp = NULL;
12272 		hasAxisRange = 1;
12273 	    }
12274 	}
12275     }
12276     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12277     /*
12278     * Axis traversal -----------------------------------------------------
12279     */
12280     /*
12281      * 2.3 Node Tests
12282      *  - For the attribute axis, the principal node type is attribute.
12283      *  - For the namespace axis, the principal node type is namespace.
12284      *  - For other axes, the principal node type is element.
12285      *
12286      * A node test * is true for any node of the
12287      * principal node type. For example, child::* will
12288      * select all element children of the context node
12289      */
12290     oldContextNode = xpctxt->node;
12291     addNode = xmlXPathNodeSetAddUnique;
12292     outSeq = NULL;
12293     seq = NULL;
12294     contextNode = NULL;
12295     contextIdx = 0;
12296 
12297 
12298     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12299            (ctxt->error == XPATH_EXPRESSION_OK)) {
12300 	xpctxt->node = contextSeq->nodeTab[contextIdx++];
12301 
12302 	if (seq == NULL) {
12303 	    seq = xmlXPathNodeSetCreate(NULL);
12304 	    if (seq == NULL) {
12305 		total = 0;
12306 		goto error;
12307 	    }
12308 	}
12309 	/*
12310 	* Traverse the axis and test the nodes.
12311 	*/
12312 	pos = 0;
12313 	cur = NULL;
12314 	hasNsNodes = 0;
12315         do {
12316             cur = next(ctxt, cur);
12317             if (cur == NULL)
12318                 break;
12319 
12320 	    /*
12321 	    * QUESTION TODO: What does the "first" and "last" stuff do?
12322 	    */
12323             if ((first != NULL) && (*first != NULL)) {
12324 		if (*first == cur)
12325 		    break;
12326 		if (((total % 256) == 0) &&
12327 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12328 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12329 #else
12330 		    (xmlXPathCmpNodes(*first, cur) >= 0))
12331 #endif
12332 		{
12333 		    break;
12334 		}
12335 	    }
12336 	    if ((last != NULL) && (*last != NULL)) {
12337 		if (*last == cur)
12338 		    break;
12339 		if (((total % 256) == 0) &&
12340 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12341 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12342 #else
12343 		    (xmlXPathCmpNodes(cur, *last) >= 0))
12344 #endif
12345 		{
12346 		    break;
12347 		}
12348 	    }
12349 
12350             total++;
12351 
12352 #ifdef DEBUG_STEP
12353             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12354 #endif
12355 
12356 	    switch (test) {
12357                 case NODE_TEST_NONE:
12358 		    total = 0;
12359                     STRANGE
12360 		    goto error;
12361                 case NODE_TEST_TYPE:
12362 		    if (type == NODE_TYPE_NODE) {
12363 			switch (cur->type) {
12364 			    case XML_DOCUMENT_NODE:
12365 			    case XML_HTML_DOCUMENT_NODE:
12366 #ifdef LIBXML_DOCB_ENABLED
12367 			    case XML_DOCB_DOCUMENT_NODE:
12368 #endif
12369 			    case XML_ELEMENT_NODE:
12370 			    case XML_ATTRIBUTE_NODE:
12371 			    case XML_PI_NODE:
12372 			    case XML_COMMENT_NODE:
12373 			    case XML_CDATA_SECTION_NODE:
12374 			    case XML_TEXT_NODE:
12375 				XP_TEST_HIT
12376 				break;
12377 			    case XML_NAMESPACE_DECL: {
12378 				if (axis == AXIS_NAMESPACE) {
12379 				    XP_TEST_HIT_NS
12380 				} else {
12381 	                            hasNsNodes = 1;
12382 				    XP_TEST_HIT
12383 				}
12384 				break;
12385                             }
12386 			    default:
12387 				break;
12388 			}
12389 		    } else if (cur->type == (xmlElementType) type) {
12390 			if (cur->type == XML_NAMESPACE_DECL)
12391 			    XP_TEST_HIT_NS
12392 			else
12393 			    XP_TEST_HIT
12394 		    } else if ((type == NODE_TYPE_TEXT) &&
12395 			 (cur->type == XML_CDATA_SECTION_NODE))
12396 		    {
12397 			XP_TEST_HIT
12398 		    }
12399 		    break;
12400                 case NODE_TEST_PI:
12401                     if ((cur->type == XML_PI_NODE) &&
12402                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12403 		    {
12404 			XP_TEST_HIT
12405                     }
12406                     break;
12407                 case NODE_TEST_ALL:
12408                     if (axis == AXIS_ATTRIBUTE) {
12409                         if (cur->type == XML_ATTRIBUTE_NODE)
12410 			{
12411                             if (prefix == NULL)
12412 			    {
12413 				XP_TEST_HIT
12414                             } else if ((cur->ns != NULL) &&
12415 				(xmlStrEqual(URI, cur->ns->href)))
12416 			    {
12417 				XP_TEST_HIT
12418                             }
12419                         }
12420                     } else if (axis == AXIS_NAMESPACE) {
12421                         if (cur->type == XML_NAMESPACE_DECL)
12422 			{
12423 			    XP_TEST_HIT_NS
12424                         }
12425                     } else {
12426                         if (cur->type == XML_ELEMENT_NODE) {
12427                             if (prefix == NULL)
12428 			    {
12429 				XP_TEST_HIT
12430 
12431                             } else if ((cur->ns != NULL) &&
12432 				(xmlStrEqual(URI, cur->ns->href)))
12433 			    {
12434 				XP_TEST_HIT
12435                             }
12436                         }
12437                     }
12438                     break;
12439                 case NODE_TEST_NS:{
12440                         TODO;
12441                         break;
12442                     }
12443                 case NODE_TEST_NAME:
12444                     if (axis == AXIS_ATTRIBUTE) {
12445                         if (cur->type != XML_ATTRIBUTE_NODE)
12446 			    break;
12447 		    } else if (axis == AXIS_NAMESPACE) {
12448                         if (cur->type != XML_NAMESPACE_DECL)
12449 			    break;
12450 		    } else {
12451 		        if (cur->type != XML_ELEMENT_NODE)
12452 			    break;
12453 		    }
12454                     switch (cur->type) {
12455                         case XML_ELEMENT_NODE:
12456                             if (xmlStrEqual(name, cur->name)) {
12457                                 if (prefix == NULL) {
12458                                     if (cur->ns == NULL)
12459 				    {
12460 					XP_TEST_HIT
12461                                     }
12462                                 } else {
12463                                     if ((cur->ns != NULL) &&
12464                                         (xmlStrEqual(URI, cur->ns->href)))
12465 				    {
12466 					XP_TEST_HIT
12467                                     }
12468                                 }
12469                             }
12470                             break;
12471                         case XML_ATTRIBUTE_NODE:{
12472                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12473 
12474                                 if (xmlStrEqual(name, attr->name)) {
12475                                     if (prefix == NULL) {
12476                                         if ((attr->ns == NULL) ||
12477                                             (attr->ns->prefix == NULL))
12478 					{
12479 					    XP_TEST_HIT
12480                                         }
12481                                     } else {
12482                                         if ((attr->ns != NULL) &&
12483                                             (xmlStrEqual(URI,
12484 					      attr->ns->href)))
12485 					{
12486 					    XP_TEST_HIT
12487                                         }
12488                                     }
12489                                 }
12490                                 break;
12491                             }
12492                         case XML_NAMESPACE_DECL:
12493                             if (cur->type == XML_NAMESPACE_DECL) {
12494                                 xmlNsPtr ns = (xmlNsPtr) cur;
12495 
12496                                 if ((ns->prefix != NULL) && (name != NULL)
12497                                     && (xmlStrEqual(ns->prefix, name)))
12498 				{
12499 				    XP_TEST_HIT_NS
12500                                 }
12501                             }
12502                             break;
12503                         default:
12504                             break;
12505                     }
12506                     break;
12507 	    } /* switch(test) */
12508         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12509 
12510 	goto apply_predicates;
12511 
12512 axis_range_end: /* ----------------------------------------------------- */
12513 	/*
12514 	* We have a "/foo[n]", and position() = n was reached.
12515 	* Note that we can have as well "/foo/::parent::foo[1]", so
12516 	* a duplicate-aware merge is still needed.
12517 	* Merge with the result.
12518 	*/
12519 	if (outSeq == NULL) {
12520 	    outSeq = seq;
12521 	    seq = NULL;
12522 	} else
12523 	    outSeq = mergeAndClear(outSeq, seq, 0);
12524 	/*
12525 	* Break if only a true/false result was requested.
12526 	*/
12527 	if (toBool)
12528 	    break;
12529 	continue;
12530 
12531 first_hit: /* ---------------------------------------------------------- */
12532 	/*
12533 	* Break if only a true/false result was requested and
12534 	* no predicates existed and a node test succeeded.
12535 	*/
12536 	if (outSeq == NULL) {
12537 	    outSeq = seq;
12538 	    seq = NULL;
12539 	} else
12540 	    outSeq = mergeAndClear(outSeq, seq, 0);
12541 	break;
12542 
12543 #ifdef DEBUG_STEP
12544 	if (seq != NULL)
12545 	    nbMatches += seq->nodeNr;
12546 #endif
12547 
12548 apply_predicates: /* --------------------------------------------------- */
12549         if (ctxt->error != XPATH_EXPRESSION_OK)
12550 	    goto error;
12551 
12552         /*
12553 	* Apply predicates.
12554 	*/
12555         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12556 	    /*
12557 	    * E.g. when we have a "/foo[some expression][n]".
12558 	    */
12559 	    /*
12560 	    * QUESTION TODO: The old predicate evaluation took into
12561 	    *  account location-sets.
12562 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12563 	    *  Do we expect such a set here?
12564 	    *  All what I learned now from the evaluation semantics
12565 	    *  does not indicate that a location-set will be processed
12566 	    *  here, so this looks OK.
12567 	    */
12568 	    /*
12569 	    * Iterate over all predicates, starting with the outermost
12570 	    * predicate.
12571 	    * TODO: Problem: we cannot execute the inner predicates first
12572 	    *  since we cannot go back *up* the operator tree!
12573 	    *  Options we have:
12574 	    *  1) Use of recursive functions (like is it currently done
12575 	    *     via xmlXPathCompOpEval())
12576 	    *  2) Add a predicate evaluation information stack to the
12577 	    *     context struct
12578 	    *  3) Change the way the operators are linked; we need a
12579 	    *     "parent" field on xmlXPathStepOp
12580 	    *
12581 	    * For the moment, I'll try to solve this with a recursive
12582 	    * function: xmlXPathCompOpEvalPredicate().
12583 	    */
12584 	    size = seq->nodeNr;
12585 	    if (hasPredicateRange != 0)
12586 		newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12587 		    predOp, seq, size, maxPos, maxPos, hasNsNodes);
12588 	    else
12589 		newSize = xmlXPathCompOpEvalPredicate(ctxt,
12590 		    predOp, seq, size, hasNsNodes);
12591 
12592 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12593 		total = 0;
12594 		goto error;
12595 	    }
12596 	    /*
12597 	    * Add the filtered set of nodes to the result node set.
12598 	    */
12599 	    if (newSize == 0) {
12600 		/*
12601 		* The predicates filtered all nodes out.
12602 		*/
12603 		xmlXPathNodeSetClear(seq, hasNsNodes);
12604 	    } else if (seq->nodeNr > 0) {
12605 		/*
12606 		* Add to result set.
12607 		*/
12608 		if (outSeq == NULL) {
12609 		    if (size != newSize) {
12610 			/*
12611 			* We need to merge and clear here, since
12612 			* the sequence will contained NULLed entries.
12613 			*/
12614 			outSeq = mergeAndClear(NULL, seq, 1);
12615 		    } else {
12616 			outSeq = seq;
12617 			seq = NULL;
12618 		    }
12619 		} else
12620 		    outSeq = mergeAndClear(outSeq, seq,
12621 			(size != newSize) ? 1: 0);
12622 		/*
12623 		* Break if only a true/false result was requested.
12624 		*/
12625 		if (toBool)
12626 		    break;
12627 	    }
12628         } else if (seq->nodeNr > 0) {
12629 	    /*
12630 	    * Add to result set.
12631 	    */
12632 	    if (outSeq == NULL) {
12633 		outSeq = seq;
12634 		seq = NULL;
12635 	    } else {
12636 		outSeq = mergeAndClear(outSeq, seq, 0);
12637 	    }
12638 	}
12639     }
12640 
12641 error:
12642     if ((obj->boolval) && (obj->user != NULL)) {
12643 	/*
12644 	* QUESTION TODO: What does this do and why?
12645 	* TODO: Do we have to do this also for the "error"
12646 	* cleanup further down?
12647 	*/
12648 	ctxt->value->boolval = 1;
12649 	ctxt->value->user = obj->user;
12650 	obj->user = NULL;
12651 	obj->boolval = 0;
12652     }
12653     xmlXPathReleaseObject(xpctxt, obj);
12654 
12655     /*
12656     * Ensure we return at least an emtpy set.
12657     */
12658     if (outSeq == NULL) {
12659 	if ((seq != NULL) && (seq->nodeNr == 0))
12660 	    outSeq = seq;
12661 	else
12662 	    outSeq = xmlXPathNodeSetCreate(NULL);
12663         /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12664     }
12665     if ((seq != NULL) && (seq != outSeq)) {
12666 	 xmlXPathFreeNodeSet(seq);
12667     }
12668     /*
12669     * Hand over the result. Better to push the set also in
12670     * case of errors.
12671     */
12672     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12673     /*
12674     * Reset the context node.
12675     */
12676     xpctxt->node = oldContextNode;
12677     /*
12678     * When traversing the namespace axis in "toBool" mode, it's
12679     * possible that tmpNsList wasn't freed.
12680     */
12681     if (xpctxt->tmpNsList != NULL) {
12682         xmlFree(xpctxt->tmpNsList);
12683         xpctxt->tmpNsList = NULL;
12684     }
12685 
12686 #ifdef DEBUG_STEP
12687     xmlGenericError(xmlGenericErrorContext,
12688 	"\nExamined %d nodes, found %d nodes at that step\n",
12689 	total, nbMatches);
12690 #endif
12691 
12692     return(total);
12693 }
12694 
12695 static int
12696 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12697 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12698 
12699 /**
12700  * xmlXPathCompOpEvalFirst:
12701  * @ctxt:  the XPath parser context with the compiled expression
12702  * @op:  an XPath compiled operation
12703  * @first:  the first elem found so far
12704  *
12705  * Evaluate the Precompiled XPath operation searching only the first
12706  * element in document order
12707  *
12708  * Returns the number of examined objects.
12709  */
12710 static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12711 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12712                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12713 {
12714     int total = 0, cur;
12715     xmlXPathCompExprPtr comp;
12716     xmlXPathObjectPtr arg1, arg2;
12717 
12718     CHECK_ERROR0;
12719     comp = ctxt->comp;
12720     switch (op->op) {
12721         case XPATH_OP_END:
12722             return (0);
12723         case XPATH_OP_UNION:
12724             total =
12725                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12726                                         first);
12727 	    CHECK_ERROR0;
12728             if ((ctxt->value != NULL)
12729                 && (ctxt->value->type == XPATH_NODESET)
12730                 && (ctxt->value->nodesetval != NULL)
12731                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12732                 /*
12733                  * limit tree traversing to first node in the result
12734                  */
12735 		/*
12736 		* OPTIMIZE TODO: This implicitely sorts
12737 		*  the result, even if not needed. E.g. if the argument
12738 		*  of the count() function, no sorting is needed.
12739 		* OPTIMIZE TODO: How do we know if the node-list wasn't
12740 		*  aready sorted?
12741 		*/
12742 		if (ctxt->value->nodesetval->nodeNr > 1)
12743 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12744                 *first = ctxt->value->nodesetval->nodeTab[0];
12745             }
12746             cur =
12747                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12748                                         first);
12749 	    CHECK_ERROR0;
12750 
12751             arg2 = valuePop(ctxt);
12752             arg1 = valuePop(ctxt);
12753             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12754                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12755 	        xmlXPathReleaseObject(ctxt->context, arg1);
12756 	        xmlXPathReleaseObject(ctxt->context, arg2);
12757                 XP_ERROR0(XPATH_INVALID_TYPE);
12758             }
12759 
12760             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12761                                                     arg2->nodesetval);
12762             valuePush(ctxt, arg1);
12763 	    xmlXPathReleaseObject(ctxt->context, arg2);
12764             /* optimizer */
12765 	    if (total > cur)
12766 		xmlXPathCompSwap(op);
12767             return (total + cur);
12768         case XPATH_OP_ROOT:
12769             xmlXPathRoot(ctxt);
12770             return (0);
12771         case XPATH_OP_NODE:
12772             if (op->ch1 != -1)
12773                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12774 	    CHECK_ERROR0;
12775             if (op->ch2 != -1)
12776                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12777 	    CHECK_ERROR0;
12778 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12779 		ctxt->context->node));
12780             return (total);
12781         case XPATH_OP_RESET:
12782             if (op->ch1 != -1)
12783                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12784 	    CHECK_ERROR0;
12785             if (op->ch2 != -1)
12786                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12787 	    CHECK_ERROR0;
12788             ctxt->context->node = NULL;
12789             return (total);
12790         case XPATH_OP_COLLECT:{
12791                 if (op->ch1 == -1)
12792                     return (total);
12793 
12794                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12795 		CHECK_ERROR0;
12796 
12797                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12798                 return (total);
12799             }
12800         case XPATH_OP_VALUE:
12801             valuePush(ctxt,
12802                       xmlXPathCacheObjectCopy(ctxt->context,
12803 			(xmlXPathObjectPtr) op->value4));
12804             return (0);
12805         case XPATH_OP_SORT:
12806             if (op->ch1 != -1)
12807                 total +=
12808                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12809                                             first);
12810 	    CHECK_ERROR0;
12811             if ((ctxt->value != NULL)
12812                 && (ctxt->value->type == XPATH_NODESET)
12813                 && (ctxt->value->nodesetval != NULL)
12814 		&& (ctxt->value->nodesetval->nodeNr > 1))
12815                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12816             return (total);
12817 #ifdef XP_OPTIMIZED_FILTER_FIRST
12818 	case XPATH_OP_FILTER:
12819                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12820             return (total);
12821 #endif
12822         default:
12823             return (xmlXPathCompOpEval(ctxt, op));
12824     }
12825 }
12826 
12827 /**
12828  * xmlXPathCompOpEvalLast:
12829  * @ctxt:  the XPath parser context with the compiled expression
12830  * @op:  an XPath compiled operation
12831  * @last:  the last elem found so far
12832  *
12833  * Evaluate the Precompiled XPath operation searching only the last
12834  * element in document order
12835  *
12836  * Returns the number of nodes traversed
12837  */
12838 static int
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * last)12839 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12840                        xmlNodePtr * last)
12841 {
12842     int total = 0, cur;
12843     xmlXPathCompExprPtr comp;
12844     xmlXPathObjectPtr arg1, arg2;
12845     xmlNodePtr bak;
12846     xmlDocPtr bakd;
12847     int pp;
12848     int cs;
12849 
12850     CHECK_ERROR0;
12851     comp = ctxt->comp;
12852     switch (op->op) {
12853         case XPATH_OP_END:
12854             return (0);
12855         case XPATH_OP_UNION:
12856 	    bakd = ctxt->context->doc;
12857 	    bak = ctxt->context->node;
12858 	    pp = ctxt->context->proximityPosition;
12859 	    cs = ctxt->context->contextSize;
12860             total =
12861                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12862 	    CHECK_ERROR0;
12863             if ((ctxt->value != NULL)
12864                 && (ctxt->value->type == XPATH_NODESET)
12865                 && (ctxt->value->nodesetval != NULL)
12866                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12867                 /*
12868                  * limit tree traversing to first node in the result
12869                  */
12870 		if (ctxt->value->nodesetval->nodeNr > 1)
12871 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12872                 *last =
12873                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12874                                                      nodesetval->nodeNr -
12875                                                      1];
12876             }
12877 	    ctxt->context->doc = bakd;
12878 	    ctxt->context->node = bak;
12879 	    ctxt->context->proximityPosition = pp;
12880 	    ctxt->context->contextSize = cs;
12881             cur =
12882                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12883 	    CHECK_ERROR0;
12884             if ((ctxt->value != NULL)
12885                 && (ctxt->value->type == XPATH_NODESET)
12886                 && (ctxt->value->nodesetval != NULL)
12887                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12888             }
12889 
12890             arg2 = valuePop(ctxt);
12891             arg1 = valuePop(ctxt);
12892             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12893                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12894 	        xmlXPathReleaseObject(ctxt->context, arg1);
12895 	        xmlXPathReleaseObject(ctxt->context, arg2);
12896                 XP_ERROR0(XPATH_INVALID_TYPE);
12897             }
12898 
12899             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12900                                                     arg2->nodesetval);
12901             valuePush(ctxt, arg1);
12902 	    xmlXPathReleaseObject(ctxt->context, arg2);
12903             /* optimizer */
12904 	    if (total > cur)
12905 		xmlXPathCompSwap(op);
12906             return (total + cur);
12907         case XPATH_OP_ROOT:
12908             xmlXPathRoot(ctxt);
12909             return (0);
12910         case XPATH_OP_NODE:
12911             if (op->ch1 != -1)
12912                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12913 	    CHECK_ERROR0;
12914             if (op->ch2 != -1)
12915                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12916 	    CHECK_ERROR0;
12917 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12918 		ctxt->context->node));
12919             return (total);
12920         case XPATH_OP_RESET:
12921             if (op->ch1 != -1)
12922                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12923 	    CHECK_ERROR0;
12924             if (op->ch2 != -1)
12925                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12926 	    CHECK_ERROR0;
12927             ctxt->context->node = NULL;
12928             return (total);
12929         case XPATH_OP_COLLECT:{
12930                 if (op->ch1 == -1)
12931                     return (0);
12932 
12933                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12934 		CHECK_ERROR0;
12935 
12936                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12937                 return (total);
12938             }
12939         case XPATH_OP_VALUE:
12940             valuePush(ctxt,
12941                       xmlXPathCacheObjectCopy(ctxt->context,
12942 			(xmlXPathObjectPtr) op->value4));
12943             return (0);
12944         case XPATH_OP_SORT:
12945             if (op->ch1 != -1)
12946                 total +=
12947                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12948                                            last);
12949 	    CHECK_ERROR0;
12950             if ((ctxt->value != NULL)
12951                 && (ctxt->value->type == XPATH_NODESET)
12952                 && (ctxt->value->nodesetval != NULL)
12953 		&& (ctxt->value->nodesetval->nodeNr > 1))
12954                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12955             return (total);
12956         default:
12957             return (xmlXPathCompOpEval(ctxt, op));
12958     }
12959 }
12960 
12961 #ifdef XP_OPTIMIZED_FILTER_FIRST
12962 static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12963 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12964 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
12965 {
12966     int total = 0;
12967     xmlXPathCompExprPtr comp;
12968     xmlXPathObjectPtr res;
12969     xmlXPathObjectPtr obj;
12970     xmlNodeSetPtr oldset;
12971     xmlNodePtr oldnode;
12972     xmlDocPtr oldDoc;
12973     int i;
12974 
12975     CHECK_ERROR0;
12976     comp = ctxt->comp;
12977     /*
12978     * Optimization for ()[last()] selection i.e. the last elem
12979     */
12980     if ((op->ch1 != -1) && (op->ch2 != -1) &&
12981 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12982 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12983 	int f = comp->steps[op->ch2].ch1;
12984 
12985 	if ((f != -1) &&
12986 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12987 	    (comp->steps[f].value5 == NULL) &&
12988 	    (comp->steps[f].value == 0) &&
12989 	    (comp->steps[f].value4 != NULL) &&
12990 	    (xmlStrEqual
12991 	    (comp->steps[f].value4, BAD_CAST "last"))) {
12992 	    xmlNodePtr last = NULL;
12993 
12994 	    total +=
12995 		xmlXPathCompOpEvalLast(ctxt,
12996 		    &comp->steps[op->ch1],
12997 		    &last);
12998 	    CHECK_ERROR0;
12999 	    /*
13000 	    * The nodeset should be in document order,
13001 	    * Keep only the last value
13002 	    */
13003 	    if ((ctxt->value != NULL) &&
13004 		(ctxt->value->type == XPATH_NODESET) &&
13005 		(ctxt->value->nodesetval != NULL) &&
13006 		(ctxt->value->nodesetval->nodeTab != NULL) &&
13007 		(ctxt->value->nodesetval->nodeNr > 1)) {
13008                 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13009 		*first = *(ctxt->value->nodesetval->nodeTab);
13010 	    }
13011 	    return (total);
13012 	}
13013     }
13014 
13015     if (op->ch1 != -1)
13016 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13017     CHECK_ERROR0;
13018     if (op->ch2 == -1)
13019 	return (total);
13020     if (ctxt->value == NULL)
13021 	return (total);
13022 
13023 #ifdef LIBXML_XPTR_ENABLED
13024     oldnode = ctxt->context->node;
13025     /*
13026     * Hum are we filtering the result of an XPointer expression
13027     */
13028     if (ctxt->value->type == XPATH_LOCATIONSET) {
13029 	xmlXPathObjectPtr tmp = NULL;
13030 	xmlLocationSetPtr newlocset = NULL;
13031 	xmlLocationSetPtr oldlocset;
13032 
13033 	/*
13034 	* Extract the old locset, and then evaluate the result of the
13035 	* expression for all the element in the locset. use it to grow
13036 	* up a new locset.
13037 	*/
13038 	CHECK_TYPE0(XPATH_LOCATIONSET);
13039 	obj = valuePop(ctxt);
13040 	oldlocset = obj->user;
13041 	ctxt->context->node = NULL;
13042 
13043 	if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13044 	    ctxt->context->contextSize = 0;
13045 	    ctxt->context->proximityPosition = 0;
13046 	    if (op->ch2 != -1)
13047 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13048 	    res = valuePop(ctxt);
13049 	    if (res != NULL) {
13050 		xmlXPathReleaseObject(ctxt->context, res);
13051 	    }
13052 	    valuePush(ctxt, obj);
13053 	    CHECK_ERROR0;
13054 	    return (total);
13055 	}
13056 	newlocset = xmlXPtrLocationSetCreate(NULL);
13057 
13058 	for (i = 0; i < oldlocset->locNr; i++) {
13059 	    /*
13060 	    * Run the evaluation with a node list made of a
13061 	    * single item in the nodelocset.
13062 	    */
13063 	    ctxt->context->node = oldlocset->locTab[i]->user;
13064 	    ctxt->context->contextSize = oldlocset->locNr;
13065 	    ctxt->context->proximityPosition = i + 1;
13066 	    if (tmp == NULL) {
13067 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13068 		    ctxt->context->node);
13069 	    } else {
13070 		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13071 		                             ctxt->context->node) < 0) {
13072 		    ctxt->error = XPATH_MEMORY_ERROR;
13073 		}
13074 	    }
13075 	    valuePush(ctxt, tmp);
13076 	    if (op->ch2 != -1)
13077 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13078 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13079 		xmlXPathFreeObject(obj);
13080 		return(0);
13081 	    }
13082 	    /*
13083 	    * The result of the evaluation need to be tested to
13084 	    * decided whether the filter succeeded or not
13085 	    */
13086 	    res = valuePop(ctxt);
13087 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13088 		xmlXPtrLocationSetAdd(newlocset,
13089 		    xmlXPathCacheObjectCopy(ctxt->context,
13090 			oldlocset->locTab[i]));
13091 	    }
13092 	    /*
13093 	    * Cleanup
13094 	    */
13095 	    if (res != NULL) {
13096 		xmlXPathReleaseObject(ctxt->context, res);
13097 	    }
13098 	    if (ctxt->value == tmp) {
13099 		valuePop(ctxt);
13100 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13101 		/*
13102 		* REVISIT TODO: Don't create a temporary nodeset
13103 		* for everly iteration.
13104 		*/
13105 		/* OLD: xmlXPathFreeObject(res); */
13106 	    } else
13107 		tmp = NULL;
13108 	    ctxt->context->node = NULL;
13109 	    /*
13110 	    * Only put the first node in the result, then leave.
13111 	    */
13112 	    if (newlocset->locNr > 0) {
13113 		*first = (xmlNodePtr) oldlocset->locTab[i]->user;
13114 		break;
13115 	    }
13116 	}
13117 	if (tmp != NULL) {
13118 	    xmlXPathReleaseObject(ctxt->context, tmp);
13119 	}
13120 	/*
13121 	* The result is used as the new evaluation locset.
13122 	*/
13123 	xmlXPathReleaseObject(ctxt->context, obj);
13124 	ctxt->context->node = NULL;
13125 	ctxt->context->contextSize = -1;
13126 	ctxt->context->proximityPosition = -1;
13127 	valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13128 	ctxt->context->node = oldnode;
13129 	return (total);
13130     }
13131 #endif /* LIBXML_XPTR_ENABLED */
13132 
13133     /*
13134     * Extract the old set, and then evaluate the result of the
13135     * expression for all the element in the set. use it to grow
13136     * up a new set.
13137     */
13138     CHECK_TYPE0(XPATH_NODESET);
13139     obj = valuePop(ctxt);
13140     oldset = obj->nodesetval;
13141 
13142     oldnode = ctxt->context->node;
13143     oldDoc = ctxt->context->doc;
13144     ctxt->context->node = NULL;
13145 
13146     if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13147 	ctxt->context->contextSize = 0;
13148 	ctxt->context->proximityPosition = 0;
13149 	/* QUESTION TODO: Why was this code commented out?
13150 	    if (op->ch2 != -1)
13151 		total +=
13152 		    xmlXPathCompOpEval(ctxt,
13153 			&comp->steps[op->ch2]);
13154 	    CHECK_ERROR0;
13155 	    res = valuePop(ctxt);
13156 	    if (res != NULL)
13157 		xmlXPathFreeObject(res);
13158 	*/
13159 	valuePush(ctxt, obj);
13160 	ctxt->context->node = oldnode;
13161 	CHECK_ERROR0;
13162     } else {
13163 	xmlNodeSetPtr newset;
13164 	xmlXPathObjectPtr tmp = NULL;
13165 	/*
13166 	* Initialize the new set.
13167 	* Also set the xpath document in case things like
13168 	* key() evaluation are attempted on the predicate
13169 	*/
13170 	newset = xmlXPathNodeSetCreate(NULL);
13171         /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13172 
13173 	for (i = 0; i < oldset->nodeNr; i++) {
13174 	    /*
13175 	    * Run the evaluation with a node list made of
13176 	    * a single item in the nodeset.
13177 	    */
13178 	    ctxt->context->node = oldset->nodeTab[i];
13179 	    if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13180 		(oldset->nodeTab[i]->doc != NULL))
13181 		ctxt->context->doc = oldset->nodeTab[i]->doc;
13182 	    if (tmp == NULL) {
13183 		tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13184 		    ctxt->context->node);
13185 	    } else {
13186 		if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13187 		                             ctxt->context->node) < 0) {
13188 		    ctxt->error = XPATH_MEMORY_ERROR;
13189 		}
13190 	    }
13191 	    valuePush(ctxt, tmp);
13192 	    ctxt->context->contextSize = oldset->nodeNr;
13193 	    ctxt->context->proximityPosition = i + 1;
13194 	    if (op->ch2 != -1)
13195 		total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13196 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
13197 		xmlXPathFreeNodeSet(newset);
13198 		xmlXPathFreeObject(obj);
13199 		return(0);
13200 	    }
13201 	    /*
13202 	    * The result of the evaluation needs to be tested to
13203 	    * decide whether the filter succeeded or not
13204 	    */
13205 	    res = valuePop(ctxt);
13206 	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13207 		if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13208 		    ctxt->error = XPATH_MEMORY_ERROR;
13209 	    }
13210 	    /*
13211 	    * Cleanup
13212 	    */
13213 	    if (res != NULL) {
13214 		xmlXPathReleaseObject(ctxt->context, res);
13215 	    }
13216 	    if (ctxt->value == tmp) {
13217 		valuePop(ctxt);
13218 		/*
13219 		* Don't free the temporary nodeset
13220 		* in order to avoid massive recreation inside this
13221 		* loop.
13222 		*/
13223 		xmlXPathNodeSetClear(tmp->nodesetval, 1);
13224 	    } else
13225 		tmp = NULL;
13226 	    ctxt->context->node = NULL;
13227 	    /*
13228 	    * Only put the first node in the result, then leave.
13229 	    */
13230 	    if (newset->nodeNr > 0) {
13231 		*first = *(newset->nodeTab);
13232 		break;
13233 	    }
13234 	}
13235 	if (tmp != NULL) {
13236 	    xmlXPathReleaseObject(ctxt->context, tmp);
13237 	}
13238 	/*
13239 	* The result is used as the new evaluation set.
13240 	*/
13241 	xmlXPathReleaseObject(ctxt->context, obj);
13242 	ctxt->context->node = NULL;
13243 	ctxt->context->contextSize = -1;
13244 	ctxt->context->proximityPosition = -1;
13245 	/* may want to move this past the '}' later */
13246 	ctxt->context->doc = oldDoc;
13247 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13248     }
13249     ctxt->context->node = oldnode;
13250     return(total);
13251 }
13252 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13253 
13254 /**
13255  * xmlXPathCompOpEval:
13256  * @ctxt:  the XPath parser context with the compiled expression
13257  * @op:  an XPath compiled operation
13258  *
13259  * Evaluate the Precompiled XPath operation
13260  * Returns the number of nodes traversed
13261  */
13262 static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op)13263 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13264 {
13265     int total = 0;
13266     int equal, ret;
13267     xmlXPathCompExprPtr comp;
13268     xmlXPathObjectPtr arg1, arg2;
13269     xmlNodePtr bak;
13270     xmlDocPtr bakd;
13271     int pp;
13272     int cs;
13273 
13274     CHECK_ERROR0;
13275     comp = ctxt->comp;
13276     switch (op->op) {
13277         case XPATH_OP_END:
13278             return (0);
13279         case XPATH_OP_AND:
13280 	    bakd = ctxt->context->doc;
13281 	    bak = ctxt->context->node;
13282 	    pp = ctxt->context->proximityPosition;
13283 	    cs = ctxt->context->contextSize;
13284             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13285 	    CHECK_ERROR0;
13286             xmlXPathBooleanFunction(ctxt, 1);
13287             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13288                 return (total);
13289             arg2 = valuePop(ctxt);
13290 	    ctxt->context->doc = bakd;
13291 	    ctxt->context->node = bak;
13292 	    ctxt->context->proximityPosition = pp;
13293 	    ctxt->context->contextSize = cs;
13294             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13295 	    if (ctxt->error) {
13296 		xmlXPathFreeObject(arg2);
13297 		return(0);
13298 	    }
13299             xmlXPathBooleanFunction(ctxt, 1);
13300             arg1 = valuePop(ctxt);
13301             arg1->boolval &= arg2->boolval;
13302             valuePush(ctxt, arg1);
13303 	    xmlXPathReleaseObject(ctxt->context, arg2);
13304             return (total);
13305         case XPATH_OP_OR:
13306 	    bakd = ctxt->context->doc;
13307 	    bak = ctxt->context->node;
13308 	    pp = ctxt->context->proximityPosition;
13309 	    cs = ctxt->context->contextSize;
13310             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13311 	    CHECK_ERROR0;
13312             xmlXPathBooleanFunction(ctxt, 1);
13313             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13314                 return (total);
13315             arg2 = valuePop(ctxt);
13316 	    ctxt->context->doc = bakd;
13317 	    ctxt->context->node = bak;
13318 	    ctxt->context->proximityPosition = pp;
13319 	    ctxt->context->contextSize = cs;
13320             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13321 	    if (ctxt->error) {
13322 		xmlXPathFreeObject(arg2);
13323 		return(0);
13324 	    }
13325             xmlXPathBooleanFunction(ctxt, 1);
13326             arg1 = valuePop(ctxt);
13327             arg1->boolval |= arg2->boolval;
13328             valuePush(ctxt, arg1);
13329 	    xmlXPathReleaseObject(ctxt->context, arg2);
13330             return (total);
13331         case XPATH_OP_EQUAL:
13332 	    bakd = ctxt->context->doc;
13333 	    bak = ctxt->context->node;
13334 	    pp = ctxt->context->proximityPosition;
13335 	    cs = ctxt->context->contextSize;
13336             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13337 	    CHECK_ERROR0;
13338 	    ctxt->context->doc = bakd;
13339 	    ctxt->context->node = bak;
13340 	    ctxt->context->proximityPosition = pp;
13341 	    ctxt->context->contextSize = cs;
13342             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13343 	    CHECK_ERROR0;
13344 	    if (op->value)
13345 		equal = xmlXPathEqualValues(ctxt);
13346 	    else
13347 		equal = xmlXPathNotEqualValues(ctxt);
13348 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13349             return (total);
13350         case XPATH_OP_CMP:
13351 	    bakd = ctxt->context->doc;
13352 	    bak = ctxt->context->node;
13353 	    pp = ctxt->context->proximityPosition;
13354 	    cs = ctxt->context->contextSize;
13355             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13356 	    CHECK_ERROR0;
13357 	    ctxt->context->doc = bakd;
13358 	    ctxt->context->node = bak;
13359 	    ctxt->context->proximityPosition = pp;
13360 	    ctxt->context->contextSize = cs;
13361             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13362 	    CHECK_ERROR0;
13363             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13364 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13365             return (total);
13366         case XPATH_OP_PLUS:
13367 	    bakd = ctxt->context->doc;
13368 	    bak = ctxt->context->node;
13369 	    pp = ctxt->context->proximityPosition;
13370 	    cs = ctxt->context->contextSize;
13371             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13372 	    CHECK_ERROR0;
13373             if (op->ch2 != -1) {
13374 		ctxt->context->doc = bakd;
13375 		ctxt->context->node = bak;
13376 		ctxt->context->proximityPosition = pp;
13377 		ctxt->context->contextSize = cs;
13378                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13379 	    }
13380 	    CHECK_ERROR0;
13381             if (op->value == 0)
13382                 xmlXPathSubValues(ctxt);
13383             else if (op->value == 1)
13384                 xmlXPathAddValues(ctxt);
13385             else if (op->value == 2)
13386                 xmlXPathValueFlipSign(ctxt);
13387             else if (op->value == 3) {
13388                 CAST_TO_NUMBER;
13389                 CHECK_TYPE0(XPATH_NUMBER);
13390             }
13391             return (total);
13392         case XPATH_OP_MULT:
13393 	    bakd = ctxt->context->doc;
13394 	    bak = ctxt->context->node;
13395 	    pp = ctxt->context->proximityPosition;
13396 	    cs = ctxt->context->contextSize;
13397             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13398 	    CHECK_ERROR0;
13399 	    ctxt->context->doc = bakd;
13400 	    ctxt->context->node = bak;
13401 	    ctxt->context->proximityPosition = pp;
13402 	    ctxt->context->contextSize = cs;
13403             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13404 	    CHECK_ERROR0;
13405             if (op->value == 0)
13406                 xmlXPathMultValues(ctxt);
13407             else if (op->value == 1)
13408                 xmlXPathDivValues(ctxt);
13409             else if (op->value == 2)
13410                 xmlXPathModValues(ctxt);
13411             return (total);
13412         case XPATH_OP_UNION:
13413 	    bakd = ctxt->context->doc;
13414 	    bak = ctxt->context->node;
13415 	    pp = ctxt->context->proximityPosition;
13416 	    cs = ctxt->context->contextSize;
13417             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13418 	    CHECK_ERROR0;
13419 	    ctxt->context->doc = bakd;
13420 	    ctxt->context->node = bak;
13421 	    ctxt->context->proximityPosition = pp;
13422 	    ctxt->context->contextSize = cs;
13423             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13424 	    CHECK_ERROR0;
13425 
13426             arg2 = valuePop(ctxt);
13427             arg1 = valuePop(ctxt);
13428             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13429                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13430 	        xmlXPathReleaseObject(ctxt->context, arg1);
13431 	        xmlXPathReleaseObject(ctxt->context, arg2);
13432                 XP_ERROR0(XPATH_INVALID_TYPE);
13433             }
13434 
13435 	    if ((arg1->nodesetval == NULL) ||
13436 		((arg2->nodesetval != NULL) &&
13437 		 (arg2->nodesetval->nodeNr != 0)))
13438 	    {
13439 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13440 							arg2->nodesetval);
13441 	    }
13442 
13443             valuePush(ctxt, arg1);
13444 	    xmlXPathReleaseObject(ctxt->context, arg2);
13445             return (total);
13446         case XPATH_OP_ROOT:
13447             xmlXPathRoot(ctxt);
13448             return (total);
13449         case XPATH_OP_NODE:
13450             if (op->ch1 != -1)
13451                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13452 	    CHECK_ERROR0;
13453             if (op->ch2 != -1)
13454                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13455 	    CHECK_ERROR0;
13456 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13457 		ctxt->context->node));
13458             return (total);
13459         case XPATH_OP_RESET:
13460             if (op->ch1 != -1)
13461                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13462 	    CHECK_ERROR0;
13463             if (op->ch2 != -1)
13464                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13465 	    CHECK_ERROR0;
13466             ctxt->context->node = NULL;
13467             return (total);
13468         case XPATH_OP_COLLECT:{
13469                 if (op->ch1 == -1)
13470                     return (total);
13471 
13472                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13473 		CHECK_ERROR0;
13474 
13475                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13476                 return (total);
13477             }
13478         case XPATH_OP_VALUE:
13479             valuePush(ctxt,
13480                       xmlXPathCacheObjectCopy(ctxt->context,
13481 			(xmlXPathObjectPtr) op->value4));
13482             return (total);
13483         case XPATH_OP_VARIABLE:{
13484 		xmlXPathObjectPtr val;
13485 
13486                 if (op->ch1 != -1)
13487                     total +=
13488                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13489                 if (op->value5 == NULL) {
13490 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13491 		    if (val == NULL)
13492 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13493                     valuePush(ctxt, val);
13494 		} else {
13495                     const xmlChar *URI;
13496 
13497                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13498                     if (URI == NULL) {
13499                         xmlGenericError(xmlGenericErrorContext,
13500             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13501                                     (char *) op->value4, (char *)op->value5);
13502                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13503                         return (total);
13504                     }
13505 		    val = xmlXPathVariableLookupNS(ctxt->context,
13506                                                        op->value4, URI);
13507 		    if (val == NULL)
13508 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13509                     valuePush(ctxt, val);
13510                 }
13511                 return (total);
13512             }
13513         case XPATH_OP_FUNCTION:{
13514                 xmlXPathFunction func;
13515                 const xmlChar *oldFunc, *oldFuncURI;
13516 		int i;
13517                 int frame;
13518 
13519                 frame = xmlXPathSetFrame(ctxt);
13520                 if (op->ch1 != -1) {
13521                     total +=
13522                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13523                     if (ctxt->error != XPATH_EXPRESSION_OK) {
13524                         xmlXPathPopFrame(ctxt, frame);
13525                         return (total);
13526                     }
13527                 }
13528 		if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13529 		    xmlGenericError(xmlGenericErrorContext,
13530 			    "xmlXPathCompOpEval: parameter error\n");
13531 		    ctxt->error = XPATH_INVALID_OPERAND;
13532                     xmlXPathPopFrame(ctxt, frame);
13533 		    return (total);
13534 		}
13535 		for (i = 0; i < op->value; i++) {
13536 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13537 			xmlGenericError(xmlGenericErrorContext,
13538 				"xmlXPathCompOpEval: parameter error\n");
13539 			ctxt->error = XPATH_INVALID_OPERAND;
13540                         xmlXPathPopFrame(ctxt, frame);
13541 			return (total);
13542 		    }
13543                 }
13544                 if (op->cache != NULL)
13545                     func = op->cache;
13546                 else {
13547                     const xmlChar *URI = NULL;
13548 
13549                     if (op->value5 == NULL)
13550                         func =
13551                             xmlXPathFunctionLookup(ctxt->context,
13552                                                    op->value4);
13553                     else {
13554                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
13555                         if (URI == NULL) {
13556                             xmlGenericError(xmlGenericErrorContext,
13557             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13558                                     (char *)op->value4, (char *)op->value5);
13559                             xmlXPathPopFrame(ctxt, frame);
13560                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13561                             return (total);
13562                         }
13563                         func = xmlXPathFunctionLookupNS(ctxt->context,
13564                                                         op->value4, URI);
13565                     }
13566                     if (func == NULL) {
13567                         xmlGenericError(xmlGenericErrorContext,
13568                                 "xmlXPathCompOpEval: function %s not found\n",
13569                                         (char *)op->value4);
13570                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13571                     }
13572                     op->cache = func;
13573                     op->cacheURI = (void *) URI;
13574                 }
13575                 oldFunc = ctxt->context->function;
13576                 oldFuncURI = ctxt->context->functionURI;
13577                 ctxt->context->function = op->value4;
13578                 ctxt->context->functionURI = op->cacheURI;
13579                 func(ctxt, op->value);
13580                 ctxt->context->function = oldFunc;
13581                 ctxt->context->functionURI = oldFuncURI;
13582                 xmlXPathPopFrame(ctxt, frame);
13583                 return (total);
13584             }
13585         case XPATH_OP_ARG:
13586 	    bakd = ctxt->context->doc;
13587 	    bak = ctxt->context->node;
13588 	    pp = ctxt->context->proximityPosition;
13589 	    cs = ctxt->context->contextSize;
13590             if (op->ch1 != -1) {
13591                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13592                 ctxt->context->contextSize = cs;
13593                 ctxt->context->proximityPosition = pp;
13594                 ctxt->context->node = bak;
13595                 ctxt->context->doc = bakd;
13596 	        CHECK_ERROR0;
13597             }
13598             if (op->ch2 != -1) {
13599                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13600                 ctxt->context->contextSize = cs;
13601                 ctxt->context->proximityPosition = pp;
13602                 ctxt->context->node = bak;
13603                 ctxt->context->doc = bakd;
13604 	        CHECK_ERROR0;
13605 	    }
13606             return (total);
13607         case XPATH_OP_PREDICATE:
13608         case XPATH_OP_FILTER:{
13609                 xmlXPathObjectPtr res;
13610                 xmlXPathObjectPtr obj, tmp;
13611                 xmlNodeSetPtr newset = NULL;
13612                 xmlNodeSetPtr oldset;
13613                 xmlNodePtr oldnode;
13614 		xmlDocPtr oldDoc;
13615                 int i;
13616 
13617                 /*
13618                  * Optimization for ()[1] selection i.e. the first elem
13619                  */
13620                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13621 #ifdef XP_OPTIMIZED_FILTER_FIRST
13622 		    /*
13623 		    * FILTER TODO: Can we assume that the inner processing
13624 		    *  will result in an ordered list if we have an
13625 		    *  XPATH_OP_FILTER?
13626 		    *  What about an additional field or flag on
13627 		    *  xmlXPathObject like @sorted ? This way we wouln'd need
13628 		    *  to assume anything, so it would be more robust and
13629 		    *  easier to optimize.
13630 		    */
13631                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13632 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13633 #else
13634 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13635 #endif
13636                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13637                     xmlXPathObjectPtr val;
13638 
13639                     val = comp->steps[op->ch2].value4;
13640                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13641                         (val->floatval == 1.0)) {
13642                         xmlNodePtr first = NULL;
13643 
13644                         total +=
13645                             xmlXPathCompOpEvalFirst(ctxt,
13646                                                     &comp->steps[op->ch1],
13647                                                     &first);
13648 			CHECK_ERROR0;
13649                         /*
13650                          * The nodeset should be in document order,
13651                          * Keep only the first value
13652                          */
13653                         if ((ctxt->value != NULL) &&
13654                             (ctxt->value->type == XPATH_NODESET) &&
13655                             (ctxt->value->nodesetval != NULL) &&
13656                             (ctxt->value->nodesetval->nodeNr > 1))
13657                             xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13658                                                         1, 1);
13659                         return (total);
13660                     }
13661                 }
13662                 /*
13663                  * Optimization for ()[last()] selection i.e. the last elem
13664                  */
13665                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13666                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13667                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13668                     int f = comp->steps[op->ch2].ch1;
13669 
13670                     if ((f != -1) &&
13671                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13672                         (comp->steps[f].value5 == NULL) &&
13673                         (comp->steps[f].value == 0) &&
13674                         (comp->steps[f].value4 != NULL) &&
13675                         (xmlStrEqual
13676                          (comp->steps[f].value4, BAD_CAST "last"))) {
13677                         xmlNodePtr last = NULL;
13678 
13679                         total +=
13680                             xmlXPathCompOpEvalLast(ctxt,
13681                                                    &comp->steps[op->ch1],
13682                                                    &last);
13683 			CHECK_ERROR0;
13684                         /*
13685                          * The nodeset should be in document order,
13686                          * Keep only the last value
13687                          */
13688                         if ((ctxt->value != NULL) &&
13689                             (ctxt->value->type == XPATH_NODESET) &&
13690                             (ctxt->value->nodesetval != NULL) &&
13691                             (ctxt->value->nodesetval->nodeTab != NULL) &&
13692                             (ctxt->value->nodesetval->nodeNr > 1))
13693                             xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13694                         return (total);
13695                     }
13696                 }
13697 		/*
13698 		* Process inner predicates first.
13699 		* Example "index[parent::book][1]":
13700 		* ...
13701 		*   PREDICATE   <-- we are here "[1]"
13702 		*     PREDICATE <-- process "[parent::book]" first
13703 		*       SORT
13704 		*         COLLECT  'parent' 'name' 'node' book
13705 		*           NODE
13706 		*     ELEM Object is a number : 1
13707 		*/
13708                 if (op->ch1 != -1)
13709                     total +=
13710                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13711 		CHECK_ERROR0;
13712                 if (op->ch2 == -1)
13713                     return (total);
13714                 if (ctxt->value == NULL)
13715                     return (total);
13716 
13717                 oldnode = ctxt->context->node;
13718 
13719 #ifdef LIBXML_XPTR_ENABLED
13720                 /*
13721                  * Hum are we filtering the result of an XPointer expression
13722                  */
13723                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13724                     xmlLocationSetPtr newlocset = NULL;
13725                     xmlLocationSetPtr oldlocset;
13726 
13727                     /*
13728                      * Extract the old locset, and then evaluate the result of the
13729                      * expression for all the element in the locset. use it to grow
13730                      * up a new locset.
13731                      */
13732                     CHECK_TYPE0(XPATH_LOCATIONSET);
13733                     obj = valuePop(ctxt);
13734                     oldlocset = obj->user;
13735                     ctxt->context->node = NULL;
13736 
13737                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13738                         ctxt->context->contextSize = 0;
13739                         ctxt->context->proximityPosition = 0;
13740                         if (op->ch2 != -1)
13741                             total +=
13742                                 xmlXPathCompOpEval(ctxt,
13743                                                    &comp->steps[op->ch2]);
13744                         res = valuePop(ctxt);
13745                         if (res != NULL) {
13746 			    xmlXPathReleaseObject(ctxt->context, res);
13747 			}
13748                         valuePush(ctxt, obj);
13749                         CHECK_ERROR0;
13750                         return (total);
13751                     }
13752                     newlocset = xmlXPtrLocationSetCreate(NULL);
13753 
13754                     for (i = 0; i < oldlocset->locNr; i++) {
13755                         /*
13756                          * Run the evaluation with a node list made of a
13757                          * single item in the nodelocset.
13758                          */
13759                         ctxt->context->node = oldlocset->locTab[i]->user;
13760                         ctxt->context->contextSize = oldlocset->locNr;
13761                         ctxt->context->proximityPosition = i + 1;
13762 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13763 			    ctxt->context->node);
13764                         valuePush(ctxt, tmp);
13765 
13766                         if (op->ch2 != -1)
13767                             total +=
13768                                 xmlXPathCompOpEval(ctxt,
13769                                                    &comp->steps[op->ch2]);
13770 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13771 			    xmlXPathFreeObject(obj);
13772 			    return(0);
13773 			}
13774 
13775                         /*
13776                          * The result of the evaluation need to be tested to
13777                          * decided whether the filter succeeded or not
13778                          */
13779                         res = valuePop(ctxt);
13780                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13781                             xmlXPtrLocationSetAdd(newlocset,
13782                                                   xmlXPathObjectCopy
13783                                                   (oldlocset->locTab[i]));
13784                         }
13785 
13786                         /*
13787                          * Cleanup
13788                          */
13789                         if (res != NULL) {
13790 			    xmlXPathReleaseObject(ctxt->context, res);
13791 			}
13792                         if (ctxt->value == tmp) {
13793                             res = valuePop(ctxt);
13794 			    xmlXPathReleaseObject(ctxt->context, res);
13795                         }
13796 
13797                         ctxt->context->node = NULL;
13798                     }
13799 
13800                     /*
13801                      * The result is used as the new evaluation locset.
13802                      */
13803 		    xmlXPathReleaseObject(ctxt->context, obj);
13804                     ctxt->context->node = NULL;
13805                     ctxt->context->contextSize = -1;
13806                     ctxt->context->proximityPosition = -1;
13807                     valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13808                     ctxt->context->node = oldnode;
13809                     return (total);
13810                 }
13811 #endif /* LIBXML_XPTR_ENABLED */
13812 
13813                 /*
13814                  * Extract the old set, and then evaluate the result of the
13815                  * expression for all the element in the set. use it to grow
13816                  * up a new set.
13817                  */
13818                 CHECK_TYPE0(XPATH_NODESET);
13819                 obj = valuePop(ctxt);
13820                 oldset = obj->nodesetval;
13821 
13822                 oldnode = ctxt->context->node;
13823 		oldDoc = ctxt->context->doc;
13824                 ctxt->context->node = NULL;
13825 
13826                 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13827                     ctxt->context->contextSize = 0;
13828                     ctxt->context->proximityPosition = 0;
13829 /*
13830                     if (op->ch2 != -1)
13831                         total +=
13832                             xmlXPathCompOpEval(ctxt,
13833                                                &comp->steps[op->ch2]);
13834 		    CHECK_ERROR0;
13835                     res = valuePop(ctxt);
13836                     if (res != NULL)
13837                         xmlXPathFreeObject(res);
13838 */
13839                     valuePush(ctxt, obj);
13840                     ctxt->context->node = oldnode;
13841                     CHECK_ERROR0;
13842                 } else {
13843 		    tmp = NULL;
13844                     /*
13845                      * Initialize the new set.
13846 		     * Also set the xpath document in case things like
13847 		     * key() evaluation are attempted on the predicate
13848                      */
13849                     newset = xmlXPathNodeSetCreate(NULL);
13850 		    /*
13851 		    * SPEC XPath 1.0:
13852 		    *  "For each node in the node-set to be filtered, the
13853 		    *  PredicateExpr is evaluated with that node as the
13854 		    *  context node, with the number of nodes in the
13855 		    *  node-set as the context size, and with the proximity
13856 		    *  position of the node in the node-set with respect to
13857 		    *  the axis as the context position;"
13858 		    * @oldset is the node-set" to be filtered.
13859 		    *
13860 		    * SPEC XPath 1.0:
13861 		    *  "only predicates change the context position and
13862 		    *  context size (see [2.4 Predicates])."
13863 		    * Example:
13864 		    *   node-set  context pos
13865 		    *    nA         1
13866 		    *    nB         2
13867 		    *    nC         3
13868 		    *   After applying predicate [position() > 1] :
13869 		    *   node-set  context pos
13870 		    *    nB         1
13871 		    *    nC         2
13872 		    *
13873 		    * removed the first node in the node-set, then
13874 		    * the context position of the
13875 		    */
13876                     for (i = 0; i < oldset->nodeNr; i++) {
13877                         /*
13878                          * Run the evaluation with a node list made of
13879                          * a single item in the nodeset.
13880                          */
13881                         ctxt->context->node = oldset->nodeTab[i];
13882 			if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13883 			    (oldset->nodeTab[i]->doc != NULL))
13884 		            ctxt->context->doc = oldset->nodeTab[i]->doc;
13885 			if (tmp == NULL) {
13886 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13887 				ctxt->context->node);
13888 			} else {
13889 			    if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13890 				               ctxt->context->node) < 0) {
13891 				ctxt->error = XPATH_MEMORY_ERROR;
13892 			    }
13893 			}
13894                         valuePush(ctxt, tmp);
13895                         ctxt->context->contextSize = oldset->nodeNr;
13896                         ctxt->context->proximityPosition = i + 1;
13897 			/*
13898 			* Evaluate the predicate against the context node.
13899 			* Can/should we optimize position() predicates
13900 			* here (e.g. "[1]")?
13901 			*/
13902                         if (op->ch2 != -1)
13903                             total +=
13904                                 xmlXPathCompOpEval(ctxt,
13905                                                    &comp->steps[op->ch2]);
13906 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13907 			    xmlXPathFreeNodeSet(newset);
13908 			    xmlXPathFreeObject(obj);
13909 			    return(0);
13910 			}
13911 
13912                         /*
13913                          * The result of the evaluation needs to be tested to
13914                          * decide whether the filter succeeded or not
13915                          */
13916 			/*
13917 			* OPTIMIZE TODO: Can we use
13918 			* xmlXPathNodeSetAdd*Unique()* instead?
13919 			*/
13920                         res = valuePop(ctxt);
13921                         if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13922                             if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13923 			        < 0)
13924 				ctxt->error = XPATH_MEMORY_ERROR;
13925                         }
13926 
13927                         /*
13928                          * Cleanup
13929                          */
13930                         if (res != NULL) {
13931 			    xmlXPathReleaseObject(ctxt->context, res);
13932 			}
13933                         if (ctxt->value == tmp) {
13934                             valuePop(ctxt);
13935 			    xmlXPathNodeSetClear(tmp->nodesetval, 1);
13936 			    /*
13937 			    * Don't free the temporary nodeset
13938 			    * in order to avoid massive recreation inside this
13939 			    * loop.
13940 			    */
13941                         } else
13942 			    tmp = NULL;
13943                         ctxt->context->node = NULL;
13944                     }
13945 		    if (tmp != NULL)
13946 			xmlXPathReleaseObject(ctxt->context, tmp);
13947                     /*
13948                      * The result is used as the new evaluation set.
13949                      */
13950 		    xmlXPathReleaseObject(ctxt->context, obj);
13951                     ctxt->context->node = NULL;
13952                     ctxt->context->contextSize = -1;
13953                     ctxt->context->proximityPosition = -1;
13954 		    /* may want to move this past the '}' later */
13955 		    ctxt->context->doc = oldDoc;
13956 		    valuePush(ctxt,
13957 			xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13958                 }
13959                 ctxt->context->node = oldnode;
13960                 return (total);
13961             }
13962         case XPATH_OP_SORT:
13963             if (op->ch1 != -1)
13964                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13965 	    CHECK_ERROR0;
13966             if ((ctxt->value != NULL) &&
13967                 (ctxt->value->type == XPATH_NODESET) &&
13968                 (ctxt->value->nodesetval != NULL) &&
13969 		(ctxt->value->nodesetval->nodeNr > 1))
13970 	    {
13971                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13972 	    }
13973             return (total);
13974 #ifdef LIBXML_XPTR_ENABLED
13975         case XPATH_OP_RANGETO:{
13976                 xmlXPathObjectPtr range;
13977                 xmlXPathObjectPtr res, obj;
13978                 xmlXPathObjectPtr tmp;
13979                 xmlLocationSetPtr newlocset = NULL;
13980 		    xmlLocationSetPtr oldlocset;
13981                 xmlNodeSetPtr oldset;
13982                 int i, j;
13983 
13984                 if (op->ch1 != -1) {
13985                     total +=
13986                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13987                     CHECK_ERROR0;
13988                 }
13989                 if (ctxt->value == NULL) {
13990                     XP_ERROR0(XPATH_INVALID_OPERAND);
13991                 }
13992                 if (op->ch2 == -1)
13993                     return (total);
13994 
13995                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13996                     /*
13997                      * Extract the old locset, and then evaluate the result of the
13998                      * expression for all the element in the locset. use it to grow
13999                      * up a new locset.
14000                      */
14001                     CHECK_TYPE0(XPATH_LOCATIONSET);
14002                     obj = valuePop(ctxt);
14003                     oldlocset = obj->user;
14004 
14005                     if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
14006 		        ctxt->context->node = NULL;
14007                         ctxt->context->contextSize = 0;
14008                         ctxt->context->proximityPosition = 0;
14009                         total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
14010                         res = valuePop(ctxt);
14011                         if (res != NULL) {
14012 			    xmlXPathReleaseObject(ctxt->context, res);
14013 			}
14014                         valuePush(ctxt, obj);
14015                         CHECK_ERROR0;
14016                         return (total);
14017                     }
14018                     newlocset = xmlXPtrLocationSetCreate(NULL);
14019 
14020                     for (i = 0; i < oldlocset->locNr; i++) {
14021                         /*
14022                          * Run the evaluation with a node list made of a
14023                          * single item in the nodelocset.
14024                          */
14025                         ctxt->context->node = oldlocset->locTab[i]->user;
14026                         ctxt->context->contextSize = oldlocset->locNr;
14027                         ctxt->context->proximityPosition = i + 1;
14028 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14029 			    ctxt->context->node);
14030                         valuePush(ctxt, tmp);
14031 
14032                         if (op->ch2 != -1)
14033                             total +=
14034                                 xmlXPathCompOpEval(ctxt,
14035                                                    &comp->steps[op->ch2]);
14036 			if (ctxt->error != XPATH_EXPRESSION_OK) {
14037 			    xmlXPathFreeObject(obj);
14038 			    return(0);
14039 			}
14040 
14041                         res = valuePop(ctxt);
14042 			if (res->type == XPATH_LOCATIONSET) {
14043 			    xmlLocationSetPtr rloc =
14044 			        (xmlLocationSetPtr)res->user;
14045 			    for (j=0; j<rloc->locNr; j++) {
14046 			        range = xmlXPtrNewRange(
14047 				  oldlocset->locTab[i]->user,
14048 				  oldlocset->locTab[i]->index,
14049 				  rloc->locTab[j]->user2,
14050 				  rloc->locTab[j]->index2);
14051 				if (range != NULL) {
14052 				    xmlXPtrLocationSetAdd(newlocset, range);
14053 				}
14054 			    }
14055 			} else {
14056 			    range = xmlXPtrNewRangeNodeObject(
14057 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
14058                             if (range != NULL) {
14059                                 xmlXPtrLocationSetAdd(newlocset,range);
14060 			    }
14061                         }
14062 
14063                         /*
14064                          * Cleanup
14065                          */
14066                         if (res != NULL) {
14067 			    xmlXPathReleaseObject(ctxt->context, res);
14068 			}
14069                         if (ctxt->value == tmp) {
14070                             res = valuePop(ctxt);
14071 			    xmlXPathReleaseObject(ctxt->context, res);
14072                         }
14073 
14074                         ctxt->context->node = NULL;
14075                     }
14076 		} else {	/* Not a location set */
14077                     CHECK_TYPE0(XPATH_NODESET);
14078                     obj = valuePop(ctxt);
14079                     oldset = obj->nodesetval;
14080                     ctxt->context->node = NULL;
14081 
14082                     newlocset = xmlXPtrLocationSetCreate(NULL);
14083 
14084                     if (oldset != NULL) {
14085                         for (i = 0; i < oldset->nodeNr; i++) {
14086                             /*
14087                              * Run the evaluation with a node list made of a single item
14088                              * in the nodeset.
14089                              */
14090                             ctxt->context->node = oldset->nodeTab[i];
14091 			    /*
14092 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
14093 			    */
14094 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14095 				ctxt->context->node);
14096                             valuePush(ctxt, tmp);
14097 
14098                             if (op->ch2 != -1)
14099                                 total +=
14100                                     xmlXPathCompOpEval(ctxt,
14101                                                    &comp->steps[op->ch2]);
14102 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
14103 				xmlXPathFreeObject(obj);
14104 				return(0);
14105 			    }
14106 
14107                             res = valuePop(ctxt);
14108                             range =
14109                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14110                                                       res);
14111                             if (range != NULL) {
14112                                 xmlXPtrLocationSetAdd(newlocset, range);
14113                             }
14114 
14115                             /*
14116                              * Cleanup
14117                              */
14118                             if (res != NULL) {
14119 				xmlXPathReleaseObject(ctxt->context, res);
14120 			    }
14121                             if (ctxt->value == tmp) {
14122                                 res = valuePop(ctxt);
14123 				xmlXPathReleaseObject(ctxt->context, res);
14124                             }
14125 
14126                             ctxt->context->node = NULL;
14127                         }
14128                     }
14129                 }
14130 
14131                 /*
14132                  * The result is used as the new evaluation set.
14133                  */
14134 		xmlXPathReleaseObject(ctxt->context, obj);
14135                 ctxt->context->node = NULL;
14136                 ctxt->context->contextSize = -1;
14137                 ctxt->context->proximityPosition = -1;
14138                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
14139                 return (total);
14140             }
14141 #endif /* LIBXML_XPTR_ENABLED */
14142     }
14143     xmlGenericError(xmlGenericErrorContext,
14144                     "XPath: unknown precompiled operation %d\n", op->op);
14145     ctxt->error = XPATH_INVALID_OPERAND;
14146     return (total);
14147 }
14148 
14149 /**
14150  * xmlXPathCompOpEvalToBoolean:
14151  * @ctxt:  the XPath parser context
14152  *
14153  * Evaluates if the expression evaluates to true.
14154  *
14155  * Returns 1 if true, 0 if false and -1 on API or internal errors.
14156  */
14157 static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int isPredicate)14158 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14159 			    xmlXPathStepOpPtr op,
14160 			    int isPredicate)
14161 {
14162     xmlXPathObjectPtr resObj = NULL;
14163 
14164 start:
14165     /* comp = ctxt->comp; */
14166     switch (op->op) {
14167         case XPATH_OP_END:
14168             return (0);
14169 	case XPATH_OP_VALUE:
14170 	    resObj = (xmlXPathObjectPtr) op->value4;
14171 	    if (isPredicate)
14172 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14173 	    return(xmlXPathCastToBoolean(resObj));
14174 	case XPATH_OP_SORT:
14175 	    /*
14176 	    * We don't need sorting for boolean results. Skip this one.
14177 	    */
14178             if (op->ch1 != -1) {
14179 		op = &ctxt->comp->steps[op->ch1];
14180 		goto start;
14181 	    }
14182 	    return(0);
14183 	case XPATH_OP_COLLECT:
14184 	    if (op->ch1 == -1)
14185 		return(0);
14186 
14187             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14188 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14189 		return(-1);
14190 
14191             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14192 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14193 		return(-1);
14194 
14195 	    resObj = valuePop(ctxt);
14196 	    if (resObj == NULL)
14197 		return(-1);
14198 	    break;
14199 	default:
14200 	    /*
14201 	    * Fallback to call xmlXPathCompOpEval().
14202 	    */
14203 	    xmlXPathCompOpEval(ctxt, op);
14204 	    if (ctxt->error != XPATH_EXPRESSION_OK)
14205 		return(-1);
14206 
14207 	    resObj = valuePop(ctxt);
14208 	    if (resObj == NULL)
14209 		return(-1);
14210 	    break;
14211     }
14212 
14213     if (resObj) {
14214 	int res;
14215 
14216 	if (resObj->type == XPATH_BOOLEAN) {
14217 	    res = resObj->boolval;
14218 	} else if (isPredicate) {
14219 	    /*
14220 	    * For predicates a result of type "number" is handled
14221 	    * differently:
14222 	    * SPEC XPath 1.0:
14223 	    * "If the result is a number, the result will be converted
14224 	    *  to true if the number is equal to the context position
14225 	    *  and will be converted to false otherwise;"
14226 	    */
14227 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14228 	} else {
14229 	    res = xmlXPathCastToBoolean(resObj);
14230 	}
14231 	xmlXPathReleaseObject(ctxt->context, resObj);
14232 	return(res);
14233     }
14234 
14235     return(0);
14236 }
14237 
14238 #ifdef XPATH_STREAMING
14239 /**
14240  * xmlXPathRunStreamEval:
14241  * @ctxt:  the XPath parser context with the compiled expression
14242  *
14243  * Evaluate the Precompiled Streamable XPath expression in the given context.
14244  */
14245 static int
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt,xmlPatternPtr comp,xmlXPathObjectPtr * resultSeq,int toBool)14246 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14247 		      xmlXPathObjectPtr *resultSeq, int toBool)
14248 {
14249     int max_depth, min_depth;
14250     int from_root;
14251     int ret, depth;
14252     int eval_all_nodes;
14253     xmlNodePtr cur = NULL, limit = NULL;
14254     xmlStreamCtxtPtr patstream = NULL;
14255 
14256     int nb_nodes = 0;
14257 
14258     if ((ctxt == NULL) || (comp == NULL))
14259         return(-1);
14260     max_depth = xmlPatternMaxDepth(comp);
14261     if (max_depth == -1)
14262         return(-1);
14263     if (max_depth == -2)
14264         max_depth = 10000;
14265     min_depth = xmlPatternMinDepth(comp);
14266     if (min_depth == -1)
14267         return(-1);
14268     from_root = xmlPatternFromRoot(comp);
14269     if (from_root < 0)
14270         return(-1);
14271 #if 0
14272     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14273 #endif
14274 
14275     if (! toBool) {
14276 	if (resultSeq == NULL)
14277 	    return(-1);
14278 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14279 	if (*resultSeq == NULL)
14280 	    return(-1);
14281     }
14282 
14283     /*
14284      * handle the special cases of "/" amd "." being matched
14285      */
14286     if (min_depth == 0) {
14287 	if (from_root) {
14288 	    /* Select "/" */
14289 	    if (toBool)
14290 		return(1);
14291 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14292 		                     (xmlNodePtr) ctxt->doc);
14293 	} else {
14294 	    /* Select "self::node()" */
14295 	    if (toBool)
14296 		return(1);
14297 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14298 	}
14299     }
14300     if (max_depth == 0) {
14301 	return(0);
14302     }
14303 
14304     if (from_root) {
14305         cur = (xmlNodePtr)ctxt->doc;
14306     } else if (ctxt->node != NULL) {
14307         switch (ctxt->node->type) {
14308             case XML_ELEMENT_NODE:
14309             case XML_DOCUMENT_NODE:
14310             case XML_DOCUMENT_FRAG_NODE:
14311             case XML_HTML_DOCUMENT_NODE:
14312 #ifdef LIBXML_DOCB_ENABLED
14313             case XML_DOCB_DOCUMENT_NODE:
14314 #endif
14315 	        cur = ctxt->node;
14316 		break;
14317             case XML_ATTRIBUTE_NODE:
14318             case XML_TEXT_NODE:
14319             case XML_CDATA_SECTION_NODE:
14320             case XML_ENTITY_REF_NODE:
14321             case XML_ENTITY_NODE:
14322             case XML_PI_NODE:
14323             case XML_COMMENT_NODE:
14324             case XML_NOTATION_NODE:
14325             case XML_DTD_NODE:
14326             case XML_DOCUMENT_TYPE_NODE:
14327             case XML_ELEMENT_DECL:
14328             case XML_ATTRIBUTE_DECL:
14329             case XML_ENTITY_DECL:
14330             case XML_NAMESPACE_DECL:
14331             case XML_XINCLUDE_START:
14332             case XML_XINCLUDE_END:
14333 		break;
14334 	}
14335 	limit = cur;
14336     }
14337     if (cur == NULL) {
14338         return(0);
14339     }
14340 
14341     patstream = xmlPatternGetStreamCtxt(comp);
14342     if (patstream == NULL) {
14343 	/*
14344 	* QUESTION TODO: Is this an error?
14345 	*/
14346 	return(0);
14347     }
14348 
14349     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14350 
14351     if (from_root) {
14352 	ret = xmlStreamPush(patstream, NULL, NULL);
14353 	if (ret < 0) {
14354 	} else if (ret == 1) {
14355 	    if (toBool)
14356 		goto return_1;
14357 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14358 	}
14359     }
14360     depth = 0;
14361     goto scan_children;
14362 next_node:
14363     do {
14364         nb_nodes++;
14365 
14366 	switch (cur->type) {
14367 	    case XML_ELEMENT_NODE:
14368 	    case XML_TEXT_NODE:
14369 	    case XML_CDATA_SECTION_NODE:
14370 	    case XML_COMMENT_NODE:
14371 	    case XML_PI_NODE:
14372 		if (cur->type == XML_ELEMENT_NODE) {
14373 		    ret = xmlStreamPush(patstream, cur->name,
14374 				(cur->ns ? cur->ns->href : NULL));
14375 		} else if (eval_all_nodes)
14376 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14377 		else
14378 		    break;
14379 
14380 		if (ret < 0) {
14381 		    /* NOP. */
14382 		} else if (ret == 1) {
14383 		    if (toBool)
14384 			goto return_1;
14385 		    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14386 		        < 0) {
14387 			ctxt->lastError.domain = XML_FROM_XPATH;
14388 			ctxt->lastError.code = XML_ERR_NO_MEMORY;
14389 		    }
14390 		}
14391 		if ((cur->children == NULL) || (depth >= max_depth)) {
14392 		    ret = xmlStreamPop(patstream);
14393 		    while (cur->next != NULL) {
14394 			cur = cur->next;
14395 			if ((cur->type != XML_ENTITY_DECL) &&
14396 			    (cur->type != XML_DTD_NODE))
14397 			    goto next_node;
14398 		    }
14399 		}
14400 	    default:
14401 		break;
14402 	}
14403 
14404 scan_children:
14405 	if (cur->type == XML_NAMESPACE_DECL) break;
14406 	if ((cur->children != NULL) && (depth < max_depth)) {
14407 	    /*
14408 	     * Do not descend on entities declarations
14409 	     */
14410 	    if (cur->children->type != XML_ENTITY_DECL) {
14411 		cur = cur->children;
14412 		depth++;
14413 		/*
14414 		 * Skip DTDs
14415 		 */
14416 		if (cur->type != XML_DTD_NODE)
14417 		    continue;
14418 	    }
14419 	}
14420 
14421 	if (cur == limit)
14422 	    break;
14423 
14424 	while (cur->next != NULL) {
14425 	    cur = cur->next;
14426 	    if ((cur->type != XML_ENTITY_DECL) &&
14427 		(cur->type != XML_DTD_NODE))
14428 		goto next_node;
14429 	}
14430 
14431 	do {
14432 	    cur = cur->parent;
14433 	    depth--;
14434 	    if ((cur == NULL) || (cur == limit))
14435 	        goto done;
14436 	    if (cur->type == XML_ELEMENT_NODE) {
14437 		ret = xmlStreamPop(patstream);
14438 	    } else if ((eval_all_nodes) &&
14439 		((cur->type == XML_TEXT_NODE) ||
14440 		 (cur->type == XML_CDATA_SECTION_NODE) ||
14441 		 (cur->type == XML_COMMENT_NODE) ||
14442 		 (cur->type == XML_PI_NODE)))
14443 	    {
14444 		ret = xmlStreamPop(patstream);
14445 	    }
14446 	    if (cur->next != NULL) {
14447 		cur = cur->next;
14448 		break;
14449 	    }
14450 	} while (cur != NULL);
14451 
14452     } while ((cur != NULL) && (depth >= 0));
14453 
14454 done:
14455 
14456 #if 0
14457     printf("stream eval: checked %d nodes selected %d\n",
14458            nb_nodes, retObj->nodesetval->nodeNr);
14459 #endif
14460 
14461     if (patstream)
14462 	xmlFreeStreamCtxt(patstream);
14463     return(0);
14464 
14465 return_1:
14466     if (patstream)
14467 	xmlFreeStreamCtxt(patstream);
14468     return(1);
14469 }
14470 #endif /* XPATH_STREAMING */
14471 
14472 /**
14473  * xmlXPathRunEval:
14474  * @ctxt:  the XPath parser context with the compiled expression
14475  * @toBool:  evaluate to a boolean result
14476  *
14477  * Evaluate the Precompiled XPath expression in the given context.
14478  */
14479 static int
xmlXPathRunEval(xmlXPathParserContextPtr ctxt,int toBool)14480 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14481 {
14482     xmlXPathCompExprPtr comp;
14483 
14484     if ((ctxt == NULL) || (ctxt->comp == NULL))
14485 	return(-1);
14486 
14487     if (ctxt->valueTab == NULL) {
14488 	/* Allocate the value stack */
14489 	ctxt->valueTab = (xmlXPathObjectPtr *)
14490 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14491 	if (ctxt->valueTab == NULL) {
14492 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14493 	    xmlFree(ctxt);
14494 	}
14495 	ctxt->valueNr = 0;
14496 	ctxt->valueMax = 10;
14497 	ctxt->value = NULL;
14498         ctxt->valueFrame = 0;
14499     }
14500 #ifdef XPATH_STREAMING
14501     if (ctxt->comp->stream) {
14502 	int res;
14503 
14504 	if (toBool) {
14505 	    /*
14506 	    * Evaluation to boolean result.
14507 	    */
14508 	    res = xmlXPathRunStreamEval(ctxt->context,
14509 		ctxt->comp->stream, NULL, 1);
14510 	    if (res != -1)
14511 		return(res);
14512 	} else {
14513 	    xmlXPathObjectPtr resObj = NULL;
14514 
14515 	    /*
14516 	    * Evaluation to a sequence.
14517 	    */
14518 	    res = xmlXPathRunStreamEval(ctxt->context,
14519 		ctxt->comp->stream, &resObj, 0);
14520 
14521 	    if ((res != -1) && (resObj != NULL)) {
14522 		valuePush(ctxt, resObj);
14523 		return(0);
14524 	    }
14525 	    if (resObj != NULL)
14526 		xmlXPathReleaseObject(ctxt->context, resObj);
14527 	}
14528 	/*
14529 	* QUESTION TODO: This falls back to normal XPath evaluation
14530 	* if res == -1. Is this intended?
14531 	*/
14532     }
14533 #endif
14534     comp = ctxt->comp;
14535     if (comp->last < 0) {
14536 	xmlGenericError(xmlGenericErrorContext,
14537 	    "xmlXPathRunEval: last is less than zero\n");
14538 	return(-1);
14539     }
14540     if (toBool)
14541 	return(xmlXPathCompOpEvalToBoolean(ctxt,
14542 	    &comp->steps[comp->last], 0));
14543     else
14544 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14545 
14546     return(0);
14547 }
14548 
14549 /************************************************************************
14550  *									*
14551  *			Public interfaces				*
14552  *									*
14553  ************************************************************************/
14554 
14555 /**
14556  * xmlXPathEvalPredicate:
14557  * @ctxt:  the XPath context
14558  * @res:  the Predicate Expression evaluation result
14559  *
14560  * Evaluate a predicate result for the current node.
14561  * A PredicateExpr is evaluated by evaluating the Expr and converting
14562  * the result to a boolean. If the result is a number, the result will
14563  * be converted to true if the number is equal to the position of the
14564  * context node in the context node list (as returned by the position
14565  * function) and will be converted to false otherwise; if the result
14566  * is not a number, then the result will be converted as if by a call
14567  * to the boolean function.
14568  *
14569  * Returns 1 if predicate is true, 0 otherwise
14570  */
14571 int
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt,xmlXPathObjectPtr res)14572 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14573     if ((ctxt == NULL) || (res == NULL)) return(0);
14574     switch (res->type) {
14575         case XPATH_BOOLEAN:
14576 	    return(res->boolval);
14577         case XPATH_NUMBER:
14578 	    return(res->floatval == ctxt->proximityPosition);
14579         case XPATH_NODESET:
14580         case XPATH_XSLT_TREE:
14581 	    if (res->nodesetval == NULL)
14582 		return(0);
14583 	    return(res->nodesetval->nodeNr != 0);
14584         case XPATH_STRING:
14585 	    return((res->stringval != NULL) &&
14586 	           (xmlStrlen(res->stringval) != 0));
14587         default:
14588 	    STRANGE
14589     }
14590     return(0);
14591 }
14592 
14593 /**
14594  * xmlXPathEvaluatePredicateResult:
14595  * @ctxt:  the XPath Parser context
14596  * @res:  the Predicate Expression evaluation result
14597  *
14598  * Evaluate a predicate result for the current node.
14599  * A PredicateExpr is evaluated by evaluating the Expr and converting
14600  * the result to a boolean. If the result is a number, the result will
14601  * be converted to true if the number is equal to the position of the
14602  * context node in the context node list (as returned by the position
14603  * function) and will be converted to false otherwise; if the result
14604  * is not a number, then the result will be converted as if by a call
14605  * to the boolean function.
14606  *
14607  * Returns 1 if predicate is true, 0 otherwise
14608  */
14609 int
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr res)14610 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14611                                 xmlXPathObjectPtr res) {
14612     if ((ctxt == NULL) || (res == NULL)) return(0);
14613     switch (res->type) {
14614         case XPATH_BOOLEAN:
14615 	    return(res->boolval);
14616         case XPATH_NUMBER:
14617 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14618 	    return((res->floatval == ctxt->context->proximityPosition) &&
14619 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14620 #else
14621 	    return(res->floatval == ctxt->context->proximityPosition);
14622 #endif
14623         case XPATH_NODESET:
14624         case XPATH_XSLT_TREE:
14625 	    if (res->nodesetval == NULL)
14626 		return(0);
14627 	    return(res->nodesetval->nodeNr != 0);
14628         case XPATH_STRING:
14629 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
14630 #ifdef LIBXML_XPTR_ENABLED
14631 	case XPATH_LOCATIONSET:{
14632 	    xmlLocationSetPtr ptr = res->user;
14633 	    if (ptr == NULL)
14634 	        return(0);
14635 	    return (ptr->locNr != 0);
14636 	    }
14637 #endif
14638         default:
14639 	    STRANGE
14640     }
14641     return(0);
14642 }
14643 
14644 #ifdef XPATH_STREAMING
14645 /**
14646  * xmlXPathTryStreamCompile:
14647  * @ctxt: an XPath context
14648  * @str:  the XPath expression
14649  *
14650  * Try to compile the XPath expression as a streamable subset.
14651  *
14652  * Returns the compiled expression or NULL if failed to compile.
14653  */
14654 static xmlXPathCompExprPtr
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14655 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14656     /*
14657      * Optimization: use streaming patterns when the XPath expression can
14658      * be compiled to a stream lookup
14659      */
14660     xmlPatternPtr stream;
14661     xmlXPathCompExprPtr comp;
14662     xmlDictPtr dict = NULL;
14663     const xmlChar **namespaces = NULL;
14664     xmlNsPtr ns;
14665     int i, j;
14666 
14667     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14668         (!xmlStrchr(str, '@'))) {
14669 	const xmlChar *tmp;
14670 
14671 	/*
14672 	 * We don't try to handle expressions using the verbose axis
14673 	 * specifiers ("::"), just the simplied form at this point.
14674 	 * Additionally, if there is no list of namespaces available and
14675 	 *  there's a ":" in the expression, indicating a prefixed QName,
14676 	 *  then we won't try to compile either. xmlPatterncompile() needs
14677 	 *  to have a list of namespaces at compilation time in order to
14678 	 *  compile prefixed name tests.
14679 	 */
14680 	tmp = xmlStrchr(str, ':');
14681 	if ((tmp != NULL) &&
14682 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14683 	    return(NULL);
14684 
14685 	if (ctxt != NULL) {
14686 	    dict = ctxt->dict;
14687 	    if (ctxt->nsNr > 0) {
14688 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14689 		if (namespaces == NULL) {
14690 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14691 		    return(NULL);
14692 		}
14693 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14694 		    ns = ctxt->namespaces[j];
14695 		    namespaces[i++] = ns->href;
14696 		    namespaces[i++] = ns->prefix;
14697 		}
14698 		namespaces[i++] = NULL;
14699 		namespaces[i] = NULL;
14700 	    }
14701 	}
14702 
14703 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14704 			&namespaces[0]);
14705 	if (namespaces != NULL) {
14706 	    xmlFree((xmlChar **)namespaces);
14707 	}
14708 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14709 	    comp = xmlXPathNewCompExpr();
14710 	    if (comp == NULL) {
14711 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14712 		return(NULL);
14713 	    }
14714 	    comp->stream = stream;
14715 	    comp->dict = dict;
14716 	    if (comp->dict)
14717 		xmlDictReference(comp->dict);
14718 	    return(comp);
14719 	}
14720 	xmlFreePattern(stream);
14721     }
14722     return(NULL);
14723 }
14724 #endif /* XPATH_STREAMING */
14725 
14726 static void
xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op)14727 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14728 {
14729     /*
14730     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14731     * internal representation.
14732     */
14733 
14734     if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14735         (op->ch1 != -1) &&
14736         (op->ch2 == -1 /* no predicate */))
14737     {
14738         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14739 
14740         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14741             ((xmlXPathAxisVal) prevop->value ==
14742                 AXIS_DESCENDANT_OR_SELF) &&
14743             (prevop->ch2 == -1) &&
14744             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14745             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14746         {
14747             /*
14748             * This is a "descendant-or-self::node()" without predicates.
14749             * Try to eliminate it.
14750             */
14751 
14752             switch ((xmlXPathAxisVal) op->value) {
14753                 case AXIS_CHILD:
14754                 case AXIS_DESCENDANT:
14755                     /*
14756                     * Convert "descendant-or-self::node()/child::" or
14757                     * "descendant-or-self::node()/descendant::" to
14758                     * "descendant::"
14759                     */
14760                     op->ch1   = prevop->ch1;
14761                     op->value = AXIS_DESCENDANT;
14762                     break;
14763                 case AXIS_SELF:
14764                 case AXIS_DESCENDANT_OR_SELF:
14765                     /*
14766                     * Convert "descendant-or-self::node()/self::" or
14767                     * "descendant-or-self::node()/descendant-or-self::" to
14768                     * to "descendant-or-self::"
14769                     */
14770                     op->ch1   = prevop->ch1;
14771                     op->value = AXIS_DESCENDANT_OR_SELF;
14772                     break;
14773                 default:
14774                     break;
14775             }
14776 	}
14777     }
14778 
14779     /* OP_VALUE has invalid ch1. */
14780     if (op->op == XPATH_OP_VALUE)
14781         return;
14782 
14783     /* Recurse */
14784     if (op->ch1 != -1)
14785         xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
14786     if (op->ch2 != -1)
14787 	xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
14788 }
14789 
14790 /**
14791  * xmlXPathCtxtCompile:
14792  * @ctxt: an XPath context
14793  * @str:  the XPath expression
14794  *
14795  * Compile an XPath expression
14796  *
14797  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14798  *         the caller has to free the object.
14799  */
14800 xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14801 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14802     xmlXPathParserContextPtr pctxt;
14803     xmlXPathCompExprPtr comp;
14804 
14805 #ifdef XPATH_STREAMING
14806     comp = xmlXPathTryStreamCompile(ctxt, str);
14807     if (comp != NULL)
14808         return(comp);
14809 #endif
14810 
14811     xmlXPathInit();
14812 
14813     pctxt = xmlXPathNewParserContext(str, ctxt);
14814     if (pctxt == NULL)
14815         return NULL;
14816     xmlXPathCompileExpr(pctxt, 1);
14817 
14818     if( pctxt->error != XPATH_EXPRESSION_OK )
14819     {
14820         xmlXPathFreeParserContext(pctxt);
14821         return(NULL);
14822     }
14823 
14824     if (*pctxt->cur != 0) {
14825 	/*
14826 	 * aleksey: in some cases this line prints *second* error message
14827 	 * (see bug #78858) and probably this should be fixed.
14828 	 * However, we are not sure that all error messages are printed
14829 	 * out in other places. It's not critical so we leave it as-is for now
14830 	 */
14831 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14832 	comp = NULL;
14833     } else {
14834 	comp = pctxt->comp;
14835 	pctxt->comp = NULL;
14836     }
14837     xmlXPathFreeParserContext(pctxt);
14838 
14839     if (comp != NULL) {
14840 	comp->expr = xmlStrdup(str);
14841 #ifdef DEBUG_EVAL_COUNTS
14842 	comp->string = xmlStrdup(str);
14843 	comp->nb = 0;
14844 #endif
14845 	if ((comp->nbStep > 1) && (comp->last >= 0)) {
14846 	    xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
14847 	}
14848     }
14849     return(comp);
14850 }
14851 
14852 /**
14853  * xmlXPathCompile:
14854  * @str:  the XPath expression
14855  *
14856  * Compile an XPath expression
14857  *
14858  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14859  *         the caller has to free the object.
14860  */
14861 xmlXPathCompExprPtr
xmlXPathCompile(const xmlChar * str)14862 xmlXPathCompile(const xmlChar *str) {
14863     return(xmlXPathCtxtCompile(NULL, str));
14864 }
14865 
14866 /**
14867  * xmlXPathCompiledEvalInternal:
14868  * @comp:  the compiled XPath expression
14869  * @ctxt:  the XPath context
14870  * @resObj: the resulting XPath object or NULL
14871  * @toBool: 1 if only a boolean result is requested
14872  *
14873  * Evaluate the Precompiled XPath expression in the given context.
14874  * The caller has to free @resObj.
14875  *
14876  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14877  *         the caller has to free the object.
14878  */
14879 static int
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt,xmlXPathObjectPtr * resObjPtr,int toBool)14880 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14881 			     xmlXPathContextPtr ctxt,
14882 			     xmlXPathObjectPtr *resObjPtr,
14883 			     int toBool)
14884 {
14885     xmlXPathParserContextPtr pctxt;
14886     xmlXPathObjectPtr resObj;
14887 #ifndef LIBXML_THREAD_ENABLED
14888     static int reentance = 0;
14889 #endif
14890     int res;
14891 
14892     CHECK_CTXT_NEG(ctxt)
14893 
14894     if (comp == NULL)
14895 	return(-1);
14896     xmlXPathInit();
14897 
14898 #ifndef LIBXML_THREAD_ENABLED
14899     reentance++;
14900     if (reentance > 1)
14901 	xmlXPathDisableOptimizer = 1;
14902 #endif
14903 
14904 #ifdef DEBUG_EVAL_COUNTS
14905     comp->nb++;
14906     if ((comp->string != NULL) && (comp->nb > 100)) {
14907 	fprintf(stderr, "100 x %s\n", comp->string);
14908 	comp->nb = 0;
14909     }
14910 #endif
14911     pctxt = xmlXPathCompParserContext(comp, ctxt);
14912     res = xmlXPathRunEval(pctxt, toBool);
14913 
14914     if (pctxt->error != XPATH_EXPRESSION_OK) {
14915         resObj = NULL;
14916     } else {
14917         resObj = valuePop(pctxt);
14918         if (resObj == NULL) {
14919             if (!toBool)
14920                 xmlGenericError(xmlGenericErrorContext,
14921                     "xmlXPathCompiledEval: No result on the stack.\n");
14922         } else if (pctxt->valueNr > 0) {
14923             xmlGenericError(xmlGenericErrorContext,
14924                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14925                 pctxt->valueNr);
14926         }
14927     }
14928 
14929     if (resObjPtr)
14930         *resObjPtr = resObj;
14931     else
14932         xmlXPathReleaseObject(ctxt, resObj);
14933 
14934     pctxt->comp = NULL;
14935     xmlXPathFreeParserContext(pctxt);
14936 #ifndef LIBXML_THREAD_ENABLED
14937     reentance--;
14938 #endif
14939 
14940     return(res);
14941 }
14942 
14943 /**
14944  * xmlXPathCompiledEval:
14945  * @comp:  the compiled XPath expression
14946  * @ctx:  the XPath context
14947  *
14948  * Evaluate the Precompiled XPath expression in the given context.
14949  *
14950  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14951  *         the caller has to free the object.
14952  */
14953 xmlXPathObjectPtr
xmlXPathCompiledEval(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctx)14954 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14955 {
14956     xmlXPathObjectPtr res = NULL;
14957 
14958     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14959     return(res);
14960 }
14961 
14962 /**
14963  * xmlXPathCompiledEvalToBoolean:
14964  * @comp:  the compiled XPath expression
14965  * @ctxt:  the XPath context
14966  *
14967  * Applies the XPath boolean() function on the result of the given
14968  * compiled expression.
14969  *
14970  * Returns 1 if the expression evaluated to true, 0 if to false and
14971  *         -1 in API and internal errors.
14972  */
14973 int
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)14974 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14975 			      xmlXPathContextPtr ctxt)
14976 {
14977     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14978 }
14979 
14980 /**
14981  * xmlXPathEvalExpr:
14982  * @ctxt:  the XPath Parser context
14983  *
14984  * Parse and evaluate an XPath expression in the given context,
14985  * then push the result on the context stack
14986  */
14987 void
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt)14988 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14989 #ifdef XPATH_STREAMING
14990     xmlXPathCompExprPtr comp;
14991 #endif
14992 
14993     if (ctxt == NULL) return;
14994 
14995 #ifdef XPATH_STREAMING
14996     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14997     if (comp != NULL) {
14998         if (ctxt->comp != NULL)
14999 	    xmlXPathFreeCompExpr(ctxt->comp);
15000         ctxt->comp = comp;
15001     } else
15002 #endif
15003     {
15004 	xmlXPathCompileExpr(ctxt, 1);
15005         CHECK_ERROR;
15006 
15007         /* Check for trailing characters. */
15008         if (*ctxt->cur != 0)
15009             XP_ERROR(XPATH_EXPR_ERROR);
15010 
15011 	if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0))
15012 	    xmlXPathOptimizeExpression(ctxt->comp,
15013 		&ctxt->comp->steps[ctxt->comp->last]);
15014     }
15015 
15016     xmlXPathRunEval(ctxt, 0);
15017 }
15018 
15019 /**
15020  * xmlXPathEval:
15021  * @str:  the XPath expression
15022  * @ctx:  the XPath context
15023  *
15024  * Evaluate the XPath Location Path in the given context.
15025  *
15026  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15027  *         the caller has to free the object.
15028  */
15029 xmlXPathObjectPtr
xmlXPathEval(const xmlChar * str,xmlXPathContextPtr ctx)15030 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
15031     xmlXPathParserContextPtr ctxt;
15032     xmlXPathObjectPtr res;
15033 
15034     CHECK_CTXT(ctx)
15035 
15036     xmlXPathInit();
15037 
15038     ctxt = xmlXPathNewParserContext(str, ctx);
15039     if (ctxt == NULL)
15040         return NULL;
15041     xmlXPathEvalExpr(ctxt);
15042 
15043     if (ctxt->error != XPATH_EXPRESSION_OK) {
15044 	res = NULL;
15045     } else {
15046 	res = valuePop(ctxt);
15047         if (res == NULL) {
15048             xmlGenericError(xmlGenericErrorContext,
15049                 "xmlXPathCompiledEval: No result on the stack.\n");
15050         } else if (ctxt->valueNr > 0) {
15051             xmlGenericError(xmlGenericErrorContext,
15052                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
15053                 ctxt->valueNr);
15054         }
15055     }
15056 
15057     xmlXPathFreeParserContext(ctxt);
15058     return(res);
15059 }
15060 
15061 /**
15062  * xmlXPathSetContextNode:
15063  * @node: the node to to use as the context node
15064  * @ctx:  the XPath context
15065  *
15066  * Sets 'node' as the context node. The node must be in the same
15067  * document as that associated with the context.
15068  *
15069  * Returns -1 in case of error or 0 if successful
15070  */
15071 int
xmlXPathSetContextNode(xmlNodePtr node,xmlXPathContextPtr ctx)15072 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
15073     if ((node == NULL) || (ctx == NULL))
15074         return(-1);
15075 
15076     if (node->doc == ctx->doc) {
15077         ctx->node = node;
15078 	return(0);
15079     }
15080     return(-1);
15081 }
15082 
15083 /**
15084  * xmlXPathNodeEval:
15085  * @node: the node to to use as the context node
15086  * @str:  the XPath expression
15087  * @ctx:  the XPath context
15088  *
15089  * Evaluate the XPath Location Path in the given context. The node 'node'
15090  * is set as the context node. The context node is not restored.
15091  *
15092  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15093  *         the caller has to free the object.
15094  */
15095 xmlXPathObjectPtr
xmlXPathNodeEval(xmlNodePtr node,const xmlChar * str,xmlXPathContextPtr ctx)15096 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
15097     if (str == NULL)
15098         return(NULL);
15099     if (xmlXPathSetContextNode(node, ctx) < 0)
15100         return(NULL);
15101     return(xmlXPathEval(str, ctx));
15102 }
15103 
15104 /**
15105  * xmlXPathEvalExpression:
15106  * @str:  the XPath expression
15107  * @ctxt:  the XPath context
15108  *
15109  * Alias for xmlXPathEval().
15110  *
15111  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15112  *         the caller has to free the object.
15113  */
15114 xmlXPathObjectPtr
xmlXPathEvalExpression(const xmlChar * str,xmlXPathContextPtr ctxt)15115 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15116     return(xmlXPathEval(str, ctxt));
15117 }
15118 
15119 /************************************************************************
15120  *									*
15121  *	Extra functions not pertaining to the XPath spec		*
15122  *									*
15123  ************************************************************************/
15124 /**
15125  * xmlXPathEscapeUriFunction:
15126  * @ctxt:  the XPath Parser context
15127  * @nargs:  the number of arguments
15128  *
15129  * Implement the escape-uri() XPath function
15130  *    string escape-uri(string $str, bool $escape-reserved)
15131  *
15132  * This function applies the URI escaping rules defined in section 2 of [RFC
15133  * 2396] to the string supplied as $uri-part, which typically represents all
15134  * or part of a URI. The effect of the function is to replace any special
15135  * character in the string by an escape sequence of the form %xx%yy...,
15136  * where xxyy... is the hexadecimal representation of the octets used to
15137  * represent the character in UTF-8.
15138  *
15139  * The set of characters that are escaped depends on the setting of the
15140  * boolean argument $escape-reserved.
15141  *
15142  * If $escape-reserved is true, all characters are escaped other than lower
15143  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15144  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15145  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15146  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15147  * A-F).
15148  *
15149  * If $escape-reserved is false, the behavior differs in that characters
15150  * referred to in [RFC 2396] as reserved characters are not escaped. These
15151  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15152  *
15153  * [RFC 2396] does not define whether escaped URIs should use lower case or
15154  * upper case for hexadecimal digits. To ensure that escaped URIs can be
15155  * compared using string comparison functions, this function must always use
15156  * the upper-case letters A-F.
15157  *
15158  * Generally, $escape-reserved should be set to true when escaping a string
15159  * that is to form a single part of a URI, and to false when escaping an
15160  * entire URI or URI reference.
15161  *
15162  * In the case of non-ascii characters, the string is encoded according to
15163  * utf-8 and then converted according to RFC 2396.
15164  *
15165  * Examples
15166  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15167  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15168  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15169  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15170  *
15171  */
15172 static void
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt,int nargs)15173 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15174     xmlXPathObjectPtr str;
15175     int escape_reserved;
15176     xmlBufPtr target;
15177     xmlChar *cptr;
15178     xmlChar escape[4];
15179 
15180     CHECK_ARITY(2);
15181 
15182     escape_reserved = xmlXPathPopBoolean(ctxt);
15183 
15184     CAST_TO_STRING;
15185     str = valuePop(ctxt);
15186 
15187     target = xmlBufCreate();
15188 
15189     escape[0] = '%';
15190     escape[3] = 0;
15191 
15192     if (target) {
15193 	for (cptr = str->stringval; *cptr; cptr++) {
15194 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
15195 		(*cptr >= 'a' && *cptr <= 'z') ||
15196 		(*cptr >= '0' && *cptr <= '9') ||
15197 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
15198 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
15199 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15200 		(*cptr == '%' &&
15201 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15202 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15203 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
15204 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15205 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15206 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15207 		(!escape_reserved &&
15208 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15209 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15210 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15211 		  *cptr == ','))) {
15212 		xmlBufAdd(target, cptr, 1);
15213 	    } else {
15214 		if ((*cptr >> 4) < 10)
15215 		    escape[1] = '0' + (*cptr >> 4);
15216 		else
15217 		    escape[1] = 'A' - 10 + (*cptr >> 4);
15218 		if ((*cptr & 0xF) < 10)
15219 		    escape[2] = '0' + (*cptr & 0xF);
15220 		else
15221 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
15222 
15223 		xmlBufAdd(target, &escape[0], 3);
15224 	    }
15225 	}
15226     }
15227     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15228 	xmlBufContent(target)));
15229     xmlBufFree(target);
15230     xmlXPathReleaseObject(ctxt->context, str);
15231 }
15232 
15233 /**
15234  * xmlXPathRegisterAllFunctions:
15235  * @ctxt:  the XPath context
15236  *
15237  * Registers all default XPath functions in this context
15238  */
15239 void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)15240 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15241 {
15242     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15243                          xmlXPathBooleanFunction);
15244     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15245                          xmlXPathCeilingFunction);
15246     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15247                          xmlXPathCountFunction);
15248     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15249                          xmlXPathConcatFunction);
15250     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15251                          xmlXPathContainsFunction);
15252     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15253                          xmlXPathIdFunction);
15254     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15255                          xmlXPathFalseFunction);
15256     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15257                          xmlXPathFloorFunction);
15258     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15259                          xmlXPathLastFunction);
15260     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15261                          xmlXPathLangFunction);
15262     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15263                          xmlXPathLocalNameFunction);
15264     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15265                          xmlXPathNotFunction);
15266     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15267                          xmlXPathNameFunction);
15268     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15269                          xmlXPathNamespaceURIFunction);
15270     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15271                          xmlXPathNormalizeFunction);
15272     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15273                          xmlXPathNumberFunction);
15274     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15275                          xmlXPathPositionFunction);
15276     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15277                          xmlXPathRoundFunction);
15278     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15279                          xmlXPathStringFunction);
15280     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15281                          xmlXPathStringLengthFunction);
15282     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15283                          xmlXPathStartsWithFunction);
15284     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15285                          xmlXPathSubstringFunction);
15286     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15287                          xmlXPathSubstringBeforeFunction);
15288     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15289                          xmlXPathSubstringAfterFunction);
15290     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15291                          xmlXPathSumFunction);
15292     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15293                          xmlXPathTrueFunction);
15294     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15295                          xmlXPathTranslateFunction);
15296 
15297     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15298 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15299                          xmlXPathEscapeUriFunction);
15300 }
15301 
15302 #endif /* LIBXML_XPATH_ENABLED */
15303 #define bottom_xpath
15304 #include "elfgcchack.h"
15305