1 /*
2  * xpath.c: XML Path Language implementation
3  *          XPath is a language for addressing parts of an XML document,
4  *          designed to be used by both XSLT and XPointer
5  *
6  * Reference: W3C Recommendation 16 November 1999
7  *     http://www.w3.org/TR/1999/REC-xpath-19991116
8  * Public reference:
9  *     http://www.w3.org/TR/xpath
10  *
11  * See Copyright for the status of this software
12  *
13  * Author: daniel@veillard.com
14  *
15  */
16 
17 /* To avoid EBCDIC trouble when parsing on zOS */
18 #if defined(__MVS__)
19 #pragma convert("ISO8859-1")
20 #endif
21 
22 #define IN_LIBXML
23 #include "libxml.h"
24 
25 #include <limits.h>
26 #include <string.h>
27 #include <stddef.h>
28 
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
31 #endif
32 #ifdef HAVE_MATH_H
33 #include <math.h>
34 #endif
35 #ifdef HAVE_FLOAT_H
36 #include <float.h>
37 #endif
38 #ifdef HAVE_CTYPE_H
39 #include <ctype.h>
40 #endif
41 #ifdef HAVE_SIGNAL_H
42 #include <signal.h>
43 #endif
44 
45 #include <libxml/xmlmemory.h>
46 #include <libxml/tree.h>
47 #include <libxml/valid.h>
48 #include <libxml/xpath.h>
49 #include <libxml/xpathInternals.h>
50 #include <libxml/parserInternals.h>
51 #include <libxml/hash.h>
52 #ifdef LIBXML_XPTR_ENABLED
53 #include <libxml/xpointer.h>
54 #endif
55 #ifdef LIBXML_DEBUG_ENABLED
56 #include <libxml/debugXML.h>
57 #endif
58 #include <libxml/xmlerror.h>
59 #include <libxml/threads.h>
60 #include <libxml/globals.h>
61 #ifdef LIBXML_PATTERN_ENABLED
62 #include <libxml/pattern.h>
63 #endif
64 
65 #include "buf.h"
66 
67 #ifdef LIBXML_PATTERN_ENABLED
68 #define XPATH_STREAMING
69 #endif
70 
71 #define TODO								\
72     xmlGenericError(xmlGenericErrorContext,				\
73 	    "Unimplemented block at %s:%d\n",				\
74             __FILE__, __LINE__);
75 
76 /**
77  * WITH_TIM_SORT:
78  *
79  * Use the Timsort algorithm provided in timsort.h to sort
80  * nodeset as this is a great improvement over the old Shell sort
81  * used in xmlXPathNodeSetSort()
82  */
83 #define WITH_TIM_SORT
84 
85 /*
86 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
87 * If defined, this will use xmlXPathCmpNodesExt() instead of
88 * xmlXPathCmpNodes(). The new function is optimized comparison of
89 * non-element nodes; actually it will speed up comparison only if
90 * xmlXPathOrderDocElems() was called in order to index the elements of
91 * a tree in document order; Libxslt does such an indexing, thus it will
92 * benefit from this optimization.
93 */
94 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
95 
96 /*
97 * XP_OPTIMIZED_FILTER_FIRST:
98 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
99 * in a way, that it stop evaluation at the first node.
100 */
101 #define XP_OPTIMIZED_FILTER_FIRST
102 
103 /*
104 * XP_DEBUG_OBJ_USAGE:
105 * Internal flag to enable tracking of how much XPath objects have been
106 * created.
107 */
108 /* #define XP_DEBUG_OBJ_USAGE */
109 
110 /*
111  * XPATH_MAX_STEPS:
112  * when compiling an XPath expression we arbitrary limit the maximum
113  * number of step operation in the compiled expression. 1000000 is
114  * an insanely large value which should never be reached under normal
115  * circumstances
116  */
117 #define XPATH_MAX_STEPS 1000000
118 
119 /*
120  * XPATH_MAX_STACK_DEPTH:
121  * when evaluating an XPath expression we arbitrary limit the maximum
122  * number of object allowed to be pushed on the stack. 1000000 is
123  * an insanely large value which should never be reached under normal
124  * circumstances
125  */
126 #define XPATH_MAX_STACK_DEPTH 1000000
127 
128 /*
129  * XPATH_MAX_NODESET_LENGTH:
130  * when evaluating an XPath expression nodesets are created and we
131  * arbitrary limit the maximum length of those node set. 10000000 is
132  * an insanely large value which should never be reached under normal
133  * circumstances, one would first need to construct an in memory tree
134  * with more than 10 millions nodes.
135  */
136 #define XPATH_MAX_NODESET_LENGTH 10000000
137 
138 /*
139  * XPATH_MAX_RECRUSION_DEPTH:
140  * Maximum amount of nested functions calls when parsing or evaluating
141  * expressions
142  */
143 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
144 #define XPATH_MAX_RECURSION_DEPTH 500
145 #else
146 #define XPATH_MAX_RECURSION_DEPTH 5000
147 #endif
148 
149 /*
150  * TODO:
151  * There are a few spots where some tests are done which depend upon ascii
152  * data.  These should be enhanced for full UTF8 support (see particularly
153  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
154  */
155 
156 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
157 /**
158  * xmlXPathCmpNodesExt:
159  * @node1:  the first node
160  * @node2:  the second node
161  *
162  * Compare two nodes w.r.t document order.
163  * This one is optimized for handling of non-element nodes.
164  *
165  * Returns -2 in case of error 1 if first point < second point, 0 if
166  *         it's the same node, -1 otherwise
167  */
168 static int
xmlXPathCmpNodesExt(xmlNodePtr node1,xmlNodePtr node2)169 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
170     int depth1, depth2;
171     int misc = 0, precedence1 = 0, precedence2 = 0;
172     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
173     xmlNodePtr cur, root;
174     ptrdiff_t l1, l2;
175 
176     if ((node1 == NULL) || (node2 == NULL))
177 	return(-2);
178 
179     if (node1 == node2)
180 	return(0);
181 
182     /*
183      * a couple of optimizations which will avoid computations in most cases
184      */
185     switch (node1->type) {
186 	case XML_ELEMENT_NODE:
187 	    if (node2->type == XML_ELEMENT_NODE) {
188 		if ((0 > (ptrdiff_t) node1->content) &&
189 		    (0 > (ptrdiff_t) node2->content) &&
190 		    (node1->doc == node2->doc))
191 		{
192 		    l1 = -((ptrdiff_t) node1->content);
193 		    l2 = -((ptrdiff_t) node2->content);
194 		    if (l1 < l2)
195 			return(1);
196 		    if (l1 > l2)
197 			return(-1);
198 		} else
199 		    goto turtle_comparison;
200 	    }
201 	    break;
202 	case XML_ATTRIBUTE_NODE:
203 	    precedence1 = 1; /* element is owner */
204 	    miscNode1 = node1;
205 	    node1 = node1->parent;
206 	    misc = 1;
207 	    break;
208 	case XML_TEXT_NODE:
209 	case XML_CDATA_SECTION_NODE:
210 	case XML_COMMENT_NODE:
211 	case XML_PI_NODE: {
212 	    miscNode1 = node1;
213 	    /*
214 	    * Find nearest element node.
215 	    */
216 	    if (node1->prev != NULL) {
217 		do {
218 		    node1 = node1->prev;
219 		    if (node1->type == XML_ELEMENT_NODE) {
220 			precedence1 = 3; /* element in prev-sibl axis */
221 			break;
222 		    }
223 		    if (node1->prev == NULL) {
224 			precedence1 = 2; /* element is parent */
225 			/*
226 			* URGENT TODO: Are there any cases, where the
227 			* parent of such a node is not an element node?
228 			*/
229 			node1 = node1->parent;
230 			break;
231 		    }
232 		} while (1);
233 	    } else {
234 		precedence1 = 2; /* element is parent */
235 		node1 = node1->parent;
236 	    }
237 	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
238 		(0 <= (ptrdiff_t) node1->content)) {
239 		/*
240 		* Fallback for whatever case.
241 		*/
242 		node1 = miscNode1;
243 		precedence1 = 0;
244 	    } else
245 		misc = 1;
246 	}
247 	    break;
248 	case XML_NAMESPACE_DECL:
249 	    /*
250 	    * TODO: why do we return 1 for namespace nodes?
251 	    */
252 	    return(1);
253 	default:
254 	    break;
255     }
256     switch (node2->type) {
257 	case XML_ELEMENT_NODE:
258 	    break;
259 	case XML_ATTRIBUTE_NODE:
260 	    precedence2 = 1; /* element is owner */
261 	    miscNode2 = node2;
262 	    node2 = node2->parent;
263 	    misc = 1;
264 	    break;
265 	case XML_TEXT_NODE:
266 	case XML_CDATA_SECTION_NODE:
267 	case XML_COMMENT_NODE:
268 	case XML_PI_NODE: {
269 	    miscNode2 = node2;
270 	    if (node2->prev != NULL) {
271 		do {
272 		    node2 = node2->prev;
273 		    if (node2->type == XML_ELEMENT_NODE) {
274 			precedence2 = 3; /* element in prev-sibl axis */
275 			break;
276 		    }
277 		    if (node2->prev == NULL) {
278 			precedence2 = 2; /* element is parent */
279 			node2 = node2->parent;
280 			break;
281 		    }
282 		} while (1);
283 	    } else {
284 		precedence2 = 2; /* element is parent */
285 		node2 = node2->parent;
286 	    }
287 	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
288 		(0 <= (ptrdiff_t) node2->content))
289 	    {
290 		node2 = miscNode2;
291 		precedence2 = 0;
292 	    } else
293 		misc = 1;
294 	}
295 	    break;
296 	case XML_NAMESPACE_DECL:
297 	    return(1);
298 	default:
299 	    break;
300     }
301     if (misc) {
302 	if (node1 == node2) {
303 	    if (precedence1 == precedence2) {
304 		/*
305 		* The ugly case; but normally there aren't many
306 		* adjacent non-element nodes around.
307 		*/
308 		cur = miscNode2->prev;
309 		while (cur != NULL) {
310 		    if (cur == miscNode1)
311 			return(1);
312 		    if (cur->type == XML_ELEMENT_NODE)
313 			return(-1);
314 		    cur = cur->prev;
315 		}
316 		return (-1);
317 	    } else {
318 		/*
319 		* Evaluate based on higher precedence wrt to the element.
320 		* TODO: This assumes attributes are sorted before content.
321 		*   Is this 100% correct?
322 		*/
323 		if (precedence1 < precedence2)
324 		    return(1);
325 		else
326 		    return(-1);
327 	    }
328 	}
329 	/*
330 	* Special case: One of the helper-elements is contained by the other.
331 	* <foo>
332 	*   <node2>
333 	*     <node1>Text-1(precedence1 == 2)</node1>
334 	*   </node2>
335 	*   Text-6(precedence2 == 3)
336 	* </foo>
337 	*/
338 	if ((precedence2 == 3) && (precedence1 > 1)) {
339 	    cur = node1->parent;
340 	    while (cur) {
341 		if (cur == node2)
342 		    return(1);
343 		cur = cur->parent;
344 	    }
345 	}
346 	if ((precedence1 == 3) && (precedence2 > 1)) {
347 	    cur = node2->parent;
348 	    while (cur) {
349 		if (cur == node1)
350 		    return(-1);
351 		cur = cur->parent;
352 	    }
353 	}
354     }
355 
356     /*
357      * Speedup using document order if available.
358      */
359     if ((node1->type == XML_ELEMENT_NODE) &&
360 	(node2->type == XML_ELEMENT_NODE) &&
361 	(0 > (ptrdiff_t) node1->content) &&
362 	(0 > (ptrdiff_t) node2->content) &&
363 	(node1->doc == node2->doc)) {
364 
365 	l1 = -((ptrdiff_t) node1->content);
366 	l2 = -((ptrdiff_t) node2->content);
367 	if (l1 < l2)
368 	    return(1);
369 	if (l1 > l2)
370 	    return(-1);
371     }
372 
373 turtle_comparison:
374 
375     if (node1 == node2->prev)
376 	return(1);
377     if (node1 == node2->next)
378 	return(-1);
379     /*
380      * compute depth to root
381      */
382     for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
383 	if (cur->parent == node1)
384 	    return(1);
385 	depth2++;
386     }
387     root = cur;
388     for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
389 	if (cur->parent == node2)
390 	    return(-1);
391 	depth1++;
392     }
393     /*
394      * Distinct document (or distinct entities :-( ) case.
395      */
396     if (root != cur) {
397 	return(-2);
398     }
399     /*
400      * get the nearest common ancestor.
401      */
402     while (depth1 > depth2) {
403 	depth1--;
404 	node1 = node1->parent;
405     }
406     while (depth2 > depth1) {
407 	depth2--;
408 	node2 = node2->parent;
409     }
410     while (node1->parent != node2->parent) {
411 	node1 = node1->parent;
412 	node2 = node2->parent;
413 	/* should not happen but just in case ... */
414 	if ((node1 == NULL) || (node2 == NULL))
415 	    return(-2);
416     }
417     /*
418      * Find who's first.
419      */
420     if (node1 == node2->prev)
421 	return(1);
422     if (node1 == node2->next)
423 	return(-1);
424     /*
425      * Speedup using document order if available.
426      */
427     if ((node1->type == XML_ELEMENT_NODE) &&
428 	(node2->type == XML_ELEMENT_NODE) &&
429 	(0 > (ptrdiff_t) node1->content) &&
430 	(0 > (ptrdiff_t) node2->content) &&
431 	(node1->doc == node2->doc)) {
432 
433 	l1 = -((ptrdiff_t) node1->content);
434 	l2 = -((ptrdiff_t) node2->content);
435 	if (l1 < l2)
436 	    return(1);
437 	if (l1 > l2)
438 	    return(-1);
439     }
440 
441     for (cur = node1->next;cur != NULL;cur = cur->next)
442 	if (cur == node2)
443 	    return(1);
444     return(-1); /* assume there is no sibling list corruption */
445 }
446 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
447 
448 /*
449  * Wrapper for the Timsort algorithm from timsort.h
450  */
451 #ifdef WITH_TIM_SORT
452 #define SORT_NAME libxml_domnode
453 #define SORT_TYPE xmlNodePtr
454 /**
455  * wrap_cmp:
456  * @x: a node
457  * @y: another node
458  *
459  * Comparison function for the Timsort implementation
460  *
461  * Returns -2 in case of error -1 if first point < second point, 0 if
462  *         it's the same node, +1 otherwise
463  */
464 static
465 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
466 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
wrap_cmp(xmlNodePtr x,xmlNodePtr y)467     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
468     {
469         int res = xmlXPathCmpNodesExt(x, y);
470         return res == -2 ? res : -res;
471     }
472 #else
wrap_cmp(xmlNodePtr x,xmlNodePtr y)473     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
474     {
475         int res = xmlXPathCmpNodes(x, y);
476         return res == -2 ? res : -res;
477     }
478 #endif
479 #define SORT_CMP(x, y)  (wrap_cmp(x, y))
480 #include "timsort.h"
481 #endif /* WITH_TIM_SORT */
482 
483 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
484 
485 /************************************************************************
486  *									*
487  *			Floating point stuff				*
488  *									*
489  ************************************************************************/
490 
491 double xmlXPathNAN;
492 double xmlXPathPINF;
493 double xmlXPathNINF;
494 
495 /**
496  * xmlXPathInit:
497  *
498  * Initialize the XPath environment
499  */
500 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
501 void
xmlXPathInit(void)502 xmlXPathInit(void) {
503     /* MSVC doesn't allow division by zero in constant expressions. */
504     double zero = 0.0;
505     xmlXPathNAN = 0.0 / zero;
506     xmlXPathPINF = 1.0 / zero;
507     xmlXPathNINF = -xmlXPathPINF;
508 }
509 
510 /**
511  * xmlXPathIsNaN:
512  * @val:  a double value
513  *
514  * Returns 1 if the value is a NaN, 0 otherwise
515  */
516 int
xmlXPathIsNaN(double val)517 xmlXPathIsNaN(double val) {
518 #ifdef isnan
519     return isnan(val);
520 #else
521     return !(val == val);
522 #endif
523 }
524 
525 /**
526  * xmlXPathIsInf:
527  * @val:  a double value
528  *
529  * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
530  */
531 int
xmlXPathIsInf(double val)532 xmlXPathIsInf(double val) {
533 #ifdef isinf
534     return isinf(val) ? (val > 0 ? 1 : -1) : 0;
535 #else
536     if (val >= xmlXPathPINF)
537         return 1;
538     if (val <= -xmlXPathPINF)
539         return -1;
540     return 0;
541 #endif
542 }
543 
544 #endif /* SCHEMAS or XPATH */
545 
546 #ifdef LIBXML_XPATH_ENABLED
547 
548 /*
549  * TODO: when compatibility allows remove all "fake node libxslt" strings
550  *       the test should just be name[0] = ' '
551  */
552 #ifdef DEBUG_XPATH_EXPRESSION
553 #define DEBUG_STEP
554 #define DEBUG_EXPR
555 #define DEBUG_EVAL_COUNTS
556 #endif
557 
558 static xmlNs xmlXPathXMLNamespaceStruct = {
559     NULL,
560     XML_NAMESPACE_DECL,
561     XML_XML_NAMESPACE,
562     BAD_CAST "xml",
563     NULL,
564     NULL
565 };
566 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
567 #ifndef LIBXML_THREAD_ENABLED
568 /*
569  * Optimizer is disabled only when threaded apps are detected while
570  * the library ain't compiled for thread safety.
571  */
572 static int xmlXPathDisableOptimizer = 0;
573 #endif
574 
575 /************************************************************************
576  *									*
577  *			Error handling routines				*
578  *									*
579  ************************************************************************/
580 
581 /**
582  * XP_ERRORNULL:
583  * @X:  the error code
584  *
585  * Macro to raise an XPath error and return NULL.
586  */
587 #define XP_ERRORNULL(X)							\
588     { xmlXPathErr(ctxt, X); return(NULL); }
589 
590 /*
591  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
592  */
593 static const char *xmlXPathErrorMessages[] = {
594     "Ok\n",
595     "Number encoding\n",
596     "Unfinished literal\n",
597     "Start of literal\n",
598     "Expected $ for variable reference\n",
599     "Undefined variable\n",
600     "Invalid predicate\n",
601     "Invalid expression\n",
602     "Missing closing curly brace\n",
603     "Unregistered function\n",
604     "Invalid operand\n",
605     "Invalid type\n",
606     "Invalid number of arguments\n",
607     "Invalid context size\n",
608     "Invalid context position\n",
609     "Memory allocation error\n",
610     "Syntax error\n",
611     "Resource error\n",
612     "Sub resource error\n",
613     "Undefined namespace prefix\n",
614     "Encoding error\n",
615     "Char out of XML range\n",
616     "Invalid or incomplete context\n",
617     "Stack usage error\n",
618     "Forbidden variable\n",
619     "Operation limit exceeded\n",
620     "Recursion limit exceeded\n",
621     "?? Unknown error ??\n"	/* Must be last in the list! */
622 };
623 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
624 		   sizeof(xmlXPathErrorMessages[0])) - 1)
625 /**
626  * xmlXPathErrMemory:
627  * @ctxt:  an XPath context
628  * @extra:  extra information
629  *
630  * Handle a redefinition of attribute error
631  */
632 static void
xmlXPathErrMemory(xmlXPathContextPtr ctxt,const char * extra)633 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
634 {
635     if (ctxt != NULL) {
636         xmlResetError(&ctxt->lastError);
637         if (extra) {
638             xmlChar buf[200];
639 
640             xmlStrPrintf(buf, 200,
641                          "Memory allocation failed : %s\n",
642                          extra);
643             ctxt->lastError.message = (char *) xmlStrdup(buf);
644         } else {
645             ctxt->lastError.message = (char *)
646 	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
647         }
648         ctxt->lastError.domain = XML_FROM_XPATH;
649         ctxt->lastError.code = XML_ERR_NO_MEMORY;
650 	if (ctxt->error != NULL)
651 	    ctxt->error(ctxt->userData, &ctxt->lastError);
652     } else {
653         if (extra)
654             __xmlRaiseError(NULL, NULL, NULL,
655                             NULL, NULL, XML_FROM_XPATH,
656                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
657                             extra, NULL, NULL, 0, 0,
658                             "Memory allocation failed : %s\n", extra);
659         else
660             __xmlRaiseError(NULL, NULL, NULL,
661                             NULL, NULL, XML_FROM_XPATH,
662                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
663                             NULL, NULL, NULL, 0, 0,
664                             "Memory allocation failed\n");
665     }
666 }
667 
668 /**
669  * xmlXPathPErrMemory:
670  * @ctxt:  an XPath parser context
671  * @extra:  extra information
672  *
673  * Handle a redefinition of attribute error
674  */
675 static void
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt,const char * extra)676 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
677 {
678     if (ctxt == NULL)
679 	xmlXPathErrMemory(NULL, extra);
680     else {
681 	ctxt->error = XPATH_MEMORY_ERROR;
682 	xmlXPathErrMemory(ctxt->context, extra);
683     }
684 }
685 
686 /**
687  * xmlXPathErr:
688  * @ctxt:  a XPath parser context
689  * @error:  the error code
690  *
691  * Handle an XPath error
692  */
693 void
xmlXPathErr(xmlXPathParserContextPtr ctxt,int error)694 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
695 {
696     if ((error < 0) || (error > MAXERRNO))
697 	error = MAXERRNO;
698     if (ctxt == 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 			NULL, NULL, NULL, 0, 0,
704 			"%s", xmlXPathErrorMessages[error]);
705 	return;
706     }
707     ctxt->error = error;
708     if (ctxt->context == NULL) {
709 	__xmlRaiseError(NULL, NULL, NULL,
710 			NULL, NULL, XML_FROM_XPATH,
711 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
712 			XML_ERR_ERROR, NULL, 0,
713 			(const char *) ctxt->base, NULL, NULL,
714 			ctxt->cur - ctxt->base, 0,
715 			"%s", xmlXPathErrorMessages[error]);
716 	return;
717     }
718 
719     /* cleanup current last error */
720     xmlResetError(&ctxt->context->lastError);
721 
722     ctxt->context->lastError.domain = XML_FROM_XPATH;
723     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
724                            XPATH_EXPRESSION_OK;
725     ctxt->context->lastError.level = XML_ERR_ERROR;
726     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
727     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
728     ctxt->context->lastError.node = ctxt->context->debugNode;
729     if (ctxt->context->error != NULL) {
730 	ctxt->context->error(ctxt->context->userData,
731 	                     &ctxt->context->lastError);
732     } else {
733 	__xmlRaiseError(NULL, NULL, NULL,
734 			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
735 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
736 			XML_ERR_ERROR, NULL, 0,
737 			(const char *) ctxt->base, NULL, NULL,
738 			ctxt->cur - ctxt->base, 0,
739 			"%s", xmlXPathErrorMessages[error]);
740     }
741 
742 }
743 
744 /**
745  * xmlXPatherror:
746  * @ctxt:  the XPath Parser context
747  * @file:  the file name
748  * @line:  the line number
749  * @no:  the error number
750  *
751  * Formats an error message.
752  */
753 void
xmlXPatherror(xmlXPathParserContextPtr ctxt,const char * file ATTRIBUTE_UNUSED,int line ATTRIBUTE_UNUSED,int no)754 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
755               int line ATTRIBUTE_UNUSED, int no) {
756     xmlXPathErr(ctxt, no);
757 }
758 
759 /**
760  * xmlXPathCheckOpLimit:
761  * @ctxt:  the XPath Parser context
762  * @opCount:  the number of operations to be added
763  *
764  * Adds opCount to the running total of operations and returns -1 if the
765  * operation limit is exceeded. Returns 0 otherwise.
766  */
767 static int
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt,unsigned long opCount)768 xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
769     xmlXPathContextPtr xpctxt = ctxt->context;
770 
771     if ((opCount > xpctxt->opLimit) ||
772         (xpctxt->opCount > xpctxt->opLimit - opCount)) {
773         xpctxt->opCount = xpctxt->opLimit;
774         xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
775         return(-1);
776     }
777 
778     xpctxt->opCount += opCount;
779     return(0);
780 }
781 
782 #define OP_LIMIT_EXCEEDED(ctxt, n) \
783     ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
784 
785 /************************************************************************
786  *									*
787  *			Utilities					*
788  *									*
789  ************************************************************************/
790 
791 /**
792  * xsltPointerList:
793  *
794  * Pointer-list for various purposes.
795  */
796 typedef struct _xmlPointerList xmlPointerList;
797 typedef xmlPointerList *xmlPointerListPtr;
798 struct _xmlPointerList {
799     void **items;
800     int number;
801     int size;
802 };
803 /*
804 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
805 * and here, we should make the functions public.
806 */
807 static int
xmlPointerListAddSize(xmlPointerListPtr list,void * item,int initialSize)808 xmlPointerListAddSize(xmlPointerListPtr list,
809 		       void *item,
810 		       int initialSize)
811 {
812     if (list->items == NULL) {
813 	if (initialSize <= 0)
814 	    initialSize = 1;
815 	list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
816 	if (list->items == NULL) {
817 	    xmlXPathErrMemory(NULL,
818 		"xmlPointerListCreate: allocating item\n");
819 	    return(-1);
820 	}
821 	list->number = 0;
822 	list->size = initialSize;
823     } else if (list->size <= list->number) {
824         if (list->size > 50000000) {
825 	    xmlXPathErrMemory(NULL,
826 		"xmlPointerListAddSize: re-allocating item\n");
827             return(-1);
828         }
829 	list->size *= 2;
830 	list->items = (void **) xmlRealloc(list->items,
831 	    list->size * sizeof(void *));
832 	if (list->items == NULL) {
833 	    xmlXPathErrMemory(NULL,
834 		"xmlPointerListAddSize: re-allocating item\n");
835 	    list->size = 0;
836 	    return(-1);
837 	}
838     }
839     list->items[list->number++] = item;
840     return(0);
841 }
842 
843 /**
844  * xsltPointerListCreate:
845  *
846  * Creates an xsltPointerList structure.
847  *
848  * Returns a xsltPointerList structure or NULL in case of an error.
849  */
850 static xmlPointerListPtr
xmlPointerListCreate(int initialSize)851 xmlPointerListCreate(int initialSize)
852 {
853     xmlPointerListPtr ret;
854 
855     ret = xmlMalloc(sizeof(xmlPointerList));
856     if (ret == NULL) {
857 	xmlXPathErrMemory(NULL,
858 	    "xmlPointerListCreate: allocating item\n");
859 	return (NULL);
860     }
861     memset(ret, 0, sizeof(xmlPointerList));
862     if (initialSize > 0) {
863 	xmlPointerListAddSize(ret, NULL, initialSize);
864 	ret->number = 0;
865     }
866     return (ret);
867 }
868 
869 /**
870  * xsltPointerListFree:
871  *
872  * Frees the xsltPointerList structure. This does not free
873  * the content of the list.
874  */
875 static void
xmlPointerListFree(xmlPointerListPtr list)876 xmlPointerListFree(xmlPointerListPtr list)
877 {
878     if (list == NULL)
879 	return;
880     if (list->items != NULL)
881 	xmlFree(list->items);
882     xmlFree(list);
883 }
884 
885 /************************************************************************
886  *									*
887  *			Parser Types					*
888  *									*
889  ************************************************************************/
890 
891 /*
892  * Types are private:
893  */
894 
895 typedef enum {
896     XPATH_OP_END=0,
897     XPATH_OP_AND,
898     XPATH_OP_OR,
899     XPATH_OP_EQUAL,
900     XPATH_OP_CMP,
901     XPATH_OP_PLUS,
902     XPATH_OP_MULT,
903     XPATH_OP_UNION,
904     XPATH_OP_ROOT,
905     XPATH_OP_NODE,
906     XPATH_OP_COLLECT,
907     XPATH_OP_VALUE, /* 11 */
908     XPATH_OP_VARIABLE,
909     XPATH_OP_FUNCTION,
910     XPATH_OP_ARG,
911     XPATH_OP_PREDICATE,
912     XPATH_OP_FILTER, /* 16 */
913     XPATH_OP_SORT /* 17 */
914 #ifdef LIBXML_XPTR_ENABLED
915     ,XPATH_OP_RANGETO
916 #endif
917 } xmlXPathOp;
918 
919 typedef enum {
920     AXIS_ANCESTOR = 1,
921     AXIS_ANCESTOR_OR_SELF,
922     AXIS_ATTRIBUTE,
923     AXIS_CHILD,
924     AXIS_DESCENDANT,
925     AXIS_DESCENDANT_OR_SELF,
926     AXIS_FOLLOWING,
927     AXIS_FOLLOWING_SIBLING,
928     AXIS_NAMESPACE,
929     AXIS_PARENT,
930     AXIS_PRECEDING,
931     AXIS_PRECEDING_SIBLING,
932     AXIS_SELF
933 } xmlXPathAxisVal;
934 
935 typedef enum {
936     NODE_TEST_NONE = 0,
937     NODE_TEST_TYPE = 1,
938     NODE_TEST_PI = 2,
939     NODE_TEST_ALL = 3,
940     NODE_TEST_NS = 4,
941     NODE_TEST_NAME = 5
942 } xmlXPathTestVal;
943 
944 typedef enum {
945     NODE_TYPE_NODE = 0,
946     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
947     NODE_TYPE_TEXT = XML_TEXT_NODE,
948     NODE_TYPE_PI = XML_PI_NODE
949 } xmlXPathTypeVal;
950 
951 typedef struct _xmlXPathStepOp xmlXPathStepOp;
952 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
953 struct _xmlXPathStepOp {
954     xmlXPathOp op;		/* The identifier of the operation */
955     int ch1;			/* First child */
956     int ch2;			/* Second child */
957     int value;
958     int value2;
959     int value3;
960     void *value4;
961     void *value5;
962     xmlXPathFunction cache;
963     void *cacheURI;
964 };
965 
966 struct _xmlXPathCompExpr {
967     int nbStep;			/* Number of steps in this expression */
968     int maxStep;		/* Maximum number of steps allocated */
969     xmlXPathStepOp *steps;	/* ops for computation of this expression */
970     int last;			/* index of last step in expression */
971     xmlChar *expr;		/* the expression being computed */
972     xmlDictPtr dict;		/* the dictionary to use if any */
973 #ifdef DEBUG_EVAL_COUNTS
974     int nb;
975     xmlChar *string;
976 #endif
977 #ifdef XPATH_STREAMING
978     xmlPatternPtr stream;
979 #endif
980 };
981 
982 /************************************************************************
983  *									*
984  *			Forward declarations				*
985  *									*
986  ************************************************************************/
987 static void
988 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
989 static void
990 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
991 static int
992 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
993                         xmlXPathStepOpPtr op, xmlNodePtr *first);
994 static int
995 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
996 			    xmlXPathStepOpPtr op,
997 			    int isPredicate);
998 static void
999 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
1000 
1001 /************************************************************************
1002  *									*
1003  *			Parser Type functions				*
1004  *									*
1005  ************************************************************************/
1006 
1007 /**
1008  * xmlXPathNewCompExpr:
1009  *
1010  * Create a new Xpath component
1011  *
1012  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1013  */
1014 static xmlXPathCompExprPtr
xmlXPathNewCompExpr(void)1015 xmlXPathNewCompExpr(void) {
1016     xmlXPathCompExprPtr cur;
1017 
1018     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1019     if (cur == NULL) {
1020         xmlXPathErrMemory(NULL, "allocating component\n");
1021 	return(NULL);
1022     }
1023     memset(cur, 0, sizeof(xmlXPathCompExpr));
1024     cur->maxStep = 10;
1025     cur->nbStep = 0;
1026     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1027 	                                   sizeof(xmlXPathStepOp));
1028     if (cur->steps == NULL) {
1029         xmlXPathErrMemory(NULL, "allocating steps\n");
1030 	xmlFree(cur);
1031 	return(NULL);
1032     }
1033     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1034     cur->last = -1;
1035 #ifdef DEBUG_EVAL_COUNTS
1036     cur->nb = 0;
1037 #endif
1038     return(cur);
1039 }
1040 
1041 /**
1042  * xmlXPathFreeCompExpr:
1043  * @comp:  an XPATH comp
1044  *
1045  * Free up the memory allocated by @comp
1046  */
1047 void
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)1048 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1049 {
1050     xmlXPathStepOpPtr op;
1051     int i;
1052 
1053     if (comp == NULL)
1054         return;
1055     if (comp->dict == NULL) {
1056 	for (i = 0; i < comp->nbStep; i++) {
1057 	    op = &comp->steps[i];
1058 	    if (op->value4 != NULL) {
1059 		if (op->op == XPATH_OP_VALUE)
1060 		    xmlXPathFreeObject(op->value4);
1061 		else
1062 		    xmlFree(op->value4);
1063 	    }
1064 	    if (op->value5 != NULL)
1065 		xmlFree(op->value5);
1066 	}
1067     } else {
1068 	for (i = 0; i < comp->nbStep; i++) {
1069 	    op = &comp->steps[i];
1070 	    if (op->value4 != NULL) {
1071 		if (op->op == XPATH_OP_VALUE)
1072 		    xmlXPathFreeObject(op->value4);
1073 	    }
1074 	}
1075         xmlDictFree(comp->dict);
1076     }
1077     if (comp->steps != NULL) {
1078         xmlFree(comp->steps);
1079     }
1080 #ifdef DEBUG_EVAL_COUNTS
1081     if (comp->string != NULL) {
1082         xmlFree(comp->string);
1083     }
1084 #endif
1085 #ifdef XPATH_STREAMING
1086     if (comp->stream != NULL) {
1087         xmlFreePatternList(comp->stream);
1088     }
1089 #endif
1090     if (comp->expr != NULL) {
1091         xmlFree(comp->expr);
1092     }
1093 
1094     xmlFree(comp);
1095 }
1096 
1097 /**
1098  * xmlXPathCompExprAdd:
1099  * @comp:  the compiled expression
1100  * @ch1: first child index
1101  * @ch2: second child index
1102  * @op:  an op
1103  * @value:  the first int value
1104  * @value2:  the second int value
1105  * @value3:  the third int value
1106  * @value4:  the first string value
1107  * @value5:  the second string value
1108  *
1109  * Add a step to an XPath Compiled Expression
1110  *
1111  * Returns -1 in case of failure, the index otherwise
1112  */
1113 static int
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt,int ch1,int ch2,xmlXPathOp op,int value,int value2,int value3,void * value4,void * value5)1114 xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1115    xmlXPathOp op, int value,
1116    int value2, int value3, void *value4, void *value5) {
1117     xmlXPathCompExprPtr comp = ctxt->comp;
1118     if (comp->nbStep >= comp->maxStep) {
1119 	xmlXPathStepOp *real;
1120 
1121         if (comp->maxStep >= XPATH_MAX_STEPS) {
1122 	    xmlXPathPErrMemory(ctxt, "adding step\n");
1123 	    return(-1);
1124         }
1125 	comp->maxStep *= 2;
1126 	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1127 		                      comp->maxStep * sizeof(xmlXPathStepOp));
1128 	if (real == NULL) {
1129 	    comp->maxStep /= 2;
1130 	    xmlXPathPErrMemory(ctxt, "adding step\n");
1131 	    return(-1);
1132 	}
1133 	comp->steps = real;
1134     }
1135     comp->last = comp->nbStep;
1136     comp->steps[comp->nbStep].ch1 = ch1;
1137     comp->steps[comp->nbStep].ch2 = ch2;
1138     comp->steps[comp->nbStep].op = op;
1139     comp->steps[comp->nbStep].value = value;
1140     comp->steps[comp->nbStep].value2 = value2;
1141     comp->steps[comp->nbStep].value3 = value3;
1142     if ((comp->dict != NULL) &&
1143         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1144 	 (op == XPATH_OP_COLLECT))) {
1145         if (value4 != NULL) {
1146 	    comp->steps[comp->nbStep].value4 = (xmlChar *)
1147 	        (void *)xmlDictLookup(comp->dict, value4, -1);
1148 	    xmlFree(value4);
1149 	} else
1150 	    comp->steps[comp->nbStep].value4 = NULL;
1151         if (value5 != NULL) {
1152 	    comp->steps[comp->nbStep].value5 = (xmlChar *)
1153 	        (void *)xmlDictLookup(comp->dict, value5, -1);
1154 	    xmlFree(value5);
1155 	} else
1156 	    comp->steps[comp->nbStep].value5 = NULL;
1157     } else {
1158 	comp->steps[comp->nbStep].value4 = value4;
1159 	comp->steps[comp->nbStep].value5 = value5;
1160     }
1161     comp->steps[comp->nbStep].cache = NULL;
1162     return(comp->nbStep++);
1163 }
1164 
1165 /**
1166  * xmlXPathCompSwap:
1167  * @comp:  the compiled expression
1168  * @op: operation index
1169  *
1170  * Swaps 2 operations in the compiled expression
1171  */
1172 static void
xmlXPathCompSwap(xmlXPathStepOpPtr op)1173 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1174     int tmp;
1175 
1176 #ifndef LIBXML_THREAD_ENABLED
1177     /*
1178      * Since this manipulates possibly shared variables, this is
1179      * disabled if one detects that the library is used in a multithreaded
1180      * application
1181      */
1182     if (xmlXPathDisableOptimizer)
1183 	return;
1184 #endif
1185 
1186     tmp = op->ch1;
1187     op->ch1 = op->ch2;
1188     op->ch2 = tmp;
1189 }
1190 
1191 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
1192     xmlXPathCompExprAdd(ctxt, (op1), (op2),			\
1193 	                (op), (val), (val2), (val3), (val4), (val5))
1194 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
1195     xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,		\
1196 	                (op), (val), (val2), (val3), (val4), (val5))
1197 
1198 #define PUSH_LEAVE_EXPR(op, val, val2)					\
1199 xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1200 
1201 #define PUSH_UNARY_EXPR(op, ch, val, val2)				\
1202 xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1203 
1204 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
1205 xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),			\
1206 			(val), (val2), 0 ,NULL ,NULL)
1207 
1208 /************************************************************************
1209  *									*
1210  *		XPath object cache structures				*
1211  *									*
1212  ************************************************************************/
1213 
1214 /* #define XP_DEFAULT_CACHE_ON */
1215 
1216 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1217 
1218 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1219 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1220 struct _xmlXPathContextCache {
1221     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1222     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1223     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1224     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1225     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1226     int maxNodeset;
1227     int maxString;
1228     int maxBoolean;
1229     int maxNumber;
1230     int maxMisc;
1231 #ifdef XP_DEBUG_OBJ_USAGE
1232     int dbgCachedAll;
1233     int dbgCachedNodeset;
1234     int dbgCachedString;
1235     int dbgCachedBool;
1236     int dbgCachedNumber;
1237     int dbgCachedPoint;
1238     int dbgCachedRange;
1239     int dbgCachedLocset;
1240     int dbgCachedUsers;
1241     int dbgCachedXSLTTree;
1242     int dbgCachedUndefined;
1243 
1244 
1245     int dbgReusedAll;
1246     int dbgReusedNodeset;
1247     int dbgReusedString;
1248     int dbgReusedBool;
1249     int dbgReusedNumber;
1250     int dbgReusedPoint;
1251     int dbgReusedRange;
1252     int dbgReusedLocset;
1253     int dbgReusedUsers;
1254     int dbgReusedXSLTTree;
1255     int dbgReusedUndefined;
1256 
1257 #endif
1258 };
1259 
1260 /************************************************************************
1261  *									*
1262  *		Debugging related functions				*
1263  *									*
1264  ************************************************************************/
1265 
1266 #define STRANGE							\
1267     xmlGenericError(xmlGenericErrorContext,				\
1268 	    "Internal error at %s:%d\n",				\
1269             __FILE__, __LINE__);
1270 
1271 #ifdef LIBXML_DEBUG_ENABLED
1272 static void
xmlXPathDebugDumpNode(FILE * output,xmlNodePtr cur,int depth)1273 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1274     int i;
1275     char shift[100];
1276 
1277     for (i = 0;((i < depth) && (i < 25));i++)
1278         shift[2 * i] = shift[2 * i + 1] = ' ';
1279     shift[2 * i] = shift[2 * i + 1] = 0;
1280     if (cur == NULL) {
1281 	fprintf(output, "%s", shift);
1282 	fprintf(output, "Node is NULL !\n");
1283 	return;
1284 
1285     }
1286 
1287     if ((cur->type == XML_DOCUMENT_NODE) ||
1288 	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
1289 	fprintf(output, "%s", shift);
1290 	fprintf(output, " /\n");
1291     } else if (cur->type == XML_ATTRIBUTE_NODE)
1292 	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1293     else
1294 	xmlDebugDumpOneNode(output, cur, depth);
1295 }
1296 static void
xmlXPathDebugDumpNodeList(FILE * output,xmlNodePtr cur,int depth)1297 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1298     xmlNodePtr tmp;
1299     int i;
1300     char shift[100];
1301 
1302     for (i = 0;((i < depth) && (i < 25));i++)
1303         shift[2 * i] = shift[2 * i + 1] = ' ';
1304     shift[2 * i] = shift[2 * i + 1] = 0;
1305     if (cur == NULL) {
1306 	fprintf(output, "%s", shift);
1307 	fprintf(output, "Node is NULL !\n");
1308 	return;
1309 
1310     }
1311 
1312     while (cur != NULL) {
1313 	tmp = cur;
1314 	cur = cur->next;
1315 	xmlDebugDumpOneNode(output, tmp, depth);
1316     }
1317 }
1318 
1319 static void
xmlXPathDebugDumpNodeSet(FILE * output,xmlNodeSetPtr cur,int depth)1320 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1321     int i;
1322     char shift[100];
1323 
1324     for (i = 0;((i < depth) && (i < 25));i++)
1325         shift[2 * i] = shift[2 * i + 1] = ' ';
1326     shift[2 * i] = shift[2 * i + 1] = 0;
1327 
1328     if (cur == NULL) {
1329 	fprintf(output, "%s", shift);
1330 	fprintf(output, "NodeSet is NULL !\n");
1331 	return;
1332 
1333     }
1334 
1335     if (cur != NULL) {
1336 	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1337 	for (i = 0;i < cur->nodeNr;i++) {
1338 	    fprintf(output, "%s", shift);
1339 	    fprintf(output, "%d", i + 1);
1340 	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1341 	}
1342     }
1343 }
1344 
1345 static void
xmlXPathDebugDumpValueTree(FILE * output,xmlNodeSetPtr cur,int depth)1346 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1347     int i;
1348     char shift[100];
1349 
1350     for (i = 0;((i < depth) && (i < 25));i++)
1351         shift[2 * i] = shift[2 * i + 1] = ' ';
1352     shift[2 * i] = shift[2 * i + 1] = 0;
1353 
1354     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1355 	fprintf(output, "%s", shift);
1356 	fprintf(output, "Value Tree is NULL !\n");
1357 	return;
1358 
1359     }
1360 
1361     fprintf(output, "%s", shift);
1362     fprintf(output, "%d", i + 1);
1363     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1364 }
1365 #if defined(LIBXML_XPTR_ENABLED)
1366 static void
xmlXPathDebugDumpLocationSet(FILE * output,xmlLocationSetPtr cur,int depth)1367 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1368     int i;
1369     char shift[100];
1370 
1371     for (i = 0;((i < depth) && (i < 25));i++)
1372         shift[2 * i] = shift[2 * i + 1] = ' ';
1373     shift[2 * i] = shift[2 * i + 1] = 0;
1374 
1375     if (cur == NULL) {
1376 	fprintf(output, "%s", shift);
1377 	fprintf(output, "LocationSet is NULL !\n");
1378 	return;
1379 
1380     }
1381 
1382     for (i = 0;i < cur->locNr;i++) {
1383 	fprintf(output, "%s", shift);
1384         fprintf(output, "%d : ", i + 1);
1385 	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1386     }
1387 }
1388 #endif /* LIBXML_XPTR_ENABLED */
1389 
1390 /**
1391  * xmlXPathDebugDumpObject:
1392  * @output:  the FILE * to dump the output
1393  * @cur:  the object to inspect
1394  * @depth:  indentation level
1395  *
1396  * Dump the content of the object for debugging purposes
1397  */
1398 void
xmlXPathDebugDumpObject(FILE * output,xmlXPathObjectPtr cur,int depth)1399 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1400     int i;
1401     char shift[100];
1402 
1403     if (output == NULL) return;
1404 
1405     for (i = 0;((i < depth) && (i < 25));i++)
1406         shift[2 * i] = shift[2 * i + 1] = ' ';
1407     shift[2 * i] = shift[2 * i + 1] = 0;
1408 
1409 
1410     fprintf(output, "%s", shift);
1411 
1412     if (cur == NULL) {
1413         fprintf(output, "Object is empty (NULL)\n");
1414 	return;
1415     }
1416     switch(cur->type) {
1417         case XPATH_UNDEFINED:
1418 	    fprintf(output, "Object is uninitialized\n");
1419 	    break;
1420         case XPATH_NODESET:
1421 	    fprintf(output, "Object is a Node Set :\n");
1422 	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1423 	    break;
1424 	case XPATH_XSLT_TREE:
1425 	    fprintf(output, "Object is an XSLT value tree :\n");
1426 	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1427 	    break;
1428         case XPATH_BOOLEAN:
1429 	    fprintf(output, "Object is a Boolean : ");
1430 	    if (cur->boolval) fprintf(output, "true\n");
1431 	    else fprintf(output, "false\n");
1432 	    break;
1433         case XPATH_NUMBER:
1434 	    switch (xmlXPathIsInf(cur->floatval)) {
1435 	    case 1:
1436 		fprintf(output, "Object is a number : Infinity\n");
1437 		break;
1438 	    case -1:
1439 		fprintf(output, "Object is a number : -Infinity\n");
1440 		break;
1441 	    default:
1442 		if (xmlXPathIsNaN(cur->floatval)) {
1443 		    fprintf(output, "Object is a number : NaN\n");
1444 		} else if (cur->floatval == 0) {
1445                     /* Omit sign for negative zero. */
1446 		    fprintf(output, "Object is a number : 0\n");
1447 		} else {
1448 		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
1449 		}
1450 	    }
1451 	    break;
1452         case XPATH_STRING:
1453 	    fprintf(output, "Object is a string : ");
1454 	    xmlDebugDumpString(output, cur->stringval);
1455 	    fprintf(output, "\n");
1456 	    break;
1457 	case XPATH_POINT:
1458 	    fprintf(output, "Object is a point : index %d in node", cur->index);
1459 	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1460 	    fprintf(output, "\n");
1461 	    break;
1462 	case XPATH_RANGE:
1463 	    if ((cur->user2 == NULL) ||
1464 		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1465 		fprintf(output, "Object is a collapsed range :\n");
1466 		fprintf(output, "%s", shift);
1467 		if (cur->index >= 0)
1468 		    fprintf(output, "index %d in ", cur->index);
1469 		fprintf(output, "node\n");
1470 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1471 			              depth + 1);
1472 	    } else  {
1473 		fprintf(output, "Object is a range :\n");
1474 		fprintf(output, "%s", shift);
1475 		fprintf(output, "From ");
1476 		if (cur->index >= 0)
1477 		    fprintf(output, "index %d in ", cur->index);
1478 		fprintf(output, "node\n");
1479 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1480 			              depth + 1);
1481 		fprintf(output, "%s", shift);
1482 		fprintf(output, "To ");
1483 		if (cur->index2 >= 0)
1484 		    fprintf(output, "index %d in ", cur->index2);
1485 		fprintf(output, "node\n");
1486 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1487 			              depth + 1);
1488 		fprintf(output, "\n");
1489 	    }
1490 	    break;
1491 	case XPATH_LOCATIONSET:
1492 #if defined(LIBXML_XPTR_ENABLED)
1493 	    fprintf(output, "Object is a Location Set:\n");
1494 	    xmlXPathDebugDumpLocationSet(output,
1495 		    (xmlLocationSetPtr) cur->user, depth);
1496 #endif
1497 	    break;
1498 	case XPATH_USERS:
1499 	    fprintf(output, "Object is user defined\n");
1500 	    break;
1501     }
1502 }
1503 
1504 static void
xmlXPathDebugDumpStepOp(FILE * output,xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op,int depth)1505 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1506 	                     xmlXPathStepOpPtr op, int depth) {
1507     int i;
1508     char shift[100];
1509 
1510     for (i = 0;((i < depth) && (i < 25));i++)
1511         shift[2 * i] = shift[2 * i + 1] = ' ';
1512     shift[2 * i] = shift[2 * i + 1] = 0;
1513 
1514     fprintf(output, "%s", shift);
1515     if (op == NULL) {
1516 	fprintf(output, "Step is NULL\n");
1517 	return;
1518     }
1519     switch (op->op) {
1520         case XPATH_OP_END:
1521 	    fprintf(output, "END"); break;
1522         case XPATH_OP_AND:
1523 	    fprintf(output, "AND"); break;
1524         case XPATH_OP_OR:
1525 	    fprintf(output, "OR"); break;
1526         case XPATH_OP_EQUAL:
1527 	     if (op->value)
1528 		 fprintf(output, "EQUAL =");
1529 	     else
1530 		 fprintf(output, "EQUAL !=");
1531 	     break;
1532         case XPATH_OP_CMP:
1533 	     if (op->value)
1534 		 fprintf(output, "CMP <");
1535 	     else
1536 		 fprintf(output, "CMP >");
1537 	     if (!op->value2)
1538 		 fprintf(output, "=");
1539 	     break;
1540         case XPATH_OP_PLUS:
1541 	     if (op->value == 0)
1542 		 fprintf(output, "PLUS -");
1543 	     else if (op->value == 1)
1544 		 fprintf(output, "PLUS +");
1545 	     else if (op->value == 2)
1546 		 fprintf(output, "PLUS unary -");
1547 	     else if (op->value == 3)
1548 		 fprintf(output, "PLUS unary - -");
1549 	     break;
1550         case XPATH_OP_MULT:
1551 	     if (op->value == 0)
1552 		 fprintf(output, "MULT *");
1553 	     else if (op->value == 1)
1554 		 fprintf(output, "MULT div");
1555 	     else
1556 		 fprintf(output, "MULT mod");
1557 	     break;
1558         case XPATH_OP_UNION:
1559 	     fprintf(output, "UNION"); break;
1560         case XPATH_OP_ROOT:
1561 	     fprintf(output, "ROOT"); break;
1562         case XPATH_OP_NODE:
1563 	     fprintf(output, "NODE"); break;
1564         case XPATH_OP_SORT:
1565 	     fprintf(output, "SORT"); break;
1566         case XPATH_OP_COLLECT: {
1567 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1568 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1569 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1570 	    const xmlChar *prefix = op->value4;
1571 	    const xmlChar *name = op->value5;
1572 
1573 	    fprintf(output, "COLLECT ");
1574 	    switch (axis) {
1575 		case AXIS_ANCESTOR:
1576 		    fprintf(output, " 'ancestors' "); break;
1577 		case AXIS_ANCESTOR_OR_SELF:
1578 		    fprintf(output, " 'ancestors-or-self' "); break;
1579 		case AXIS_ATTRIBUTE:
1580 		    fprintf(output, " 'attributes' "); break;
1581 		case AXIS_CHILD:
1582 		    fprintf(output, " 'child' "); break;
1583 		case AXIS_DESCENDANT:
1584 		    fprintf(output, " 'descendant' "); break;
1585 		case AXIS_DESCENDANT_OR_SELF:
1586 		    fprintf(output, " 'descendant-or-self' "); break;
1587 		case AXIS_FOLLOWING:
1588 		    fprintf(output, " 'following' "); break;
1589 		case AXIS_FOLLOWING_SIBLING:
1590 		    fprintf(output, " 'following-siblings' "); break;
1591 		case AXIS_NAMESPACE:
1592 		    fprintf(output, " 'namespace' "); break;
1593 		case AXIS_PARENT:
1594 		    fprintf(output, " 'parent' "); break;
1595 		case AXIS_PRECEDING:
1596 		    fprintf(output, " 'preceding' "); break;
1597 		case AXIS_PRECEDING_SIBLING:
1598 		    fprintf(output, " 'preceding-sibling' "); break;
1599 		case AXIS_SELF:
1600 		    fprintf(output, " 'self' "); break;
1601 	    }
1602 	    switch (test) {
1603                 case NODE_TEST_NONE:
1604 		    fprintf(output, "'none' "); break;
1605                 case NODE_TEST_TYPE:
1606 		    fprintf(output, "'type' "); break;
1607                 case NODE_TEST_PI:
1608 		    fprintf(output, "'PI' "); break;
1609                 case NODE_TEST_ALL:
1610 		    fprintf(output, "'all' "); break;
1611                 case NODE_TEST_NS:
1612 		    fprintf(output, "'namespace' "); break;
1613                 case NODE_TEST_NAME:
1614 		    fprintf(output, "'name' "); break;
1615 	    }
1616 	    switch (type) {
1617                 case NODE_TYPE_NODE:
1618 		    fprintf(output, "'node' "); break;
1619                 case NODE_TYPE_COMMENT:
1620 		    fprintf(output, "'comment' "); break;
1621                 case NODE_TYPE_TEXT:
1622 		    fprintf(output, "'text' "); break;
1623                 case NODE_TYPE_PI:
1624 		    fprintf(output, "'PI' "); break;
1625 	    }
1626 	    if (prefix != NULL)
1627 		fprintf(output, "%s:", prefix);
1628 	    if (name != NULL)
1629 		fprintf(output, "%s", (const char *) name);
1630 	    break;
1631 
1632         }
1633 	case XPATH_OP_VALUE: {
1634 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1635 
1636 	    fprintf(output, "ELEM ");
1637 	    xmlXPathDebugDumpObject(output, object, 0);
1638 	    goto finish;
1639 	}
1640 	case XPATH_OP_VARIABLE: {
1641 	    const xmlChar *prefix = op->value5;
1642 	    const xmlChar *name = op->value4;
1643 
1644 	    if (prefix != NULL)
1645 		fprintf(output, "VARIABLE %s:%s", prefix, name);
1646 	    else
1647 		fprintf(output, "VARIABLE %s", name);
1648 	    break;
1649 	}
1650 	case XPATH_OP_FUNCTION: {
1651 	    int nbargs = op->value;
1652 	    const xmlChar *prefix = op->value5;
1653 	    const xmlChar *name = op->value4;
1654 
1655 	    if (prefix != NULL)
1656 		fprintf(output, "FUNCTION %s:%s(%d args)",
1657 			prefix, name, nbargs);
1658 	    else
1659 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1660 	    break;
1661 	}
1662         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1663         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1664         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1665 #ifdef LIBXML_XPTR_ENABLED
1666         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1667 #endif
1668 	default:
1669         fprintf(output, "UNKNOWN %d\n", op->op); return;
1670     }
1671     fprintf(output, "\n");
1672 finish:
1673     if (op->ch1 >= 0)
1674 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1675     if (op->ch2 >= 0)
1676 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1677 }
1678 
1679 /**
1680  * xmlXPathDebugDumpCompExpr:
1681  * @output:  the FILE * for the output
1682  * @comp:  the precompiled XPath expression
1683  * @depth:  the indentation level.
1684  *
1685  * Dumps the tree of the compiled XPath expression.
1686  */
1687 void
xmlXPathDebugDumpCompExpr(FILE * output,xmlXPathCompExprPtr comp,int depth)1688 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1689 	                  int depth) {
1690     int i;
1691     char shift[100];
1692 
1693     if ((output == NULL) || (comp == NULL)) return;
1694 
1695     for (i = 0;((i < depth) && (i < 25));i++)
1696         shift[2 * i] = shift[2 * i + 1] = ' ';
1697     shift[2 * i] = shift[2 * i + 1] = 0;
1698 
1699     fprintf(output, "%s", shift);
1700 
1701 #ifdef XPATH_STREAMING
1702     if (comp->stream) {
1703         fprintf(output, "Streaming Expression\n");
1704     } else
1705 #endif
1706     {
1707         fprintf(output, "Compiled Expression : %d elements\n",
1708                 comp->nbStep);
1709         i = comp->last;
1710         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1711     }
1712 }
1713 
1714 #ifdef XP_DEBUG_OBJ_USAGE
1715 
1716 /*
1717 * XPath object usage related debugging variables.
1718 */
1719 static int xmlXPathDebugObjCounterUndefined = 0;
1720 static int xmlXPathDebugObjCounterNodeset = 0;
1721 static int xmlXPathDebugObjCounterBool = 0;
1722 static int xmlXPathDebugObjCounterNumber = 0;
1723 static int xmlXPathDebugObjCounterString = 0;
1724 static int xmlXPathDebugObjCounterPoint = 0;
1725 static int xmlXPathDebugObjCounterRange = 0;
1726 static int xmlXPathDebugObjCounterLocset = 0;
1727 static int xmlXPathDebugObjCounterUsers = 0;
1728 static int xmlXPathDebugObjCounterXSLTTree = 0;
1729 static int xmlXPathDebugObjCounterAll = 0;
1730 
1731 static int xmlXPathDebugObjTotalUndefined = 0;
1732 static int xmlXPathDebugObjTotalNodeset = 0;
1733 static int xmlXPathDebugObjTotalBool = 0;
1734 static int xmlXPathDebugObjTotalNumber = 0;
1735 static int xmlXPathDebugObjTotalString = 0;
1736 static int xmlXPathDebugObjTotalPoint = 0;
1737 static int xmlXPathDebugObjTotalRange = 0;
1738 static int xmlXPathDebugObjTotalLocset = 0;
1739 static int xmlXPathDebugObjTotalUsers = 0;
1740 static int xmlXPathDebugObjTotalXSLTTree = 0;
1741 static int xmlXPathDebugObjTotalAll = 0;
1742 
1743 static int xmlXPathDebugObjMaxUndefined = 0;
1744 static int xmlXPathDebugObjMaxNodeset = 0;
1745 static int xmlXPathDebugObjMaxBool = 0;
1746 static int xmlXPathDebugObjMaxNumber = 0;
1747 static int xmlXPathDebugObjMaxString = 0;
1748 static int xmlXPathDebugObjMaxPoint = 0;
1749 static int xmlXPathDebugObjMaxRange = 0;
1750 static int xmlXPathDebugObjMaxLocset = 0;
1751 static int xmlXPathDebugObjMaxUsers = 0;
1752 static int xmlXPathDebugObjMaxXSLTTree = 0;
1753 static int xmlXPathDebugObjMaxAll = 0;
1754 
1755 static void
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)1756 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1757 {
1758     if (ctxt != NULL) {
1759 	if (ctxt->cache != NULL) {
1760 	    xmlXPathContextCachePtr cache =
1761 		(xmlXPathContextCachePtr) ctxt->cache;
1762 
1763 	    cache->dbgCachedAll = 0;
1764 	    cache->dbgCachedNodeset = 0;
1765 	    cache->dbgCachedString = 0;
1766 	    cache->dbgCachedBool = 0;
1767 	    cache->dbgCachedNumber = 0;
1768 	    cache->dbgCachedPoint = 0;
1769 	    cache->dbgCachedRange = 0;
1770 	    cache->dbgCachedLocset = 0;
1771 	    cache->dbgCachedUsers = 0;
1772 	    cache->dbgCachedXSLTTree = 0;
1773 	    cache->dbgCachedUndefined = 0;
1774 
1775 	    cache->dbgReusedAll = 0;
1776 	    cache->dbgReusedNodeset = 0;
1777 	    cache->dbgReusedString = 0;
1778 	    cache->dbgReusedBool = 0;
1779 	    cache->dbgReusedNumber = 0;
1780 	    cache->dbgReusedPoint = 0;
1781 	    cache->dbgReusedRange = 0;
1782 	    cache->dbgReusedLocset = 0;
1783 	    cache->dbgReusedUsers = 0;
1784 	    cache->dbgReusedXSLTTree = 0;
1785 	    cache->dbgReusedUndefined = 0;
1786 	}
1787     }
1788 
1789     xmlXPathDebugObjCounterUndefined = 0;
1790     xmlXPathDebugObjCounterNodeset = 0;
1791     xmlXPathDebugObjCounterBool = 0;
1792     xmlXPathDebugObjCounterNumber = 0;
1793     xmlXPathDebugObjCounterString = 0;
1794     xmlXPathDebugObjCounterPoint = 0;
1795     xmlXPathDebugObjCounterRange = 0;
1796     xmlXPathDebugObjCounterLocset = 0;
1797     xmlXPathDebugObjCounterUsers = 0;
1798     xmlXPathDebugObjCounterXSLTTree = 0;
1799     xmlXPathDebugObjCounterAll = 0;
1800 
1801     xmlXPathDebugObjTotalUndefined = 0;
1802     xmlXPathDebugObjTotalNodeset = 0;
1803     xmlXPathDebugObjTotalBool = 0;
1804     xmlXPathDebugObjTotalNumber = 0;
1805     xmlXPathDebugObjTotalString = 0;
1806     xmlXPathDebugObjTotalPoint = 0;
1807     xmlXPathDebugObjTotalRange = 0;
1808     xmlXPathDebugObjTotalLocset = 0;
1809     xmlXPathDebugObjTotalUsers = 0;
1810     xmlXPathDebugObjTotalXSLTTree = 0;
1811     xmlXPathDebugObjTotalAll = 0;
1812 
1813     xmlXPathDebugObjMaxUndefined = 0;
1814     xmlXPathDebugObjMaxNodeset = 0;
1815     xmlXPathDebugObjMaxBool = 0;
1816     xmlXPathDebugObjMaxNumber = 0;
1817     xmlXPathDebugObjMaxString = 0;
1818     xmlXPathDebugObjMaxPoint = 0;
1819     xmlXPathDebugObjMaxRange = 0;
1820     xmlXPathDebugObjMaxLocset = 0;
1821     xmlXPathDebugObjMaxUsers = 0;
1822     xmlXPathDebugObjMaxXSLTTree = 0;
1823     xmlXPathDebugObjMaxAll = 0;
1824 
1825 }
1826 
1827 static void
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,xmlXPathObjectType objType)1828 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1829 			      xmlXPathObjectType objType)
1830 {
1831     int isCached = 0;
1832 
1833     if (ctxt != NULL) {
1834 	if (ctxt->cache != NULL) {
1835 	    xmlXPathContextCachePtr cache =
1836 		(xmlXPathContextCachePtr) ctxt->cache;
1837 
1838 	    isCached = 1;
1839 
1840 	    cache->dbgReusedAll++;
1841 	    switch (objType) {
1842 		case XPATH_UNDEFINED:
1843 		    cache->dbgReusedUndefined++;
1844 		    break;
1845 		case XPATH_NODESET:
1846 		    cache->dbgReusedNodeset++;
1847 		    break;
1848 		case XPATH_BOOLEAN:
1849 		    cache->dbgReusedBool++;
1850 		    break;
1851 		case XPATH_NUMBER:
1852 		    cache->dbgReusedNumber++;
1853 		    break;
1854 		case XPATH_STRING:
1855 		    cache->dbgReusedString++;
1856 		    break;
1857 		case XPATH_POINT:
1858 		    cache->dbgReusedPoint++;
1859 		    break;
1860 		case XPATH_RANGE:
1861 		    cache->dbgReusedRange++;
1862 		    break;
1863 		case XPATH_LOCATIONSET:
1864 		    cache->dbgReusedLocset++;
1865 		    break;
1866 		case XPATH_USERS:
1867 		    cache->dbgReusedUsers++;
1868 		    break;
1869 		case XPATH_XSLT_TREE:
1870 		    cache->dbgReusedXSLTTree++;
1871 		    break;
1872 		default:
1873 		    break;
1874 	    }
1875 	}
1876     }
1877 
1878     switch (objType) {
1879 	case XPATH_UNDEFINED:
1880 	    if (! isCached)
1881 		xmlXPathDebugObjTotalUndefined++;
1882 	    xmlXPathDebugObjCounterUndefined++;
1883 	    if (xmlXPathDebugObjCounterUndefined >
1884 		xmlXPathDebugObjMaxUndefined)
1885 		xmlXPathDebugObjMaxUndefined =
1886 		    xmlXPathDebugObjCounterUndefined;
1887 	    break;
1888 	case XPATH_NODESET:
1889 	    if (! isCached)
1890 		xmlXPathDebugObjTotalNodeset++;
1891 	    xmlXPathDebugObjCounterNodeset++;
1892 	    if (xmlXPathDebugObjCounterNodeset >
1893 		xmlXPathDebugObjMaxNodeset)
1894 		xmlXPathDebugObjMaxNodeset =
1895 		    xmlXPathDebugObjCounterNodeset;
1896 	    break;
1897 	case XPATH_BOOLEAN:
1898 	    if (! isCached)
1899 		xmlXPathDebugObjTotalBool++;
1900 	    xmlXPathDebugObjCounterBool++;
1901 	    if (xmlXPathDebugObjCounterBool >
1902 		xmlXPathDebugObjMaxBool)
1903 		xmlXPathDebugObjMaxBool =
1904 		    xmlXPathDebugObjCounterBool;
1905 	    break;
1906 	case XPATH_NUMBER:
1907 	    if (! isCached)
1908 		xmlXPathDebugObjTotalNumber++;
1909 	    xmlXPathDebugObjCounterNumber++;
1910 	    if (xmlXPathDebugObjCounterNumber >
1911 		xmlXPathDebugObjMaxNumber)
1912 		xmlXPathDebugObjMaxNumber =
1913 		    xmlXPathDebugObjCounterNumber;
1914 	    break;
1915 	case XPATH_STRING:
1916 	    if (! isCached)
1917 		xmlXPathDebugObjTotalString++;
1918 	    xmlXPathDebugObjCounterString++;
1919 	    if (xmlXPathDebugObjCounterString >
1920 		xmlXPathDebugObjMaxString)
1921 		xmlXPathDebugObjMaxString =
1922 		    xmlXPathDebugObjCounterString;
1923 	    break;
1924 	case XPATH_POINT:
1925 	    if (! isCached)
1926 		xmlXPathDebugObjTotalPoint++;
1927 	    xmlXPathDebugObjCounterPoint++;
1928 	    if (xmlXPathDebugObjCounterPoint >
1929 		xmlXPathDebugObjMaxPoint)
1930 		xmlXPathDebugObjMaxPoint =
1931 		    xmlXPathDebugObjCounterPoint;
1932 	    break;
1933 	case XPATH_RANGE:
1934 	    if (! isCached)
1935 		xmlXPathDebugObjTotalRange++;
1936 	    xmlXPathDebugObjCounterRange++;
1937 	    if (xmlXPathDebugObjCounterRange >
1938 		xmlXPathDebugObjMaxRange)
1939 		xmlXPathDebugObjMaxRange =
1940 		    xmlXPathDebugObjCounterRange;
1941 	    break;
1942 	case XPATH_LOCATIONSET:
1943 	    if (! isCached)
1944 		xmlXPathDebugObjTotalLocset++;
1945 	    xmlXPathDebugObjCounterLocset++;
1946 	    if (xmlXPathDebugObjCounterLocset >
1947 		xmlXPathDebugObjMaxLocset)
1948 		xmlXPathDebugObjMaxLocset =
1949 		    xmlXPathDebugObjCounterLocset;
1950 	    break;
1951 	case XPATH_USERS:
1952 	    if (! isCached)
1953 		xmlXPathDebugObjTotalUsers++;
1954 	    xmlXPathDebugObjCounterUsers++;
1955 	    if (xmlXPathDebugObjCounterUsers >
1956 		xmlXPathDebugObjMaxUsers)
1957 		xmlXPathDebugObjMaxUsers =
1958 		    xmlXPathDebugObjCounterUsers;
1959 	    break;
1960 	case XPATH_XSLT_TREE:
1961 	    if (! isCached)
1962 		xmlXPathDebugObjTotalXSLTTree++;
1963 	    xmlXPathDebugObjCounterXSLTTree++;
1964 	    if (xmlXPathDebugObjCounterXSLTTree >
1965 		xmlXPathDebugObjMaxXSLTTree)
1966 		xmlXPathDebugObjMaxXSLTTree =
1967 		    xmlXPathDebugObjCounterXSLTTree;
1968 	    break;
1969 	default:
1970 	    break;
1971     }
1972     if (! isCached)
1973 	xmlXPathDebugObjTotalAll++;
1974     xmlXPathDebugObjCounterAll++;
1975     if (xmlXPathDebugObjCounterAll >
1976 	xmlXPathDebugObjMaxAll)
1977 	xmlXPathDebugObjMaxAll =
1978 	    xmlXPathDebugObjCounterAll;
1979 }
1980 
1981 static void
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,xmlXPathObjectType objType)1982 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1983 			      xmlXPathObjectType objType)
1984 {
1985     int isCached = 0;
1986 
1987     if (ctxt != NULL) {
1988 	if (ctxt->cache != NULL) {
1989 	    xmlXPathContextCachePtr cache =
1990 		(xmlXPathContextCachePtr) ctxt->cache;
1991 
1992 	    isCached = 1;
1993 
1994 	    cache->dbgCachedAll++;
1995 	    switch (objType) {
1996 		case XPATH_UNDEFINED:
1997 		    cache->dbgCachedUndefined++;
1998 		    break;
1999 		case XPATH_NODESET:
2000 		    cache->dbgCachedNodeset++;
2001 		    break;
2002 		case XPATH_BOOLEAN:
2003 		    cache->dbgCachedBool++;
2004 		    break;
2005 		case XPATH_NUMBER:
2006 		    cache->dbgCachedNumber++;
2007 		    break;
2008 		case XPATH_STRING:
2009 		    cache->dbgCachedString++;
2010 		    break;
2011 		case XPATH_POINT:
2012 		    cache->dbgCachedPoint++;
2013 		    break;
2014 		case XPATH_RANGE:
2015 		    cache->dbgCachedRange++;
2016 		    break;
2017 		case XPATH_LOCATIONSET:
2018 		    cache->dbgCachedLocset++;
2019 		    break;
2020 		case XPATH_USERS:
2021 		    cache->dbgCachedUsers++;
2022 		    break;
2023 		case XPATH_XSLT_TREE:
2024 		    cache->dbgCachedXSLTTree++;
2025 		    break;
2026 		default:
2027 		    break;
2028 	    }
2029 
2030 	}
2031     }
2032     switch (objType) {
2033 	case XPATH_UNDEFINED:
2034 	    xmlXPathDebugObjCounterUndefined--;
2035 	    break;
2036 	case XPATH_NODESET:
2037 	    xmlXPathDebugObjCounterNodeset--;
2038 	    break;
2039 	case XPATH_BOOLEAN:
2040 	    xmlXPathDebugObjCounterBool--;
2041 	    break;
2042 	case XPATH_NUMBER:
2043 	    xmlXPathDebugObjCounterNumber--;
2044 	    break;
2045 	case XPATH_STRING:
2046 	    xmlXPathDebugObjCounterString--;
2047 	    break;
2048 	case XPATH_POINT:
2049 	    xmlXPathDebugObjCounterPoint--;
2050 	    break;
2051 	case XPATH_RANGE:
2052 	    xmlXPathDebugObjCounterRange--;
2053 	    break;
2054 	case XPATH_LOCATIONSET:
2055 	    xmlXPathDebugObjCounterLocset--;
2056 	    break;
2057 	case XPATH_USERS:
2058 	    xmlXPathDebugObjCounterUsers--;
2059 	    break;
2060 	case XPATH_XSLT_TREE:
2061 	    xmlXPathDebugObjCounterXSLTTree--;
2062 	    break;
2063 	default:
2064 	    break;
2065     }
2066     xmlXPathDebugObjCounterAll--;
2067 }
2068 
2069 static void
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)2070 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2071 {
2072     int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2073 	reqXSLTTree, reqUndefined;
2074     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2075 	caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2076     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2077 	reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2078     int leftObjs = xmlXPathDebugObjCounterAll;
2079 
2080     reqAll = xmlXPathDebugObjTotalAll;
2081     reqNodeset = xmlXPathDebugObjTotalNodeset;
2082     reqString = xmlXPathDebugObjTotalString;
2083     reqBool = xmlXPathDebugObjTotalBool;
2084     reqNumber = xmlXPathDebugObjTotalNumber;
2085     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2086     reqUndefined = xmlXPathDebugObjTotalUndefined;
2087 
2088     printf("# XPath object usage:\n");
2089 
2090     if (ctxt != NULL) {
2091 	if (ctxt->cache != NULL) {
2092 	    xmlXPathContextCachePtr cache =
2093 		(xmlXPathContextCachePtr) ctxt->cache;
2094 
2095 	    reAll = cache->dbgReusedAll;
2096 	    reqAll += reAll;
2097 	    reNodeset = cache->dbgReusedNodeset;
2098 	    reqNodeset += reNodeset;
2099 	    reString = cache->dbgReusedString;
2100 	    reqString += reString;
2101 	    reBool = cache->dbgReusedBool;
2102 	    reqBool += reBool;
2103 	    reNumber = cache->dbgReusedNumber;
2104 	    reqNumber += reNumber;
2105 	    reXSLTTree = cache->dbgReusedXSLTTree;
2106 	    reqXSLTTree += reXSLTTree;
2107 	    reUndefined = cache->dbgReusedUndefined;
2108 	    reqUndefined += reUndefined;
2109 
2110 	    caAll = cache->dbgCachedAll;
2111 	    caBool = cache->dbgCachedBool;
2112 	    caNodeset = cache->dbgCachedNodeset;
2113 	    caString = cache->dbgCachedString;
2114 	    caNumber = cache->dbgCachedNumber;
2115 	    caXSLTTree = cache->dbgCachedXSLTTree;
2116 	    caUndefined = cache->dbgCachedUndefined;
2117 
2118 	    if (cache->nodesetObjs)
2119 		leftObjs -= cache->nodesetObjs->number;
2120 	    if (cache->stringObjs)
2121 		leftObjs -= cache->stringObjs->number;
2122 	    if (cache->booleanObjs)
2123 		leftObjs -= cache->booleanObjs->number;
2124 	    if (cache->numberObjs)
2125 		leftObjs -= cache->numberObjs->number;
2126 	    if (cache->miscObjs)
2127 		leftObjs -= cache->miscObjs->number;
2128 	}
2129     }
2130 
2131     printf("# all\n");
2132     printf("#   total  : %d\n", reqAll);
2133     printf("#   left  : %d\n", leftObjs);
2134     printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2135     printf("#   reused : %d\n", reAll);
2136     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2137 
2138     printf("# node-sets\n");
2139     printf("#   total  : %d\n", reqNodeset);
2140     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2141     printf("#   reused : %d\n", reNodeset);
2142     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2143 
2144     printf("# strings\n");
2145     printf("#   total  : %d\n", reqString);
2146     printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2147     printf("#   reused : %d\n", reString);
2148     printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2149 
2150     printf("# booleans\n");
2151     printf("#   total  : %d\n", reqBool);
2152     printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2153     printf("#   reused : %d\n", reBool);
2154     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2155 
2156     printf("# numbers\n");
2157     printf("#   total  : %d\n", reqNumber);
2158     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2159     printf("#   reused : %d\n", reNumber);
2160     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2161 
2162     printf("# XSLT result tree fragments\n");
2163     printf("#   total  : %d\n", reqXSLTTree);
2164     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2165     printf("#   reused : %d\n", reXSLTTree);
2166     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2167 
2168     printf("# undefined\n");
2169     printf("#   total  : %d\n", reqUndefined);
2170     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2171     printf("#   reused : %d\n", reUndefined);
2172     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2173 
2174 }
2175 
2176 #endif /* XP_DEBUG_OBJ_USAGE */
2177 
2178 #endif /* LIBXML_DEBUG_ENABLED */
2179 
2180 /************************************************************************
2181  *									*
2182  *			XPath object caching				*
2183  *									*
2184  ************************************************************************/
2185 
2186 /**
2187  * xmlXPathNewCache:
2188  *
2189  * Create a new object cache
2190  *
2191  * Returns the xmlXPathCache just allocated.
2192  */
2193 static xmlXPathContextCachePtr
xmlXPathNewCache(void)2194 xmlXPathNewCache(void)
2195 {
2196     xmlXPathContextCachePtr ret;
2197 
2198     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2199     if (ret == NULL) {
2200         xmlXPathErrMemory(NULL, "creating object cache\n");
2201 	return(NULL);
2202     }
2203     memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2204     ret->maxNodeset = 100;
2205     ret->maxString = 100;
2206     ret->maxBoolean = 100;
2207     ret->maxNumber = 100;
2208     ret->maxMisc = 100;
2209     return(ret);
2210 }
2211 
2212 static void
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)2213 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2214 {
2215     int i;
2216     xmlXPathObjectPtr obj;
2217 
2218     if (list == NULL)
2219 	return;
2220 
2221     for (i = 0; i < list->number; i++) {
2222 	obj = list->items[i];
2223 	/*
2224 	* Note that it is already assured that we don't need to
2225 	* look out for namespace nodes in the node-set.
2226 	*/
2227 	if (obj->nodesetval != NULL) {
2228 	    if (obj->nodesetval->nodeTab != NULL)
2229 		xmlFree(obj->nodesetval->nodeTab);
2230 	    xmlFree(obj->nodesetval);
2231 	}
2232 	xmlFree(obj);
2233 #ifdef XP_DEBUG_OBJ_USAGE
2234 	xmlXPathDebugObjCounterAll--;
2235 #endif
2236     }
2237     xmlPointerListFree(list);
2238 }
2239 
2240 static void
xmlXPathFreeCache(xmlXPathContextCachePtr cache)2241 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2242 {
2243     if (cache == NULL)
2244 	return;
2245     if (cache->nodesetObjs)
2246 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2247     if (cache->stringObjs)
2248 	xmlXPathCacheFreeObjectList(cache->stringObjs);
2249     if (cache->booleanObjs)
2250 	xmlXPathCacheFreeObjectList(cache->booleanObjs);
2251     if (cache->numberObjs)
2252 	xmlXPathCacheFreeObjectList(cache->numberObjs);
2253     if (cache->miscObjs)
2254 	xmlXPathCacheFreeObjectList(cache->miscObjs);
2255     xmlFree(cache);
2256 }
2257 
2258 /**
2259  * xmlXPathContextSetCache:
2260  *
2261  * @ctxt:  the XPath context
2262  * @active: enables/disables (creates/frees) the cache
2263  * @value: a value with semantics dependent on @options
2264  * @options: options (currently only the value 0 is used)
2265  *
2266  * Creates/frees an object cache on the XPath context.
2267  * If activates XPath objects (xmlXPathObject) will be cached internally
2268  * to be reused.
2269  * @options:
2270  *   0: This will set the XPath object caching:
2271  *      @value:
2272  *        This will set the maximum number of XPath objects
2273  *        to be cached per slot
2274  *        There are 5 slots for: node-set, string, number, boolean, and
2275  *        misc objects. Use <0 for the default number (100).
2276  *   Other values for @options have currently no effect.
2277  *
2278  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2279  */
2280 int
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,int active,int value,int options)2281 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2282 			int active,
2283 			int value,
2284 			int options)
2285 {
2286     if (ctxt == NULL)
2287 	return(-1);
2288     if (active) {
2289 	xmlXPathContextCachePtr cache;
2290 
2291 	if (ctxt->cache == NULL) {
2292 	    ctxt->cache = xmlXPathNewCache();
2293 	    if (ctxt->cache == NULL)
2294 		return(-1);
2295 	}
2296 	cache = (xmlXPathContextCachePtr) ctxt->cache;
2297 	if (options == 0) {
2298 	    if (value < 0)
2299 		value = 100;
2300 	    cache->maxNodeset = value;
2301 	    cache->maxString = value;
2302 	    cache->maxNumber = value;
2303 	    cache->maxBoolean = value;
2304 	    cache->maxMisc = value;
2305 	}
2306     } else if (ctxt->cache != NULL) {
2307 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2308 	ctxt->cache = NULL;
2309     }
2310     return(0);
2311 }
2312 
2313 /**
2314  * xmlXPathCacheWrapNodeSet:
2315  * @ctxt: the XPath context
2316  * @val:  the NodePtr value
2317  *
2318  * This is the cached version of xmlXPathWrapNodeSet().
2319  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2320  *
2321  * Returns the created or reused object.
2322  */
2323 static xmlXPathObjectPtr
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt,xmlNodeSetPtr val)2324 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2325 {
2326     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2327 	xmlXPathContextCachePtr cache =
2328 	    (xmlXPathContextCachePtr) ctxt->cache;
2329 
2330 	if ((cache->miscObjs != NULL) &&
2331 	    (cache->miscObjs->number != 0))
2332 	{
2333 	    xmlXPathObjectPtr ret;
2334 
2335 	    ret = (xmlXPathObjectPtr)
2336 		cache->miscObjs->items[--cache->miscObjs->number];
2337 	    ret->type = XPATH_NODESET;
2338 	    ret->nodesetval = val;
2339 #ifdef XP_DEBUG_OBJ_USAGE
2340 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2341 #endif
2342 	    return(ret);
2343 	}
2344     }
2345 
2346     return(xmlXPathWrapNodeSet(val));
2347 
2348 }
2349 
2350 /**
2351  * xmlXPathCacheWrapString:
2352  * @ctxt: the XPath context
2353  * @val:  the xmlChar * value
2354  *
2355  * This is the cached version of xmlXPathWrapString().
2356  * Wraps the @val string into an XPath object.
2357  *
2358  * Returns the created or reused object.
2359  */
2360 static xmlXPathObjectPtr
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt,xmlChar * val)2361 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2362 {
2363     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2364 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2365 
2366 	if ((cache->stringObjs != NULL) &&
2367 	    (cache->stringObjs->number != 0))
2368 	{
2369 
2370 	    xmlXPathObjectPtr ret;
2371 
2372 	    ret = (xmlXPathObjectPtr)
2373 		cache->stringObjs->items[--cache->stringObjs->number];
2374 	    ret->type = XPATH_STRING;
2375 	    ret->stringval = val;
2376 #ifdef XP_DEBUG_OBJ_USAGE
2377 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2378 #endif
2379 	    return(ret);
2380 	} else if ((cache->miscObjs != NULL) &&
2381 	    (cache->miscObjs->number != 0))
2382 	{
2383 	    xmlXPathObjectPtr ret;
2384 	    /*
2385 	    * Fallback to misc-cache.
2386 	    */
2387 	    ret = (xmlXPathObjectPtr)
2388 		cache->miscObjs->items[--cache->miscObjs->number];
2389 
2390 	    ret->type = XPATH_STRING;
2391 	    ret->stringval = val;
2392 #ifdef XP_DEBUG_OBJ_USAGE
2393 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2394 #endif
2395 	    return(ret);
2396 	}
2397     }
2398     return(xmlXPathWrapString(val));
2399 }
2400 
2401 /**
2402  * xmlXPathCacheNewNodeSet:
2403  * @ctxt: the XPath context
2404  * @val:  the NodePtr value
2405  *
2406  * This is the cached version of xmlXPathNewNodeSet().
2407  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2408  * it with the single Node @val
2409  *
2410  * Returns the created or reused object.
2411  */
2412 static xmlXPathObjectPtr
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt,xmlNodePtr val)2413 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2414 {
2415     if ((ctxt != NULL) && (ctxt->cache)) {
2416 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2417 
2418 	if ((cache->nodesetObjs != NULL) &&
2419 	    (cache->nodesetObjs->number != 0))
2420 	{
2421 	    xmlXPathObjectPtr ret;
2422 	    /*
2423 	    * Use the nodeset-cache.
2424 	    */
2425 	    ret = (xmlXPathObjectPtr)
2426 		cache->nodesetObjs->items[--cache->nodesetObjs->number];
2427 	    ret->type = XPATH_NODESET;
2428 	    ret->boolval = 0;
2429 	    if (val) {
2430 		if ((ret->nodesetval->nodeMax == 0) ||
2431 		    (val->type == XML_NAMESPACE_DECL))
2432 		{
2433                     /* TODO: Check memory error. */
2434 		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2435 		} else {
2436 		    ret->nodesetval->nodeTab[0] = val;
2437 		    ret->nodesetval->nodeNr = 1;
2438 		}
2439 	    }
2440 #ifdef XP_DEBUG_OBJ_USAGE
2441 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2442 #endif
2443 	    return(ret);
2444 	} else if ((cache->miscObjs != NULL) &&
2445 	    (cache->miscObjs->number != 0))
2446 	{
2447 	    xmlXPathObjectPtr ret;
2448 	    /*
2449 	    * Fallback to misc-cache.
2450 	    */
2451 
2452 	    ret = (xmlXPathObjectPtr)
2453 		cache->miscObjs->items[--cache->miscObjs->number];
2454 
2455 	    ret->type = XPATH_NODESET;
2456 	    ret->boolval = 0;
2457 	    ret->nodesetval = xmlXPathNodeSetCreate(val);
2458 	    if (ret->nodesetval == NULL) {
2459 		ctxt->lastError.domain = XML_FROM_XPATH;
2460 		ctxt->lastError.code = XML_ERR_NO_MEMORY;
2461 		return(NULL);
2462 	    }
2463 #ifdef XP_DEBUG_OBJ_USAGE
2464 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2465 #endif
2466 	    return(ret);
2467 	}
2468     }
2469     return(xmlXPathNewNodeSet(val));
2470 }
2471 
2472 /**
2473  * xmlXPathCacheNewCString:
2474  * @ctxt: the XPath context
2475  * @val:  the char * value
2476  *
2477  * This is the cached version of xmlXPathNewCString().
2478  * Acquire an xmlXPathObjectPtr of type string and of value @val
2479  *
2480  * Returns the created or reused object.
2481  */
2482 static xmlXPathObjectPtr
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt,const char * val)2483 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2484 {
2485     if ((ctxt != NULL) && (ctxt->cache)) {
2486 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2487 
2488 	if ((cache->stringObjs != NULL) &&
2489 	    (cache->stringObjs->number != 0))
2490 	{
2491 	    xmlXPathObjectPtr ret;
2492 
2493 	    ret = (xmlXPathObjectPtr)
2494 		cache->stringObjs->items[--cache->stringObjs->number];
2495 
2496 	    ret->type = XPATH_STRING;
2497 	    ret->stringval = xmlStrdup(BAD_CAST val);
2498 #ifdef XP_DEBUG_OBJ_USAGE
2499 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2500 #endif
2501 	    return(ret);
2502 	} else if ((cache->miscObjs != NULL) &&
2503 	    (cache->miscObjs->number != 0))
2504 	{
2505 	    xmlXPathObjectPtr ret;
2506 
2507 	    ret = (xmlXPathObjectPtr)
2508 		cache->miscObjs->items[--cache->miscObjs->number];
2509 
2510 	    ret->type = XPATH_STRING;
2511 	    ret->stringval = xmlStrdup(BAD_CAST val);
2512 #ifdef XP_DEBUG_OBJ_USAGE
2513 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2514 #endif
2515 	    return(ret);
2516 	}
2517     }
2518     return(xmlXPathNewCString(val));
2519 }
2520 
2521 /**
2522  * xmlXPathCacheNewString:
2523  * @ctxt: the XPath context
2524  * @val:  the xmlChar * value
2525  *
2526  * This is the cached version of xmlXPathNewString().
2527  * Acquire an xmlXPathObjectPtr of type string and of value @val
2528  *
2529  * Returns the created or reused object.
2530  */
2531 static xmlXPathObjectPtr
xmlXPathCacheNewString(xmlXPathContextPtr ctxt,const xmlChar * val)2532 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2533 {
2534     if ((ctxt != NULL) && (ctxt->cache)) {
2535 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2536 
2537 	if ((cache->stringObjs != NULL) &&
2538 	    (cache->stringObjs->number != 0))
2539 	{
2540 	    xmlXPathObjectPtr ret;
2541 
2542 	    ret = (xmlXPathObjectPtr)
2543 		cache->stringObjs->items[--cache->stringObjs->number];
2544 	    ret->type = XPATH_STRING;
2545 	    if (val != NULL)
2546 		ret->stringval = xmlStrdup(val);
2547 	    else
2548 		ret->stringval = xmlStrdup((const xmlChar *)"");
2549 #ifdef XP_DEBUG_OBJ_USAGE
2550 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2551 #endif
2552 	    return(ret);
2553 	} else if ((cache->miscObjs != NULL) &&
2554 	    (cache->miscObjs->number != 0))
2555 	{
2556 	    xmlXPathObjectPtr ret;
2557 
2558 	    ret = (xmlXPathObjectPtr)
2559 		cache->miscObjs->items[--cache->miscObjs->number];
2560 
2561 	    ret->type = XPATH_STRING;
2562 	    if (val != NULL)
2563 		ret->stringval = xmlStrdup(val);
2564 	    else
2565 		ret->stringval = xmlStrdup((const xmlChar *)"");
2566 #ifdef XP_DEBUG_OBJ_USAGE
2567 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2568 #endif
2569 	    return(ret);
2570 	}
2571     }
2572     return(xmlXPathNewString(val));
2573 }
2574 
2575 /**
2576  * xmlXPathCacheNewBoolean:
2577  * @ctxt: the XPath context
2578  * @val:  the boolean value
2579  *
2580  * This is the cached version of xmlXPathNewBoolean().
2581  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2582  *
2583  * Returns the created or reused object.
2584  */
2585 static xmlXPathObjectPtr
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt,int val)2586 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2587 {
2588     if ((ctxt != NULL) && (ctxt->cache)) {
2589 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2590 
2591 	if ((cache->booleanObjs != NULL) &&
2592 	    (cache->booleanObjs->number != 0))
2593 	{
2594 	    xmlXPathObjectPtr ret;
2595 
2596 	    ret = (xmlXPathObjectPtr)
2597 		cache->booleanObjs->items[--cache->booleanObjs->number];
2598 	    ret->type = XPATH_BOOLEAN;
2599 	    ret->boolval = (val != 0);
2600 #ifdef XP_DEBUG_OBJ_USAGE
2601 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2602 #endif
2603 	    return(ret);
2604 	} else if ((cache->miscObjs != NULL) &&
2605 	    (cache->miscObjs->number != 0))
2606 	{
2607 	    xmlXPathObjectPtr ret;
2608 
2609 	    ret = (xmlXPathObjectPtr)
2610 		cache->miscObjs->items[--cache->miscObjs->number];
2611 
2612 	    ret->type = XPATH_BOOLEAN;
2613 	    ret->boolval = (val != 0);
2614 #ifdef XP_DEBUG_OBJ_USAGE
2615 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2616 #endif
2617 	    return(ret);
2618 	}
2619     }
2620     return(xmlXPathNewBoolean(val));
2621 }
2622 
2623 /**
2624  * xmlXPathCacheNewFloat:
2625  * @ctxt: the XPath context
2626  * @val:  the double value
2627  *
2628  * This is the cached version of xmlXPathNewFloat().
2629  * Acquires an xmlXPathObjectPtr of type double and of value @val
2630  *
2631  * Returns the created or reused object.
2632  */
2633 static xmlXPathObjectPtr
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt,double val)2634 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2635 {
2636      if ((ctxt != NULL) && (ctxt->cache)) {
2637 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2638 
2639 	if ((cache->numberObjs != NULL) &&
2640 	    (cache->numberObjs->number != 0))
2641 	{
2642 	    xmlXPathObjectPtr ret;
2643 
2644 	    ret = (xmlXPathObjectPtr)
2645 		cache->numberObjs->items[--cache->numberObjs->number];
2646 	    ret->type = XPATH_NUMBER;
2647 	    ret->floatval = val;
2648 #ifdef XP_DEBUG_OBJ_USAGE
2649 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2650 #endif
2651 	    return(ret);
2652 	} else if ((cache->miscObjs != NULL) &&
2653 	    (cache->miscObjs->number != 0))
2654 	{
2655 	    xmlXPathObjectPtr ret;
2656 
2657 	    ret = (xmlXPathObjectPtr)
2658 		cache->miscObjs->items[--cache->miscObjs->number];
2659 
2660 	    ret->type = XPATH_NUMBER;
2661 	    ret->floatval = val;
2662 #ifdef XP_DEBUG_OBJ_USAGE
2663 	    xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2664 #endif
2665 	    return(ret);
2666 	}
2667     }
2668     return(xmlXPathNewFloat(val));
2669 }
2670 
2671 /**
2672  * xmlXPathCacheConvertString:
2673  * @ctxt: the XPath context
2674  * @val:  an XPath object
2675  *
2676  * This is the cached version of xmlXPathConvertString().
2677  * Converts an existing object to its string() equivalent
2678  *
2679  * Returns a created or reused object, the old one is freed (cached)
2680  *         (or the operation is done directly on @val)
2681  */
2682 
2683 static xmlXPathObjectPtr
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2684 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2685     xmlChar *res = NULL;
2686 
2687     if (val == NULL)
2688 	return(xmlXPathCacheNewCString(ctxt, ""));
2689 
2690     switch (val->type) {
2691     case XPATH_UNDEFINED:
2692 #ifdef DEBUG_EXPR
2693 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2694 #endif
2695 	break;
2696     case XPATH_NODESET:
2697     case XPATH_XSLT_TREE:
2698 	res = xmlXPathCastNodeSetToString(val->nodesetval);
2699 	break;
2700     case XPATH_STRING:
2701 	return(val);
2702     case XPATH_BOOLEAN:
2703 	res = xmlXPathCastBooleanToString(val->boolval);
2704 	break;
2705     case XPATH_NUMBER:
2706 	res = xmlXPathCastNumberToString(val->floatval);
2707 	break;
2708     case XPATH_USERS:
2709     case XPATH_POINT:
2710     case XPATH_RANGE:
2711     case XPATH_LOCATIONSET:
2712 	TODO;
2713 	break;
2714     }
2715     xmlXPathReleaseObject(ctxt, val);
2716     if (res == NULL)
2717 	return(xmlXPathCacheNewCString(ctxt, ""));
2718     return(xmlXPathCacheWrapString(ctxt, res));
2719 }
2720 
2721 /**
2722  * xmlXPathCacheObjectCopy:
2723  * @ctxt: the XPath context
2724  * @val:  the original object
2725  *
2726  * This is the cached version of xmlXPathObjectCopy().
2727  * Acquire a copy of a given object
2728  *
2729  * Returns a created or reused created object.
2730  */
2731 static xmlXPathObjectPtr
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2732 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2733 {
2734     if (val == NULL)
2735 	return(NULL);
2736 
2737     if (XP_HAS_CACHE(ctxt)) {
2738 	switch (val->type) {
2739 	    case XPATH_NODESET:
2740 		return(xmlXPathCacheWrapNodeSet(ctxt,
2741 		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2742 	    case XPATH_STRING:
2743 		return(xmlXPathCacheNewString(ctxt, val->stringval));
2744 	    case XPATH_BOOLEAN:
2745 		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2746 	    case XPATH_NUMBER:
2747 		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2748 	    default:
2749 		break;
2750 	}
2751     }
2752     return(xmlXPathObjectCopy(val));
2753 }
2754 
2755 /**
2756  * xmlXPathCacheConvertBoolean:
2757  * @ctxt: the XPath context
2758  * @val:  an XPath object
2759  *
2760  * This is the cached version of xmlXPathConvertBoolean().
2761  * Converts an existing object to its boolean() equivalent
2762  *
2763  * Returns a created or reused object, the old one is freed (or the operation
2764  *         is done directly on @val)
2765  */
2766 static xmlXPathObjectPtr
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2767 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2768     xmlXPathObjectPtr ret;
2769 
2770     if (val == NULL)
2771 	return(xmlXPathCacheNewBoolean(ctxt, 0));
2772     if (val->type == XPATH_BOOLEAN)
2773 	return(val);
2774     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2775     xmlXPathReleaseObject(ctxt, val);
2776     return(ret);
2777 }
2778 
2779 /**
2780  * xmlXPathCacheConvertNumber:
2781  * @ctxt: the XPath context
2782  * @val:  an XPath object
2783  *
2784  * This is the cached version of xmlXPathConvertNumber().
2785  * Converts an existing object to its number() equivalent
2786  *
2787  * Returns a created or reused object, the old one is freed (or the operation
2788  *         is done directly on @val)
2789  */
2790 static xmlXPathObjectPtr
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2791 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2792     xmlXPathObjectPtr ret;
2793 
2794     if (val == NULL)
2795 	return(xmlXPathCacheNewFloat(ctxt, 0.0));
2796     if (val->type == XPATH_NUMBER)
2797 	return(val);
2798     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2799     xmlXPathReleaseObject(ctxt, val);
2800     return(ret);
2801 }
2802 
2803 /************************************************************************
2804  *									*
2805  *		Parser stacks related functions and macros		*
2806  *									*
2807  ************************************************************************/
2808 
2809 /**
2810  * xmlXPathSetFrame:
2811  * @ctxt: an XPath parser context
2812  *
2813  * Set the callee evaluation frame
2814  *
2815  * Returns the previous frame value to be restored once done
2816  */
2817 static int
xmlXPathSetFrame(xmlXPathParserContextPtr ctxt)2818 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2819     int ret;
2820 
2821     if (ctxt == NULL)
2822         return(0);
2823     ret = ctxt->valueFrame;
2824     ctxt->valueFrame = ctxt->valueNr;
2825     return(ret);
2826 }
2827 
2828 /**
2829  * xmlXPathPopFrame:
2830  * @ctxt: an XPath parser context
2831  * @frame: the previous frame value
2832  *
2833  * Remove the callee evaluation frame
2834  */
2835 static void
xmlXPathPopFrame(xmlXPathParserContextPtr ctxt,int frame)2836 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2837     if (ctxt == NULL)
2838         return;
2839     if (ctxt->valueNr < ctxt->valueFrame) {
2840         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2841     }
2842     ctxt->valueFrame = frame;
2843 }
2844 
2845 /**
2846  * valuePop:
2847  * @ctxt: an XPath evaluation context
2848  *
2849  * Pops the top XPath object from the value stack
2850  *
2851  * Returns the XPath object just removed
2852  */
2853 xmlXPathObjectPtr
valuePop(xmlXPathParserContextPtr ctxt)2854 valuePop(xmlXPathParserContextPtr ctxt)
2855 {
2856     xmlXPathObjectPtr ret;
2857 
2858     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2859         return (NULL);
2860 
2861     if (ctxt->valueNr <= ctxt->valueFrame) {
2862         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2863         return (NULL);
2864     }
2865 
2866     ctxt->valueNr--;
2867     if (ctxt->valueNr > 0)
2868         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2869     else
2870         ctxt->value = NULL;
2871     ret = ctxt->valueTab[ctxt->valueNr];
2872     ctxt->valueTab[ctxt->valueNr] = NULL;
2873     return (ret);
2874 }
2875 /**
2876  * valuePush:
2877  * @ctxt:  an XPath evaluation context
2878  * @value:  the XPath object
2879  *
2880  * Pushes a new XPath object on top of the value stack. If value is NULL,
2881  * a memory error is recorded in the parser context.
2882  *
2883  * Returns the number of items on the value stack, or -1 in case of error.
2884  */
2885 int
valuePush(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr value)2886 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2887 {
2888     if (ctxt == NULL) return(-1);
2889     if (value == NULL) {
2890         /*
2891          * A NULL value typically indicates that a memory allocation failed,
2892          * so we set ctxt->error here to propagate the error.
2893          */
2894 	ctxt->error = XPATH_MEMORY_ERROR;
2895         return(-1);
2896     }
2897     if (ctxt->valueNr >= ctxt->valueMax) {
2898         xmlXPathObjectPtr *tmp;
2899 
2900         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2901             xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2902             return (-1);
2903         }
2904         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2905                                              2 * ctxt->valueMax *
2906                                              sizeof(ctxt->valueTab[0]));
2907         if (tmp == NULL) {
2908             xmlXPathPErrMemory(ctxt, "pushing value\n");
2909             return (-1);
2910         }
2911         ctxt->valueMax *= 2;
2912 	ctxt->valueTab = tmp;
2913     }
2914     ctxt->valueTab[ctxt->valueNr] = value;
2915     ctxt->value = value;
2916     return (ctxt->valueNr++);
2917 }
2918 
2919 /**
2920  * xmlXPathPopBoolean:
2921  * @ctxt:  an XPath parser context
2922  *
2923  * Pops a boolean from the stack, handling conversion if needed.
2924  * Check error with #xmlXPathCheckError.
2925  *
2926  * Returns the boolean
2927  */
2928 int
xmlXPathPopBoolean(xmlXPathParserContextPtr ctxt)2929 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2930     xmlXPathObjectPtr obj;
2931     int ret;
2932 
2933     obj = valuePop(ctxt);
2934     if (obj == NULL) {
2935 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2936 	return(0);
2937     }
2938     if (obj->type != XPATH_BOOLEAN)
2939 	ret = xmlXPathCastToBoolean(obj);
2940     else
2941         ret = obj->boolval;
2942     xmlXPathReleaseObject(ctxt->context, obj);
2943     return(ret);
2944 }
2945 
2946 /**
2947  * xmlXPathPopNumber:
2948  * @ctxt:  an XPath parser context
2949  *
2950  * Pops a number from the stack, handling conversion if needed.
2951  * Check error with #xmlXPathCheckError.
2952  *
2953  * Returns the number
2954  */
2955 double
xmlXPathPopNumber(xmlXPathParserContextPtr ctxt)2956 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2957     xmlXPathObjectPtr obj;
2958     double ret;
2959 
2960     obj = valuePop(ctxt);
2961     if (obj == NULL) {
2962 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2963 	return(0);
2964     }
2965     if (obj->type != XPATH_NUMBER)
2966 	ret = xmlXPathCastToNumber(obj);
2967     else
2968         ret = obj->floatval;
2969     xmlXPathReleaseObject(ctxt->context, obj);
2970     return(ret);
2971 }
2972 
2973 /**
2974  * xmlXPathPopString:
2975  * @ctxt:  an XPath parser context
2976  *
2977  * Pops a string from the stack, handling conversion if needed.
2978  * Check error with #xmlXPathCheckError.
2979  *
2980  * Returns the string
2981  */
2982 xmlChar *
xmlXPathPopString(xmlXPathParserContextPtr ctxt)2983 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2984     xmlXPathObjectPtr obj;
2985     xmlChar * ret;
2986 
2987     obj = valuePop(ctxt);
2988     if (obj == NULL) {
2989 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2990 	return(NULL);
2991     }
2992     ret = xmlXPathCastToString(obj);	/* this does required strdup */
2993     /* TODO: needs refactoring somewhere else */
2994     if (obj->stringval == ret)
2995 	obj->stringval = NULL;
2996     xmlXPathReleaseObject(ctxt->context, obj);
2997     return(ret);
2998 }
2999 
3000 /**
3001  * xmlXPathPopNodeSet:
3002  * @ctxt:  an XPath parser context
3003  *
3004  * Pops a node-set from the stack, handling conversion if needed.
3005  * Check error with #xmlXPathCheckError.
3006  *
3007  * Returns the node-set
3008  */
3009 xmlNodeSetPtr
xmlXPathPopNodeSet(xmlXPathParserContextPtr ctxt)3010 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
3011     xmlXPathObjectPtr obj;
3012     xmlNodeSetPtr ret;
3013 
3014     if (ctxt == NULL) return(NULL);
3015     if (ctxt->value == NULL) {
3016 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3017 	return(NULL);
3018     }
3019     if (!xmlXPathStackIsNodeSet(ctxt)) {
3020 	xmlXPathSetTypeError(ctxt);
3021 	return(NULL);
3022     }
3023     obj = valuePop(ctxt);
3024     ret = obj->nodesetval;
3025 #if 0
3026     /* to fix memory leak of not clearing obj->user */
3027     if (obj->boolval && obj->user != NULL)
3028         xmlFreeNodeList((xmlNodePtr) obj->user);
3029 #endif
3030     obj->nodesetval = NULL;
3031     xmlXPathReleaseObject(ctxt->context, obj);
3032     return(ret);
3033 }
3034 
3035 /**
3036  * xmlXPathPopExternal:
3037  * @ctxt:  an XPath parser context
3038  *
3039  * Pops an external object from the stack, handling conversion if needed.
3040  * Check error with #xmlXPathCheckError.
3041  *
3042  * Returns the object
3043  */
3044 void *
xmlXPathPopExternal(xmlXPathParserContextPtr ctxt)3045 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3046     xmlXPathObjectPtr obj;
3047     void * ret;
3048 
3049     if ((ctxt == NULL) || (ctxt->value == NULL)) {
3050 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3051 	return(NULL);
3052     }
3053     if (ctxt->value->type != XPATH_USERS) {
3054 	xmlXPathSetTypeError(ctxt);
3055 	return(NULL);
3056     }
3057     obj = valuePop(ctxt);
3058     ret = obj->user;
3059     obj->user = NULL;
3060     xmlXPathReleaseObject(ctxt->context, obj);
3061     return(ret);
3062 }
3063 
3064 /*
3065  * Macros for accessing the content. Those should be used only by the parser,
3066  * and not exported.
3067  *
3068  * Dirty macros, i.e. one need to make assumption on the context to use them
3069  *
3070  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3071  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3072  *           in ISO-Latin or UTF-8.
3073  *           This should be used internally by the parser
3074  *           only to compare to ASCII values otherwise it would break when
3075  *           running with UTF-8 encoding.
3076  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3077  *           to compare on ASCII based substring.
3078  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3079  *           strings within the parser.
3080  *   CURRENT Returns the current char value, with the full decoding of
3081  *           UTF-8 if we are using this mode. It returns an int.
3082  *   NEXT    Skip to the next character, this does the proper decoding
3083  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3084  *           It returns the pointer to the current xmlChar.
3085  */
3086 
3087 #define CUR (*ctxt->cur)
3088 #define SKIP(val) ctxt->cur += (val)
3089 #define NXT(val) ctxt->cur[(val)]
3090 #define CUR_PTR ctxt->cur
3091 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3092 
3093 #define COPY_BUF(l,b,i,v)                                              \
3094     if (l == 1) b[i++] = (xmlChar) v;                                  \
3095     else i += xmlCopyChar(l,&b[i],v)
3096 
3097 #define NEXTL(l)  ctxt->cur += l
3098 
3099 #define SKIP_BLANKS							\
3100     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3101 
3102 #define CURRENT (*ctxt->cur)
3103 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3104 
3105 
3106 #ifndef DBL_DIG
3107 #define DBL_DIG 16
3108 #endif
3109 #ifndef DBL_EPSILON
3110 #define DBL_EPSILON 1E-9
3111 #endif
3112 
3113 #define UPPER_DOUBLE 1E9
3114 #define LOWER_DOUBLE 1E-5
3115 #define	LOWER_DOUBLE_EXP 5
3116 
3117 #define INTEGER_DIGITS DBL_DIG
3118 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3119 #define EXPONENT_DIGITS (3 + 2)
3120 
3121 /**
3122  * xmlXPathFormatNumber:
3123  * @number:     number to format
3124  * @buffer:     output buffer
3125  * @buffersize: size of output buffer
3126  *
3127  * Convert the number into a string representation.
3128  */
3129 static void
xmlXPathFormatNumber(double number,char buffer[],int buffersize)3130 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3131 {
3132     switch (xmlXPathIsInf(number)) {
3133     case 1:
3134 	if (buffersize > (int)sizeof("Infinity"))
3135 	    snprintf(buffer, buffersize, "Infinity");
3136 	break;
3137     case -1:
3138 	if (buffersize > (int)sizeof("-Infinity"))
3139 	    snprintf(buffer, buffersize, "-Infinity");
3140 	break;
3141     default:
3142 	if (xmlXPathIsNaN(number)) {
3143 	    if (buffersize > (int)sizeof("NaN"))
3144 		snprintf(buffer, buffersize, "NaN");
3145 	} else if (number == 0) {
3146             /* Omit sign for negative zero. */
3147 	    snprintf(buffer, buffersize, "0");
3148 	} else if ((number > INT_MIN) && (number < INT_MAX) &&
3149                    (number == (int) number)) {
3150 	    char work[30];
3151 	    char *ptr, *cur;
3152 	    int value = (int) number;
3153 
3154             ptr = &buffer[0];
3155 	    if (value == 0) {
3156 		*ptr++ = '0';
3157 	    } else {
3158 		snprintf(work, 29, "%d", value);
3159 		cur = &work[0];
3160 		while ((*cur) && (ptr - buffer < buffersize)) {
3161 		    *ptr++ = *cur++;
3162 		}
3163 	    }
3164 	    if (ptr - buffer < buffersize) {
3165 		*ptr = 0;
3166 	    } else if (buffersize > 0) {
3167 		ptr--;
3168 		*ptr = 0;
3169 	    }
3170 	} else {
3171 	    /*
3172 	      For the dimension of work,
3173 	          DBL_DIG is number of significant digits
3174 		  EXPONENT is only needed for "scientific notation"
3175 	          3 is sign, decimal point, and terminating zero
3176 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3177 	      Note that this dimension is slightly (a few characters)
3178 	      larger than actually necessary.
3179 	    */
3180 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3181 	    int integer_place, fraction_place;
3182 	    char *ptr;
3183 	    char *after_fraction;
3184 	    double absolute_value;
3185 	    int size;
3186 
3187 	    absolute_value = fabs(number);
3188 
3189 	    /*
3190 	     * First choose format - scientific or regular floating point.
3191 	     * In either case, result is in work, and after_fraction points
3192 	     * just past the fractional part.
3193 	    */
3194 	    if ( ((absolute_value > UPPER_DOUBLE) ||
3195 		  (absolute_value < LOWER_DOUBLE)) &&
3196 		 (absolute_value != 0.0) ) {
3197 		/* Use scientific notation */
3198 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3199 		fraction_place = DBL_DIG - 1;
3200 		size = snprintf(work, sizeof(work),"%*.*e",
3201 			 integer_place, fraction_place, number);
3202 		while ((size > 0) && (work[size] != 'e')) size--;
3203 
3204 	    }
3205 	    else {
3206 		/* Use regular notation */
3207 		if (absolute_value > 0.0) {
3208 		    integer_place = (int)log10(absolute_value);
3209 		    if (integer_place > 0)
3210 		        fraction_place = DBL_DIG - integer_place - 1;
3211 		    else
3212 		        fraction_place = DBL_DIG - integer_place;
3213 		} else {
3214 		    fraction_place = 1;
3215 		}
3216 		size = snprintf(work, sizeof(work), "%0.*f",
3217 				fraction_place, number);
3218 	    }
3219 
3220 	    /* Remove leading spaces sometimes inserted by snprintf */
3221 	    while (work[0] == ' ') {
3222 	        for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3223 		size--;
3224 	    }
3225 
3226 	    /* Remove fractional trailing zeroes */
3227 	    after_fraction = work + size;
3228 	    ptr = after_fraction;
3229 	    while (*(--ptr) == '0')
3230 		;
3231 	    if (*ptr != '.')
3232 	        ptr++;
3233 	    while ((*ptr++ = *after_fraction++) != 0);
3234 
3235 	    /* Finally copy result back to caller */
3236 	    size = strlen(work) + 1;
3237 	    if (size > buffersize) {
3238 		work[buffersize - 1] = 0;
3239 		size = buffersize;
3240 	    }
3241 	    memmove(buffer, work, size);
3242 	}
3243 	break;
3244     }
3245 }
3246 
3247 
3248 /************************************************************************
3249  *									*
3250  *			Routines to handle NodeSets			*
3251  *									*
3252  ************************************************************************/
3253 
3254 /**
3255  * xmlXPathOrderDocElems:
3256  * @doc:  an input document
3257  *
3258  * Call this routine to speed up XPath computation on static documents.
3259  * This stamps all the element nodes with the document order
3260  * Like for line information, the order is kept in the element->content
3261  * field, the value stored is actually - the node number (starting at -1)
3262  * to be able to differentiate from line numbers.
3263  *
3264  * Returns the number of elements found in the document or -1 in case
3265  *    of error.
3266  */
3267 long
xmlXPathOrderDocElems(xmlDocPtr doc)3268 xmlXPathOrderDocElems(xmlDocPtr doc) {
3269     ptrdiff_t count = 0;
3270     xmlNodePtr cur;
3271 
3272     if (doc == NULL)
3273 	return(-1);
3274     cur = doc->children;
3275     while (cur != NULL) {
3276 	if (cur->type == XML_ELEMENT_NODE) {
3277 	    cur->content = (void *) (-(++count));
3278 	    if (cur->children != NULL) {
3279 		cur = cur->children;
3280 		continue;
3281 	    }
3282 	}
3283 	if (cur->next != NULL) {
3284 	    cur = cur->next;
3285 	    continue;
3286 	}
3287 	do {
3288 	    cur = cur->parent;
3289 	    if (cur == NULL)
3290 		break;
3291 	    if (cur == (xmlNodePtr) doc) {
3292 		cur = NULL;
3293 		break;
3294 	    }
3295 	    if (cur->next != NULL) {
3296 		cur = cur->next;
3297 		break;
3298 	    }
3299 	} while (cur != NULL);
3300     }
3301     return((long) count);
3302 }
3303 
3304 /**
3305  * xmlXPathCmpNodes:
3306  * @node1:  the first node
3307  * @node2:  the second node
3308  *
3309  * Compare two nodes w.r.t document order
3310  *
3311  * Returns -2 in case of error 1 if first point < second point, 0 if
3312  *         it's the same node, -1 otherwise
3313  */
3314 int
xmlXPathCmpNodes(xmlNodePtr node1,xmlNodePtr node2)3315 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3316     int depth1, depth2;
3317     int attr1 = 0, attr2 = 0;
3318     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3319     xmlNodePtr cur, root;
3320 
3321     if ((node1 == NULL) || (node2 == NULL))
3322 	return(-2);
3323     /*
3324      * a couple of optimizations which will avoid computations in most cases
3325      */
3326     if (node1 == node2)		/* trivial case */
3327 	return(0);
3328     if (node1->type == XML_ATTRIBUTE_NODE) {
3329 	attr1 = 1;
3330 	attrNode1 = node1;
3331 	node1 = node1->parent;
3332     }
3333     if (node2->type == XML_ATTRIBUTE_NODE) {
3334 	attr2 = 1;
3335 	attrNode2 = node2;
3336 	node2 = node2->parent;
3337     }
3338     if (node1 == node2) {
3339 	if (attr1 == attr2) {
3340 	    /* not required, but we keep attributes in order */
3341 	    if (attr1 != 0) {
3342 	        cur = attrNode2->prev;
3343 		while (cur != NULL) {
3344 		    if (cur == attrNode1)
3345 		        return (1);
3346 		    cur = cur->prev;
3347 		}
3348 		return (-1);
3349 	    }
3350 	    return(0);
3351 	}
3352 	if (attr2 == 1)
3353 	    return(1);
3354 	return(-1);
3355     }
3356     if ((node1->type == XML_NAMESPACE_DECL) ||
3357         (node2->type == XML_NAMESPACE_DECL))
3358 	return(1);
3359     if (node1 == node2->prev)
3360 	return(1);
3361     if (node1 == node2->next)
3362 	return(-1);
3363 
3364     /*
3365      * Speedup using document order if available.
3366      */
3367     if ((node1->type == XML_ELEMENT_NODE) &&
3368 	(node2->type == XML_ELEMENT_NODE) &&
3369 	(0 > (ptrdiff_t) node1->content) &&
3370 	(0 > (ptrdiff_t) node2->content) &&
3371 	(node1->doc == node2->doc)) {
3372 	ptrdiff_t l1, l2;
3373 
3374 	l1 = -((ptrdiff_t) node1->content);
3375 	l2 = -((ptrdiff_t) node2->content);
3376 	if (l1 < l2)
3377 	    return(1);
3378 	if (l1 > l2)
3379 	    return(-1);
3380     }
3381 
3382     /*
3383      * compute depth to root
3384      */
3385     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3386 	if (cur->parent == node1)
3387 	    return(1);
3388 	depth2++;
3389     }
3390     root = cur;
3391     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3392 	if (cur->parent == node2)
3393 	    return(-1);
3394 	depth1++;
3395     }
3396     /*
3397      * Distinct document (or distinct entities :-( ) case.
3398      */
3399     if (root != cur) {
3400 	return(-2);
3401     }
3402     /*
3403      * get the nearest common ancestor.
3404      */
3405     while (depth1 > depth2) {
3406 	depth1--;
3407 	node1 = node1->parent;
3408     }
3409     while (depth2 > depth1) {
3410 	depth2--;
3411 	node2 = node2->parent;
3412     }
3413     while (node1->parent != node2->parent) {
3414 	node1 = node1->parent;
3415 	node2 = node2->parent;
3416 	/* should not happen but just in case ... */
3417 	if ((node1 == NULL) || (node2 == NULL))
3418 	    return(-2);
3419     }
3420     /*
3421      * Find who's first.
3422      */
3423     if (node1 == node2->prev)
3424 	return(1);
3425     if (node1 == node2->next)
3426 	return(-1);
3427     /*
3428      * Speedup using document order if available.
3429      */
3430     if ((node1->type == XML_ELEMENT_NODE) &&
3431 	(node2->type == XML_ELEMENT_NODE) &&
3432 	(0 > (ptrdiff_t) node1->content) &&
3433 	(0 > (ptrdiff_t) node2->content) &&
3434 	(node1->doc == node2->doc)) {
3435 	ptrdiff_t l1, l2;
3436 
3437 	l1 = -((ptrdiff_t) node1->content);
3438 	l2 = -((ptrdiff_t) node2->content);
3439 	if (l1 < l2)
3440 	    return(1);
3441 	if (l1 > l2)
3442 	    return(-1);
3443     }
3444 
3445     for (cur = node1->next;cur != NULL;cur = cur->next)
3446 	if (cur == node2)
3447 	    return(1);
3448     return(-1); /* assume there is no sibling list corruption */
3449 }
3450 
3451 /**
3452  * xmlXPathNodeSetSort:
3453  * @set:  the node set
3454  *
3455  * Sort the node set in document order
3456  */
3457 void
xmlXPathNodeSetSort(xmlNodeSetPtr set)3458 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3459 #ifndef WITH_TIM_SORT
3460     int i, j, incr, len;
3461     xmlNodePtr tmp;
3462 #endif
3463 
3464     if (set == NULL)
3465 	return;
3466 
3467 #ifndef WITH_TIM_SORT
3468     /*
3469      * Use the old Shell's sort implementation to sort the node-set
3470      * Timsort ought to be quite faster
3471      */
3472     len = set->nodeNr;
3473     for (incr = len / 2; incr > 0; incr /= 2) {
3474 	for (i = incr; i < len; i++) {
3475 	    j = i - incr;
3476 	    while (j >= 0) {
3477 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3478 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
3479 			set->nodeTab[j + incr]) == -1)
3480 #else
3481 		if (xmlXPathCmpNodes(set->nodeTab[j],
3482 			set->nodeTab[j + incr]) == -1)
3483 #endif
3484 		{
3485 		    tmp = set->nodeTab[j];
3486 		    set->nodeTab[j] = set->nodeTab[j + incr];
3487 		    set->nodeTab[j + incr] = tmp;
3488 		    j -= incr;
3489 		} else
3490 		    break;
3491 	    }
3492 	}
3493     }
3494 #else /* WITH_TIM_SORT */
3495     libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3496 #endif /* WITH_TIM_SORT */
3497 }
3498 
3499 #define XML_NODESET_DEFAULT	10
3500 /**
3501  * xmlXPathNodeSetDupNs:
3502  * @node:  the parent node of the namespace XPath node
3503  * @ns:  the libxml namespace declaration node.
3504  *
3505  * Namespace node in libxml don't match the XPath semantic. In a node set
3506  * the namespace nodes are duplicated and the next pointer is set to the
3507  * parent node in the XPath semantic.
3508  *
3509  * Returns the newly created object.
3510  */
3511 static xmlNodePtr
xmlXPathNodeSetDupNs(xmlNodePtr node,xmlNsPtr ns)3512 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3513     xmlNsPtr cur;
3514 
3515     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3516 	return(NULL);
3517     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3518 	return((xmlNodePtr) ns);
3519 
3520     /*
3521      * Allocate a new Namespace and fill the fields.
3522      */
3523     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3524     if (cur == NULL) {
3525         xmlXPathErrMemory(NULL, "duplicating namespace\n");
3526 	return(NULL);
3527     }
3528     memset(cur, 0, sizeof(xmlNs));
3529     cur->type = XML_NAMESPACE_DECL;
3530     if (ns->href != NULL)
3531 	cur->href = xmlStrdup(ns->href);
3532     if (ns->prefix != NULL)
3533 	cur->prefix = xmlStrdup(ns->prefix);
3534     cur->next = (xmlNsPtr) node;
3535     return((xmlNodePtr) cur);
3536 }
3537 
3538 /**
3539  * xmlXPathNodeSetFreeNs:
3540  * @ns:  the XPath namespace node found in a nodeset.
3541  *
3542  * Namespace nodes in libxml don't match the XPath semantic. In a node set
3543  * the namespace nodes are duplicated and the next pointer is set to the
3544  * parent node in the XPath semantic. Check if such a node needs to be freed
3545  */
3546 void
xmlXPathNodeSetFreeNs(xmlNsPtr ns)3547 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3548     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3549 	return;
3550 
3551     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3552 	if (ns->href != NULL)
3553 	    xmlFree((xmlChar *)ns->href);
3554 	if (ns->prefix != NULL)
3555 	    xmlFree((xmlChar *)ns->prefix);
3556 	xmlFree(ns);
3557     }
3558 }
3559 
3560 /**
3561  * xmlXPathNodeSetCreate:
3562  * @val:  an initial xmlNodePtr, or NULL
3563  *
3564  * Create a new xmlNodeSetPtr of type double and of value @val
3565  *
3566  * Returns the newly created object.
3567  */
3568 xmlNodeSetPtr
xmlXPathNodeSetCreate(xmlNodePtr val)3569 xmlXPathNodeSetCreate(xmlNodePtr val) {
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 (val != NULL) {
3579         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3580 					     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 ,
3587 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3588         ret->nodeMax = XML_NODESET_DEFAULT;
3589 	if (val->type == XML_NAMESPACE_DECL) {
3590 	    xmlNsPtr ns = (xmlNsPtr) val;
3591 
3592             /* TODO: Check memory error. */
3593 	    ret->nodeTab[ret->nodeNr++] =
3594 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3595 	} else
3596 	    ret->nodeTab[ret->nodeNr++] = val;
3597     }
3598     return(ret);
3599 }
3600 
3601 /**
3602  * xmlXPathNodeSetContains:
3603  * @cur:  the node-set
3604  * @val:  the node
3605  *
3606  * checks whether @cur contains @val
3607  *
3608  * Returns true (1) if @cur contains @val, false (0) otherwise
3609  */
3610 int
xmlXPathNodeSetContains(xmlNodeSetPtr cur,xmlNodePtr val)3611 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3612     int i;
3613 
3614     if ((cur == NULL) || (val == NULL)) return(0);
3615     if (val->type == XML_NAMESPACE_DECL) {
3616 	for (i = 0; i < cur->nodeNr; i++) {
3617 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3618 		xmlNsPtr ns1, ns2;
3619 
3620 		ns1 = (xmlNsPtr) val;
3621 		ns2 = (xmlNsPtr) cur->nodeTab[i];
3622 		if (ns1 == ns2)
3623 		    return(1);
3624 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3625 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
3626 		    return(1);
3627 	    }
3628 	}
3629     } else {
3630 	for (i = 0; i < cur->nodeNr; i++) {
3631 	    if (cur->nodeTab[i] == val)
3632 		return(1);
3633 	}
3634     }
3635     return(0);
3636 }
3637 
3638 /**
3639  * xmlXPathNodeSetAddNs:
3640  * @cur:  the initial node set
3641  * @node:  the hosting node
3642  * @ns:  a the namespace node
3643  *
3644  * add a new namespace node to an existing NodeSet
3645  *
3646  * Returns 0 in case of success and -1 in case of error
3647  */
3648 int
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur,xmlNodePtr node,xmlNsPtr ns)3649 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3650     int i;
3651 
3652 
3653     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3654         (ns->type != XML_NAMESPACE_DECL) ||
3655 	(node->type != XML_ELEMENT_NODE))
3656 	return(-1);
3657 
3658     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3659     /*
3660      * prevent duplicates
3661      */
3662     for (i = 0;i < cur->nodeNr;i++) {
3663         if ((cur->nodeTab[i] != NULL) &&
3664 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3665 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3666 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3667 	    return(0);
3668     }
3669 
3670     /*
3671      * grow the nodeTab if needed
3672      */
3673     if (cur->nodeMax == 0) {
3674         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3675 					     sizeof(xmlNodePtr));
3676 	if (cur->nodeTab == NULL) {
3677 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3678 	    return(-1);
3679 	}
3680 	memset(cur->nodeTab, 0 ,
3681 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3682         cur->nodeMax = XML_NODESET_DEFAULT;
3683     } else if (cur->nodeNr == cur->nodeMax) {
3684         xmlNodePtr *temp;
3685 
3686         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3687             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3688             return(-1);
3689         }
3690 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3691 				      sizeof(xmlNodePtr));
3692 	if (temp == NULL) {
3693 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3694 	    return(-1);
3695 	}
3696         cur->nodeMax *= 2;
3697 	cur->nodeTab = temp;
3698     }
3699     /* TODO: Check memory error. */
3700     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3701     return(0);
3702 }
3703 
3704 /**
3705  * xmlXPathNodeSetAdd:
3706  * @cur:  the initial node set
3707  * @val:  a new xmlNodePtr
3708  *
3709  * add a new xmlNodePtr to an existing NodeSet
3710  *
3711  * Returns 0 in case of success, and -1 in case of error
3712  */
3713 int
xmlXPathNodeSetAdd(xmlNodeSetPtr cur,xmlNodePtr val)3714 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3715     int i;
3716 
3717     if ((cur == NULL) || (val == NULL)) return(-1);
3718 
3719     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3720     /*
3721      * prevent duplicates
3722      */
3723     for (i = 0;i < cur->nodeNr;i++)
3724         if (cur->nodeTab[i] == val) return(0);
3725 
3726     /*
3727      * grow the nodeTab if needed
3728      */
3729     if (cur->nodeMax == 0) {
3730         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3731 					     sizeof(xmlNodePtr));
3732 	if (cur->nodeTab == NULL) {
3733 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3734 	    return(-1);
3735 	}
3736 	memset(cur->nodeTab, 0 ,
3737 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3738         cur->nodeMax = XML_NODESET_DEFAULT;
3739     } else if (cur->nodeNr == cur->nodeMax) {
3740         xmlNodePtr *temp;
3741 
3742         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3743             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3744             return(-1);
3745         }
3746 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3747 				      sizeof(xmlNodePtr));
3748 	if (temp == NULL) {
3749 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3750 	    return(-1);
3751 	}
3752         cur->nodeMax *= 2;
3753 	cur->nodeTab = temp;
3754     }
3755     if (val->type == XML_NAMESPACE_DECL) {
3756 	xmlNsPtr ns = (xmlNsPtr) val;
3757 
3758         /* TODO: Check memory error. */
3759 	cur->nodeTab[cur->nodeNr++] =
3760 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3761     } else
3762 	cur->nodeTab[cur->nodeNr++] = val;
3763     return(0);
3764 }
3765 
3766 /**
3767  * xmlXPathNodeSetAddUnique:
3768  * @cur:  the initial node set
3769  * @val:  a new xmlNodePtr
3770  *
3771  * add a new xmlNodePtr to an existing NodeSet, optimized version
3772  * when we are sure the node is not already in the set.
3773  *
3774  * Returns 0 in case of success and -1 in case of failure
3775  */
3776 int
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur,xmlNodePtr val)3777 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3778     if ((cur == NULL) || (val == NULL)) return(-1);
3779 
3780     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3781     /*
3782      * grow the nodeTab if needed
3783      */
3784     if (cur->nodeMax == 0) {
3785         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3786 					     sizeof(xmlNodePtr));
3787 	if (cur->nodeTab == NULL) {
3788 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3789 	    return(-1);
3790 	}
3791 	memset(cur->nodeTab, 0 ,
3792 	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3793         cur->nodeMax = XML_NODESET_DEFAULT;
3794     } else if (cur->nodeNr == cur->nodeMax) {
3795         xmlNodePtr *temp;
3796 
3797         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3798             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3799             return(-1);
3800         }
3801 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3802 				      sizeof(xmlNodePtr));
3803 	if (temp == NULL) {
3804 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3805 	    return(-1);
3806 	}
3807 	cur->nodeTab = temp;
3808         cur->nodeMax *= 2;
3809     }
3810     if (val->type == XML_NAMESPACE_DECL) {
3811 	xmlNsPtr ns = (xmlNsPtr) val;
3812 
3813         /* TODO: Check memory error. */
3814 	cur->nodeTab[cur->nodeNr++] =
3815 	    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3816     } else
3817 	cur->nodeTab[cur->nodeNr++] = val;
3818     return(0);
3819 }
3820 
3821 /**
3822  * xmlXPathNodeSetMerge:
3823  * @val1:  the first NodeSet or NULL
3824  * @val2:  the second NodeSet
3825  *
3826  * Merges two nodesets, all nodes from @val2 are added to @val1
3827  * if @val1 is NULL, a new set is created and copied from @val2
3828  *
3829  * Returns @val1 once extended or NULL in case of error.
3830  */
3831 xmlNodeSetPtr
xmlXPathNodeSetMerge(xmlNodeSetPtr val1,xmlNodeSetPtr val2)3832 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3833     int i, j, initNr, skip;
3834     xmlNodePtr n1, n2;
3835 
3836     if (val2 == NULL) return(val1);
3837     if (val1 == NULL) {
3838 	val1 = xmlXPathNodeSetCreate(NULL);
3839     if (val1 == NULL)
3840         return (NULL);
3841 #if 0
3842 	/*
3843 	* TODO: The optimization won't work in every case, since
3844 	*  those nasty namespace nodes need to be added with
3845 	*  xmlXPathNodeSetDupNs() to the set; thus a pure
3846 	*  memcpy is not possible.
3847 	*  If there was a flag on the nodesetval, indicating that
3848 	*  some temporary nodes are in, that would be helpful.
3849 	*/
3850 	/*
3851 	* Optimization: Create an equally sized node-set
3852 	* and memcpy the content.
3853 	*/
3854 	val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3855 	if (val1 == NULL)
3856 	    return(NULL);
3857 	if (val2->nodeNr != 0) {
3858 	    if (val2->nodeNr == 1)
3859 		*(val1->nodeTab) = *(val2->nodeTab);
3860 	    else {
3861 		memcpy(val1->nodeTab, val2->nodeTab,
3862 		    val2->nodeNr * sizeof(xmlNodePtr));
3863 	    }
3864 	    val1->nodeNr = val2->nodeNr;
3865 	}
3866 	return(val1);
3867 #endif
3868     }
3869 
3870     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3871     initNr = val1->nodeNr;
3872 
3873     for (i = 0;i < val2->nodeNr;i++) {
3874 	n2 = val2->nodeTab[i];
3875 	/*
3876 	 * check against duplicates
3877 	 */
3878 	skip = 0;
3879 	for (j = 0; j < initNr; j++) {
3880 	    n1 = val1->nodeTab[j];
3881 	    if (n1 == n2) {
3882 		skip = 1;
3883 		break;
3884 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3885 		       (n2->type == XML_NAMESPACE_DECL)) {
3886 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3887 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3888 			((xmlNsPtr) n2)->prefix)))
3889 		{
3890 		    skip = 1;
3891 		    break;
3892 		}
3893 	    }
3894 	}
3895 	if (skip)
3896 	    continue;
3897 
3898 	/*
3899 	 * grow the nodeTab if needed
3900 	 */
3901 	if (val1->nodeMax == 0) {
3902 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3903 						    sizeof(xmlNodePtr));
3904 	    if (val1->nodeTab == NULL) {
3905 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3906 		return(NULL);
3907 	    }
3908 	    memset(val1->nodeTab, 0 ,
3909 		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3910 	    val1->nodeMax = XML_NODESET_DEFAULT;
3911 	} else if (val1->nodeNr == val1->nodeMax) {
3912 	    xmlNodePtr *temp;
3913 
3914             if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3915                 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3916                 return(NULL);
3917             }
3918 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3919 					     sizeof(xmlNodePtr));
3920 	    if (temp == NULL) {
3921 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3922 		return(NULL);
3923 	    }
3924 	    val1->nodeTab = temp;
3925 	    val1->nodeMax *= 2;
3926 	}
3927 	if (n2->type == XML_NAMESPACE_DECL) {
3928 	    xmlNsPtr ns = (xmlNsPtr) n2;
3929 
3930             /* TODO: Check memory error. */
3931 	    val1->nodeTab[val1->nodeNr++] =
3932 		xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3933 	} else
3934 	    val1->nodeTab[val1->nodeNr++] = n2;
3935     }
3936 
3937     return(val1);
3938 }
3939 
3940 
3941 /**
3942  * xmlXPathNodeSetMergeAndClear:
3943  * @set1:  the first NodeSet or NULL
3944  * @set2:  the second NodeSet
3945  *
3946  * Merges two nodesets, all nodes from @set2 are added to @set1.
3947  * Checks for duplicate nodes. Clears set2.
3948  *
3949  * Returns @set1 once extended or NULL in case of error.
3950  */
3951 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1,xmlNodeSetPtr set2)3952 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3953 {
3954     {
3955 	int i, j, initNbSet1;
3956 	xmlNodePtr n1, n2;
3957 
3958 	initNbSet1 = set1->nodeNr;
3959 	for (i = 0;i < set2->nodeNr;i++) {
3960 	    n2 = set2->nodeTab[i];
3961 	    /*
3962 	    * Skip duplicates.
3963 	    */
3964 	    for (j = 0; j < initNbSet1; j++) {
3965 		n1 = set1->nodeTab[j];
3966 		if (n1 == n2) {
3967 		    goto skip_node;
3968 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
3969 		    (n2->type == XML_NAMESPACE_DECL))
3970 		{
3971 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3972 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
3973 			((xmlNsPtr) n2)->prefix)))
3974 		    {
3975 			/*
3976 			* Free the namespace node.
3977 			*/
3978 			set2->nodeTab[i] = NULL;
3979 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3980 			goto skip_node;
3981 		    }
3982 		}
3983 	    }
3984 	    /*
3985 	    * grow the nodeTab if needed
3986 	    */
3987 	    if (set1->nodeMax == 0) {
3988 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3989 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3990 		if (set1->nodeTab == NULL) {
3991 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3992 		    return(NULL);
3993 		}
3994 		memset(set1->nodeTab, 0,
3995 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3996 		set1->nodeMax = XML_NODESET_DEFAULT;
3997 	    } else if (set1->nodeNr >= set1->nodeMax) {
3998 		xmlNodePtr *temp;
3999 
4000                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4001                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4002                     return(NULL);
4003                 }
4004 		temp = (xmlNodePtr *) xmlRealloc(
4005 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4006 		if (temp == NULL) {
4007 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4008 		    return(NULL);
4009 		}
4010 		set1->nodeTab = temp;
4011 		set1->nodeMax *= 2;
4012 	    }
4013 	    set1->nodeTab[set1->nodeNr++] = n2;
4014 skip_node:
4015 	    {}
4016 	}
4017     }
4018     set2->nodeNr = 0;
4019     return(set1);
4020 }
4021 
4022 /**
4023  * xmlXPathNodeSetMergeAndClearNoDupls:
4024  * @set1:  the first NodeSet or NULL
4025  * @set2:  the second NodeSet
4026  *
4027  * Merges two nodesets, all nodes from @set2 are added to @set1.
4028  * Doesn't check for duplicate nodes. Clears set2.
4029  *
4030  * Returns @set1 once extended or NULL in case of error.
4031  */
4032 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1,xmlNodeSetPtr set2)4033 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
4034 {
4035     {
4036 	int i;
4037 	xmlNodePtr n2;
4038 
4039 	for (i = 0;i < set2->nodeNr;i++) {
4040 	    n2 = set2->nodeTab[i];
4041 	    if (set1->nodeMax == 0) {
4042 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4043 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4044 		if (set1->nodeTab == NULL) {
4045 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4046 		    return(NULL);
4047 		}
4048 		memset(set1->nodeTab, 0,
4049 		    XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4050 		set1->nodeMax = XML_NODESET_DEFAULT;
4051 	    } else if (set1->nodeNr >= set1->nodeMax) {
4052 		xmlNodePtr *temp;
4053 
4054                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4055                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4056                     return(NULL);
4057                 }
4058 		temp = (xmlNodePtr *) xmlRealloc(
4059 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4060 		if (temp == NULL) {
4061 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
4062 		    return(NULL);
4063 		}
4064 		set1->nodeTab = temp;
4065 		set1->nodeMax *= 2;
4066 	    }
4067 	    set1->nodeTab[set1->nodeNr++] = n2;
4068 	}
4069     }
4070     set2->nodeNr = 0;
4071     return(set1);
4072 }
4073 
4074 /**
4075  * xmlXPathNodeSetDel:
4076  * @cur:  the initial node set
4077  * @val:  an xmlNodePtr
4078  *
4079  * Removes an xmlNodePtr from an existing NodeSet
4080  */
4081 void
xmlXPathNodeSetDel(xmlNodeSetPtr cur,xmlNodePtr val)4082 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4083     int i;
4084 
4085     if (cur == NULL) return;
4086     if (val == NULL) return;
4087 
4088     /*
4089      * find node in nodeTab
4090      */
4091     for (i = 0;i < cur->nodeNr;i++)
4092         if (cur->nodeTab[i] == val) break;
4093 
4094     if (i >= cur->nodeNr) {	/* not found */
4095 #ifdef DEBUG
4096         xmlGenericError(xmlGenericErrorContext,
4097 	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4098 		val->name);
4099 #endif
4100         return;
4101     }
4102     if ((cur->nodeTab[i] != NULL) &&
4103 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4104 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4105     cur->nodeNr--;
4106     for (;i < cur->nodeNr;i++)
4107         cur->nodeTab[i] = cur->nodeTab[i + 1];
4108     cur->nodeTab[cur->nodeNr] = NULL;
4109 }
4110 
4111 /**
4112  * xmlXPathNodeSetRemove:
4113  * @cur:  the initial node set
4114  * @val:  the index to remove
4115  *
4116  * Removes an entry from an existing NodeSet list.
4117  */
4118 void
xmlXPathNodeSetRemove(xmlNodeSetPtr cur,int val)4119 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4120     if (cur == NULL) return;
4121     if (val >= cur->nodeNr) return;
4122     if ((cur->nodeTab[val] != NULL) &&
4123 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4124 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4125     cur->nodeNr--;
4126     for (;val < cur->nodeNr;val++)
4127         cur->nodeTab[val] = cur->nodeTab[val + 1];
4128     cur->nodeTab[cur->nodeNr] = NULL;
4129 }
4130 
4131 /**
4132  * xmlXPathFreeNodeSet:
4133  * @obj:  the xmlNodeSetPtr to free
4134  *
4135  * Free the NodeSet compound (not the actual nodes !).
4136  */
4137 void
xmlXPathFreeNodeSet(xmlNodeSetPtr obj)4138 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4139     if (obj == NULL) return;
4140     if (obj->nodeTab != NULL) {
4141 	int i;
4142 
4143 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
4144 	for (i = 0;i < obj->nodeNr;i++)
4145 	    if ((obj->nodeTab[i] != NULL) &&
4146 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4147 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4148 	xmlFree(obj->nodeTab);
4149     }
4150     xmlFree(obj);
4151 }
4152 
4153 /**
4154  * xmlXPathNodeSetClearFromPos:
4155  * @set: the node set to be cleared
4156  * @pos: the start position to clear from
4157  *
4158  * Clears the list from temporary XPath objects (e.g. namespace nodes
4159  * are feed) starting with the entry at @pos, but does *not* free the list
4160  * itself. Sets the length of the list to @pos.
4161  */
4162 static void
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set,int pos,int hasNsNodes)4163 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4164 {
4165     if ((set == NULL) || (pos >= set->nodeNr))
4166 	return;
4167     else if ((hasNsNodes)) {
4168 	int i;
4169 	xmlNodePtr node;
4170 
4171 	for (i = pos; i < set->nodeNr; i++) {
4172 	    node = set->nodeTab[i];
4173 	    if ((node != NULL) &&
4174 		(node->type == XML_NAMESPACE_DECL))
4175 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4176 	}
4177     }
4178     set->nodeNr = pos;
4179 }
4180 
4181 /**
4182  * xmlXPathNodeSetClear:
4183  * @set:  the node set to clear
4184  *
4185  * Clears the list from all temporary XPath objects (e.g. namespace nodes
4186  * are feed), but does *not* free the list itself. Sets the length of the
4187  * list to 0.
4188  */
4189 static void
xmlXPathNodeSetClear(xmlNodeSetPtr set,int hasNsNodes)4190 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4191 {
4192     xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4193 }
4194 
4195 /**
4196  * xmlXPathNodeSetKeepLast:
4197  * @set: the node set to be cleared
4198  *
4199  * Move the last node to the first position and clear temporary XPath objects
4200  * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4201  * to 1.
4202  */
4203 static void
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)4204 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4205 {
4206     int i;
4207     xmlNodePtr node;
4208 
4209     if ((set == NULL) || (set->nodeNr <= 1))
4210 	return;
4211     for (i = 0; i < set->nodeNr - 1; i++) {
4212         node = set->nodeTab[i];
4213         if ((node != NULL) &&
4214             (node->type == XML_NAMESPACE_DECL))
4215             xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4216     }
4217     set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4218     set->nodeNr = 1;
4219 }
4220 
4221 /**
4222  * xmlXPathFreeValueTree:
4223  * @obj:  the xmlNodeSetPtr to free
4224  *
4225  * Free the NodeSet compound and the actual tree, this is different
4226  * from xmlXPathFreeNodeSet()
4227  */
4228 static void
xmlXPathFreeValueTree(xmlNodeSetPtr obj)4229 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4230     int i;
4231 
4232     if (obj == NULL) return;
4233 
4234     if (obj->nodeTab != NULL) {
4235 	for (i = 0;i < obj->nodeNr;i++) {
4236 	    if (obj->nodeTab[i] != NULL) {
4237 		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4238 		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4239 		} else {
4240 		    xmlFreeNodeList(obj->nodeTab[i]);
4241 		}
4242 	    }
4243 	}
4244 	xmlFree(obj->nodeTab);
4245     }
4246     xmlFree(obj);
4247 }
4248 
4249 #if defined(DEBUG) || defined(DEBUG_STEP)
4250 /**
4251  * xmlGenericErrorContextNodeSet:
4252  * @output:  a FILE * for the output
4253  * @obj:  the xmlNodeSetPtr to display
4254  *
4255  * Quick display of a NodeSet
4256  */
4257 void
xmlGenericErrorContextNodeSet(FILE * output,xmlNodeSetPtr obj)4258 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4259     int i;
4260 
4261     if (output == NULL) output = xmlGenericErrorContext;
4262     if (obj == NULL)  {
4263         fprintf(output, "NodeSet == NULL !\n");
4264 	return;
4265     }
4266     if (obj->nodeNr == 0) {
4267         fprintf(output, "NodeSet is empty\n");
4268 	return;
4269     }
4270     if (obj->nodeTab == NULL) {
4271 	fprintf(output, " nodeTab == NULL !\n");
4272 	return;
4273     }
4274     for (i = 0; i < obj->nodeNr; i++) {
4275         if (obj->nodeTab[i] == NULL) {
4276 	    fprintf(output, " NULL !\n");
4277 	    return;
4278         }
4279 	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4280 	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4281 	    fprintf(output, " /");
4282 	else if (obj->nodeTab[i]->name == NULL)
4283 	    fprintf(output, " noname!");
4284 	else fprintf(output, " %s", obj->nodeTab[i]->name);
4285     }
4286     fprintf(output, "\n");
4287 }
4288 #endif
4289 
4290 /**
4291  * xmlXPathNewNodeSet:
4292  * @val:  the NodePtr value
4293  *
4294  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4295  * it with the single Node @val
4296  *
4297  * Returns the newly created object.
4298  */
4299 xmlXPathObjectPtr
xmlXPathNewNodeSet(xmlNodePtr val)4300 xmlXPathNewNodeSet(xmlNodePtr val) {
4301     xmlXPathObjectPtr ret;
4302 
4303     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4304     if (ret == NULL) {
4305         xmlXPathErrMemory(NULL, "creating nodeset\n");
4306 	return(NULL);
4307     }
4308     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4309     ret->type = XPATH_NODESET;
4310     ret->boolval = 0;
4311     /* TODO: Check memory error. */
4312     ret->nodesetval = xmlXPathNodeSetCreate(val);
4313     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4314 #ifdef XP_DEBUG_OBJ_USAGE
4315     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4316 #endif
4317     return(ret);
4318 }
4319 
4320 /**
4321  * xmlXPathNewValueTree:
4322  * @val:  the NodePtr value
4323  *
4324  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4325  * it with the tree root @val
4326  *
4327  * Returns the newly created object.
4328  */
4329 xmlXPathObjectPtr
xmlXPathNewValueTree(xmlNodePtr val)4330 xmlXPathNewValueTree(xmlNodePtr val) {
4331     xmlXPathObjectPtr ret;
4332 
4333     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4334     if (ret == NULL) {
4335         xmlXPathErrMemory(NULL, "creating result value tree\n");
4336 	return(NULL);
4337     }
4338     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4339     ret->type = XPATH_XSLT_TREE;
4340     ret->boolval = 1;
4341     ret->user = (void *) val;
4342     ret->nodesetval = xmlXPathNodeSetCreate(val);
4343 #ifdef XP_DEBUG_OBJ_USAGE
4344     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4345 #endif
4346     return(ret);
4347 }
4348 
4349 /**
4350  * xmlXPathNewNodeSetList:
4351  * @val:  an existing NodeSet
4352  *
4353  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4354  * it with the Nodeset @val
4355  *
4356  * Returns the newly created object.
4357  */
4358 xmlXPathObjectPtr
xmlXPathNewNodeSetList(xmlNodeSetPtr val)4359 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4360 {
4361     xmlXPathObjectPtr ret;
4362     int i;
4363 
4364     if (val == NULL)
4365         ret = NULL;
4366     else if (val->nodeTab == NULL)
4367         ret = xmlXPathNewNodeSet(NULL);
4368     else {
4369         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4370         if (ret) {
4371             for (i = 1; i < val->nodeNr; ++i) {
4372                 /* TODO: Propagate memory error. */
4373                 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4374 		    < 0) break;
4375 	    }
4376 	}
4377     }
4378 
4379     return (ret);
4380 }
4381 
4382 /**
4383  * xmlXPathWrapNodeSet:
4384  * @val:  the NodePtr value
4385  *
4386  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4387  *
4388  * Returns the newly created object.
4389  */
4390 xmlXPathObjectPtr
xmlXPathWrapNodeSet(xmlNodeSetPtr val)4391 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4392     xmlXPathObjectPtr ret;
4393 
4394     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4395     if (ret == NULL) {
4396         xmlXPathErrMemory(NULL, "creating node set object\n");
4397 	return(NULL);
4398     }
4399     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4400     ret->type = XPATH_NODESET;
4401     ret->nodesetval = val;
4402 #ifdef XP_DEBUG_OBJ_USAGE
4403     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4404 #endif
4405     return(ret);
4406 }
4407 
4408 /**
4409  * xmlXPathFreeNodeSetList:
4410  * @obj:  an existing NodeSetList object
4411  *
4412  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4413  * the list contrary to xmlXPathFreeObject().
4414  */
4415 void
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj)4416 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4417     if (obj == NULL) return;
4418 #ifdef XP_DEBUG_OBJ_USAGE
4419     xmlXPathDebugObjUsageReleased(NULL, obj->type);
4420 #endif
4421     xmlFree(obj);
4422 }
4423 
4424 /**
4425  * xmlXPathDifference:
4426  * @nodes1:  a node-set
4427  * @nodes2:  a node-set
4428  *
4429  * Implements the EXSLT - Sets difference() function:
4430  *    node-set set:difference (node-set, node-set)
4431  *
4432  * Returns the difference between the two node sets, or nodes1 if
4433  *         nodes2 is empty
4434  */
4435 xmlNodeSetPtr
xmlXPathDifference(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4436 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4437     xmlNodeSetPtr ret;
4438     int i, l1;
4439     xmlNodePtr cur;
4440 
4441     if (xmlXPathNodeSetIsEmpty(nodes2))
4442 	return(nodes1);
4443 
4444     /* TODO: Check memory error. */
4445     ret = xmlXPathNodeSetCreate(NULL);
4446     if (xmlXPathNodeSetIsEmpty(nodes1))
4447 	return(ret);
4448 
4449     l1 = xmlXPathNodeSetGetLength(nodes1);
4450 
4451     for (i = 0; i < l1; i++) {
4452 	cur = xmlXPathNodeSetItem(nodes1, i);
4453 	if (!xmlXPathNodeSetContains(nodes2, cur)) {
4454             /* TODO: Propagate memory error. */
4455 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4456 	        break;
4457 	}
4458     }
4459     return(ret);
4460 }
4461 
4462 /**
4463  * xmlXPathIntersection:
4464  * @nodes1:  a node-set
4465  * @nodes2:  a node-set
4466  *
4467  * Implements the EXSLT - Sets intersection() function:
4468  *    node-set set:intersection (node-set, node-set)
4469  *
4470  * Returns a node set comprising the nodes that are within both the
4471  *         node sets passed as arguments
4472  */
4473 xmlNodeSetPtr
xmlXPathIntersection(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4474 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4475     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4476     int i, l1;
4477     xmlNodePtr cur;
4478 
4479     if (ret == NULL)
4480         return(ret);
4481     if (xmlXPathNodeSetIsEmpty(nodes1))
4482 	return(ret);
4483     if (xmlXPathNodeSetIsEmpty(nodes2))
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             /* TODO: Propagate memory error. */
4492 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4493 	        break;
4494 	}
4495     }
4496     return(ret);
4497 }
4498 
4499 /**
4500  * xmlXPathDistinctSorted:
4501  * @nodes:  a node-set, sorted by document order
4502  *
4503  * Implements the EXSLT - Sets distinct() function:
4504  *    node-set set:distinct (node-set)
4505  *
4506  * Returns a subset of the nodes contained in @nodes, or @nodes if
4507  *         it is empty
4508  */
4509 xmlNodeSetPtr
xmlXPathDistinctSorted(xmlNodeSetPtr nodes)4510 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4511     xmlNodeSetPtr ret;
4512     xmlHashTablePtr hash;
4513     int i, l;
4514     xmlChar * strval;
4515     xmlNodePtr cur;
4516 
4517     if (xmlXPathNodeSetIsEmpty(nodes))
4518 	return(nodes);
4519 
4520     ret = xmlXPathNodeSetCreate(NULL);
4521     if (ret == NULL)
4522         return(ret);
4523     l = xmlXPathNodeSetGetLength(nodes);
4524     hash = xmlHashCreate (l);
4525     for (i = 0; i < l; i++) {
4526 	cur = xmlXPathNodeSetItem(nodes, i);
4527 	strval = xmlXPathCastNodeToString(cur);
4528 	if (xmlHashLookup(hash, strval) == NULL) {
4529 	    xmlHashAddEntry(hash, strval, strval);
4530             /* TODO: Propagate memory error. */
4531 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4532 	        break;
4533 	} else {
4534 	    xmlFree(strval);
4535 	}
4536     }
4537     xmlHashFree(hash, xmlHashDefaultDeallocator);
4538     return(ret);
4539 }
4540 
4541 /**
4542  * xmlXPathDistinct:
4543  * @nodes:  a node-set
4544  *
4545  * Implements the EXSLT - Sets distinct() function:
4546  *    node-set set:distinct (node-set)
4547  * @nodes is sorted by document order, then #exslSetsDistinctSorted
4548  * is called with the sorted node-set
4549  *
4550  * Returns a subset of the nodes contained in @nodes, or @nodes if
4551  *         it is empty
4552  */
4553 xmlNodeSetPtr
xmlXPathDistinct(xmlNodeSetPtr nodes)4554 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4555     if (xmlXPathNodeSetIsEmpty(nodes))
4556 	return(nodes);
4557 
4558     xmlXPathNodeSetSort(nodes);
4559     return(xmlXPathDistinctSorted(nodes));
4560 }
4561 
4562 /**
4563  * xmlXPathHasSameNodes:
4564  * @nodes1:  a node-set
4565  * @nodes2:  a node-set
4566  *
4567  * Implements the EXSLT - Sets has-same-nodes function:
4568  *    boolean set:has-same-node(node-set, node-set)
4569  *
4570  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4571  *         otherwise
4572  */
4573 int
xmlXPathHasSameNodes(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4574 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4575     int i, l;
4576     xmlNodePtr cur;
4577 
4578     if (xmlXPathNodeSetIsEmpty(nodes1) ||
4579 	xmlXPathNodeSetIsEmpty(nodes2))
4580 	return(0);
4581 
4582     l = xmlXPathNodeSetGetLength(nodes1);
4583     for (i = 0; i < l; i++) {
4584 	cur = xmlXPathNodeSetItem(nodes1, i);
4585 	if (xmlXPathNodeSetContains(nodes2, cur))
4586 	    return(1);
4587     }
4588     return(0);
4589 }
4590 
4591 /**
4592  * xmlXPathNodeLeadingSorted:
4593  * @nodes: a node-set, sorted by document order
4594  * @node: a node
4595  *
4596  * Implements the EXSLT - Sets leading() function:
4597  *    node-set set:leading (node-set, node-set)
4598  *
4599  * Returns the nodes in @nodes that precede @node in document order,
4600  *         @nodes if @node is NULL or an empty node-set if @nodes
4601  *         doesn't contain @node
4602  */
4603 xmlNodeSetPtr
xmlXPathNodeLeadingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4604 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4605     int i, l;
4606     xmlNodePtr cur;
4607     xmlNodeSetPtr ret;
4608 
4609     if (node == NULL)
4610 	return(nodes);
4611 
4612     ret = xmlXPathNodeSetCreate(NULL);
4613     if (ret == NULL)
4614         return(ret);
4615     if (xmlXPathNodeSetIsEmpty(nodes) ||
4616 	(!xmlXPathNodeSetContains(nodes, node)))
4617 	return(ret);
4618 
4619     l = xmlXPathNodeSetGetLength(nodes);
4620     for (i = 0; i < l; i++) {
4621 	cur = xmlXPathNodeSetItem(nodes, i);
4622 	if (cur == node)
4623 	    break;
4624         /* TODO: Propagate memory error. */
4625 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4626 	    break;
4627     }
4628     return(ret);
4629 }
4630 
4631 /**
4632  * xmlXPathNodeLeading:
4633  * @nodes:  a node-set
4634  * @node:  a node
4635  *
4636  * Implements the EXSLT - Sets leading() function:
4637  *    node-set set:leading (node-set, node-set)
4638  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4639  * is called.
4640  *
4641  * Returns the nodes in @nodes that precede @node in document order,
4642  *         @nodes if @node is NULL or an empty node-set if @nodes
4643  *         doesn't contain @node
4644  */
4645 xmlNodeSetPtr
xmlXPathNodeLeading(xmlNodeSetPtr nodes,xmlNodePtr node)4646 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4647     xmlXPathNodeSetSort(nodes);
4648     return(xmlXPathNodeLeadingSorted(nodes, node));
4649 }
4650 
4651 /**
4652  * xmlXPathLeadingSorted:
4653  * @nodes1:  a node-set, sorted by document order
4654  * @nodes2:  a node-set, sorted by document order
4655  *
4656  * Implements the EXSLT - Sets leading() function:
4657  *    node-set set:leading (node-set, node-set)
4658  *
4659  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4660  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4661  *         an empty node-set if @nodes1 doesn't contain @nodes2
4662  */
4663 xmlNodeSetPtr
xmlXPathLeadingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4664 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4665     if (xmlXPathNodeSetIsEmpty(nodes2))
4666 	return(nodes1);
4667     return(xmlXPathNodeLeadingSorted(nodes1,
4668 				     xmlXPathNodeSetItem(nodes2, 1)));
4669 }
4670 
4671 /**
4672  * xmlXPathLeading:
4673  * @nodes1:  a node-set
4674  * @nodes2:  a node-set
4675  *
4676  * Implements the EXSLT - Sets leading() function:
4677  *    node-set set:leading (node-set, node-set)
4678  * @nodes1 and @nodes2 are sorted by document order, then
4679  * #exslSetsLeadingSorted is called.
4680  *
4681  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4682  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4683  *         an empty node-set if @nodes1 doesn't contain @nodes2
4684  */
4685 xmlNodeSetPtr
xmlXPathLeading(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4686 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4687     if (xmlXPathNodeSetIsEmpty(nodes2))
4688 	return(nodes1);
4689     if (xmlXPathNodeSetIsEmpty(nodes1))
4690 	return(xmlXPathNodeSetCreate(NULL));
4691     xmlXPathNodeSetSort(nodes1);
4692     xmlXPathNodeSetSort(nodes2);
4693     return(xmlXPathNodeLeadingSorted(nodes1,
4694 				     xmlXPathNodeSetItem(nodes2, 1)));
4695 }
4696 
4697 /**
4698  * xmlXPathNodeTrailingSorted:
4699  * @nodes: a node-set, sorted by document order
4700  * @node: a node
4701  *
4702  * Implements the EXSLT - Sets trailing() function:
4703  *    node-set set:trailing (node-set, node-set)
4704  *
4705  * Returns the nodes in @nodes that follow @node in document order,
4706  *         @nodes if @node is NULL or an empty node-set if @nodes
4707  *         doesn't contain @node
4708  */
4709 xmlNodeSetPtr
xmlXPathNodeTrailingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4710 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4711     int i, l;
4712     xmlNodePtr cur;
4713     xmlNodeSetPtr ret;
4714 
4715     if (node == NULL)
4716 	return(nodes);
4717 
4718     ret = xmlXPathNodeSetCreate(NULL);
4719     if (ret == NULL)
4720         return(ret);
4721     if (xmlXPathNodeSetIsEmpty(nodes) ||
4722 	(!xmlXPathNodeSetContains(nodes, node)))
4723 	return(ret);
4724 
4725     l = xmlXPathNodeSetGetLength(nodes);
4726     for (i = l - 1; i >= 0; i--) {
4727 	cur = xmlXPathNodeSetItem(nodes, i);
4728 	if (cur == node)
4729 	    break;
4730         /* TODO: Propagate memory error. */
4731 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4732 	    break;
4733     }
4734     xmlXPathNodeSetSort(ret);	/* bug 413451 */
4735     return(ret);
4736 }
4737 
4738 /**
4739  * xmlXPathNodeTrailing:
4740  * @nodes:  a node-set
4741  * @node:  a node
4742  *
4743  * Implements the EXSLT - Sets trailing() function:
4744  *    node-set set:trailing (node-set, node-set)
4745  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4746  * is called.
4747  *
4748  * Returns the nodes in @nodes that follow @node in document order,
4749  *         @nodes if @node is NULL or an empty node-set if @nodes
4750  *         doesn't contain @node
4751  */
4752 xmlNodeSetPtr
xmlXPathNodeTrailing(xmlNodeSetPtr nodes,xmlNodePtr node)4753 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4754     xmlXPathNodeSetSort(nodes);
4755     return(xmlXPathNodeTrailingSorted(nodes, node));
4756 }
4757 
4758 /**
4759  * xmlXPathTrailingSorted:
4760  * @nodes1:  a node-set, sorted by document order
4761  * @nodes2:  a node-set, sorted by document order
4762  *
4763  * Implements the EXSLT - Sets trailing() function:
4764  *    node-set set:trailing (node-set, node-set)
4765  *
4766  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4767  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4768  *         an empty node-set if @nodes1 doesn't contain @nodes2
4769  */
4770 xmlNodeSetPtr
xmlXPathTrailingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4771 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4772     if (xmlXPathNodeSetIsEmpty(nodes2))
4773 	return(nodes1);
4774     return(xmlXPathNodeTrailingSorted(nodes1,
4775 				      xmlXPathNodeSetItem(nodes2, 0)));
4776 }
4777 
4778 /**
4779  * xmlXPathTrailing:
4780  * @nodes1:  a node-set
4781  * @nodes2:  a node-set
4782  *
4783  * Implements the EXSLT - Sets trailing() function:
4784  *    node-set set:trailing (node-set, node-set)
4785  * @nodes1 and @nodes2 are sorted by document order, then
4786  * #xmlXPathTrailingSorted is called.
4787  *
4788  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4789  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4790  *         an empty node-set if @nodes1 doesn't contain @nodes2
4791  */
4792 xmlNodeSetPtr
xmlXPathTrailing(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4793 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4794     if (xmlXPathNodeSetIsEmpty(nodes2))
4795 	return(nodes1);
4796     if (xmlXPathNodeSetIsEmpty(nodes1))
4797 	return(xmlXPathNodeSetCreate(NULL));
4798     xmlXPathNodeSetSort(nodes1);
4799     xmlXPathNodeSetSort(nodes2);
4800     return(xmlXPathNodeTrailingSorted(nodes1,
4801 				      xmlXPathNodeSetItem(nodes2, 0)));
4802 }
4803 
4804 /************************************************************************
4805  *									*
4806  *		Routines to handle extra functions			*
4807  *									*
4808  ************************************************************************/
4809 
4810 /**
4811  * xmlXPathRegisterFunc:
4812  * @ctxt:  the XPath context
4813  * @name:  the function name
4814  * @f:  the function implementation or NULL
4815  *
4816  * Register a new function. If @f is NULL it unregisters the function
4817  *
4818  * Returns 0 in case of success, -1 in case of error
4819  */
4820 int
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathFunction f)4821 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4822 		     xmlXPathFunction f) {
4823     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4824 }
4825 
4826 /**
4827  * xmlXPathRegisterFuncNS:
4828  * @ctxt:  the XPath context
4829  * @name:  the function name
4830  * @ns_uri:  the function namespace URI
4831  * @f:  the function implementation or NULL
4832  *
4833  * Register a new function. If @f is NULL it unregisters the function
4834  *
4835  * Returns 0 in case of success, -1 in case of error
4836  */
4837 int
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathFunction f)4838 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4839 		       const xmlChar *ns_uri, xmlXPathFunction f) {
4840     if (ctxt == NULL)
4841 	return(-1);
4842     if (name == NULL)
4843 	return(-1);
4844 
4845     if (ctxt->funcHash == NULL)
4846 	ctxt->funcHash = xmlHashCreate(0);
4847     if (ctxt->funcHash == NULL)
4848 	return(-1);
4849     if (f == NULL)
4850         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4851 XML_IGNORE_PEDANTIC_WARNINGS
4852     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4853 XML_POP_WARNINGS
4854 }
4855 
4856 /**
4857  * xmlXPathRegisterFuncLookup:
4858  * @ctxt:  the XPath context
4859  * @f:  the lookup function
4860  * @funcCtxt:  the lookup data
4861  *
4862  * Registers an external mechanism to do function lookup.
4863  */
4864 void
xmlXPathRegisterFuncLookup(xmlXPathContextPtr ctxt,xmlXPathFuncLookupFunc f,void * funcCtxt)4865 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4866 			    xmlXPathFuncLookupFunc f,
4867 			    void *funcCtxt) {
4868     if (ctxt == NULL)
4869 	return;
4870     ctxt->funcLookupFunc = f;
4871     ctxt->funcLookupData = funcCtxt;
4872 }
4873 
4874 /**
4875  * xmlXPathFunctionLookup:
4876  * @ctxt:  the XPath context
4877  * @name:  the function name
4878  *
4879  * Search in the Function array of the context for the given
4880  * function.
4881  *
4882  * Returns the xmlXPathFunction or NULL if not found
4883  */
4884 xmlXPathFunction
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt,const xmlChar * name)4885 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4886     if (ctxt == NULL)
4887 	return (NULL);
4888 
4889     if (ctxt->funcLookupFunc != NULL) {
4890 	xmlXPathFunction ret;
4891 	xmlXPathFuncLookupFunc f;
4892 
4893 	f = ctxt->funcLookupFunc;
4894 	ret = f(ctxt->funcLookupData, name, NULL);
4895 	if (ret != NULL)
4896 	    return(ret);
4897     }
4898     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4899 }
4900 
4901 /**
4902  * xmlXPathFunctionLookupNS:
4903  * @ctxt:  the XPath context
4904  * @name:  the function name
4905  * @ns_uri:  the function namespace URI
4906  *
4907  * Search in the Function array of the context for the given
4908  * function.
4909  *
4910  * Returns the xmlXPathFunction or NULL if not found
4911  */
4912 xmlXPathFunction
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4913 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4914 			 const xmlChar *ns_uri) {
4915     xmlXPathFunction ret;
4916 
4917     if (ctxt == NULL)
4918 	return(NULL);
4919     if (name == NULL)
4920 	return(NULL);
4921 
4922     if (ctxt->funcLookupFunc != NULL) {
4923 	xmlXPathFuncLookupFunc f;
4924 
4925 	f = ctxt->funcLookupFunc;
4926 	ret = f(ctxt->funcLookupData, name, ns_uri);
4927 	if (ret != NULL)
4928 	    return(ret);
4929     }
4930 
4931     if (ctxt->funcHash == NULL)
4932 	return(NULL);
4933 
4934 XML_IGNORE_PEDANTIC_WARNINGS
4935     ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4936 XML_POP_WARNINGS
4937     return(ret);
4938 }
4939 
4940 /**
4941  * xmlXPathRegisteredFuncsCleanup:
4942  * @ctxt:  the XPath context
4943  *
4944  * Cleanup the XPath context data associated to registered functions
4945  */
4946 void
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt)4947 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4948     if (ctxt == NULL)
4949 	return;
4950 
4951     xmlHashFree(ctxt->funcHash, NULL);
4952     ctxt->funcHash = NULL;
4953 }
4954 
4955 /************************************************************************
4956  *									*
4957  *			Routines to handle Variables			*
4958  *									*
4959  ************************************************************************/
4960 
4961 /**
4962  * xmlXPathRegisterVariable:
4963  * @ctxt:  the XPath context
4964  * @name:  the variable name
4965  * @value:  the variable value or NULL
4966  *
4967  * Register a new variable value. If @value is NULL it unregisters
4968  * the variable
4969  *
4970  * Returns 0 in case of success, -1 in case of error
4971  */
4972 int
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathObjectPtr value)4973 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4974 			 xmlXPathObjectPtr value) {
4975     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4976 }
4977 
4978 /**
4979  * xmlXPathRegisterVariableNS:
4980  * @ctxt:  the XPath context
4981  * @name:  the variable name
4982  * @ns_uri:  the variable namespace URI
4983  * @value:  the variable value or NULL
4984  *
4985  * Register a new variable value. If @value is NULL it unregisters
4986  * the variable
4987  *
4988  * Returns 0 in case of success, -1 in case of error
4989  */
4990 int
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathObjectPtr value)4991 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4992 			   const xmlChar *ns_uri,
4993 			   xmlXPathObjectPtr value) {
4994     if (ctxt == NULL)
4995 	return(-1);
4996     if (name == NULL)
4997 	return(-1);
4998 
4999     if (ctxt->varHash == NULL)
5000 	ctxt->varHash = xmlHashCreate(0);
5001     if (ctxt->varHash == NULL)
5002 	return(-1);
5003     if (value == NULL)
5004         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5005 	                           xmlXPathFreeObjectEntry));
5006     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5007 			       (void *) value, xmlXPathFreeObjectEntry));
5008 }
5009 
5010 /**
5011  * xmlXPathRegisterVariableLookup:
5012  * @ctxt:  the XPath context
5013  * @f:  the lookup function
5014  * @data:  the lookup data
5015  *
5016  * register an external mechanism to do variable lookup
5017  */
5018 void
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,xmlXPathVariableLookupFunc f,void * data)5019 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5020 	 xmlXPathVariableLookupFunc f, void *data) {
5021     if (ctxt == NULL)
5022 	return;
5023     ctxt->varLookupFunc = f;
5024     ctxt->varLookupData = data;
5025 }
5026 
5027 /**
5028  * xmlXPathVariableLookup:
5029  * @ctxt:  the XPath context
5030  * @name:  the variable name
5031  *
5032  * Search in the Variable array of the context for the given
5033  * variable value.
5034  *
5035  * Returns a copy of the value or NULL if not found
5036  */
5037 xmlXPathObjectPtr
xmlXPathVariableLookup(xmlXPathContextPtr ctxt,const xmlChar * name)5038 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5039     if (ctxt == NULL)
5040 	return(NULL);
5041 
5042     if (ctxt->varLookupFunc != NULL) {
5043 	xmlXPathObjectPtr ret;
5044 
5045 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5046 	        (ctxt->varLookupData, name, NULL);
5047 	return(ret);
5048     }
5049     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5050 }
5051 
5052 /**
5053  * xmlXPathVariableLookupNS:
5054  * @ctxt:  the XPath context
5055  * @name:  the variable name
5056  * @ns_uri:  the variable namespace URI
5057  *
5058  * Search in the Variable array of the context for the given
5059  * variable value.
5060  *
5061  * Returns the a copy of the value or NULL if not found
5062  */
5063 xmlXPathObjectPtr
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)5064 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5065 			 const xmlChar *ns_uri) {
5066     if (ctxt == NULL)
5067 	return(NULL);
5068 
5069     if (ctxt->varLookupFunc != NULL) {
5070 	xmlXPathObjectPtr ret;
5071 
5072 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5073 	        (ctxt->varLookupData, name, ns_uri);
5074 	if (ret != NULL) return(ret);
5075     }
5076 
5077     if (ctxt->varHash == NULL)
5078 	return(NULL);
5079     if (name == NULL)
5080 	return(NULL);
5081 
5082     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5083 		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5084 }
5085 
5086 /**
5087  * xmlXPathRegisteredVariablesCleanup:
5088  * @ctxt:  the XPath context
5089  *
5090  * Cleanup the XPath context data associated to registered variables
5091  */
5092 void
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt)5093 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5094     if (ctxt == NULL)
5095 	return;
5096 
5097     xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5098     ctxt->varHash = NULL;
5099 }
5100 
5101 /**
5102  * xmlXPathRegisterNs:
5103  * @ctxt:  the XPath context
5104  * @prefix:  the namespace prefix cannot be NULL or empty string
5105  * @ns_uri:  the namespace name
5106  *
5107  * Register a new namespace. If @ns_uri is NULL it unregisters
5108  * the namespace
5109  *
5110  * Returns 0 in case of success, -1 in case of error
5111  */
5112 int
xmlXPathRegisterNs(xmlXPathContextPtr ctxt,const xmlChar * prefix,const xmlChar * ns_uri)5113 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5114 			   const xmlChar *ns_uri) {
5115     if (ctxt == NULL)
5116 	return(-1);
5117     if (prefix == NULL)
5118 	return(-1);
5119     if (prefix[0] == 0)
5120 	return(-1);
5121 
5122     if (ctxt->nsHash == NULL)
5123 	ctxt->nsHash = xmlHashCreate(10);
5124     if (ctxt->nsHash == NULL)
5125 	return(-1);
5126     if (ns_uri == NULL)
5127         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5128 	                          xmlHashDefaultDeallocator));
5129     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5130 			      xmlHashDefaultDeallocator));
5131 }
5132 
5133 /**
5134  * xmlXPathNsLookup:
5135  * @ctxt:  the XPath context
5136  * @prefix:  the namespace prefix value
5137  *
5138  * Search in the namespace declaration array of the context for the given
5139  * namespace name associated to the given prefix
5140  *
5141  * Returns the value or NULL if not found
5142  */
5143 const xmlChar *
xmlXPathNsLookup(xmlXPathContextPtr ctxt,const xmlChar * prefix)5144 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5145     if (ctxt == NULL)
5146 	return(NULL);
5147     if (prefix == NULL)
5148 	return(NULL);
5149 
5150 #ifdef XML_XML_NAMESPACE
5151     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5152 	return(XML_XML_NAMESPACE);
5153 #endif
5154 
5155     if (ctxt->namespaces != NULL) {
5156 	int i;
5157 
5158 	for (i = 0;i < ctxt->nsNr;i++) {
5159 	    if ((ctxt->namespaces[i] != NULL) &&
5160 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5161 		return(ctxt->namespaces[i]->href);
5162 	}
5163     }
5164 
5165     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5166 }
5167 
5168 /**
5169  * xmlXPathRegisteredNsCleanup:
5170  * @ctxt:  the XPath context
5171  *
5172  * Cleanup the XPath context data associated to registered variables
5173  */
5174 void
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt)5175 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5176     if (ctxt == NULL)
5177 	return;
5178 
5179     xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5180     ctxt->nsHash = NULL;
5181 }
5182 
5183 /************************************************************************
5184  *									*
5185  *			Routines to handle Values			*
5186  *									*
5187  ************************************************************************/
5188 
5189 /* Allocations are terrible, one needs to optimize all this !!! */
5190 
5191 /**
5192  * xmlXPathNewFloat:
5193  * @val:  the double value
5194  *
5195  * Create a new xmlXPathObjectPtr of type double and of value @val
5196  *
5197  * Returns the newly created object.
5198  */
5199 xmlXPathObjectPtr
xmlXPathNewFloat(double val)5200 xmlXPathNewFloat(double val) {
5201     xmlXPathObjectPtr ret;
5202 
5203     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5204     if (ret == NULL) {
5205         xmlXPathErrMemory(NULL, "creating float object\n");
5206 	return(NULL);
5207     }
5208     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5209     ret->type = XPATH_NUMBER;
5210     ret->floatval = val;
5211 #ifdef XP_DEBUG_OBJ_USAGE
5212     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5213 #endif
5214     return(ret);
5215 }
5216 
5217 /**
5218  * xmlXPathNewBoolean:
5219  * @val:  the boolean value
5220  *
5221  * Create a new xmlXPathObjectPtr of type boolean and of value @val
5222  *
5223  * Returns the newly created object.
5224  */
5225 xmlXPathObjectPtr
xmlXPathNewBoolean(int val)5226 xmlXPathNewBoolean(int val) {
5227     xmlXPathObjectPtr ret;
5228 
5229     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5230     if (ret == NULL) {
5231         xmlXPathErrMemory(NULL, "creating boolean object\n");
5232 	return(NULL);
5233     }
5234     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5235     ret->type = XPATH_BOOLEAN;
5236     ret->boolval = (val != 0);
5237 #ifdef XP_DEBUG_OBJ_USAGE
5238     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5239 #endif
5240     return(ret);
5241 }
5242 
5243 /**
5244  * xmlXPathNewString:
5245  * @val:  the xmlChar * value
5246  *
5247  * Create a new xmlXPathObjectPtr of type string and of value @val
5248  *
5249  * Returns the newly created object.
5250  */
5251 xmlXPathObjectPtr
xmlXPathNewString(const xmlChar * val)5252 xmlXPathNewString(const xmlChar *val) {
5253     xmlXPathObjectPtr ret;
5254 
5255     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5256     if (ret == NULL) {
5257         xmlXPathErrMemory(NULL, "creating string object\n");
5258 	return(NULL);
5259     }
5260     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5261     ret->type = XPATH_STRING;
5262     if (val != NULL)
5263 	ret->stringval = xmlStrdup(val);
5264     else
5265 	ret->stringval = xmlStrdup((const xmlChar *)"");
5266 #ifdef XP_DEBUG_OBJ_USAGE
5267     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5268 #endif
5269     return(ret);
5270 }
5271 
5272 /**
5273  * xmlXPathWrapString:
5274  * @val:  the xmlChar * value
5275  *
5276  * Wraps the @val string into an XPath object.
5277  *
5278  * Returns the newly created object.
5279  */
5280 xmlXPathObjectPtr
xmlXPathWrapString(xmlChar * val)5281 xmlXPathWrapString (xmlChar *val) {
5282     xmlXPathObjectPtr ret;
5283 
5284     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5285     if (ret == NULL) {
5286         xmlXPathErrMemory(NULL, "creating string object\n");
5287 	return(NULL);
5288     }
5289     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5290     ret->type = XPATH_STRING;
5291     ret->stringval = val;
5292 #ifdef XP_DEBUG_OBJ_USAGE
5293     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5294 #endif
5295     return(ret);
5296 }
5297 
5298 /**
5299  * xmlXPathNewCString:
5300  * @val:  the char * value
5301  *
5302  * Create a new xmlXPathObjectPtr of type string and of value @val
5303  *
5304  * Returns the newly created object.
5305  */
5306 xmlXPathObjectPtr
xmlXPathNewCString(const char * val)5307 xmlXPathNewCString(const char *val) {
5308     xmlXPathObjectPtr ret;
5309 
5310     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5311     if (ret == NULL) {
5312         xmlXPathErrMemory(NULL, "creating string object\n");
5313 	return(NULL);
5314     }
5315     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5316     ret->type = XPATH_STRING;
5317     ret->stringval = xmlStrdup(BAD_CAST val);
5318 #ifdef XP_DEBUG_OBJ_USAGE
5319     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5320 #endif
5321     return(ret);
5322 }
5323 
5324 /**
5325  * xmlXPathWrapCString:
5326  * @val:  the char * value
5327  *
5328  * Wraps a string into an XPath object.
5329  *
5330  * Returns the newly created object.
5331  */
5332 xmlXPathObjectPtr
xmlXPathWrapCString(char * val)5333 xmlXPathWrapCString (char * val) {
5334     return(xmlXPathWrapString((xmlChar *)(val)));
5335 }
5336 
5337 /**
5338  * xmlXPathWrapExternal:
5339  * @val:  the user data
5340  *
5341  * Wraps the @val data into an XPath object.
5342  *
5343  * Returns the newly created object.
5344  */
5345 xmlXPathObjectPtr
xmlXPathWrapExternal(void * val)5346 xmlXPathWrapExternal (void *val) {
5347     xmlXPathObjectPtr ret;
5348 
5349     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5350     if (ret == NULL) {
5351         xmlXPathErrMemory(NULL, "creating user object\n");
5352 	return(NULL);
5353     }
5354     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5355     ret->type = XPATH_USERS;
5356     ret->user = val;
5357 #ifdef XP_DEBUG_OBJ_USAGE
5358     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5359 #endif
5360     return(ret);
5361 }
5362 
5363 /**
5364  * xmlXPathObjectCopy:
5365  * @val:  the original object
5366  *
5367  * allocate a new copy of a given object
5368  *
5369  * Returns the newly created object.
5370  */
5371 xmlXPathObjectPtr
xmlXPathObjectCopy(xmlXPathObjectPtr val)5372 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5373     xmlXPathObjectPtr ret;
5374 
5375     if (val == NULL)
5376 	return(NULL);
5377 
5378     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5379     if (ret == NULL) {
5380         xmlXPathErrMemory(NULL, "copying object\n");
5381 	return(NULL);
5382     }
5383     memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5384 #ifdef XP_DEBUG_OBJ_USAGE
5385     xmlXPathDebugObjUsageRequested(NULL, val->type);
5386 #endif
5387     switch (val->type) {
5388 	case XPATH_BOOLEAN:
5389 	case XPATH_NUMBER:
5390 	case XPATH_POINT:
5391 	case XPATH_RANGE:
5392 	    break;
5393 	case XPATH_STRING:
5394 	    ret->stringval = xmlStrdup(val->stringval);
5395 	    break;
5396 	case XPATH_XSLT_TREE:
5397 #if 0
5398 /*
5399   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5400   this previous handling is no longer correct, and can cause some serious
5401   problems (ref. bug 145547)
5402 */
5403 	    if ((val->nodesetval != NULL) &&
5404 		(val->nodesetval->nodeTab != NULL)) {
5405 		xmlNodePtr cur, tmp;
5406 		xmlDocPtr top;
5407 
5408 		ret->boolval = 1;
5409 		top =  xmlNewDoc(NULL);
5410 		top->name = (char *)
5411 		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
5412 		ret->user = top;
5413 		if (top != NULL) {
5414 		    top->doc = top;
5415 		    cur = val->nodesetval->nodeTab[0]->children;
5416 		    while (cur != NULL) {
5417 			tmp = xmlDocCopyNode(cur, top, 1);
5418 			xmlAddChild((xmlNodePtr) top, tmp);
5419 			cur = cur->next;
5420 		    }
5421 		}
5422 
5423 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5424 	    } else
5425 		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5426 	    /* Deallocate the copied tree value */
5427 	    break;
5428 #endif
5429 	case XPATH_NODESET:
5430             /* TODO: Check memory error. */
5431 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5432 	    /* Do not deallocate the copied tree value */
5433 	    ret->boolval = 0;
5434 	    break;
5435 	case XPATH_LOCATIONSET:
5436 #ifdef LIBXML_XPTR_ENABLED
5437 	{
5438 	    xmlLocationSetPtr loc = val->user;
5439 	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5440 	    break;
5441 	}
5442 #endif
5443         case XPATH_USERS:
5444 	    ret->user = val->user;
5445 	    break;
5446         case XPATH_UNDEFINED:
5447 	    xmlGenericError(xmlGenericErrorContext,
5448 		    "xmlXPathObjectCopy: unsupported type %d\n",
5449 		    val->type);
5450 	    break;
5451     }
5452     return(ret);
5453 }
5454 
5455 /**
5456  * xmlXPathFreeObject:
5457  * @obj:  the object to free
5458  *
5459  * Free up an xmlXPathObjectPtr object.
5460  */
5461 void
xmlXPathFreeObject(xmlXPathObjectPtr obj)5462 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5463     if (obj == NULL) return;
5464     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5465 	if (obj->boolval) {
5466 #if 0
5467 	    if (obj->user != NULL) {
5468                 xmlXPathFreeNodeSet(obj->nodesetval);
5469 		xmlFreeNodeList((xmlNodePtr) obj->user);
5470 	    } else
5471 #endif
5472 	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5473 	    if (obj->nodesetval != NULL)
5474 		xmlXPathFreeValueTree(obj->nodesetval);
5475 	} else {
5476 	    if (obj->nodesetval != NULL)
5477 		xmlXPathFreeNodeSet(obj->nodesetval);
5478 	}
5479 #ifdef LIBXML_XPTR_ENABLED
5480     } else if (obj->type == XPATH_LOCATIONSET) {
5481 	if (obj->user != NULL)
5482 	    xmlXPtrFreeLocationSet(obj->user);
5483 #endif
5484     } else if (obj->type == XPATH_STRING) {
5485 	if (obj->stringval != NULL)
5486 	    xmlFree(obj->stringval);
5487     }
5488 #ifdef XP_DEBUG_OBJ_USAGE
5489     xmlXPathDebugObjUsageReleased(NULL, obj->type);
5490 #endif
5491     xmlFree(obj);
5492 }
5493 
5494 static void
xmlXPathFreeObjectEntry(void * obj,const xmlChar * name ATTRIBUTE_UNUSED)5495 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5496     xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5497 }
5498 
5499 /**
5500  * xmlXPathReleaseObject:
5501  * @obj:  the xmlXPathObjectPtr to free or to cache
5502  *
5503  * Depending on the state of the cache this frees the given
5504  * XPath object or stores it in the cache.
5505  */
5506 static void
xmlXPathReleaseObject(xmlXPathContextPtr ctxt,xmlXPathObjectPtr obj)5507 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5508 {
5509 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5510 	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5511     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5512 
5513 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5514 
5515     if (obj == NULL)
5516 	return;
5517     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5518 	 xmlXPathFreeObject(obj);
5519     } else {
5520 	xmlXPathContextCachePtr cache =
5521 	    (xmlXPathContextCachePtr) ctxt->cache;
5522 
5523 	switch (obj->type) {
5524 	    case XPATH_NODESET:
5525 	    case XPATH_XSLT_TREE:
5526 		if (obj->nodesetval != NULL) {
5527 		    if (obj->boolval) {
5528 			/*
5529 			* It looks like the @boolval is used for
5530 			* evaluation if this an XSLT Result Tree Fragment.
5531 			* TODO: Check if this assumption is correct.
5532 			*/
5533 			obj->type = XPATH_XSLT_TREE; /* just for debugging */
5534 			xmlXPathFreeValueTree(obj->nodesetval);
5535 			obj->nodesetval = NULL;
5536 		    } else if ((obj->nodesetval->nodeMax <= 40) &&
5537 			(XP_CACHE_WANTS(cache->nodesetObjs,
5538 					cache->maxNodeset)))
5539 		    {
5540 			XP_CACHE_ADD(cache->nodesetObjs, obj);
5541 			goto obj_cached;
5542 		    } else {
5543 			xmlXPathFreeNodeSet(obj->nodesetval);
5544 			obj->nodesetval = NULL;
5545 		    }
5546 		}
5547 		break;
5548 	    case XPATH_STRING:
5549 		if (obj->stringval != NULL)
5550 		    xmlFree(obj->stringval);
5551 
5552 		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5553 		    XP_CACHE_ADD(cache->stringObjs, obj);
5554 		    goto obj_cached;
5555 		}
5556 		break;
5557 	    case XPATH_BOOLEAN:
5558 		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5559 		    XP_CACHE_ADD(cache->booleanObjs, obj);
5560 		    goto obj_cached;
5561 		}
5562 		break;
5563 	    case XPATH_NUMBER:
5564 		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5565 		    XP_CACHE_ADD(cache->numberObjs, obj);
5566 		    goto obj_cached;
5567 		}
5568 		break;
5569 #ifdef LIBXML_XPTR_ENABLED
5570 	    case XPATH_LOCATIONSET:
5571 		if (obj->user != NULL) {
5572 		    xmlXPtrFreeLocationSet(obj->user);
5573 		}
5574 		goto free_obj;
5575 #endif
5576 	    default:
5577 		goto free_obj;
5578 	}
5579 
5580 	/*
5581 	* Fallback to adding to the misc-objects slot.
5582 	*/
5583 	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5584 	    XP_CACHE_ADD(cache->miscObjs, obj);
5585 	} else
5586 	    goto free_obj;
5587 
5588 obj_cached:
5589 
5590 #ifdef XP_DEBUG_OBJ_USAGE
5591 	xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5592 #endif
5593 
5594 	if (obj->nodesetval != NULL) {
5595 	    xmlNodeSetPtr tmpset = obj->nodesetval;
5596 
5597 	    /*
5598 	    * TODO: Due to those nasty ns-nodes, we need to traverse
5599 	    *  the list and free the ns-nodes.
5600 	    * URGENT TODO: Check if it's actually slowing things down.
5601 	    *  Maybe we shouldn't try to preserve the list.
5602 	    */
5603 	    if (tmpset->nodeNr > 1) {
5604 		int i;
5605 		xmlNodePtr node;
5606 
5607 		for (i = 0; i < tmpset->nodeNr; i++) {
5608 		    node = tmpset->nodeTab[i];
5609 		    if ((node != NULL) &&
5610 			(node->type == XML_NAMESPACE_DECL))
5611 		    {
5612 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5613 		    }
5614 		}
5615 	    } else if (tmpset->nodeNr == 1) {
5616 		if ((tmpset->nodeTab[0] != NULL) &&
5617 		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5618 		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5619 	    }
5620 	    tmpset->nodeNr = 0;
5621 	    memset(obj, 0, sizeof(xmlXPathObject));
5622 	    obj->nodesetval = tmpset;
5623 	} else
5624 	    memset(obj, 0, sizeof(xmlXPathObject));
5625 
5626 	return;
5627 
5628 free_obj:
5629 	/*
5630 	* Cache is full; free the object.
5631 	*/
5632 	if (obj->nodesetval != NULL)
5633 	    xmlXPathFreeNodeSet(obj->nodesetval);
5634 #ifdef XP_DEBUG_OBJ_USAGE
5635 	xmlXPathDebugObjUsageReleased(NULL, obj->type);
5636 #endif
5637 	xmlFree(obj);
5638     }
5639     return;
5640 }
5641 
5642 
5643 /************************************************************************
5644  *									*
5645  *			Type Casting Routines				*
5646  *									*
5647  ************************************************************************/
5648 
5649 /**
5650  * xmlXPathCastBooleanToString:
5651  * @val:  a boolean
5652  *
5653  * Converts a boolean to its string value.
5654  *
5655  * Returns a newly allocated string.
5656  */
5657 xmlChar *
xmlXPathCastBooleanToString(int val)5658 xmlXPathCastBooleanToString (int val) {
5659     xmlChar *ret;
5660     if (val)
5661 	ret = xmlStrdup((const xmlChar *) "true");
5662     else
5663 	ret = xmlStrdup((const xmlChar *) "false");
5664     return(ret);
5665 }
5666 
5667 /**
5668  * xmlXPathCastNumberToString:
5669  * @val:  a number
5670  *
5671  * Converts a number to its string value.
5672  *
5673  * Returns a newly allocated string.
5674  */
5675 xmlChar *
xmlXPathCastNumberToString(double val)5676 xmlXPathCastNumberToString (double val) {
5677     xmlChar *ret;
5678     switch (xmlXPathIsInf(val)) {
5679     case 1:
5680 	ret = xmlStrdup((const xmlChar *) "Infinity");
5681 	break;
5682     case -1:
5683 	ret = xmlStrdup((const xmlChar *) "-Infinity");
5684 	break;
5685     default:
5686 	if (xmlXPathIsNaN(val)) {
5687 	    ret = xmlStrdup((const xmlChar *) "NaN");
5688 	} else if (val == 0) {
5689             /* Omit sign for negative zero. */
5690 	    ret = xmlStrdup((const xmlChar *) "0");
5691 	} else {
5692 	    /* could be improved */
5693 	    char buf[100];
5694 	    xmlXPathFormatNumber(val, buf, 99);
5695 	    buf[99] = 0;
5696 	    ret = xmlStrdup((const xmlChar *) buf);
5697 	}
5698     }
5699     return(ret);
5700 }
5701 
5702 /**
5703  * xmlXPathCastNodeToString:
5704  * @node:  a node
5705  *
5706  * Converts a node to its string value.
5707  *
5708  * Returns a newly allocated string.
5709  */
5710 xmlChar *
xmlXPathCastNodeToString(xmlNodePtr node)5711 xmlXPathCastNodeToString (xmlNodePtr node) {
5712 xmlChar *ret;
5713     if ((ret = xmlNodeGetContent(node)) == NULL)
5714 	ret = xmlStrdup((const xmlChar *) "");
5715     return(ret);
5716 }
5717 
5718 /**
5719  * xmlXPathCastNodeSetToString:
5720  * @ns:  a node-set
5721  *
5722  * Converts a node-set to its string value.
5723  *
5724  * Returns a newly allocated string.
5725  */
5726 xmlChar *
xmlXPathCastNodeSetToString(xmlNodeSetPtr ns)5727 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5728     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5729 	return(xmlStrdup((const xmlChar *) ""));
5730 
5731     if (ns->nodeNr > 1)
5732 	xmlXPathNodeSetSort(ns);
5733     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5734 }
5735 
5736 /**
5737  * xmlXPathCastToString:
5738  * @val:  an XPath object
5739  *
5740  * Converts an existing object to its string() equivalent
5741  *
5742  * Returns the allocated string value of the object, NULL in case of error.
5743  *         It's up to the caller to free the string memory with xmlFree().
5744  */
5745 xmlChar *
xmlXPathCastToString(xmlXPathObjectPtr val)5746 xmlXPathCastToString(xmlXPathObjectPtr val) {
5747     xmlChar *ret = NULL;
5748 
5749     if (val == NULL)
5750 	return(xmlStrdup((const xmlChar *) ""));
5751     switch (val->type) {
5752 	case XPATH_UNDEFINED:
5753 #ifdef DEBUG_EXPR
5754 	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5755 #endif
5756 	    ret = xmlStrdup((const xmlChar *) "");
5757 	    break;
5758         case XPATH_NODESET:
5759         case XPATH_XSLT_TREE:
5760 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
5761 	    break;
5762 	case XPATH_STRING:
5763 	    return(xmlStrdup(val->stringval));
5764         case XPATH_BOOLEAN:
5765 	    ret = xmlXPathCastBooleanToString(val->boolval);
5766 	    break;
5767 	case XPATH_NUMBER: {
5768 	    ret = xmlXPathCastNumberToString(val->floatval);
5769 	    break;
5770 	}
5771 	case XPATH_USERS:
5772 	case XPATH_POINT:
5773 	case XPATH_RANGE:
5774 	case XPATH_LOCATIONSET:
5775 	    TODO
5776 	    ret = xmlStrdup((const xmlChar *) "");
5777 	    break;
5778     }
5779     return(ret);
5780 }
5781 
5782 /**
5783  * xmlXPathConvertString:
5784  * @val:  an XPath object
5785  *
5786  * Converts an existing object to its string() equivalent
5787  *
5788  * Returns the new object, the old one is freed (or the operation
5789  *         is done directly on @val)
5790  */
5791 xmlXPathObjectPtr
xmlXPathConvertString(xmlXPathObjectPtr val)5792 xmlXPathConvertString(xmlXPathObjectPtr val) {
5793     xmlChar *res = NULL;
5794 
5795     if (val == NULL)
5796 	return(xmlXPathNewCString(""));
5797 
5798     switch (val->type) {
5799     case XPATH_UNDEFINED:
5800 #ifdef DEBUG_EXPR
5801 	xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5802 #endif
5803 	break;
5804     case XPATH_NODESET:
5805     case XPATH_XSLT_TREE:
5806 	res = xmlXPathCastNodeSetToString(val->nodesetval);
5807 	break;
5808     case XPATH_STRING:
5809 	return(val);
5810     case XPATH_BOOLEAN:
5811 	res = xmlXPathCastBooleanToString(val->boolval);
5812 	break;
5813     case XPATH_NUMBER:
5814 	res = xmlXPathCastNumberToString(val->floatval);
5815 	break;
5816     case XPATH_USERS:
5817     case XPATH_POINT:
5818     case XPATH_RANGE:
5819     case XPATH_LOCATIONSET:
5820 	TODO;
5821 	break;
5822     }
5823     xmlXPathFreeObject(val);
5824     if (res == NULL)
5825 	return(xmlXPathNewCString(""));
5826     return(xmlXPathWrapString(res));
5827 }
5828 
5829 /**
5830  * xmlXPathCastBooleanToNumber:
5831  * @val:  a boolean
5832  *
5833  * Converts a boolean to its number value
5834  *
5835  * Returns the number value
5836  */
5837 double
xmlXPathCastBooleanToNumber(int val)5838 xmlXPathCastBooleanToNumber(int val) {
5839     if (val)
5840 	return(1.0);
5841     return(0.0);
5842 }
5843 
5844 /**
5845  * xmlXPathCastStringToNumber:
5846  * @val:  a string
5847  *
5848  * Converts a string to its number value
5849  *
5850  * Returns the number value
5851  */
5852 double
xmlXPathCastStringToNumber(const xmlChar * val)5853 xmlXPathCastStringToNumber(const xmlChar * val) {
5854     return(xmlXPathStringEvalNumber(val));
5855 }
5856 
5857 /**
5858  * xmlXPathCastNodeToNumber:
5859  * @node:  a node
5860  *
5861  * Converts a node to its number value
5862  *
5863  * Returns the number value
5864  */
5865 double
xmlXPathCastNodeToNumber(xmlNodePtr node)5866 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5867     xmlChar *strval;
5868     double ret;
5869 
5870     if (node == NULL)
5871 	return(xmlXPathNAN);
5872     strval = xmlXPathCastNodeToString(node);
5873     if (strval == NULL)
5874 	return(xmlXPathNAN);
5875     ret = xmlXPathCastStringToNumber(strval);
5876     xmlFree(strval);
5877 
5878     return(ret);
5879 }
5880 
5881 /**
5882  * xmlXPathCastNodeSetToNumber:
5883  * @ns:  a node-set
5884  *
5885  * Converts a node-set to its number value
5886  *
5887  * Returns the number value
5888  */
5889 double
xmlXPathCastNodeSetToNumber(xmlNodeSetPtr ns)5890 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5891     xmlChar *str;
5892     double ret;
5893 
5894     if (ns == NULL)
5895 	return(xmlXPathNAN);
5896     str = xmlXPathCastNodeSetToString(ns);
5897     ret = xmlXPathCastStringToNumber(str);
5898     xmlFree(str);
5899     return(ret);
5900 }
5901 
5902 /**
5903  * xmlXPathCastToNumber:
5904  * @val:  an XPath object
5905  *
5906  * Converts an XPath object to its number value
5907  *
5908  * Returns the number value
5909  */
5910 double
xmlXPathCastToNumber(xmlXPathObjectPtr val)5911 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5912     double ret = 0.0;
5913 
5914     if (val == NULL)
5915 	return(xmlXPathNAN);
5916     switch (val->type) {
5917     case XPATH_UNDEFINED:
5918 #ifdef DEBUG_EXPR
5919 	xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5920 #endif
5921 	ret = xmlXPathNAN;
5922 	break;
5923     case XPATH_NODESET:
5924     case XPATH_XSLT_TREE:
5925 	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5926 	break;
5927     case XPATH_STRING:
5928 	ret = xmlXPathCastStringToNumber(val->stringval);
5929 	break;
5930     case XPATH_NUMBER:
5931 	ret = val->floatval;
5932 	break;
5933     case XPATH_BOOLEAN:
5934 	ret = xmlXPathCastBooleanToNumber(val->boolval);
5935 	break;
5936     case XPATH_USERS:
5937     case XPATH_POINT:
5938     case XPATH_RANGE:
5939     case XPATH_LOCATIONSET:
5940 	TODO;
5941 	ret = xmlXPathNAN;
5942 	break;
5943     }
5944     return(ret);
5945 }
5946 
5947 /**
5948  * xmlXPathConvertNumber:
5949  * @val:  an XPath object
5950  *
5951  * Converts an existing object to its number() equivalent
5952  *
5953  * Returns the new object, the old one is freed (or the operation
5954  *         is done directly on @val)
5955  */
5956 xmlXPathObjectPtr
xmlXPathConvertNumber(xmlXPathObjectPtr val)5957 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5958     xmlXPathObjectPtr ret;
5959 
5960     if (val == NULL)
5961 	return(xmlXPathNewFloat(0.0));
5962     if (val->type == XPATH_NUMBER)
5963 	return(val);
5964     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5965     xmlXPathFreeObject(val);
5966     return(ret);
5967 }
5968 
5969 /**
5970  * xmlXPathCastNumberToBoolean:
5971  * @val:  a number
5972  *
5973  * Converts a number to its boolean value
5974  *
5975  * Returns the boolean value
5976  */
5977 int
xmlXPathCastNumberToBoolean(double val)5978 xmlXPathCastNumberToBoolean (double val) {
5979      if (xmlXPathIsNaN(val) || (val == 0.0))
5980 	 return(0);
5981      return(1);
5982 }
5983 
5984 /**
5985  * xmlXPathCastStringToBoolean:
5986  * @val:  a string
5987  *
5988  * Converts a string to its boolean value
5989  *
5990  * Returns the boolean value
5991  */
5992 int
xmlXPathCastStringToBoolean(const xmlChar * val)5993 xmlXPathCastStringToBoolean (const xmlChar *val) {
5994     if ((val == NULL) || (xmlStrlen(val) == 0))
5995 	return(0);
5996     return(1);
5997 }
5998 
5999 /**
6000  * xmlXPathCastNodeSetToBoolean:
6001  * @ns:  a node-set
6002  *
6003  * Converts a node-set to its boolean value
6004  *
6005  * Returns the boolean value
6006  */
6007 int
xmlXPathCastNodeSetToBoolean(xmlNodeSetPtr ns)6008 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6009     if ((ns == NULL) || (ns->nodeNr == 0))
6010 	return(0);
6011     return(1);
6012 }
6013 
6014 /**
6015  * xmlXPathCastToBoolean:
6016  * @val:  an XPath object
6017  *
6018  * Converts an XPath object to its boolean value
6019  *
6020  * Returns the boolean value
6021  */
6022 int
xmlXPathCastToBoolean(xmlXPathObjectPtr val)6023 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6024     int ret = 0;
6025 
6026     if (val == NULL)
6027 	return(0);
6028     switch (val->type) {
6029     case XPATH_UNDEFINED:
6030 #ifdef DEBUG_EXPR
6031 	xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6032 #endif
6033 	ret = 0;
6034 	break;
6035     case XPATH_NODESET:
6036     case XPATH_XSLT_TREE:
6037 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6038 	break;
6039     case XPATH_STRING:
6040 	ret = xmlXPathCastStringToBoolean(val->stringval);
6041 	break;
6042     case XPATH_NUMBER:
6043 	ret = xmlXPathCastNumberToBoolean(val->floatval);
6044 	break;
6045     case XPATH_BOOLEAN:
6046 	ret = val->boolval;
6047 	break;
6048     case XPATH_USERS:
6049     case XPATH_POINT:
6050     case XPATH_RANGE:
6051     case XPATH_LOCATIONSET:
6052 	TODO;
6053 	ret = 0;
6054 	break;
6055     }
6056     return(ret);
6057 }
6058 
6059 
6060 /**
6061  * xmlXPathConvertBoolean:
6062  * @val:  an XPath object
6063  *
6064  * Converts an existing object to its boolean() equivalent
6065  *
6066  * Returns the new object, the old one is freed (or the operation
6067  *         is done directly on @val)
6068  */
6069 xmlXPathObjectPtr
xmlXPathConvertBoolean(xmlXPathObjectPtr val)6070 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6071     xmlXPathObjectPtr ret;
6072 
6073     if (val == NULL)
6074 	return(xmlXPathNewBoolean(0));
6075     if (val->type == XPATH_BOOLEAN)
6076 	return(val);
6077     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6078     xmlXPathFreeObject(val);
6079     return(ret);
6080 }
6081 
6082 /************************************************************************
6083  *									*
6084  *		Routines to handle XPath contexts			*
6085  *									*
6086  ************************************************************************/
6087 
6088 /**
6089  * xmlXPathNewContext:
6090  * @doc:  the XML document
6091  *
6092  * Create a new xmlXPathContext
6093  *
6094  * Returns the xmlXPathContext just allocated. The caller will need to free it.
6095  */
6096 xmlXPathContextPtr
xmlXPathNewContext(xmlDocPtr doc)6097 xmlXPathNewContext(xmlDocPtr doc) {
6098     xmlXPathContextPtr ret;
6099 
6100     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6101     if (ret == NULL) {
6102         xmlXPathErrMemory(NULL, "creating context\n");
6103 	return(NULL);
6104     }
6105     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6106     ret->doc = doc;
6107     ret->node = NULL;
6108 
6109     ret->varHash = NULL;
6110 
6111     ret->nb_types = 0;
6112     ret->max_types = 0;
6113     ret->types = NULL;
6114 
6115     ret->funcHash = xmlHashCreate(0);
6116 
6117     ret->nb_axis = 0;
6118     ret->max_axis = 0;
6119     ret->axis = NULL;
6120 
6121     ret->nsHash = NULL;
6122     ret->user = NULL;
6123 
6124     ret->contextSize = -1;
6125     ret->proximityPosition = -1;
6126 
6127 #ifdef XP_DEFAULT_CACHE_ON
6128     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6129 	xmlXPathFreeContext(ret);
6130 	return(NULL);
6131     }
6132 #endif
6133 
6134     xmlXPathRegisterAllFunctions(ret);
6135 
6136     return(ret);
6137 }
6138 
6139 /**
6140  * xmlXPathFreeContext:
6141  * @ctxt:  the context to free
6142  *
6143  * Free up an xmlXPathContext
6144  */
6145 void
xmlXPathFreeContext(xmlXPathContextPtr ctxt)6146 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6147     if (ctxt == NULL) return;
6148 
6149     if (ctxt->cache != NULL)
6150 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6151     xmlXPathRegisteredNsCleanup(ctxt);
6152     xmlXPathRegisteredFuncsCleanup(ctxt);
6153     xmlXPathRegisteredVariablesCleanup(ctxt);
6154     xmlResetError(&ctxt->lastError);
6155     xmlFree(ctxt);
6156 }
6157 
6158 /************************************************************************
6159  *									*
6160  *		Routines to handle XPath parser contexts		*
6161  *									*
6162  ************************************************************************/
6163 
6164 #define CHECK_CTXT(ctxt)						\
6165     if (ctxt == NULL) {						\
6166 	__xmlRaiseError(NULL, NULL, NULL,				\
6167 		NULL, NULL, XML_FROM_XPATH,				\
6168 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6169 		__FILE__, __LINE__,					\
6170 		NULL, NULL, NULL, 0, 0,					\
6171 		"NULL context pointer\n");				\
6172 	return(NULL);							\
6173     }									\
6174 
6175 #define CHECK_CTXT_NEG(ctxt)						\
6176     if (ctxt == NULL) {						\
6177 	__xmlRaiseError(NULL, NULL, NULL,				\
6178 		NULL, NULL, XML_FROM_XPATH,				\
6179 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
6180 		__FILE__, __LINE__,					\
6181 		NULL, NULL, NULL, 0, 0,					\
6182 		"NULL context pointer\n");				\
6183 	return(-1);							\
6184     }									\
6185 
6186 
6187 #define CHECK_CONTEXT(ctxt)						\
6188     if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
6189         (ctxt->doc->children == NULL)) {				\
6190 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
6191 	return(NULL);							\
6192     }
6193 
6194 
6195 /**
6196  * xmlXPathNewParserContext:
6197  * @str:  the XPath expression
6198  * @ctxt:  the XPath context
6199  *
6200  * Create a new xmlXPathParserContext
6201  *
6202  * Returns the xmlXPathParserContext just allocated.
6203  */
6204 xmlXPathParserContextPtr
xmlXPathNewParserContext(const xmlChar * str,xmlXPathContextPtr ctxt)6205 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6206     xmlXPathParserContextPtr ret;
6207 
6208     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6209     if (ret == NULL) {
6210         xmlXPathErrMemory(ctxt, "creating parser context\n");
6211 	return(NULL);
6212     }
6213     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6214     ret->cur = ret->base = str;
6215     ret->context = ctxt;
6216 
6217     ret->comp = xmlXPathNewCompExpr();
6218     if (ret->comp == NULL) {
6219 	xmlFree(ret->valueTab);
6220 	xmlFree(ret);
6221 	return(NULL);
6222     }
6223     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6224         ret->comp->dict = ctxt->dict;
6225 	xmlDictReference(ret->comp->dict);
6226     }
6227 
6228     return(ret);
6229 }
6230 
6231 /**
6232  * xmlXPathCompParserContext:
6233  * @comp:  the XPath compiled expression
6234  * @ctxt:  the XPath context
6235  *
6236  * Create a new xmlXPathParserContext when processing a compiled expression
6237  *
6238  * Returns the xmlXPathParserContext just allocated.
6239  */
6240 static xmlXPathParserContextPtr
xmlXPathCompParserContext(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)6241 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6242     xmlXPathParserContextPtr ret;
6243 
6244     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6245     if (ret == NULL) {
6246         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6247 	return(NULL);
6248     }
6249     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6250 
6251     /* Allocate the value stack */
6252     ret->valueTab = (xmlXPathObjectPtr *)
6253                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6254     if (ret->valueTab == NULL) {
6255 	xmlFree(ret);
6256 	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6257 	return(NULL);
6258     }
6259     ret->valueNr = 0;
6260     ret->valueMax = 10;
6261     ret->value = NULL;
6262     ret->valueFrame = 0;
6263 
6264     ret->context = ctxt;
6265     ret->comp = comp;
6266 
6267     return(ret);
6268 }
6269 
6270 /**
6271  * xmlXPathFreeParserContext:
6272  * @ctxt:  the context to free
6273  *
6274  * Free up an xmlXPathParserContext
6275  */
6276 void
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt)6277 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6278     int i;
6279 
6280     if (ctxt->valueTab != NULL) {
6281         for (i = 0; i < ctxt->valueNr; i++) {
6282             if (ctxt->context)
6283                 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6284             else
6285                 xmlXPathFreeObject(ctxt->valueTab[i]);
6286         }
6287         xmlFree(ctxt->valueTab);
6288     }
6289     if (ctxt->comp != NULL) {
6290 #ifdef XPATH_STREAMING
6291 	if (ctxt->comp->stream != NULL) {
6292 	    xmlFreePatternList(ctxt->comp->stream);
6293 	    ctxt->comp->stream = NULL;
6294 	}
6295 #endif
6296 	xmlXPathFreeCompExpr(ctxt->comp);
6297     }
6298     xmlFree(ctxt);
6299 }
6300 
6301 /************************************************************************
6302  *									*
6303  *		The implicit core function library			*
6304  *									*
6305  ************************************************************************/
6306 
6307 /**
6308  * xmlXPathNodeValHash:
6309  * @node:  a node pointer
6310  *
6311  * Function computing the beginning of the string value of the node,
6312  * used to speed up comparisons
6313  *
6314  * Returns an int usable as a hash
6315  */
6316 static unsigned int
xmlXPathNodeValHash(xmlNodePtr node)6317 xmlXPathNodeValHash(xmlNodePtr node) {
6318     int len = 2;
6319     const xmlChar * string = NULL;
6320     xmlNodePtr tmp = NULL;
6321     unsigned int ret = 0;
6322 
6323     if (node == NULL)
6324 	return(0);
6325 
6326     if (node->type == XML_DOCUMENT_NODE) {
6327 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
6328 	if (tmp == NULL)
6329 	    node = node->children;
6330 	else
6331 	    node = tmp;
6332 
6333 	if (node == NULL)
6334 	    return(0);
6335     }
6336 
6337     switch (node->type) {
6338 	case XML_COMMENT_NODE:
6339 	case XML_PI_NODE:
6340 	case XML_CDATA_SECTION_NODE:
6341 	case XML_TEXT_NODE:
6342 	    string = node->content;
6343 	    if (string == NULL)
6344 		return(0);
6345 	    if (string[0] == 0)
6346 		return(0);
6347 	    return(((unsigned int) string[0]) +
6348 		   (((unsigned int) string[1]) << 8));
6349 	case XML_NAMESPACE_DECL:
6350 	    string = ((xmlNsPtr)node)->href;
6351 	    if (string == NULL)
6352 		return(0);
6353 	    if (string[0] == 0)
6354 		return(0);
6355 	    return(((unsigned int) string[0]) +
6356 		   (((unsigned int) string[1]) << 8));
6357 	case XML_ATTRIBUTE_NODE:
6358 	    tmp = ((xmlAttrPtr) node)->children;
6359 	    break;
6360 	case XML_ELEMENT_NODE:
6361 	    tmp = node->children;
6362 	    break;
6363 	default:
6364 	    return(0);
6365     }
6366     while (tmp != NULL) {
6367 	switch (tmp->type) {
6368 	    case XML_CDATA_SECTION_NODE:
6369 	    case XML_TEXT_NODE:
6370 		string = tmp->content;
6371 		break;
6372 	    default:
6373                 string = NULL;
6374 		break;
6375 	}
6376 	if ((string != NULL) && (string[0] != 0)) {
6377 	    if (len == 1) {
6378 		return(ret + (((unsigned int) string[0]) << 8));
6379 	    }
6380 	    if (string[1] == 0) {
6381 		len = 1;
6382 		ret = (unsigned int) string[0];
6383 	    } else {
6384 		return(((unsigned int) string[0]) +
6385 		       (((unsigned int) string[1]) << 8));
6386 	    }
6387 	}
6388 	/*
6389 	 * Skip to next node
6390 	 */
6391 	if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6392 	    if (tmp->children->type != XML_ENTITY_DECL) {
6393 		tmp = tmp->children;
6394 		continue;
6395 	    }
6396 	}
6397 	if (tmp == node)
6398 	    break;
6399 
6400 	if (tmp->next != NULL) {
6401 	    tmp = tmp->next;
6402 	    continue;
6403 	}
6404 
6405 	do {
6406 	    tmp = tmp->parent;
6407 	    if (tmp == NULL)
6408 		break;
6409 	    if (tmp == node) {
6410 		tmp = NULL;
6411 		break;
6412 	    }
6413 	    if (tmp->next != NULL) {
6414 		tmp = tmp->next;
6415 		break;
6416 	    }
6417 	} while (tmp != NULL);
6418     }
6419     return(ret);
6420 }
6421 
6422 /**
6423  * xmlXPathStringHash:
6424  * @string:  a string
6425  *
6426  * Function computing the beginning of the string value of the node,
6427  * used to speed up comparisons
6428  *
6429  * Returns an int usable as a hash
6430  */
6431 static unsigned int
xmlXPathStringHash(const xmlChar * string)6432 xmlXPathStringHash(const xmlChar * string) {
6433     if (string == NULL)
6434 	return((unsigned int) 0);
6435     if (string[0] == 0)
6436 	return(0);
6437     return(((unsigned int) string[0]) +
6438 	   (((unsigned int) string[1]) << 8));
6439 }
6440 
6441 /**
6442  * xmlXPathCompareNodeSetFloat:
6443  * @ctxt:  the XPath Parser context
6444  * @inf:  less than (1) or greater than (0)
6445  * @strict:  is the comparison strict
6446  * @arg:  the node set
6447  * @f:  the value
6448  *
6449  * Implement the compare operation between a nodeset and a number
6450  *     @ns < @val    (1, 1, ...
6451  *     @ns <= @val   (1, 0, ...
6452  *     @ns > @val    (0, 1, ...
6453  *     @ns >= @val   (0, 0, ...
6454  *
6455  * If one object to be compared is a node-set and the other is a number,
6456  * then the comparison will be true if and only if there is a node in the
6457  * node-set such that the result of performing the comparison on the number
6458  * to be compared and on the result of converting the string-value of that
6459  * node to a number using the number function is true.
6460  *
6461  * Returns 0 or 1 depending on the results of the test.
6462  */
6463 static int
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr f)6464 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6465 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6466     int i, ret = 0;
6467     xmlNodeSetPtr ns;
6468     xmlChar *str2;
6469 
6470     if ((f == NULL) || (arg == NULL) ||
6471 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6472 	xmlXPathReleaseObject(ctxt->context, arg);
6473 	xmlXPathReleaseObject(ctxt->context, f);
6474         return(0);
6475     }
6476     ns = arg->nodesetval;
6477     if (ns != NULL) {
6478 	for (i = 0;i < ns->nodeNr;i++) {
6479 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6480 	     if (str2 != NULL) {
6481 		 valuePush(ctxt,
6482 			   xmlXPathCacheNewString(ctxt->context, str2));
6483 		 xmlFree(str2);
6484 		 xmlXPathNumberFunction(ctxt, 1);
6485 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6486 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6487 		 if (ret)
6488 		     break;
6489 	     }
6490 	}
6491     }
6492     xmlXPathReleaseObject(ctxt->context, arg);
6493     xmlXPathReleaseObject(ctxt->context, f);
6494     return(ret);
6495 }
6496 
6497 /**
6498  * xmlXPathCompareNodeSetString:
6499  * @ctxt:  the XPath Parser context
6500  * @inf:  less than (1) or greater than (0)
6501  * @strict:  is the comparison strict
6502  * @arg:  the node set
6503  * @s:  the value
6504  *
6505  * Implement the compare operation between a nodeset and a string
6506  *     @ns < @val    (1, 1, ...
6507  *     @ns <= @val   (1, 0, ...
6508  *     @ns > @val    (0, 1, ...
6509  *     @ns >= @val   (0, 0, ...
6510  *
6511  * If one object to be compared is a node-set and the other is a string,
6512  * then the comparison will be true if and only if there is a node in
6513  * the node-set such that the result of performing the comparison on the
6514  * string-value of the node and the other string is true.
6515  *
6516  * Returns 0 or 1 depending on the results of the test.
6517  */
6518 static int
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr s)6519 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6520 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6521     int i, ret = 0;
6522     xmlNodeSetPtr ns;
6523     xmlChar *str2;
6524 
6525     if ((s == NULL) || (arg == NULL) ||
6526 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6527 	xmlXPathReleaseObject(ctxt->context, arg);
6528 	xmlXPathReleaseObject(ctxt->context, s);
6529         return(0);
6530     }
6531     ns = arg->nodesetval;
6532     if (ns != NULL) {
6533 	for (i = 0;i < ns->nodeNr;i++) {
6534 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6535 	     if (str2 != NULL) {
6536 		 valuePush(ctxt,
6537 			   xmlXPathCacheNewString(ctxt->context, str2));
6538 		 xmlFree(str2);
6539 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6540 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
6541 		 if (ret)
6542 		     break;
6543 	     }
6544 	}
6545     }
6546     xmlXPathReleaseObject(ctxt->context, arg);
6547     xmlXPathReleaseObject(ctxt->context, s);
6548     return(ret);
6549 }
6550 
6551 /**
6552  * xmlXPathCompareNodeSets:
6553  * @inf:  less than (1) or greater than (0)
6554  * @strict:  is the comparison strict
6555  * @arg1:  the first node set object
6556  * @arg2:  the second node set object
6557  *
6558  * Implement the compare operation on nodesets:
6559  *
6560  * If both objects to be compared are node-sets, then the comparison
6561  * will be true if and only if there is a node in the first node-set
6562  * and a node in the second node-set such that the result of performing
6563  * the comparison on the string-values of the two nodes is true.
6564  * ....
6565  * When neither object to be compared is a node-set and the operator
6566  * is <=, <, >= or >, then the objects are compared by converting both
6567  * objects to numbers and comparing the numbers according to IEEE 754.
6568  * ....
6569  * The number function converts its argument to a number as follows:
6570  *  - a string that consists of optional whitespace followed by an
6571  *    optional minus sign followed by a Number followed by whitespace
6572  *    is converted to the IEEE 754 number that is nearest (according
6573  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6574  *    represented by the string; any other string is converted to NaN
6575  *
6576  * Conclusion all nodes need to be converted first to their string value
6577  * and then the comparison must be done when possible
6578  */
6579 static int
xmlXPathCompareNodeSets(int inf,int strict,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6580 xmlXPathCompareNodeSets(int inf, int strict,
6581 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6582     int i, j, init = 0;
6583     double val1;
6584     double *values2;
6585     int ret = 0;
6586     xmlNodeSetPtr ns1;
6587     xmlNodeSetPtr ns2;
6588 
6589     if ((arg1 == NULL) ||
6590 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6591 	xmlXPathFreeObject(arg2);
6592         return(0);
6593     }
6594     if ((arg2 == NULL) ||
6595 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6596 	xmlXPathFreeObject(arg1);
6597 	xmlXPathFreeObject(arg2);
6598         return(0);
6599     }
6600 
6601     ns1 = arg1->nodesetval;
6602     ns2 = arg2->nodesetval;
6603 
6604     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6605 	xmlXPathFreeObject(arg1);
6606 	xmlXPathFreeObject(arg2);
6607 	return(0);
6608     }
6609     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6610 	xmlXPathFreeObject(arg1);
6611 	xmlXPathFreeObject(arg2);
6612 	return(0);
6613     }
6614 
6615     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6616     if (values2 == NULL) {
6617         /* TODO: Propagate memory error. */
6618         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6619 	xmlXPathFreeObject(arg1);
6620 	xmlXPathFreeObject(arg2);
6621 	return(0);
6622     }
6623     for (i = 0;i < ns1->nodeNr;i++) {
6624 	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6625 	if (xmlXPathIsNaN(val1))
6626 	    continue;
6627 	for (j = 0;j < ns2->nodeNr;j++) {
6628 	    if (init == 0) {
6629 		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6630 	    }
6631 	    if (xmlXPathIsNaN(values2[j]))
6632 		continue;
6633 	    if (inf && strict)
6634 		ret = (val1 < values2[j]);
6635 	    else if (inf && !strict)
6636 		ret = (val1 <= values2[j]);
6637 	    else if (!inf && strict)
6638 		ret = (val1 > values2[j]);
6639 	    else if (!inf && !strict)
6640 		ret = (val1 >= values2[j]);
6641 	    if (ret)
6642 		break;
6643 	}
6644 	if (ret)
6645 	    break;
6646 	init = 1;
6647     }
6648     xmlFree(values2);
6649     xmlXPathFreeObject(arg1);
6650     xmlXPathFreeObject(arg2);
6651     return(ret);
6652 }
6653 
6654 /**
6655  * xmlXPathCompareNodeSetValue:
6656  * @ctxt:  the XPath Parser context
6657  * @inf:  less than (1) or greater than (0)
6658  * @strict:  is the comparison strict
6659  * @arg:  the node set
6660  * @val:  the value
6661  *
6662  * Implement the compare operation between a nodeset and a value
6663  *     @ns < @val    (1, 1, ...
6664  *     @ns <= @val   (1, 0, ...
6665  *     @ns > @val    (0, 1, ...
6666  *     @ns >= @val   (0, 0, ...
6667  *
6668  * If one object to be compared is a node-set and the other is a boolean,
6669  * then the comparison will be true if and only if the result of performing
6670  * the comparison on the boolean and on the result of converting
6671  * the node-set to a boolean using the boolean function is true.
6672  *
6673  * Returns 0 or 1 depending on the results of the test.
6674  */
6675 static int
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr val)6676 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6677 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6678     if ((val == NULL) || (arg == NULL) ||
6679 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6680         return(0);
6681 
6682     switch(val->type) {
6683         case XPATH_NUMBER:
6684 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6685         case XPATH_NODESET:
6686         case XPATH_XSLT_TREE:
6687 	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6688         case XPATH_STRING:
6689 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6690         case XPATH_BOOLEAN:
6691 	    valuePush(ctxt, arg);
6692 	    xmlXPathBooleanFunction(ctxt, 1);
6693 	    valuePush(ctxt, val);
6694 	    return(xmlXPathCompareValues(ctxt, inf, strict));
6695 	default:
6696             xmlGenericError(xmlGenericErrorContext,
6697                     "xmlXPathCompareNodeSetValue: Can't compare node set "
6698                     "and object of type %d\n",
6699                     val->type);
6700             xmlXPathReleaseObject(ctxt->context, arg);
6701             xmlXPathReleaseObject(ctxt->context, val);
6702             XP_ERROR0(XPATH_INVALID_TYPE);
6703     }
6704     return(0);
6705 }
6706 
6707 /**
6708  * xmlXPathEqualNodeSetString:
6709  * @arg:  the nodeset object argument
6710  * @str:  the string to compare to.
6711  * @neq:  flag to show whether for '=' (0) or '!=' (1)
6712  *
6713  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6714  * If one object to be compared is a node-set and the other is a string,
6715  * then the comparison will be true if and only if there is a node in
6716  * the node-set such that the result of performing the comparison on the
6717  * string-value of the node and the other string is true.
6718  *
6719  * Returns 0 or 1 depending on the results of the test.
6720  */
6721 static int
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg,const xmlChar * str,int neq)6722 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6723 {
6724     int i;
6725     xmlNodeSetPtr ns;
6726     xmlChar *str2;
6727     unsigned int hash;
6728 
6729     if ((str == NULL) || (arg == NULL) ||
6730         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6731         return (0);
6732     ns = arg->nodesetval;
6733     /*
6734      * A NULL nodeset compared with a string is always false
6735      * (since there is no node equal, and no node not equal)
6736      */
6737     if ((ns == NULL) || (ns->nodeNr <= 0) )
6738         return (0);
6739     hash = xmlXPathStringHash(str);
6740     for (i = 0; i < ns->nodeNr; i++) {
6741         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6742             str2 = xmlNodeGetContent(ns->nodeTab[i]);
6743             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6744                 xmlFree(str2);
6745 		if (neq)
6746 		    continue;
6747                 return (1);
6748 	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6749 		if (neq)
6750 		    continue;
6751                 return (1);
6752             } else if (neq) {
6753 		if (str2 != NULL)
6754 		    xmlFree(str2);
6755 		return (1);
6756 	    }
6757             if (str2 != NULL)
6758                 xmlFree(str2);
6759         } else if (neq)
6760 	    return (1);
6761     }
6762     return (0);
6763 }
6764 
6765 /**
6766  * xmlXPathEqualNodeSetFloat:
6767  * @arg:  the nodeset object argument
6768  * @f:  the float to compare to
6769  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6770  *
6771  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6772  * If one object to be compared is a node-set and the other is a number,
6773  * then the comparison will be true if and only if there is a node in
6774  * the node-set such that the result of performing the comparison on the
6775  * number to be compared and on the result of converting the string-value
6776  * of that node to a number using the number function is true.
6777  *
6778  * Returns 0 or 1 depending on the results of the test.
6779  */
6780 static int
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,double f,int neq)6781 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6782     xmlXPathObjectPtr arg, double f, int neq) {
6783   int i, ret=0;
6784   xmlNodeSetPtr ns;
6785   xmlChar *str2;
6786   xmlXPathObjectPtr val;
6787   double v;
6788 
6789     if ((arg == NULL) ||
6790 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6791         return(0);
6792 
6793     ns = arg->nodesetval;
6794     if (ns != NULL) {
6795 	for (i=0;i<ns->nodeNr;i++) {
6796 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6797 	    if (str2 != NULL) {
6798 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6799 		xmlFree(str2);
6800 		xmlXPathNumberFunction(ctxt, 1);
6801 		val = valuePop(ctxt);
6802 		v = val->floatval;
6803 		xmlXPathReleaseObject(ctxt->context, val);
6804 		if (!xmlXPathIsNaN(v)) {
6805 		    if ((!neq) && (v==f)) {
6806 			ret = 1;
6807 			break;
6808 		    } else if ((neq) && (v!=f)) {
6809 			ret = 1;
6810 			break;
6811 		    }
6812 		} else {	/* NaN is unequal to any value */
6813 		    if (neq)
6814 			ret = 1;
6815 		}
6816 	    }
6817 	}
6818     }
6819 
6820     return(ret);
6821 }
6822 
6823 
6824 /**
6825  * xmlXPathEqualNodeSets:
6826  * @arg1:  first nodeset object argument
6827  * @arg2:  second nodeset object argument
6828  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6829  *
6830  * Implement the equal / not equal operation on XPath nodesets:
6831  * @arg1 == @arg2  or  @arg1 != @arg2
6832  * If both objects to be compared are node-sets, then the comparison
6833  * will be true if and only if there is a node in the first node-set and
6834  * a node in the second node-set such that the result of performing the
6835  * comparison on the string-values of the two nodes is true.
6836  *
6837  * (needless to say, this is a costly operation)
6838  *
6839  * Returns 0 or 1 depending on the results of the test.
6840  */
6841 static int
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2,int neq)6842 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6843     int i, j;
6844     unsigned int *hashs1;
6845     unsigned int *hashs2;
6846     xmlChar **values1;
6847     xmlChar **values2;
6848     int ret = 0;
6849     xmlNodeSetPtr ns1;
6850     xmlNodeSetPtr ns2;
6851 
6852     if ((arg1 == NULL) ||
6853 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6854         return(0);
6855     if ((arg2 == NULL) ||
6856 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6857         return(0);
6858 
6859     ns1 = arg1->nodesetval;
6860     ns2 = arg2->nodesetval;
6861 
6862     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6863 	return(0);
6864     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6865 	return(0);
6866 
6867     /*
6868      * for equal, check if there is a node pertaining to both sets
6869      */
6870     if (neq == 0)
6871 	for (i = 0;i < ns1->nodeNr;i++)
6872 	    for (j = 0;j < ns2->nodeNr;j++)
6873 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
6874 		    return(1);
6875 
6876     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6877     if (values1 == NULL) {
6878         /* TODO: Propagate memory error. */
6879         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6880 	return(0);
6881     }
6882     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6883     if (hashs1 == NULL) {
6884         /* TODO: Propagate memory error. */
6885         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6886 	xmlFree(values1);
6887 	return(0);
6888     }
6889     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6890     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6891     if (values2 == NULL) {
6892         /* TODO: Propagate memory error. */
6893         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6894 	xmlFree(hashs1);
6895 	xmlFree(values1);
6896 	return(0);
6897     }
6898     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6899     if (hashs2 == NULL) {
6900         /* TODO: Propagate memory error. */
6901         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6902 	xmlFree(hashs1);
6903 	xmlFree(values1);
6904 	xmlFree(values2);
6905 	return(0);
6906     }
6907     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6908     for (i = 0;i < ns1->nodeNr;i++) {
6909 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6910 	for (j = 0;j < ns2->nodeNr;j++) {
6911 	    if (i == 0)
6912 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6913 	    if (hashs1[i] != hashs2[j]) {
6914 		if (neq) {
6915 		    ret = 1;
6916 		    break;
6917 		}
6918 	    }
6919 	    else {
6920 		if (values1[i] == NULL)
6921 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6922 		if (values2[j] == NULL)
6923 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6924 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6925 		if (ret)
6926 		    break;
6927 	    }
6928 	}
6929 	if (ret)
6930 	    break;
6931     }
6932     for (i = 0;i < ns1->nodeNr;i++)
6933 	if (values1[i] != NULL)
6934 	    xmlFree(values1[i]);
6935     for (j = 0;j < ns2->nodeNr;j++)
6936 	if (values2[j] != NULL)
6937 	    xmlFree(values2[j]);
6938     xmlFree(values1);
6939     xmlFree(values2);
6940     xmlFree(hashs1);
6941     xmlFree(hashs2);
6942     return(ret);
6943 }
6944 
6945 static int
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6946 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6947   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6948     int ret = 0;
6949     /*
6950      *At this point we are assured neither arg1 nor arg2
6951      *is a nodeset, so we can just pick the appropriate routine.
6952      */
6953     switch (arg1->type) {
6954         case XPATH_UNDEFINED:
6955 #ifdef DEBUG_EXPR
6956 	    xmlGenericError(xmlGenericErrorContext,
6957 		    "Equal: undefined\n");
6958 #endif
6959 	    break;
6960         case XPATH_BOOLEAN:
6961 	    switch (arg2->type) {
6962 	        case XPATH_UNDEFINED:
6963 #ifdef DEBUG_EXPR
6964 		    xmlGenericError(xmlGenericErrorContext,
6965 			    "Equal: undefined\n");
6966 #endif
6967 		    break;
6968 		case XPATH_BOOLEAN:
6969 #ifdef DEBUG_EXPR
6970 		    xmlGenericError(xmlGenericErrorContext,
6971 			    "Equal: %d boolean %d \n",
6972 			    arg1->boolval, arg2->boolval);
6973 #endif
6974 		    ret = (arg1->boolval == arg2->boolval);
6975 		    break;
6976 		case XPATH_NUMBER:
6977 		    ret = (arg1->boolval ==
6978 			   xmlXPathCastNumberToBoolean(arg2->floatval));
6979 		    break;
6980 		case XPATH_STRING:
6981 		    if ((arg2->stringval == NULL) ||
6982 			(arg2->stringval[0] == 0)) ret = 0;
6983 		    else
6984 			ret = 1;
6985 		    ret = (arg1->boolval == ret);
6986 		    break;
6987 		case XPATH_USERS:
6988 		case XPATH_POINT:
6989 		case XPATH_RANGE:
6990 		case XPATH_LOCATIONSET:
6991 		    TODO
6992 		    break;
6993 		case XPATH_NODESET:
6994 		case XPATH_XSLT_TREE:
6995 		    break;
6996 	    }
6997 	    break;
6998         case XPATH_NUMBER:
6999 	    switch (arg2->type) {
7000 	        case XPATH_UNDEFINED:
7001 #ifdef DEBUG_EXPR
7002 		    xmlGenericError(xmlGenericErrorContext,
7003 			    "Equal: undefined\n");
7004 #endif
7005 		    break;
7006 		case XPATH_BOOLEAN:
7007 		    ret = (arg2->boolval==
7008 			   xmlXPathCastNumberToBoolean(arg1->floatval));
7009 		    break;
7010 		case XPATH_STRING:
7011 		    valuePush(ctxt, arg2);
7012 		    xmlXPathNumberFunction(ctxt, 1);
7013 		    arg2 = valuePop(ctxt);
7014                     /* Falls through. */
7015 		case XPATH_NUMBER:
7016 		    /* Hand check NaN and Infinity equalities */
7017 		    if (xmlXPathIsNaN(arg1->floatval) ||
7018 			    xmlXPathIsNaN(arg2->floatval)) {
7019 		        ret = 0;
7020 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7021 		        if (xmlXPathIsInf(arg2->floatval) == 1)
7022 			    ret = 1;
7023 			else
7024 			    ret = 0;
7025 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7026 			if (xmlXPathIsInf(arg2->floatval) == -1)
7027 			    ret = 1;
7028 			else
7029 			    ret = 0;
7030 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7031 			if (xmlXPathIsInf(arg1->floatval) == 1)
7032 			    ret = 1;
7033 			else
7034 			    ret = 0;
7035 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7036 			if (xmlXPathIsInf(arg1->floatval) == -1)
7037 			    ret = 1;
7038 			else
7039 			    ret = 0;
7040 		    } else {
7041 		        ret = (arg1->floatval == arg2->floatval);
7042 		    }
7043 		    break;
7044 		case XPATH_USERS:
7045 		case XPATH_POINT:
7046 		case XPATH_RANGE:
7047 		case XPATH_LOCATIONSET:
7048 		    TODO
7049 		    break;
7050 		case XPATH_NODESET:
7051 		case XPATH_XSLT_TREE:
7052 		    break;
7053 	    }
7054 	    break;
7055         case XPATH_STRING:
7056 	    switch (arg2->type) {
7057 	        case XPATH_UNDEFINED:
7058 #ifdef DEBUG_EXPR
7059 		    xmlGenericError(xmlGenericErrorContext,
7060 			    "Equal: undefined\n");
7061 #endif
7062 		    break;
7063 		case XPATH_BOOLEAN:
7064 		    if ((arg1->stringval == NULL) ||
7065 			(arg1->stringval[0] == 0)) ret = 0;
7066 		    else
7067 			ret = 1;
7068 		    ret = (arg2->boolval == ret);
7069 		    break;
7070 		case XPATH_STRING:
7071 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7072 		    break;
7073 		case XPATH_NUMBER:
7074 		    valuePush(ctxt, arg1);
7075 		    xmlXPathNumberFunction(ctxt, 1);
7076 		    arg1 = valuePop(ctxt);
7077 		    /* Hand check NaN and Infinity equalities */
7078 		    if (xmlXPathIsNaN(arg1->floatval) ||
7079 			    xmlXPathIsNaN(arg2->floatval)) {
7080 		        ret = 0;
7081 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7082 			if (xmlXPathIsInf(arg2->floatval) == 1)
7083 			    ret = 1;
7084 			else
7085 			    ret = 0;
7086 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7087 			if (xmlXPathIsInf(arg2->floatval) == -1)
7088 			    ret = 1;
7089 			else
7090 			    ret = 0;
7091 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7092 			if (xmlXPathIsInf(arg1->floatval) == 1)
7093 			    ret = 1;
7094 			else
7095 			    ret = 0;
7096 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7097 			if (xmlXPathIsInf(arg1->floatval) == -1)
7098 			    ret = 1;
7099 			else
7100 			    ret = 0;
7101 		    } else {
7102 		        ret = (arg1->floatval == arg2->floatval);
7103 		    }
7104 		    break;
7105 		case XPATH_USERS:
7106 		case XPATH_POINT:
7107 		case XPATH_RANGE:
7108 		case XPATH_LOCATIONSET:
7109 		    TODO
7110 		    break;
7111 		case XPATH_NODESET:
7112 		case XPATH_XSLT_TREE:
7113 		    break;
7114 	    }
7115 	    break;
7116         case XPATH_USERS:
7117 	case XPATH_POINT:
7118 	case XPATH_RANGE:
7119 	case XPATH_LOCATIONSET:
7120 	    TODO
7121 	    break;
7122 	case XPATH_NODESET:
7123 	case XPATH_XSLT_TREE:
7124 	    break;
7125     }
7126     xmlXPathReleaseObject(ctxt->context, arg1);
7127     xmlXPathReleaseObject(ctxt->context, arg2);
7128     return(ret);
7129 }
7130 
7131 /**
7132  * xmlXPathEqualValues:
7133  * @ctxt:  the XPath Parser context
7134  *
7135  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7136  *
7137  * Returns 0 or 1 depending on the results of the test.
7138  */
7139 int
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt)7140 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7141     xmlXPathObjectPtr arg1, arg2, argtmp;
7142     int ret = 0;
7143 
7144     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7145     arg2 = valuePop(ctxt);
7146     arg1 = valuePop(ctxt);
7147     if ((arg1 == NULL) || (arg2 == NULL)) {
7148 	if (arg1 != NULL)
7149 	    xmlXPathReleaseObject(ctxt->context, arg1);
7150 	else
7151 	    xmlXPathReleaseObject(ctxt->context, arg2);
7152 	XP_ERROR0(XPATH_INVALID_OPERAND);
7153     }
7154 
7155     if (arg1 == arg2) {
7156 #ifdef DEBUG_EXPR
7157         xmlGenericError(xmlGenericErrorContext,
7158 		"Equal: by pointer\n");
7159 #endif
7160 	xmlXPathFreeObject(arg1);
7161         return(1);
7162     }
7163 
7164     /*
7165      *If either argument is a nodeset, it's a 'special case'
7166      */
7167     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7168       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7169 	/*
7170 	 *Hack it to assure arg1 is the nodeset
7171 	 */
7172 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7173 		argtmp = arg2;
7174 		arg2 = arg1;
7175 		arg1 = argtmp;
7176 	}
7177 	switch (arg2->type) {
7178 	    case XPATH_UNDEFINED:
7179 #ifdef DEBUG_EXPR
7180 		xmlGenericError(xmlGenericErrorContext,
7181 			"Equal: undefined\n");
7182 #endif
7183 		break;
7184 	    case XPATH_NODESET:
7185 	    case XPATH_XSLT_TREE:
7186 		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7187 		break;
7188 	    case XPATH_BOOLEAN:
7189 		if ((arg1->nodesetval == NULL) ||
7190 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7191 		else
7192 		    ret = 1;
7193 		ret = (ret == arg2->boolval);
7194 		break;
7195 	    case XPATH_NUMBER:
7196 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7197 		break;
7198 	    case XPATH_STRING:
7199 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7200 		break;
7201 	    case XPATH_USERS:
7202 	    case XPATH_POINT:
7203 	    case XPATH_RANGE:
7204 	    case XPATH_LOCATIONSET:
7205 		TODO
7206 		break;
7207 	}
7208 	xmlXPathReleaseObject(ctxt->context, arg1);
7209 	xmlXPathReleaseObject(ctxt->context, arg2);
7210 	return(ret);
7211     }
7212 
7213     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7214 }
7215 
7216 /**
7217  * xmlXPathNotEqualValues:
7218  * @ctxt:  the XPath Parser context
7219  *
7220  * Implement the equal operation on XPath objects content: @arg1 == @arg2
7221  *
7222  * Returns 0 or 1 depending on the results of the test.
7223  */
7224 int
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt)7225 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7226     xmlXPathObjectPtr arg1, arg2, argtmp;
7227     int ret = 0;
7228 
7229     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7230     arg2 = valuePop(ctxt);
7231     arg1 = valuePop(ctxt);
7232     if ((arg1 == NULL) || (arg2 == NULL)) {
7233 	if (arg1 != NULL)
7234 	    xmlXPathReleaseObject(ctxt->context, arg1);
7235 	else
7236 	    xmlXPathReleaseObject(ctxt->context, arg2);
7237 	XP_ERROR0(XPATH_INVALID_OPERAND);
7238     }
7239 
7240     if (arg1 == arg2) {
7241 #ifdef DEBUG_EXPR
7242         xmlGenericError(xmlGenericErrorContext,
7243 		"NotEqual: by pointer\n");
7244 #endif
7245 	xmlXPathReleaseObject(ctxt->context, arg1);
7246         return(0);
7247     }
7248 
7249     /*
7250      *If either argument is a nodeset, it's a 'special case'
7251      */
7252     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7253       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7254 	/*
7255 	 *Hack it to assure arg1 is the nodeset
7256 	 */
7257 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7258 		argtmp = arg2;
7259 		arg2 = arg1;
7260 		arg1 = argtmp;
7261 	}
7262 	switch (arg2->type) {
7263 	    case XPATH_UNDEFINED:
7264 #ifdef DEBUG_EXPR
7265 		xmlGenericError(xmlGenericErrorContext,
7266 			"NotEqual: undefined\n");
7267 #endif
7268 		break;
7269 	    case XPATH_NODESET:
7270 	    case XPATH_XSLT_TREE:
7271 		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7272 		break;
7273 	    case XPATH_BOOLEAN:
7274 		if ((arg1->nodesetval == NULL) ||
7275 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
7276 		else
7277 		    ret = 1;
7278 		ret = (ret != arg2->boolval);
7279 		break;
7280 	    case XPATH_NUMBER:
7281 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7282 		break;
7283 	    case XPATH_STRING:
7284 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7285 		break;
7286 	    case XPATH_USERS:
7287 	    case XPATH_POINT:
7288 	    case XPATH_RANGE:
7289 	    case XPATH_LOCATIONSET:
7290 		TODO
7291 		break;
7292 	}
7293 	xmlXPathReleaseObject(ctxt->context, arg1);
7294 	xmlXPathReleaseObject(ctxt->context, arg2);
7295 	return(ret);
7296     }
7297 
7298     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7299 }
7300 
7301 /**
7302  * xmlXPathCompareValues:
7303  * @ctxt:  the XPath Parser context
7304  * @inf:  less than (1) or greater than (0)
7305  * @strict:  is the comparison strict
7306  *
7307  * Implement the compare operation on XPath objects:
7308  *     @arg1 < @arg2    (1, 1, ...
7309  *     @arg1 <= @arg2   (1, 0, ...
7310  *     @arg1 > @arg2    (0, 1, ...
7311  *     @arg1 >= @arg2   (0, 0, ...
7312  *
7313  * When neither object to be compared is a node-set and the operator is
7314  * <=, <, >=, >, then the objects are compared by converted both objects
7315  * to numbers and comparing the numbers according to IEEE 754. The <
7316  * comparison will be true if and only if the first number is less than the
7317  * second number. The <= comparison will be true if and only if the first
7318  * number is less than or equal to the second number. The > comparison
7319  * will be true if and only if the first number is greater than the second
7320  * number. The >= comparison will be true if and only if the first number
7321  * is greater than or equal to the second number.
7322  *
7323  * Returns 1 if the comparison succeeded, 0 if it failed
7324  */
7325 int
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt,int inf,int strict)7326 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7327     int ret = 0, arg1i = 0, arg2i = 0;
7328     xmlXPathObjectPtr arg1, arg2;
7329 
7330     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7331     arg2 = valuePop(ctxt);
7332     arg1 = valuePop(ctxt);
7333     if ((arg1 == NULL) || (arg2 == NULL)) {
7334 	if (arg1 != NULL)
7335 	    xmlXPathReleaseObject(ctxt->context, arg1);
7336 	else
7337 	    xmlXPathReleaseObject(ctxt->context, arg2);
7338 	XP_ERROR0(XPATH_INVALID_OPERAND);
7339     }
7340 
7341     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7342       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7343 	/*
7344 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7345 	 * are not freed from within this routine; they will be freed from the
7346 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7347 	 */
7348 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7349 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7350 	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7351 	} else {
7352 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7353 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7354 			                          arg1, arg2);
7355 	    } else {
7356 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7357 			                          arg2, arg1);
7358 	    }
7359 	}
7360 	return(ret);
7361     }
7362 
7363     if (arg1->type != XPATH_NUMBER) {
7364 	valuePush(ctxt, arg1);
7365 	xmlXPathNumberFunction(ctxt, 1);
7366 	arg1 = valuePop(ctxt);
7367     }
7368     if (arg1->type != XPATH_NUMBER) {
7369 	xmlXPathFreeObject(arg1);
7370 	xmlXPathFreeObject(arg2);
7371 	XP_ERROR0(XPATH_INVALID_OPERAND);
7372     }
7373     if (arg2->type != XPATH_NUMBER) {
7374 	valuePush(ctxt, arg2);
7375 	xmlXPathNumberFunction(ctxt, 1);
7376 	arg2 = valuePop(ctxt);
7377     }
7378     if (arg2->type != XPATH_NUMBER) {
7379 	xmlXPathReleaseObject(ctxt->context, arg1);
7380 	xmlXPathReleaseObject(ctxt->context, arg2);
7381 	XP_ERROR0(XPATH_INVALID_OPERAND);
7382     }
7383     /*
7384      * Add tests for infinity and nan
7385      * => feedback on 3.4 for Inf and NaN
7386      */
7387     /* Hand check NaN and Infinity comparisons */
7388     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7389 	ret=0;
7390     } else {
7391 	arg1i=xmlXPathIsInf(arg1->floatval);
7392 	arg2i=xmlXPathIsInf(arg2->floatval);
7393 	if (inf && strict) {
7394 	    if ((arg1i == -1 && arg2i != -1) ||
7395 		(arg2i == 1 && arg1i != 1)) {
7396 		ret = 1;
7397 	    } else if (arg1i == 0 && arg2i == 0) {
7398 		ret = (arg1->floatval < arg2->floatval);
7399 	    } else {
7400 		ret = 0;
7401 	    }
7402 	}
7403 	else if (inf && !strict) {
7404 	    if (arg1i == -1 || arg2i == 1) {
7405 		ret = 1;
7406 	    } else if (arg1i == 0 && arg2i == 0) {
7407 		ret = (arg1->floatval <= arg2->floatval);
7408 	    } else {
7409 		ret = 0;
7410 	    }
7411 	}
7412 	else if (!inf && strict) {
7413 	    if ((arg1i == 1 && arg2i != 1) ||
7414 		(arg2i == -1 && arg1i != -1)) {
7415 		ret = 1;
7416 	    } else if (arg1i == 0 && arg2i == 0) {
7417 		ret = (arg1->floatval > arg2->floatval);
7418 	    } else {
7419 		ret = 0;
7420 	    }
7421 	}
7422 	else if (!inf && !strict) {
7423 	    if (arg1i == 1 || arg2i == -1) {
7424 		ret = 1;
7425 	    } else if (arg1i == 0 && arg2i == 0) {
7426 		ret = (arg1->floatval >= arg2->floatval);
7427 	    } else {
7428 		ret = 0;
7429 	    }
7430 	}
7431     }
7432     xmlXPathReleaseObject(ctxt->context, arg1);
7433     xmlXPathReleaseObject(ctxt->context, arg2);
7434     return(ret);
7435 }
7436 
7437 /**
7438  * xmlXPathValueFlipSign:
7439  * @ctxt:  the XPath Parser context
7440  *
7441  * Implement the unary - operation on an XPath object
7442  * The numeric operators convert their operands to numbers as if
7443  * by calling the number function.
7444  */
7445 void
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt)7446 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7447     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7448     CAST_TO_NUMBER;
7449     CHECK_TYPE(XPATH_NUMBER);
7450     ctxt->value->floatval = -ctxt->value->floatval;
7451 }
7452 
7453 /**
7454  * xmlXPathAddValues:
7455  * @ctxt:  the XPath Parser context
7456  *
7457  * Implement the add operation on XPath objects:
7458  * The numeric operators convert their operands to numbers as if
7459  * by calling the number function.
7460  */
7461 void
xmlXPathAddValues(xmlXPathParserContextPtr ctxt)7462 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7463     xmlXPathObjectPtr arg;
7464     double val;
7465 
7466     arg = valuePop(ctxt);
7467     if (arg == NULL)
7468 	XP_ERROR(XPATH_INVALID_OPERAND);
7469     val = xmlXPathCastToNumber(arg);
7470     xmlXPathReleaseObject(ctxt->context, arg);
7471     CAST_TO_NUMBER;
7472     CHECK_TYPE(XPATH_NUMBER);
7473     ctxt->value->floatval += val;
7474 }
7475 
7476 /**
7477  * xmlXPathSubValues:
7478  * @ctxt:  the XPath Parser context
7479  *
7480  * Implement the subtraction operation on XPath objects:
7481  * The numeric operators convert their operands to numbers as if
7482  * by calling the number function.
7483  */
7484 void
xmlXPathSubValues(xmlXPathParserContextPtr ctxt)7485 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7486     xmlXPathObjectPtr arg;
7487     double val;
7488 
7489     arg = valuePop(ctxt);
7490     if (arg == NULL)
7491 	XP_ERROR(XPATH_INVALID_OPERAND);
7492     val = xmlXPathCastToNumber(arg);
7493     xmlXPathReleaseObject(ctxt->context, arg);
7494     CAST_TO_NUMBER;
7495     CHECK_TYPE(XPATH_NUMBER);
7496     ctxt->value->floatval -= val;
7497 }
7498 
7499 /**
7500  * xmlXPathMultValues:
7501  * @ctxt:  the XPath Parser context
7502  *
7503  * Implement the multiply operation on XPath objects:
7504  * The numeric operators convert their operands to numbers as if
7505  * by calling the number function.
7506  */
7507 void
xmlXPathMultValues(xmlXPathParserContextPtr ctxt)7508 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7509     xmlXPathObjectPtr arg;
7510     double val;
7511 
7512     arg = valuePop(ctxt);
7513     if (arg == NULL)
7514 	XP_ERROR(XPATH_INVALID_OPERAND);
7515     val = xmlXPathCastToNumber(arg);
7516     xmlXPathReleaseObject(ctxt->context, arg);
7517     CAST_TO_NUMBER;
7518     CHECK_TYPE(XPATH_NUMBER);
7519     ctxt->value->floatval *= val;
7520 }
7521 
7522 /**
7523  * xmlXPathDivValues:
7524  * @ctxt:  the XPath Parser context
7525  *
7526  * Implement the div operation on XPath objects @arg1 / @arg2:
7527  * The numeric operators convert their operands to numbers as if
7528  * by calling the number function.
7529  */
7530 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
7531 void
xmlXPathDivValues(xmlXPathParserContextPtr ctxt)7532 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7533     xmlXPathObjectPtr arg;
7534     double val;
7535 
7536     arg = valuePop(ctxt);
7537     if (arg == NULL)
7538 	XP_ERROR(XPATH_INVALID_OPERAND);
7539     val = xmlXPathCastToNumber(arg);
7540     xmlXPathReleaseObject(ctxt->context, arg);
7541     CAST_TO_NUMBER;
7542     CHECK_TYPE(XPATH_NUMBER);
7543     ctxt->value->floatval /= val;
7544 }
7545 
7546 /**
7547  * xmlXPathModValues:
7548  * @ctxt:  the XPath Parser context
7549  *
7550  * Implement the mod operation on XPath objects: @arg1 / @arg2
7551  * The numeric operators convert their operands to numbers as if
7552  * by calling the number function.
7553  */
7554 void
xmlXPathModValues(xmlXPathParserContextPtr ctxt)7555 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7556     xmlXPathObjectPtr arg;
7557     double arg1, arg2;
7558 
7559     arg = valuePop(ctxt);
7560     if (arg == NULL)
7561 	XP_ERROR(XPATH_INVALID_OPERAND);
7562     arg2 = xmlXPathCastToNumber(arg);
7563     xmlXPathReleaseObject(ctxt->context, arg);
7564     CAST_TO_NUMBER;
7565     CHECK_TYPE(XPATH_NUMBER);
7566     arg1 = ctxt->value->floatval;
7567     if (arg2 == 0)
7568 	ctxt->value->floatval = xmlXPathNAN;
7569     else {
7570 	ctxt->value->floatval = fmod(arg1, arg2);
7571     }
7572 }
7573 
7574 /************************************************************************
7575  *									*
7576  *		The traversal functions					*
7577  *									*
7578  ************************************************************************/
7579 
7580 /*
7581  * A traversal function enumerates nodes along an axis.
7582  * Initially it must be called with NULL, and it indicates
7583  * termination on the axis by returning NULL.
7584  */
7585 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7586                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7587 
7588 /*
7589  * xmlXPathTraversalFunctionExt:
7590  * A traversal function enumerates nodes along an axis.
7591  * Initially it must be called with NULL, and it indicates
7592  * termination on the axis by returning NULL.
7593  * The context node of the traversal is specified via @contextNode.
7594  */
7595 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7596                     (xmlNodePtr cur, xmlNodePtr contextNode);
7597 
7598 /*
7599  * xmlXPathNodeSetMergeFunction:
7600  * Used for merging node sets in xmlXPathCollectAndTest().
7601  */
7602 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7603 		    (xmlNodeSetPtr, xmlNodeSetPtr);
7604 
7605 
7606 /**
7607  * xmlXPathNextSelf:
7608  * @ctxt:  the XPath Parser context
7609  * @cur:  the current node in the traversal
7610  *
7611  * Traversal function for the "self" direction
7612  * The self axis contains just the context node itself
7613  *
7614  * Returns the next element following that axis
7615  */
7616 xmlNodePtr
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7617 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7618     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7619     if (cur == NULL)
7620         return(ctxt->context->node);
7621     return(NULL);
7622 }
7623 
7624 /**
7625  * xmlXPathNextChild:
7626  * @ctxt:  the XPath Parser context
7627  * @cur:  the current node in the traversal
7628  *
7629  * Traversal function for the "child" direction
7630  * The child axis contains the children of the context node in document order.
7631  *
7632  * Returns the next element following that axis
7633  */
7634 xmlNodePtr
xmlXPathNextChild(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7635 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7636     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7637     if (cur == NULL) {
7638 	if (ctxt->context->node == NULL) return(NULL);
7639 	switch (ctxt->context->node->type) {
7640             case XML_ELEMENT_NODE:
7641             case XML_TEXT_NODE:
7642             case XML_CDATA_SECTION_NODE:
7643             case XML_ENTITY_REF_NODE:
7644             case XML_ENTITY_NODE:
7645             case XML_PI_NODE:
7646             case XML_COMMENT_NODE:
7647             case XML_NOTATION_NODE:
7648             case XML_DTD_NODE:
7649 		return(ctxt->context->node->children);
7650             case XML_DOCUMENT_NODE:
7651             case XML_DOCUMENT_TYPE_NODE:
7652             case XML_DOCUMENT_FRAG_NODE:
7653             case XML_HTML_DOCUMENT_NODE:
7654 #ifdef LIBXML_DOCB_ENABLED
7655 	    case XML_DOCB_DOCUMENT_NODE:
7656 #endif
7657 		return(((xmlDocPtr) ctxt->context->node)->children);
7658 	    case XML_ELEMENT_DECL:
7659 	    case XML_ATTRIBUTE_DECL:
7660 	    case XML_ENTITY_DECL:
7661             case XML_ATTRIBUTE_NODE:
7662 	    case XML_NAMESPACE_DECL:
7663 	    case XML_XINCLUDE_START:
7664 	    case XML_XINCLUDE_END:
7665 		return(NULL);
7666 	}
7667 	return(NULL);
7668     }
7669     if ((cur->type == XML_DOCUMENT_NODE) ||
7670         (cur->type == XML_HTML_DOCUMENT_NODE))
7671 	return(NULL);
7672     return(cur->next);
7673 }
7674 
7675 /**
7676  * xmlXPathNextChildElement:
7677  * @ctxt:  the XPath Parser context
7678  * @cur:  the current node in the traversal
7679  *
7680  * Traversal function for the "child" direction and nodes of type element.
7681  * The child axis contains the children of the context node in document order.
7682  *
7683  * Returns the next element following that axis
7684  */
7685 static xmlNodePtr
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7686 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7687     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7688     if (cur == NULL) {
7689 	cur = ctxt->context->node;
7690 	if (cur == NULL) return(NULL);
7691 	/*
7692 	* Get the first element child.
7693 	*/
7694 	switch (cur->type) {
7695             case XML_ELEMENT_NODE:
7696 	    case XML_DOCUMENT_FRAG_NODE:
7697 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7698             case XML_ENTITY_NODE:
7699 		cur = cur->children;
7700 		if (cur != NULL) {
7701 		    if (cur->type == XML_ELEMENT_NODE)
7702 			return(cur);
7703 		    do {
7704 			cur = cur->next;
7705 		    } while ((cur != NULL) &&
7706 			(cur->type != XML_ELEMENT_NODE));
7707 		    return(cur);
7708 		}
7709 		return(NULL);
7710             case XML_DOCUMENT_NODE:
7711             case XML_HTML_DOCUMENT_NODE:
7712 #ifdef LIBXML_DOCB_ENABLED
7713 	    case XML_DOCB_DOCUMENT_NODE:
7714 #endif
7715 		return(xmlDocGetRootElement((xmlDocPtr) cur));
7716 	    default:
7717 		return(NULL);
7718 	}
7719 	return(NULL);
7720     }
7721     /*
7722     * Get the next sibling element node.
7723     */
7724     switch (cur->type) {
7725 	case XML_ELEMENT_NODE:
7726 	case XML_TEXT_NODE:
7727 	case XML_ENTITY_REF_NODE:
7728 	case XML_ENTITY_NODE:
7729 	case XML_CDATA_SECTION_NODE:
7730 	case XML_PI_NODE:
7731 	case XML_COMMENT_NODE:
7732 	case XML_XINCLUDE_END:
7733 	    break;
7734 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7735 	default:
7736 	    return(NULL);
7737     }
7738     if (cur->next != NULL) {
7739 	if (cur->next->type == XML_ELEMENT_NODE)
7740 	    return(cur->next);
7741 	cur = cur->next;
7742 	do {
7743 	    cur = cur->next;
7744 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7745 	return(cur);
7746     }
7747     return(NULL);
7748 }
7749 
7750 #if 0
7751 /**
7752  * xmlXPathNextDescendantOrSelfElemParent:
7753  * @ctxt:  the XPath Parser context
7754  * @cur:  the current node in the traversal
7755  *
7756  * Traversal function for the "descendant-or-self" axis.
7757  * Additionally it returns only nodes which can be parents of
7758  * element nodes.
7759  *
7760  *
7761  * Returns the next element following that axis
7762  */
7763 static xmlNodePtr
7764 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7765 				       xmlNodePtr contextNode)
7766 {
7767     if (cur == NULL) {
7768 	if (contextNode == NULL)
7769 	    return(NULL);
7770 	switch (contextNode->type) {
7771 	    case XML_ELEMENT_NODE:
7772 	    case XML_XINCLUDE_START:
7773 	    case XML_DOCUMENT_FRAG_NODE:
7774 	    case XML_DOCUMENT_NODE:
7775 #ifdef LIBXML_DOCB_ENABLED
7776 	    case XML_DOCB_DOCUMENT_NODE:
7777 #endif
7778 	    case XML_HTML_DOCUMENT_NODE:
7779 		return(contextNode);
7780 	    default:
7781 		return(NULL);
7782 	}
7783 	return(NULL);
7784     } else {
7785 	xmlNodePtr start = cur;
7786 
7787 	while (cur != NULL) {
7788 	    switch (cur->type) {
7789 		case XML_ELEMENT_NODE:
7790 		/* TODO: OK to have XInclude here? */
7791 		case XML_XINCLUDE_START:
7792 		case XML_DOCUMENT_FRAG_NODE:
7793 		    if (cur != start)
7794 			return(cur);
7795 		    if (cur->children != NULL) {
7796 			cur = cur->children;
7797 			continue;
7798 		    }
7799 		    break;
7800 		/* Not sure if we need those here. */
7801 		case XML_DOCUMENT_NODE:
7802 #ifdef LIBXML_DOCB_ENABLED
7803 		case XML_DOCB_DOCUMENT_NODE:
7804 #endif
7805 		case XML_HTML_DOCUMENT_NODE:
7806 		    if (cur != start)
7807 			return(cur);
7808 		    return(xmlDocGetRootElement((xmlDocPtr) cur));
7809 		default:
7810 		    break;
7811 	    }
7812 
7813 next_sibling:
7814 	    if ((cur == NULL) || (cur == contextNode))
7815 		return(NULL);
7816 	    if (cur->next != NULL) {
7817 		cur = cur->next;
7818 	    } else {
7819 		cur = cur->parent;
7820 		goto next_sibling;
7821 	    }
7822 	}
7823     }
7824     return(NULL);
7825 }
7826 #endif
7827 
7828 /**
7829  * xmlXPathNextDescendant:
7830  * @ctxt:  the XPath Parser context
7831  * @cur:  the current node in the traversal
7832  *
7833  * Traversal function for the "descendant" direction
7834  * the descendant axis contains the descendants of the context node in document
7835  * order; a descendant is a child or a child of a child and so on.
7836  *
7837  * Returns the next element following that axis
7838  */
7839 xmlNodePtr
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7840 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7841     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7842     if (cur == NULL) {
7843 	if (ctxt->context->node == NULL)
7844 	    return(NULL);
7845 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7846 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7847 	    return(NULL);
7848 
7849         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7850 	    return(ctxt->context->doc->children);
7851         return(ctxt->context->node->children);
7852     }
7853 
7854     if (cur->type == XML_NAMESPACE_DECL)
7855         return(NULL);
7856     if (cur->children != NULL) {
7857 	/*
7858 	 * Do not descend on entities declarations
7859 	 */
7860 	if (cur->children->type != XML_ENTITY_DECL) {
7861 	    cur = cur->children;
7862 	    /*
7863 	     * Skip DTDs
7864 	     */
7865 	    if (cur->type != XML_DTD_NODE)
7866 		return(cur);
7867 	}
7868     }
7869 
7870     if (cur == ctxt->context->node) return(NULL);
7871 
7872     while (cur->next != NULL) {
7873 	cur = cur->next;
7874 	if ((cur->type != XML_ENTITY_DECL) &&
7875 	    (cur->type != XML_DTD_NODE))
7876 	    return(cur);
7877     }
7878 
7879     do {
7880         cur = cur->parent;
7881 	if (cur == NULL) break;
7882 	if (cur == ctxt->context->node) return(NULL);
7883 	if (cur->next != NULL) {
7884 	    cur = cur->next;
7885 	    return(cur);
7886 	}
7887     } while (cur != NULL);
7888     return(cur);
7889 }
7890 
7891 /**
7892  * xmlXPathNextDescendantOrSelf:
7893  * @ctxt:  the XPath Parser context
7894  * @cur:  the current node in the traversal
7895  *
7896  * Traversal function for the "descendant-or-self" direction
7897  * the descendant-or-self axis contains the context node and the descendants
7898  * of the context node in document order; thus the context node is the first
7899  * node on the axis, and the first child of the context node is the second node
7900  * on the axis
7901  *
7902  * Returns the next element following that axis
7903  */
7904 xmlNodePtr
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7905 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7906     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7907     if (cur == NULL)
7908         return(ctxt->context->node);
7909 
7910     if (ctxt->context->node == NULL)
7911         return(NULL);
7912     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7913         (ctxt->context->node->type == XML_NAMESPACE_DECL))
7914         return(NULL);
7915 
7916     return(xmlXPathNextDescendant(ctxt, cur));
7917 }
7918 
7919 /**
7920  * xmlXPathNextParent:
7921  * @ctxt:  the XPath Parser context
7922  * @cur:  the current node in the traversal
7923  *
7924  * Traversal function for the "parent" direction
7925  * The parent axis contains the parent of the context node, if there is one.
7926  *
7927  * Returns the next element following that axis
7928  */
7929 xmlNodePtr
xmlXPathNextParent(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7930 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7931     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7932     /*
7933      * the parent of an attribute or namespace node is the element
7934      * to which the attribute or namespace node is attached
7935      * Namespace handling !!!
7936      */
7937     if (cur == NULL) {
7938 	if (ctxt->context->node == NULL) return(NULL);
7939 	switch (ctxt->context->node->type) {
7940             case XML_ELEMENT_NODE:
7941             case XML_TEXT_NODE:
7942             case XML_CDATA_SECTION_NODE:
7943             case XML_ENTITY_REF_NODE:
7944             case XML_ENTITY_NODE:
7945             case XML_PI_NODE:
7946             case XML_COMMENT_NODE:
7947             case XML_NOTATION_NODE:
7948             case XML_DTD_NODE:
7949 	    case XML_ELEMENT_DECL:
7950 	    case XML_ATTRIBUTE_DECL:
7951 	    case XML_XINCLUDE_START:
7952 	    case XML_XINCLUDE_END:
7953 	    case XML_ENTITY_DECL:
7954 		if (ctxt->context->node->parent == NULL)
7955 		    return((xmlNodePtr) ctxt->context->doc);
7956 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7957 		    ((ctxt->context->node->parent->name[0] == ' ') ||
7958 		     (xmlStrEqual(ctxt->context->node->parent->name,
7959 				 BAD_CAST "fake node libxslt"))))
7960 		    return(NULL);
7961 		return(ctxt->context->node->parent);
7962             case XML_ATTRIBUTE_NODE: {
7963 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7964 
7965 		return(att->parent);
7966 	    }
7967             case XML_DOCUMENT_NODE:
7968             case XML_DOCUMENT_TYPE_NODE:
7969             case XML_DOCUMENT_FRAG_NODE:
7970             case XML_HTML_DOCUMENT_NODE:
7971 #ifdef LIBXML_DOCB_ENABLED
7972 	    case XML_DOCB_DOCUMENT_NODE:
7973 #endif
7974                 return(NULL);
7975 	    case XML_NAMESPACE_DECL: {
7976 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7977 
7978 		if ((ns->next != NULL) &&
7979 		    (ns->next->type != XML_NAMESPACE_DECL))
7980 		    return((xmlNodePtr) ns->next);
7981                 return(NULL);
7982 	    }
7983 	}
7984     }
7985     return(NULL);
7986 }
7987 
7988 /**
7989  * xmlXPathNextAncestor:
7990  * @ctxt:  the XPath Parser context
7991  * @cur:  the current node in the traversal
7992  *
7993  * Traversal function for the "ancestor" direction
7994  * the ancestor axis contains the ancestors of the context node; the ancestors
7995  * of the context node consist of the parent of context node and the parent's
7996  * parent and so on; the nodes are ordered in reverse document order; thus the
7997  * parent is the first node on the axis, and the parent's parent is the second
7998  * node on the axis
7999  *
8000  * Returns the next element following that axis
8001  */
8002 xmlNodePtr
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8003 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8004     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8005     /*
8006      * the parent of an attribute or namespace node is the element
8007      * to which the attribute or namespace node is attached
8008      * !!!!!!!!!!!!!
8009      */
8010     if (cur == NULL) {
8011 	if (ctxt->context->node == NULL) return(NULL);
8012 	switch (ctxt->context->node->type) {
8013             case XML_ELEMENT_NODE:
8014             case XML_TEXT_NODE:
8015             case XML_CDATA_SECTION_NODE:
8016             case XML_ENTITY_REF_NODE:
8017             case XML_ENTITY_NODE:
8018             case XML_PI_NODE:
8019             case XML_COMMENT_NODE:
8020 	    case XML_DTD_NODE:
8021 	    case XML_ELEMENT_DECL:
8022 	    case XML_ATTRIBUTE_DECL:
8023 	    case XML_ENTITY_DECL:
8024             case XML_NOTATION_NODE:
8025 	    case XML_XINCLUDE_START:
8026 	    case XML_XINCLUDE_END:
8027 		if (ctxt->context->node->parent == NULL)
8028 		    return((xmlNodePtr) ctxt->context->doc);
8029 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8030 		    ((ctxt->context->node->parent->name[0] == ' ') ||
8031 		     (xmlStrEqual(ctxt->context->node->parent->name,
8032 				 BAD_CAST "fake node libxslt"))))
8033 		    return(NULL);
8034 		return(ctxt->context->node->parent);
8035             case XML_ATTRIBUTE_NODE: {
8036 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8037 
8038 		return(tmp->parent);
8039 	    }
8040             case XML_DOCUMENT_NODE:
8041             case XML_DOCUMENT_TYPE_NODE:
8042             case XML_DOCUMENT_FRAG_NODE:
8043             case XML_HTML_DOCUMENT_NODE:
8044 #ifdef LIBXML_DOCB_ENABLED
8045 	    case XML_DOCB_DOCUMENT_NODE:
8046 #endif
8047                 return(NULL);
8048 	    case XML_NAMESPACE_DECL: {
8049 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8050 
8051 		if ((ns->next != NULL) &&
8052 		    (ns->next->type != XML_NAMESPACE_DECL))
8053 		    return((xmlNodePtr) ns->next);
8054 		/* Bad, how did that namespace end up here ? */
8055                 return(NULL);
8056 	    }
8057 	}
8058 	return(NULL);
8059     }
8060     if (cur == ctxt->context->doc->children)
8061 	return((xmlNodePtr) ctxt->context->doc);
8062     if (cur == (xmlNodePtr) ctxt->context->doc)
8063 	return(NULL);
8064     switch (cur->type) {
8065 	case XML_ELEMENT_NODE:
8066 	case XML_TEXT_NODE:
8067 	case XML_CDATA_SECTION_NODE:
8068 	case XML_ENTITY_REF_NODE:
8069 	case XML_ENTITY_NODE:
8070 	case XML_PI_NODE:
8071 	case XML_COMMENT_NODE:
8072 	case XML_NOTATION_NODE:
8073 	case XML_DTD_NODE:
8074         case XML_ELEMENT_DECL:
8075         case XML_ATTRIBUTE_DECL:
8076         case XML_ENTITY_DECL:
8077 	case XML_XINCLUDE_START:
8078 	case XML_XINCLUDE_END:
8079 	    if (cur->parent == NULL)
8080 		return(NULL);
8081 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
8082 		((cur->parent->name[0] == ' ') ||
8083 		 (xmlStrEqual(cur->parent->name,
8084 			      BAD_CAST "fake node libxslt"))))
8085 		return(NULL);
8086 	    return(cur->parent);
8087 	case XML_ATTRIBUTE_NODE: {
8088 	    xmlAttrPtr att = (xmlAttrPtr) cur;
8089 
8090 	    return(att->parent);
8091 	}
8092 	case XML_NAMESPACE_DECL: {
8093 	    xmlNsPtr ns = (xmlNsPtr) cur;
8094 
8095 	    if ((ns->next != NULL) &&
8096 	        (ns->next->type != XML_NAMESPACE_DECL))
8097 	        return((xmlNodePtr) ns->next);
8098 	    /* Bad, how did that namespace end up here ? */
8099             return(NULL);
8100 	}
8101 	case XML_DOCUMENT_NODE:
8102 	case XML_DOCUMENT_TYPE_NODE:
8103 	case XML_DOCUMENT_FRAG_NODE:
8104 	case XML_HTML_DOCUMENT_NODE:
8105 #ifdef LIBXML_DOCB_ENABLED
8106 	case XML_DOCB_DOCUMENT_NODE:
8107 #endif
8108 	    return(NULL);
8109     }
8110     return(NULL);
8111 }
8112 
8113 /**
8114  * xmlXPathNextAncestorOrSelf:
8115  * @ctxt:  the XPath Parser context
8116  * @cur:  the current node in the traversal
8117  *
8118  * Traversal function for the "ancestor-or-self" direction
8119  * he ancestor-or-self axis contains the context node and ancestors of
8120  * the context node in reverse document order; thus the context node is
8121  * the first node on the axis, and the context node's parent the second;
8122  * parent here is defined the same as with the parent axis.
8123  *
8124  * Returns the next element following that axis
8125  */
8126 xmlNodePtr
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8127 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8128     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8129     if (cur == NULL)
8130         return(ctxt->context->node);
8131     return(xmlXPathNextAncestor(ctxt, cur));
8132 }
8133 
8134 /**
8135  * xmlXPathNextFollowingSibling:
8136  * @ctxt:  the XPath Parser context
8137  * @cur:  the current node in the traversal
8138  *
8139  * Traversal function for the "following-sibling" direction
8140  * The following-sibling axis contains the following siblings of the context
8141  * node in document order.
8142  *
8143  * Returns the next element following that axis
8144  */
8145 xmlNodePtr
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8146 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8147     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8148     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8149 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
8150 	return(NULL);
8151     if (cur == (xmlNodePtr) ctxt->context->doc)
8152         return(NULL);
8153     if (cur == NULL)
8154         return(ctxt->context->node->next);
8155     return(cur->next);
8156 }
8157 
8158 /**
8159  * xmlXPathNextPrecedingSibling:
8160  * @ctxt:  the XPath Parser context
8161  * @cur:  the current node in the traversal
8162  *
8163  * Traversal function for the "preceding-sibling" direction
8164  * The preceding-sibling axis contains the preceding siblings of the context
8165  * node in reverse document order; the first preceding sibling is first on the
8166  * axis; the sibling preceding that node is the second on the axis and so on.
8167  *
8168  * Returns the next element following that axis
8169  */
8170 xmlNodePtr
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8171 xmlXPathNextPrecedingSibling(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->prev);
8180     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8181 	cur = cur->prev;
8182 	if (cur == NULL)
8183 	    return(ctxt->context->node->prev);
8184     }
8185     return(cur->prev);
8186 }
8187 
8188 /**
8189  * xmlXPathNextFollowing:
8190  * @ctxt:  the XPath Parser context
8191  * @cur:  the current node in the traversal
8192  *
8193  * Traversal function for the "following" direction
8194  * The following axis contains all nodes in the same document as the context
8195  * node that are after the context node in document order, excluding any
8196  * descendants and excluding attribute nodes and namespace nodes; the nodes
8197  * are ordered in document order
8198  *
8199  * Returns the next element following that axis
8200  */
8201 xmlNodePtr
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8202 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8203     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8204     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8205         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8206         return(cur->children);
8207 
8208     if (cur == NULL) {
8209         cur = ctxt->context->node;
8210         if (cur->type == XML_ATTRIBUTE_NODE) {
8211             cur = cur->parent;
8212         } else if (cur->type == XML_NAMESPACE_DECL) {
8213             xmlNsPtr ns = (xmlNsPtr) cur;
8214 
8215             if ((ns->next == NULL) ||
8216                 (ns->next->type == XML_NAMESPACE_DECL))
8217                 return (NULL);
8218             cur = (xmlNodePtr) ns->next;
8219         }
8220     }
8221     if (cur == NULL) return(NULL) ; /* ERROR */
8222     if (cur->next != NULL) return(cur->next) ;
8223     do {
8224         cur = cur->parent;
8225         if (cur == NULL) break;
8226         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8227         if (cur->next != NULL) return(cur->next);
8228     } while (cur != NULL);
8229     return(cur);
8230 }
8231 
8232 /*
8233  * xmlXPathIsAncestor:
8234  * @ancestor:  the ancestor node
8235  * @node:  the current node
8236  *
8237  * Check that @ancestor is a @node's ancestor
8238  *
8239  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8240  */
8241 static int
xmlXPathIsAncestor(xmlNodePtr ancestor,xmlNodePtr node)8242 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8243     if ((ancestor == NULL) || (node == NULL)) return(0);
8244     if (node->type == XML_NAMESPACE_DECL)
8245         return(0);
8246     if (ancestor->type == XML_NAMESPACE_DECL)
8247         return(0);
8248     /* nodes need to be in the same document */
8249     if (ancestor->doc != node->doc) return(0);
8250     /* avoid searching if ancestor or node is the root node */
8251     if (ancestor == (xmlNodePtr) node->doc) return(1);
8252     if (node == (xmlNodePtr) ancestor->doc) return(0);
8253     while (node->parent != NULL) {
8254         if (node->parent == ancestor)
8255             return(1);
8256 	node = node->parent;
8257     }
8258     return(0);
8259 }
8260 
8261 /**
8262  * xmlXPathNextPreceding:
8263  * @ctxt:  the XPath Parser context
8264  * @cur:  the current node in the traversal
8265  *
8266  * Traversal function for the "preceding" direction
8267  * the preceding axis contains all nodes in the same document as the context
8268  * node that are before the context node in document order, excluding any
8269  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8270  * ordered in reverse document order
8271  *
8272  * Returns the next element following that axis
8273  */
8274 xmlNodePtr
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8275 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8276 {
8277     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8278     if (cur == NULL) {
8279         cur = ctxt->context->node;
8280         if (cur->type == XML_ATTRIBUTE_NODE) {
8281             cur = cur->parent;
8282         } else if (cur->type == XML_NAMESPACE_DECL) {
8283             xmlNsPtr ns = (xmlNsPtr) cur;
8284 
8285             if ((ns->next == NULL) ||
8286                 (ns->next->type == XML_NAMESPACE_DECL))
8287                 return (NULL);
8288             cur = (xmlNodePtr) ns->next;
8289         }
8290     }
8291     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8292 	return (NULL);
8293     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8294 	cur = cur->prev;
8295     do {
8296         if (cur->prev != NULL) {
8297             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8298             return (cur);
8299         }
8300 
8301         cur = cur->parent;
8302         if (cur == NULL)
8303             return (NULL);
8304         if (cur == ctxt->context->doc->children)
8305             return (NULL);
8306     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8307     return (cur);
8308 }
8309 
8310 /**
8311  * xmlXPathNextPrecedingInternal:
8312  * @ctxt:  the XPath Parser context
8313  * @cur:  the current node in the traversal
8314  *
8315  * Traversal function for the "preceding" direction
8316  * the preceding axis contains all nodes in the same document as the context
8317  * node that are before the context node in document order, excluding any
8318  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8319  * ordered in reverse document order
8320  * This is a faster implementation but internal only since it requires a
8321  * state kept in the parser context: ctxt->ancestor.
8322  *
8323  * Returns the next element following that axis
8324  */
8325 static xmlNodePtr
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8326 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8327                               xmlNodePtr cur)
8328 {
8329     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8330     if (cur == NULL) {
8331         cur = ctxt->context->node;
8332         if (cur == NULL)
8333             return (NULL);
8334         if (cur->type == XML_ATTRIBUTE_NODE) {
8335             cur = cur->parent;
8336         } else if (cur->type == XML_NAMESPACE_DECL) {
8337             xmlNsPtr ns = (xmlNsPtr) cur;
8338 
8339             if ((ns->next == NULL) ||
8340                 (ns->next->type == XML_NAMESPACE_DECL))
8341                 return (NULL);
8342             cur = (xmlNodePtr) ns->next;
8343         }
8344         ctxt->ancestor = cur->parent;
8345     }
8346     if (cur->type == XML_NAMESPACE_DECL)
8347         return(NULL);
8348     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8349 	cur = cur->prev;
8350     while (cur->prev == NULL) {
8351         cur = cur->parent;
8352         if (cur == NULL)
8353             return (NULL);
8354         if (cur == ctxt->context->doc->children)
8355             return (NULL);
8356         if (cur != ctxt->ancestor)
8357             return (cur);
8358         ctxt->ancestor = cur->parent;
8359     }
8360     cur = cur->prev;
8361     while (cur->last != NULL)
8362         cur = cur->last;
8363     return (cur);
8364 }
8365 
8366 /**
8367  * xmlXPathNextNamespace:
8368  * @ctxt:  the XPath Parser context
8369  * @cur:  the current attribute in the traversal
8370  *
8371  * Traversal function for the "namespace" direction
8372  * the namespace axis contains the namespace nodes of the context node;
8373  * the order of nodes on this axis is implementation-defined; the axis will
8374  * be empty unless the context node is an element
8375  *
8376  * We keep the XML namespace node at the end of the list.
8377  *
8378  * Returns the next element following that axis
8379  */
8380 xmlNodePtr
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8381 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8382     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8383     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8384     if (cur == NULL) {
8385         if (ctxt->context->tmpNsList != NULL)
8386 	    xmlFree(ctxt->context->tmpNsList);
8387 	ctxt->context->tmpNsList =
8388 	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8389 	ctxt->context->tmpNsNr = 0;
8390 	if (ctxt->context->tmpNsList != NULL) {
8391 	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8392 		ctxt->context->tmpNsNr++;
8393 	    }
8394 	}
8395 	return((xmlNodePtr) xmlXPathXMLNamespace);
8396     }
8397     if (ctxt->context->tmpNsNr > 0) {
8398 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8399     } else {
8400 	if (ctxt->context->tmpNsList != NULL)
8401 	    xmlFree(ctxt->context->tmpNsList);
8402 	ctxt->context->tmpNsList = NULL;
8403 	return(NULL);
8404     }
8405 }
8406 
8407 /**
8408  * xmlXPathNextAttribute:
8409  * @ctxt:  the XPath Parser context
8410  * @cur:  the current attribute in the traversal
8411  *
8412  * Traversal function for the "attribute" direction
8413  * TODO: support DTD inherited default attributes
8414  *
8415  * Returns the next element following that axis
8416  */
8417 xmlNodePtr
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8418 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8419     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8420     if (ctxt->context->node == NULL)
8421 	return(NULL);
8422     if (ctxt->context->node->type != XML_ELEMENT_NODE)
8423 	return(NULL);
8424     if (cur == NULL) {
8425         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8426 	    return(NULL);
8427         return((xmlNodePtr)ctxt->context->node->properties);
8428     }
8429     return((xmlNodePtr)cur->next);
8430 }
8431 
8432 /************************************************************************
8433  *									*
8434  *		NodeTest Functions					*
8435  *									*
8436  ************************************************************************/
8437 
8438 #define IS_FUNCTION			200
8439 
8440 
8441 /************************************************************************
8442  *									*
8443  *		Implicit tree core function library			*
8444  *									*
8445  ************************************************************************/
8446 
8447 /**
8448  * xmlXPathRoot:
8449  * @ctxt:  the XPath Parser context
8450  *
8451  * Initialize the context to the root of the document
8452  */
8453 void
xmlXPathRoot(xmlXPathParserContextPtr ctxt)8454 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8455     if ((ctxt == NULL) || (ctxt->context == NULL))
8456 	return;
8457     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8458 	(xmlNodePtr) ctxt->context->doc));
8459 }
8460 
8461 /************************************************************************
8462  *									*
8463  *		The explicit core function library			*
8464  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
8465  *									*
8466  ************************************************************************/
8467 
8468 
8469 /**
8470  * xmlXPathLastFunction:
8471  * @ctxt:  the XPath Parser context
8472  * @nargs:  the number of arguments
8473  *
8474  * Implement the last() XPath function
8475  *    number last()
8476  * The last function returns the number of nodes in the context node list.
8477  */
8478 void
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt,int nargs)8479 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8480     CHECK_ARITY(0);
8481     if (ctxt->context->contextSize >= 0) {
8482 	valuePush(ctxt,
8483 	    xmlXPathCacheNewFloat(ctxt->context,
8484 		(double) ctxt->context->contextSize));
8485 #ifdef DEBUG_EXPR
8486 	xmlGenericError(xmlGenericErrorContext,
8487 		"last() : %d\n", ctxt->context->contextSize);
8488 #endif
8489     } else {
8490 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8491     }
8492 }
8493 
8494 /**
8495  * xmlXPathPositionFunction:
8496  * @ctxt:  the XPath Parser context
8497  * @nargs:  the number of arguments
8498  *
8499  * Implement the position() XPath function
8500  *    number position()
8501  * The position function returns the position of the context node in the
8502  * context node list. The first position is 1, and so the last position
8503  * will be equal to last().
8504  */
8505 void
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt,int nargs)8506 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8507     CHECK_ARITY(0);
8508     if (ctxt->context->proximityPosition >= 0) {
8509 	valuePush(ctxt,
8510 	      xmlXPathCacheNewFloat(ctxt->context,
8511 		(double) ctxt->context->proximityPosition));
8512 #ifdef DEBUG_EXPR
8513 	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8514 		ctxt->context->proximityPosition);
8515 #endif
8516     } else {
8517 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8518     }
8519 }
8520 
8521 /**
8522  * xmlXPathCountFunction:
8523  * @ctxt:  the XPath Parser context
8524  * @nargs:  the number of arguments
8525  *
8526  * Implement the count() XPath function
8527  *    number count(node-set)
8528  */
8529 void
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt,int nargs)8530 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8531     xmlXPathObjectPtr cur;
8532 
8533     CHECK_ARITY(1);
8534     if ((ctxt->value == NULL) ||
8535 	((ctxt->value->type != XPATH_NODESET) &&
8536 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8537 	XP_ERROR(XPATH_INVALID_TYPE);
8538     cur = valuePop(ctxt);
8539 
8540     if ((cur == NULL) || (cur->nodesetval == NULL))
8541 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8542     else
8543 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8544 	    (double) cur->nodesetval->nodeNr));
8545     xmlXPathReleaseObject(ctxt->context, cur);
8546 }
8547 
8548 /**
8549  * xmlXPathGetElementsByIds:
8550  * @doc:  the document
8551  * @ids:  a whitespace separated list of IDs
8552  *
8553  * Selects elements by their unique ID.
8554  *
8555  * Returns a node-set of selected elements.
8556  */
8557 static xmlNodeSetPtr
xmlXPathGetElementsByIds(xmlDocPtr doc,const xmlChar * ids)8558 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8559     xmlNodeSetPtr ret;
8560     const xmlChar *cur = ids;
8561     xmlChar *ID;
8562     xmlAttrPtr attr;
8563     xmlNodePtr elem = NULL;
8564 
8565     if (ids == NULL) return(NULL);
8566 
8567     ret = xmlXPathNodeSetCreate(NULL);
8568     if (ret == NULL)
8569         return(ret);
8570 
8571     while (IS_BLANK_CH(*cur)) cur++;
8572     while (*cur != 0) {
8573 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8574 	    cur++;
8575 
8576         ID = xmlStrndup(ids, cur - ids);
8577 	if (ID != NULL) {
8578 	    /*
8579 	     * We used to check the fact that the value passed
8580 	     * was an NCName, but this generated much troubles for
8581 	     * me and Aleksey Sanin, people blatantly violated that
8582 	     * constraint, like Visa3D spec.
8583 	     * if (xmlValidateNCName(ID, 1) == 0)
8584 	     */
8585 	    attr = xmlGetID(doc, ID);
8586 	    if (attr != NULL) {
8587 		if (attr->type == XML_ATTRIBUTE_NODE)
8588 		    elem = attr->parent;
8589 		else if (attr->type == XML_ELEMENT_NODE)
8590 		    elem = (xmlNodePtr) attr;
8591 		else
8592 		    elem = NULL;
8593                 /* TODO: Check memory error. */
8594 		if (elem != NULL)
8595 		    xmlXPathNodeSetAdd(ret, elem);
8596 	    }
8597 	    xmlFree(ID);
8598 	}
8599 
8600 	while (IS_BLANK_CH(*cur)) cur++;
8601 	ids = cur;
8602     }
8603     return(ret);
8604 }
8605 
8606 /**
8607  * xmlXPathIdFunction:
8608  * @ctxt:  the XPath Parser context
8609  * @nargs:  the number of arguments
8610  *
8611  * Implement the id() XPath function
8612  *    node-set id(object)
8613  * The id function selects elements by their unique ID
8614  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8615  * then the result is the union of the result of applying id to the
8616  * string value of each of the nodes in the argument node-set. When the
8617  * argument to id is of any other type, the argument is converted to a
8618  * string as if by a call to the string function; the string is split
8619  * into a whitespace-separated list of tokens (whitespace is any sequence
8620  * of characters matching the production S); the result is a node-set
8621  * containing the elements in the same document as the context node that
8622  * have a unique ID equal to any of the tokens in the list.
8623  */
8624 void
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt,int nargs)8625 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8626     xmlChar *tokens;
8627     xmlNodeSetPtr ret;
8628     xmlXPathObjectPtr obj;
8629 
8630     CHECK_ARITY(1);
8631     obj = valuePop(ctxt);
8632     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8633     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8634 	xmlNodeSetPtr ns;
8635 	int i;
8636 
8637         /* TODO: Check memory error. */
8638 	ret = xmlXPathNodeSetCreate(NULL);
8639 
8640 	if (obj->nodesetval != NULL) {
8641 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8642 		tokens =
8643 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8644 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8645                 /* TODO: Check memory error. */
8646 		ret = xmlXPathNodeSetMerge(ret, ns);
8647 		xmlXPathFreeNodeSet(ns);
8648 		if (tokens != NULL)
8649 		    xmlFree(tokens);
8650 	    }
8651 	}
8652 	xmlXPathReleaseObject(ctxt->context, obj);
8653 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8654 	return;
8655     }
8656     obj = xmlXPathCacheConvertString(ctxt->context, obj);
8657     if (obj == NULL) return;
8658     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8659     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8660     xmlXPathReleaseObject(ctxt->context, obj);
8661     return;
8662 }
8663 
8664 /**
8665  * xmlXPathLocalNameFunction:
8666  * @ctxt:  the XPath Parser context
8667  * @nargs:  the number of arguments
8668  *
8669  * Implement the local-name() XPath function
8670  *    string local-name(node-set?)
8671  * The local-name function returns a string containing the local part
8672  * of the name of the node in the argument node-set that is first in
8673  * document order. If the node-set is empty or the first node has no
8674  * name, an empty string is returned. If the argument is omitted it
8675  * defaults to the context node.
8676  */
8677 void
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8678 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8679     xmlXPathObjectPtr cur;
8680 
8681     if (ctxt == NULL) return;
8682 
8683     if (nargs == 0) {
8684 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8685 	    ctxt->context->node));
8686 	nargs = 1;
8687     }
8688 
8689     CHECK_ARITY(1);
8690     if ((ctxt->value == NULL) ||
8691 	((ctxt->value->type != XPATH_NODESET) &&
8692 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8693 	XP_ERROR(XPATH_INVALID_TYPE);
8694     cur = valuePop(ctxt);
8695 
8696     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8697 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8698     } else {
8699 	int i = 0; /* Should be first in document order !!!!! */
8700 	switch (cur->nodesetval->nodeTab[i]->type) {
8701 	case XML_ELEMENT_NODE:
8702 	case XML_ATTRIBUTE_NODE:
8703 	case XML_PI_NODE:
8704 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8705 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8706 	    else
8707 		valuePush(ctxt,
8708 		      xmlXPathCacheNewString(ctxt->context,
8709 			cur->nodesetval->nodeTab[i]->name));
8710 	    break;
8711 	case XML_NAMESPACE_DECL:
8712 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8713 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8714 	    break;
8715 	default:
8716 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8717 	}
8718     }
8719     xmlXPathReleaseObject(ctxt->context, cur);
8720 }
8721 
8722 /**
8723  * xmlXPathNamespaceURIFunction:
8724  * @ctxt:  the XPath Parser context
8725  * @nargs:  the number of arguments
8726  *
8727  * Implement the namespace-uri() XPath function
8728  *    string namespace-uri(node-set?)
8729  * The namespace-uri function returns a string containing the
8730  * namespace URI of the expanded name of the node in the argument
8731  * node-set that is first in document order. If the node-set is empty,
8732  * the first node has no name, or the expanded name has no namespace
8733  * URI, an empty string is returned. If the argument is omitted it
8734  * defaults to the context node.
8735  */
8736 void
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt,int nargs)8737 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8738     xmlXPathObjectPtr cur;
8739 
8740     if (ctxt == NULL) return;
8741 
8742     if (nargs == 0) {
8743 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8744 	    ctxt->context->node));
8745 	nargs = 1;
8746     }
8747     CHECK_ARITY(1);
8748     if ((ctxt->value == NULL) ||
8749 	((ctxt->value->type != XPATH_NODESET) &&
8750 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8751 	XP_ERROR(XPATH_INVALID_TYPE);
8752     cur = valuePop(ctxt);
8753 
8754     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8755 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8756     } else {
8757 	int i = 0; /* Should be first in document order !!!!! */
8758 	switch (cur->nodesetval->nodeTab[i]->type) {
8759 	case XML_ELEMENT_NODE:
8760 	case XML_ATTRIBUTE_NODE:
8761 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
8762 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8763 	    else
8764 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8765 			  cur->nodesetval->nodeTab[i]->ns->href));
8766 	    break;
8767 	default:
8768 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8769 	}
8770     }
8771     xmlXPathReleaseObject(ctxt->context, cur);
8772 }
8773 
8774 /**
8775  * xmlXPathNameFunction:
8776  * @ctxt:  the XPath Parser context
8777  * @nargs:  the number of arguments
8778  *
8779  * Implement the name() XPath function
8780  *    string name(node-set?)
8781  * The name function returns a string containing a QName representing
8782  * the name of the node in the argument node-set that is first in document
8783  * order. The QName must represent the name with respect to the namespace
8784  * declarations in effect on the node whose name is being represented.
8785  * Typically, this will be the form in which the name occurred in the XML
8786  * source. This need not be the case if there are namespace declarations
8787  * in effect on the node that associate multiple prefixes with the same
8788  * namespace. However, an implementation may include information about
8789  * the original prefix in its representation of nodes; in this case, an
8790  * implementation can ensure that the returned string is always the same
8791  * as the QName used in the XML source. If the argument it omitted it
8792  * defaults to the context node.
8793  * Libxml keep the original prefix so the "real qualified name" used is
8794  * returned.
8795  */
8796 static void
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8797 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8798 {
8799     xmlXPathObjectPtr cur;
8800 
8801     if (nargs == 0) {
8802 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8803 	    ctxt->context->node));
8804         nargs = 1;
8805     }
8806 
8807     CHECK_ARITY(1);
8808     if ((ctxt->value == NULL) ||
8809         ((ctxt->value->type != XPATH_NODESET) &&
8810          (ctxt->value->type != XPATH_XSLT_TREE)))
8811         XP_ERROR(XPATH_INVALID_TYPE);
8812     cur = valuePop(ctxt);
8813 
8814     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8815         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8816     } else {
8817         int i = 0;              /* Should be first in document order !!!!! */
8818 
8819         switch (cur->nodesetval->nodeTab[i]->type) {
8820             case XML_ELEMENT_NODE:
8821             case XML_ATTRIBUTE_NODE:
8822 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8823 		    valuePush(ctxt,
8824 			xmlXPathCacheNewCString(ctxt->context, ""));
8825 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8826                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8827 		    valuePush(ctxt,
8828 		        xmlXPathCacheNewString(ctxt->context,
8829 			    cur->nodesetval->nodeTab[i]->name));
8830 		} else {
8831 		    xmlChar *fullname;
8832 
8833 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8834 				     cur->nodesetval->nodeTab[i]->ns->prefix,
8835 				     NULL, 0);
8836 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
8837 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8838 		    if (fullname == NULL) {
8839 			XP_ERROR(XPATH_MEMORY_ERROR);
8840 		    }
8841 		    valuePush(ctxt, xmlXPathCacheWrapString(
8842 			ctxt->context, fullname));
8843                 }
8844                 break;
8845             default:
8846 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8847 		    cur->nodesetval->nodeTab[i]));
8848                 xmlXPathLocalNameFunction(ctxt, 1);
8849         }
8850     }
8851     xmlXPathReleaseObject(ctxt->context, cur);
8852 }
8853 
8854 
8855 /**
8856  * xmlXPathStringFunction:
8857  * @ctxt:  the XPath Parser context
8858  * @nargs:  the number of arguments
8859  *
8860  * Implement the string() XPath function
8861  *    string string(object?)
8862  * The string function converts an object to a string as follows:
8863  *    - A node-set is converted to a string by returning the value of
8864  *      the node in the node-set that is first in document order.
8865  *      If the node-set is empty, an empty string is returned.
8866  *    - A number is converted to a string as follows
8867  *      + NaN is converted to the string NaN
8868  *      + positive zero is converted to the string 0
8869  *      + negative zero is converted to the string 0
8870  *      + positive infinity is converted to the string Infinity
8871  *      + negative infinity is converted to the string -Infinity
8872  *      + if the number is an integer, the number is represented in
8873  *        decimal form as a Number with no decimal point and no leading
8874  *        zeros, preceded by a minus sign (-) if the number is negative
8875  *      + otherwise, the number is represented in decimal form as a
8876  *        Number including a decimal point with at least one digit
8877  *        before the decimal point and at least one digit after the
8878  *        decimal point, preceded by a minus sign (-) if the number
8879  *        is negative; there must be no leading zeros before the decimal
8880  *        point apart possibly from the one required digit immediately
8881  *        before the decimal point; beyond the one required digit
8882  *        after the decimal point there must be as many, but only as
8883  *        many, more digits as are needed to uniquely distinguish the
8884  *        number from all other IEEE 754 numeric values.
8885  *    - The boolean false value is converted to the string false.
8886  *      The boolean true value is converted to the string true.
8887  *
8888  * If the argument is omitted, it defaults to a node-set with the
8889  * context node as its only member.
8890  */
8891 void
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt,int nargs)8892 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8893     xmlXPathObjectPtr cur;
8894 
8895     if (ctxt == NULL) return;
8896     if (nargs == 0) {
8897     valuePush(ctxt,
8898 	xmlXPathCacheWrapString(ctxt->context,
8899 	    xmlXPathCastNodeToString(ctxt->context->node)));
8900 	return;
8901     }
8902 
8903     CHECK_ARITY(1);
8904     cur = valuePop(ctxt);
8905     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8906     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8907 }
8908 
8909 /**
8910  * xmlXPathStringLengthFunction:
8911  * @ctxt:  the XPath Parser context
8912  * @nargs:  the number of arguments
8913  *
8914  * Implement the string-length() XPath function
8915  *    number string-length(string?)
8916  * The string-length returns the number of characters in the string
8917  * (see [3.6 Strings]). If the argument is omitted, it defaults to
8918  * the context node converted to a string, in other words the value
8919  * of the context node.
8920  */
8921 void
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt,int nargs)8922 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8923     xmlXPathObjectPtr cur;
8924 
8925     if (nargs == 0) {
8926         if ((ctxt == NULL) || (ctxt->context == NULL))
8927 	    return;
8928 	if (ctxt->context->node == NULL) {
8929 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8930 	} else {
8931 	    xmlChar *content;
8932 
8933 	    content = xmlXPathCastNodeToString(ctxt->context->node);
8934 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8935 		xmlUTF8Strlen(content)));
8936 	    xmlFree(content);
8937 	}
8938 	return;
8939     }
8940     CHECK_ARITY(1);
8941     CAST_TO_STRING;
8942     CHECK_TYPE(XPATH_STRING);
8943     cur = valuePop(ctxt);
8944     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8945 	xmlUTF8Strlen(cur->stringval)));
8946     xmlXPathReleaseObject(ctxt->context, cur);
8947 }
8948 
8949 /**
8950  * xmlXPathConcatFunction:
8951  * @ctxt:  the XPath Parser context
8952  * @nargs:  the number of arguments
8953  *
8954  * Implement the concat() XPath function
8955  *    string concat(string, string, string*)
8956  * The concat function returns the concatenation of its arguments.
8957  */
8958 void
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt,int nargs)8959 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8960     xmlXPathObjectPtr cur, newobj;
8961     xmlChar *tmp;
8962 
8963     if (ctxt == NULL) return;
8964     if (nargs < 2) {
8965 	CHECK_ARITY(2);
8966     }
8967 
8968     CAST_TO_STRING;
8969     cur = valuePop(ctxt);
8970     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8971 	xmlXPathReleaseObject(ctxt->context, cur);
8972 	return;
8973     }
8974     nargs--;
8975 
8976     while (nargs > 0) {
8977 	CAST_TO_STRING;
8978 	newobj = valuePop(ctxt);
8979 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8980 	    xmlXPathReleaseObject(ctxt->context, newobj);
8981 	    xmlXPathReleaseObject(ctxt->context, cur);
8982 	    XP_ERROR(XPATH_INVALID_TYPE);
8983 	}
8984 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
8985 	newobj->stringval = cur->stringval;
8986 	cur->stringval = tmp;
8987 	xmlXPathReleaseObject(ctxt->context, newobj);
8988 	nargs--;
8989     }
8990     valuePush(ctxt, cur);
8991 }
8992 
8993 /**
8994  * xmlXPathContainsFunction:
8995  * @ctxt:  the XPath Parser context
8996  * @nargs:  the number of arguments
8997  *
8998  * Implement the contains() XPath function
8999  *    boolean contains(string, string)
9000  * The contains function returns true if the first argument string
9001  * contains the second argument string, and otherwise returns false.
9002  */
9003 void
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt,int nargs)9004 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9005     xmlXPathObjectPtr hay, needle;
9006 
9007     CHECK_ARITY(2);
9008     CAST_TO_STRING;
9009     CHECK_TYPE(XPATH_STRING);
9010     needle = valuePop(ctxt);
9011     CAST_TO_STRING;
9012     hay = valuePop(ctxt);
9013 
9014     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9015 	xmlXPathReleaseObject(ctxt->context, hay);
9016 	xmlXPathReleaseObject(ctxt->context, needle);
9017 	XP_ERROR(XPATH_INVALID_TYPE);
9018     }
9019     if (xmlStrstr(hay->stringval, needle->stringval))
9020 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9021     else
9022 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9023     xmlXPathReleaseObject(ctxt->context, hay);
9024     xmlXPathReleaseObject(ctxt->context, needle);
9025 }
9026 
9027 /**
9028  * xmlXPathStartsWithFunction:
9029  * @ctxt:  the XPath Parser context
9030  * @nargs:  the number of arguments
9031  *
9032  * Implement the starts-with() XPath function
9033  *    boolean starts-with(string, string)
9034  * The starts-with function returns true if the first argument string
9035  * starts with the second argument string, and otherwise returns false.
9036  */
9037 void
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt,int nargs)9038 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9039     xmlXPathObjectPtr hay, needle;
9040     int n;
9041 
9042     CHECK_ARITY(2);
9043     CAST_TO_STRING;
9044     CHECK_TYPE(XPATH_STRING);
9045     needle = valuePop(ctxt);
9046     CAST_TO_STRING;
9047     hay = valuePop(ctxt);
9048 
9049     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9050 	xmlXPathReleaseObject(ctxt->context, hay);
9051 	xmlXPathReleaseObject(ctxt->context, needle);
9052 	XP_ERROR(XPATH_INVALID_TYPE);
9053     }
9054     n = xmlStrlen(needle->stringval);
9055     if (xmlStrncmp(hay->stringval, needle->stringval, n))
9056         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9057     else
9058         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9059     xmlXPathReleaseObject(ctxt->context, hay);
9060     xmlXPathReleaseObject(ctxt->context, needle);
9061 }
9062 
9063 /**
9064  * xmlXPathSubstringFunction:
9065  * @ctxt:  the XPath Parser context
9066  * @nargs:  the number of arguments
9067  *
9068  * Implement the substring() XPath function
9069  *    string substring(string, number, number?)
9070  * The substring function returns the substring of the first argument
9071  * starting at the position specified in the second argument with
9072  * length specified in the third argument. For example,
9073  * substring("12345",2,3) returns "234". If the third argument is not
9074  * specified, it returns the substring starting at the position specified
9075  * in the second argument and continuing to the end of the string. For
9076  * example, substring("12345",2) returns "2345".  More precisely, each
9077  * character in the string (see [3.6 Strings]) is considered to have a
9078  * numeric position: the position of the first character is 1, the position
9079  * of the second character is 2 and so on. The returned substring contains
9080  * those characters for which the position of the character is greater than
9081  * or equal to the second argument and, if the third argument is specified,
9082  * less than the sum of the second and third arguments; the comparisons
9083  * and addition used for the above follow the standard IEEE 754 rules. Thus:
9084  *  - substring("12345", 1.5, 2.6) returns "234"
9085  *  - substring("12345", 0, 3) returns "12"
9086  *  - substring("12345", 0 div 0, 3) returns ""
9087  *  - substring("12345", 1, 0 div 0) returns ""
9088  *  - substring("12345", -42, 1 div 0) returns "12345"
9089  *  - substring("12345", -1 div 0, 1 div 0) returns ""
9090  */
9091 void
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt,int nargs)9092 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9093     xmlXPathObjectPtr str, start, len;
9094     double le=0, in;
9095     int i = 1, j = INT_MAX;
9096 
9097     if (nargs < 2) {
9098 	CHECK_ARITY(2);
9099     }
9100     if (nargs > 3) {
9101 	CHECK_ARITY(3);
9102     }
9103     /*
9104      * take care of possible last (position) argument
9105     */
9106     if (nargs == 3) {
9107 	CAST_TO_NUMBER;
9108 	CHECK_TYPE(XPATH_NUMBER);
9109 	len = valuePop(ctxt);
9110 	le = len->floatval;
9111 	xmlXPathReleaseObject(ctxt->context, len);
9112     }
9113 
9114     CAST_TO_NUMBER;
9115     CHECK_TYPE(XPATH_NUMBER);
9116     start = valuePop(ctxt);
9117     in = start->floatval;
9118     xmlXPathReleaseObject(ctxt->context, start);
9119     CAST_TO_STRING;
9120     CHECK_TYPE(XPATH_STRING);
9121     str = valuePop(ctxt);
9122 
9123     if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9124         i = INT_MAX;
9125     } else if (in >= 1.0) {
9126         i = (int)in;
9127         if (in - floor(in) >= 0.5)
9128             i += 1;
9129     }
9130 
9131     if (nargs == 3) {
9132         double rin, rle, end;
9133 
9134         rin = floor(in);
9135         if (in - rin >= 0.5)
9136             rin += 1.0;
9137 
9138         rle = floor(le);
9139         if (le - rle >= 0.5)
9140             rle += 1.0;
9141 
9142         end = rin + rle;
9143         if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9144             j = 1;
9145         } else if (end < INT_MAX) {
9146             j = (int)end;
9147         }
9148     }
9149 
9150     if (i < j) {
9151         xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
9152 	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9153 	xmlFree(ret);
9154     } else {
9155 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9156     }
9157 
9158     xmlXPathReleaseObject(ctxt->context, str);
9159 }
9160 
9161 /**
9162  * xmlXPathSubstringBeforeFunction:
9163  * @ctxt:  the XPath Parser context
9164  * @nargs:  the number of arguments
9165  *
9166  * Implement the substring-before() XPath function
9167  *    string substring-before(string, string)
9168  * The substring-before function returns the substring of the first
9169  * argument string that precedes the first occurrence of the second
9170  * argument string in the first argument string, or the empty string
9171  * if the first argument string does not contain the second argument
9172  * string. For example, substring-before("1999/04/01","/") returns 1999.
9173  */
9174 void
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt,int nargs)9175 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9176   xmlXPathObjectPtr str;
9177   xmlXPathObjectPtr find;
9178   xmlBufPtr target;
9179   const xmlChar *point;
9180   int offset;
9181 
9182   CHECK_ARITY(2);
9183   CAST_TO_STRING;
9184   find = valuePop(ctxt);
9185   CAST_TO_STRING;
9186   str = valuePop(ctxt);
9187 
9188   target = xmlBufCreate();
9189   if (target) {
9190     point = xmlStrstr(str->stringval, find->stringval);
9191     if (point) {
9192       offset = (int)(point - str->stringval);
9193       xmlBufAdd(target, str->stringval, offset);
9194     }
9195     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9196 	xmlBufContent(target)));
9197     xmlBufFree(target);
9198   }
9199   xmlXPathReleaseObject(ctxt->context, str);
9200   xmlXPathReleaseObject(ctxt->context, find);
9201 }
9202 
9203 /**
9204  * xmlXPathSubstringAfterFunction:
9205  * @ctxt:  the XPath Parser context
9206  * @nargs:  the number of arguments
9207  *
9208  * Implement the substring-after() XPath function
9209  *    string substring-after(string, string)
9210  * The substring-after function returns the substring of the first
9211  * argument string that follows the first occurrence of the second
9212  * argument string in the first argument string, or the empty stringi
9213  * if the first argument string does not contain the second argument
9214  * string. For example, substring-after("1999/04/01","/") returns 04/01,
9215  * and substring-after("1999/04/01","19") returns 99/04/01.
9216  */
9217 void
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt,int nargs)9218 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9219   xmlXPathObjectPtr str;
9220   xmlXPathObjectPtr find;
9221   xmlBufPtr target;
9222   const xmlChar *point;
9223   int offset;
9224 
9225   CHECK_ARITY(2);
9226   CAST_TO_STRING;
9227   find = valuePop(ctxt);
9228   CAST_TO_STRING;
9229   str = valuePop(ctxt);
9230 
9231   target = xmlBufCreate();
9232   if (target) {
9233     point = xmlStrstr(str->stringval, find->stringval);
9234     if (point) {
9235       offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9236       xmlBufAdd(target, &str->stringval[offset],
9237 		   xmlStrlen(str->stringval) - offset);
9238     }
9239     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9240 	xmlBufContent(target)));
9241     xmlBufFree(target);
9242   }
9243   xmlXPathReleaseObject(ctxt->context, str);
9244   xmlXPathReleaseObject(ctxt->context, find);
9245 }
9246 
9247 /**
9248  * xmlXPathNormalizeFunction:
9249  * @ctxt:  the XPath Parser context
9250  * @nargs:  the number of arguments
9251  *
9252  * Implement the normalize-space() XPath function
9253  *    string normalize-space(string?)
9254  * The normalize-space function returns the argument string with white
9255  * space normalized by stripping leading and trailing whitespace
9256  * and replacing sequences of whitespace characters by a single
9257  * space. Whitespace characters are the same allowed by the S production
9258  * in XML. If the argument is omitted, it defaults to the context
9259  * node converted to a string, in other words the value of the context node.
9260  */
9261 void
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt,int nargs)9262 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9263   xmlXPathObjectPtr obj = NULL;
9264   xmlChar *source = NULL;
9265   xmlBufPtr target;
9266   xmlChar blank;
9267 
9268   if (ctxt == NULL) return;
9269   if (nargs == 0) {
9270     /* Use current context node */
9271       valuePush(ctxt,
9272 	  xmlXPathCacheWrapString(ctxt->context,
9273 	    xmlXPathCastNodeToString(ctxt->context->node)));
9274     nargs = 1;
9275   }
9276 
9277   CHECK_ARITY(1);
9278   CAST_TO_STRING;
9279   CHECK_TYPE(XPATH_STRING);
9280   obj = valuePop(ctxt);
9281   source = obj->stringval;
9282 
9283   target = xmlBufCreate();
9284   if (target && source) {
9285 
9286     /* Skip leading whitespaces */
9287     while (IS_BLANK_CH(*source))
9288       source++;
9289 
9290     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9291     blank = 0;
9292     while (*source) {
9293       if (IS_BLANK_CH(*source)) {
9294 	blank = 0x20;
9295       } else {
9296 	if (blank) {
9297 	  xmlBufAdd(target, &blank, 1);
9298 	  blank = 0;
9299 	}
9300 	xmlBufAdd(target, source, 1);
9301       }
9302       source++;
9303     }
9304     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9305 	xmlBufContent(target)));
9306     xmlBufFree(target);
9307   }
9308   xmlXPathReleaseObject(ctxt->context, obj);
9309 }
9310 
9311 /**
9312  * xmlXPathTranslateFunction:
9313  * @ctxt:  the XPath Parser context
9314  * @nargs:  the number of arguments
9315  *
9316  * Implement the translate() XPath function
9317  *    string translate(string, string, string)
9318  * The translate function returns the first argument string with
9319  * occurrences of characters in the second argument string replaced
9320  * by the character at the corresponding position in the third argument
9321  * string. For example, translate("bar","abc","ABC") returns the string
9322  * BAr. If there is a character in the second argument string with no
9323  * character at a corresponding position in the third argument string
9324  * (because the second argument string is longer than the third argument
9325  * string), then occurrences of that character in the first argument
9326  * string are removed. For example, translate("--aaa--","abc-","ABC")
9327  * returns "AAA". If a character occurs more than once in second
9328  * argument string, then the first occurrence determines the replacement
9329  * character. If the third argument string is longer than the second
9330  * argument string, then excess characters are ignored.
9331  */
9332 void
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt,int nargs)9333 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9334     xmlXPathObjectPtr str;
9335     xmlXPathObjectPtr from;
9336     xmlXPathObjectPtr to;
9337     xmlBufPtr target;
9338     int offset, max;
9339     xmlChar ch;
9340     const xmlChar *point;
9341     xmlChar *cptr;
9342 
9343     CHECK_ARITY(3);
9344 
9345     CAST_TO_STRING;
9346     to = valuePop(ctxt);
9347     CAST_TO_STRING;
9348     from = valuePop(ctxt);
9349     CAST_TO_STRING;
9350     str = valuePop(ctxt);
9351 
9352     target = xmlBufCreate();
9353     if (target) {
9354 	max = xmlUTF8Strlen(to->stringval);
9355 	for (cptr = str->stringval; (ch=*cptr); ) {
9356 	    offset = xmlUTF8Strloc(from->stringval, cptr);
9357 	    if (offset >= 0) {
9358 		if (offset < max) {
9359 		    point = xmlUTF8Strpos(to->stringval, offset);
9360 		    if (point)
9361 			xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9362 		}
9363 	    } else
9364 		xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9365 
9366 	    /* Step to next character in input */
9367 	    cptr++;
9368 	    if ( ch & 0x80 ) {
9369 		/* if not simple ascii, verify proper format */
9370 		if ( (ch & 0xc0) != 0xc0 ) {
9371 		    xmlGenericError(xmlGenericErrorContext,
9372 			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
9373                     /* not asserting an XPath error is probably better */
9374 		    break;
9375 		}
9376 		/* then skip over remaining bytes for this char */
9377 		while ( (ch <<= 1) & 0x80 )
9378 		    if ( (*cptr++ & 0xc0) != 0x80 ) {
9379 			xmlGenericError(xmlGenericErrorContext,
9380 			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9381                         /* not asserting an XPath error is probably better */
9382 			break;
9383 		    }
9384 		if (ch & 0x80) /* must have had error encountered */
9385 		    break;
9386 	    }
9387 	}
9388     }
9389     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9390 	xmlBufContent(target)));
9391     xmlBufFree(target);
9392     xmlXPathReleaseObject(ctxt->context, str);
9393     xmlXPathReleaseObject(ctxt->context, from);
9394     xmlXPathReleaseObject(ctxt->context, to);
9395 }
9396 
9397 /**
9398  * xmlXPathBooleanFunction:
9399  * @ctxt:  the XPath Parser context
9400  * @nargs:  the number of arguments
9401  *
9402  * Implement the boolean() XPath function
9403  *    boolean boolean(object)
9404  * The boolean function converts its argument to a boolean as follows:
9405  *    - a number is true if and only if it is neither positive or
9406  *      negative zero nor NaN
9407  *    - a node-set is true if and only if it is non-empty
9408  *    - a string is true if and only if its length is non-zero
9409  */
9410 void
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt,int nargs)9411 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9412     xmlXPathObjectPtr cur;
9413 
9414     CHECK_ARITY(1);
9415     cur = valuePop(ctxt);
9416     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9417     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9418     valuePush(ctxt, cur);
9419 }
9420 
9421 /**
9422  * xmlXPathNotFunction:
9423  * @ctxt:  the XPath Parser context
9424  * @nargs:  the number of arguments
9425  *
9426  * Implement the not() XPath function
9427  *    boolean not(boolean)
9428  * The not function returns true if its argument is false,
9429  * and false otherwise.
9430  */
9431 void
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt,int nargs)9432 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9433     CHECK_ARITY(1);
9434     CAST_TO_BOOLEAN;
9435     CHECK_TYPE(XPATH_BOOLEAN);
9436     ctxt->value->boolval = ! ctxt->value->boolval;
9437 }
9438 
9439 /**
9440  * xmlXPathTrueFunction:
9441  * @ctxt:  the XPath Parser context
9442  * @nargs:  the number of arguments
9443  *
9444  * Implement the true() XPath function
9445  *    boolean true()
9446  */
9447 void
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt,int nargs)9448 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9449     CHECK_ARITY(0);
9450     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9451 }
9452 
9453 /**
9454  * xmlXPathFalseFunction:
9455  * @ctxt:  the XPath Parser context
9456  * @nargs:  the number of arguments
9457  *
9458  * Implement the false() XPath function
9459  *    boolean false()
9460  */
9461 void
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt,int nargs)9462 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9463     CHECK_ARITY(0);
9464     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9465 }
9466 
9467 /**
9468  * xmlXPathLangFunction:
9469  * @ctxt:  the XPath Parser context
9470  * @nargs:  the number of arguments
9471  *
9472  * Implement the lang() XPath function
9473  *    boolean lang(string)
9474  * The lang function returns true or false depending on whether the
9475  * language of the context node as specified by xml:lang attributes
9476  * is the same as or is a sublanguage of the language specified by
9477  * the argument string. The language of the context node is determined
9478  * by the value of the xml:lang attribute on the context node, or, if
9479  * the context node has no xml:lang attribute, by the value of the
9480  * xml:lang attribute on the nearest ancestor of the context node that
9481  * has an xml:lang attribute. If there is no such attribute, then lang
9482  * returns false. If there is such an attribute, then lang returns
9483  * true if the attribute value is equal to the argument ignoring case,
9484  * or if there is some suffix starting with - such that the attribute
9485  * value is equal to the argument ignoring that suffix of the attribute
9486  * value and ignoring case.
9487  */
9488 void
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt,int nargs)9489 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9490     xmlXPathObjectPtr val = NULL;
9491     const xmlChar *theLang = NULL;
9492     const xmlChar *lang;
9493     int ret = 0;
9494     int i;
9495 
9496     CHECK_ARITY(1);
9497     CAST_TO_STRING;
9498     CHECK_TYPE(XPATH_STRING);
9499     val = valuePop(ctxt);
9500     lang = val->stringval;
9501     theLang = xmlNodeGetLang(ctxt->context->node);
9502     if ((theLang != NULL) && (lang != NULL)) {
9503         for (i = 0;lang[i] != 0;i++)
9504 	    if (toupper(lang[i]) != toupper(theLang[i]))
9505 	        goto not_equal;
9506 	if ((theLang[i] == 0) || (theLang[i] == '-'))
9507 	    ret = 1;
9508     }
9509 not_equal:
9510     if (theLang != NULL)
9511 	xmlFree((void *)theLang);
9512 
9513     xmlXPathReleaseObject(ctxt->context, val);
9514     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9515 }
9516 
9517 /**
9518  * xmlXPathNumberFunction:
9519  * @ctxt:  the XPath Parser context
9520  * @nargs:  the number of arguments
9521  *
9522  * Implement the number() XPath function
9523  *    number number(object?)
9524  */
9525 void
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt,int nargs)9526 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9527     xmlXPathObjectPtr cur;
9528     double res;
9529 
9530     if (ctxt == NULL) return;
9531     if (nargs == 0) {
9532 	if (ctxt->context->node == NULL) {
9533 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9534 	} else {
9535 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9536 
9537 	    res = xmlXPathStringEvalNumber(content);
9538 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9539 	    xmlFree(content);
9540 	}
9541 	return;
9542     }
9543 
9544     CHECK_ARITY(1);
9545     cur = valuePop(ctxt);
9546     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9547 }
9548 
9549 /**
9550  * xmlXPathSumFunction:
9551  * @ctxt:  the XPath Parser context
9552  * @nargs:  the number of arguments
9553  *
9554  * Implement the sum() XPath function
9555  *    number sum(node-set)
9556  * The sum function returns the sum of the values of the nodes in
9557  * the argument node-set.
9558  */
9559 void
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt,int nargs)9560 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9561     xmlXPathObjectPtr cur;
9562     int i;
9563     double res = 0.0;
9564 
9565     CHECK_ARITY(1);
9566     if ((ctxt->value == NULL) ||
9567 	((ctxt->value->type != XPATH_NODESET) &&
9568 	 (ctxt->value->type != XPATH_XSLT_TREE)))
9569 	XP_ERROR(XPATH_INVALID_TYPE);
9570     cur = valuePop(ctxt);
9571 
9572     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9573 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9574 	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9575 	}
9576     }
9577     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9578     xmlXPathReleaseObject(ctxt->context, cur);
9579 }
9580 
9581 /**
9582  * xmlXPathFloorFunction:
9583  * @ctxt:  the XPath Parser context
9584  * @nargs:  the number of arguments
9585  *
9586  * Implement the floor() XPath function
9587  *    number floor(number)
9588  * The floor function returns the largest (closest to positive infinity)
9589  * number that is not greater than the argument and that is an integer.
9590  */
9591 void
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt,int nargs)9592 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9593     CHECK_ARITY(1);
9594     CAST_TO_NUMBER;
9595     CHECK_TYPE(XPATH_NUMBER);
9596 
9597     ctxt->value->floatval = floor(ctxt->value->floatval);
9598 }
9599 
9600 /**
9601  * xmlXPathCeilingFunction:
9602  * @ctxt:  the XPath Parser context
9603  * @nargs:  the number of arguments
9604  *
9605  * Implement the ceiling() XPath function
9606  *    number ceiling(number)
9607  * The ceiling function returns the smallest (closest to negative infinity)
9608  * number that is not less than the argument and that is an integer.
9609  */
9610 void
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt,int nargs)9611 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9612     CHECK_ARITY(1);
9613     CAST_TO_NUMBER;
9614     CHECK_TYPE(XPATH_NUMBER);
9615 
9616 #ifdef _AIX
9617     /* Work around buggy ceil() function on AIX */
9618     ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
9619 #else
9620     ctxt->value->floatval = ceil(ctxt->value->floatval);
9621 #endif
9622 }
9623 
9624 /**
9625  * xmlXPathRoundFunction:
9626  * @ctxt:  the XPath Parser context
9627  * @nargs:  the number of arguments
9628  *
9629  * Implement the round() XPath function
9630  *    number round(number)
9631  * The round function returns the number that is closest to the
9632  * argument and that is an integer. If there are two such numbers,
9633  * then the one that is closest to positive infinity is returned.
9634  */
9635 void
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt,int nargs)9636 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9637     double f;
9638 
9639     CHECK_ARITY(1);
9640     CAST_TO_NUMBER;
9641     CHECK_TYPE(XPATH_NUMBER);
9642 
9643     f = ctxt->value->floatval;
9644 
9645     if ((f >= -0.5) && (f < 0.5)) {
9646         /* Handles negative zero. */
9647         ctxt->value->floatval *= 0.0;
9648     }
9649     else {
9650         double rounded = floor(f);
9651         if (f - rounded >= 0.5)
9652             rounded += 1.0;
9653         ctxt->value->floatval = rounded;
9654     }
9655 }
9656 
9657 /************************************************************************
9658  *									*
9659  *			The Parser					*
9660  *									*
9661  ************************************************************************/
9662 
9663 /*
9664  * a few forward declarations since we use a recursive call based
9665  * implementation.
9666  */
9667 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9668 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9669 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9670 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9671 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9672 	                                  int qualified);
9673 
9674 /**
9675  * xmlXPathCurrentChar:
9676  * @ctxt:  the XPath parser context
9677  * @cur:  pointer to the beginning of the char
9678  * @len:  pointer to the length of the char read
9679  *
9680  * The current char value, if using UTF-8 this may actually span multiple
9681  * bytes in the input buffer.
9682  *
9683  * Returns the current char value and its length
9684  */
9685 
9686 static int
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt,int * len)9687 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9688     unsigned char c;
9689     unsigned int val;
9690     const xmlChar *cur;
9691 
9692     if (ctxt == NULL)
9693 	return(0);
9694     cur = ctxt->cur;
9695 
9696     /*
9697      * We are supposed to handle UTF8, check it's valid
9698      * From rfc2044: encoding of the Unicode values on UTF-8:
9699      *
9700      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9701      * 0000 0000-0000 007F   0xxxxxxx
9702      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9703      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9704      *
9705      * Check for the 0x110000 limit too
9706      */
9707     c = *cur;
9708     if (c & 0x80) {
9709 	if ((cur[1] & 0xc0) != 0x80)
9710 	    goto encoding_error;
9711 	if ((c & 0xe0) == 0xe0) {
9712 
9713 	    if ((cur[2] & 0xc0) != 0x80)
9714 		goto encoding_error;
9715 	    if ((c & 0xf0) == 0xf0) {
9716 		if (((c & 0xf8) != 0xf0) ||
9717 		    ((cur[3] & 0xc0) != 0x80))
9718 		    goto encoding_error;
9719 		/* 4-byte code */
9720 		*len = 4;
9721 		val = (cur[0] & 0x7) << 18;
9722 		val |= (cur[1] & 0x3f) << 12;
9723 		val |= (cur[2] & 0x3f) << 6;
9724 		val |= cur[3] & 0x3f;
9725 	    } else {
9726 	      /* 3-byte code */
9727 		*len = 3;
9728 		val = (cur[0] & 0xf) << 12;
9729 		val |= (cur[1] & 0x3f) << 6;
9730 		val |= cur[2] & 0x3f;
9731 	    }
9732 	} else {
9733 	  /* 2-byte code */
9734 	    *len = 2;
9735 	    val = (cur[0] & 0x1f) << 6;
9736 	    val |= cur[1] & 0x3f;
9737 	}
9738 	if (!IS_CHAR(val)) {
9739 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9740 	}
9741 	return(val);
9742     } else {
9743 	/* 1-byte code */
9744 	*len = 1;
9745 	return((int) *cur);
9746     }
9747 encoding_error:
9748     /*
9749      * If we detect an UTF8 error that probably means that the
9750      * input encoding didn't get properly advertised in the
9751      * declaration header. Report the error and switch the encoding
9752      * to ISO-Latin-1 (if you don't like this policy, just declare the
9753      * encoding !)
9754      */
9755     *len = 0;
9756     XP_ERROR0(XPATH_ENCODING_ERROR);
9757 }
9758 
9759 /**
9760  * xmlXPathParseNCName:
9761  * @ctxt:  the XPath Parser context
9762  *
9763  * parse an XML namespace non qualified name.
9764  *
9765  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9766  *
9767  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9768  *                       CombiningChar | Extender
9769  *
9770  * Returns the namespace name or NULL
9771  */
9772 
9773 xmlChar *
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt)9774 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9775     const xmlChar *in;
9776     xmlChar *ret;
9777     int count = 0;
9778 
9779     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9780     /*
9781      * Accelerator for simple ASCII names
9782      */
9783     in = ctxt->cur;
9784     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9785 	((*in >= 0x41) && (*in <= 0x5A)) ||
9786 	(*in == '_')) {
9787 	in++;
9788 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9789 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9790 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9791 	       (*in == '_') || (*in == '.') ||
9792 	       (*in == '-'))
9793 	    in++;
9794 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9795             (*in == '[') || (*in == ']') || (*in == ':') ||
9796             (*in == '@') || (*in == '*')) {
9797 	    count = in - ctxt->cur;
9798 	    if (count == 0)
9799 		return(NULL);
9800 	    ret = xmlStrndup(ctxt->cur, count);
9801 	    ctxt->cur = in;
9802 	    return(ret);
9803 	}
9804     }
9805     return(xmlXPathParseNameComplex(ctxt, 0));
9806 }
9807 
9808 
9809 /**
9810  * xmlXPathParseQName:
9811  * @ctxt:  the XPath Parser context
9812  * @prefix:  a xmlChar **
9813  *
9814  * parse an XML qualified name
9815  *
9816  * [NS 5] QName ::= (Prefix ':')? LocalPart
9817  *
9818  * [NS 6] Prefix ::= NCName
9819  *
9820  * [NS 7] LocalPart ::= NCName
9821  *
9822  * Returns the function returns the local part, and prefix is updated
9823  *   to get the Prefix if any.
9824  */
9825 
9826 static xmlChar *
xmlXPathParseQName(xmlXPathParserContextPtr ctxt,xmlChar ** prefix)9827 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9828     xmlChar *ret = NULL;
9829 
9830     *prefix = NULL;
9831     ret = xmlXPathParseNCName(ctxt);
9832     if (ret && CUR == ':') {
9833         *prefix = ret;
9834 	NEXT;
9835 	ret = xmlXPathParseNCName(ctxt);
9836     }
9837     return(ret);
9838 }
9839 
9840 /**
9841  * xmlXPathParseName:
9842  * @ctxt:  the XPath Parser context
9843  *
9844  * parse an XML name
9845  *
9846  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9847  *                  CombiningChar | Extender
9848  *
9849  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9850  *
9851  * Returns the namespace name or NULL
9852  */
9853 
9854 xmlChar *
xmlXPathParseName(xmlXPathParserContextPtr ctxt)9855 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9856     const xmlChar *in;
9857     xmlChar *ret;
9858     size_t count = 0;
9859 
9860     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9861     /*
9862      * Accelerator for simple ASCII names
9863      */
9864     in = ctxt->cur;
9865     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9866 	((*in >= 0x41) && (*in <= 0x5A)) ||
9867 	(*in == '_') || (*in == ':')) {
9868 	in++;
9869 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9870 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9871 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9872 	       (*in == '_') || (*in == '-') ||
9873 	       (*in == ':') || (*in == '.'))
9874 	    in++;
9875 	if ((*in > 0) && (*in < 0x80)) {
9876 	    count = in - ctxt->cur;
9877             if (count > XML_MAX_NAME_LENGTH) {
9878                 ctxt->cur = in;
9879                 XP_ERRORNULL(XPATH_EXPR_ERROR);
9880             }
9881 	    ret = xmlStrndup(ctxt->cur, count);
9882 	    ctxt->cur = in;
9883 	    return(ret);
9884 	}
9885     }
9886     return(xmlXPathParseNameComplex(ctxt, 1));
9887 }
9888 
9889 static xmlChar *
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,int qualified)9890 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9891     xmlChar buf[XML_MAX_NAMELEN + 5];
9892     int len = 0, l;
9893     int c;
9894 
9895     /*
9896      * Handler for more complex cases
9897      */
9898     c = CUR_CHAR(l);
9899     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9900         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9901         (c == '*') || /* accelerators */
9902 	(!IS_LETTER(c) && (c != '_') &&
9903          ((!qualified) || (c != ':')))) {
9904 	return(NULL);
9905     }
9906 
9907     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9908 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9909             (c == '.') || (c == '-') ||
9910 	    (c == '_') || ((qualified) && (c == ':')) ||
9911 	    (IS_COMBINING(c)) ||
9912 	    (IS_EXTENDER(c)))) {
9913 	COPY_BUF(l,buf,len,c);
9914 	NEXTL(l);
9915 	c = CUR_CHAR(l);
9916 	if (len >= XML_MAX_NAMELEN) {
9917 	    /*
9918 	     * Okay someone managed to make a huge name, so he's ready to pay
9919 	     * for the processing speed.
9920 	     */
9921 	    xmlChar *buffer;
9922 	    int max = len * 2;
9923 
9924             if (len > XML_MAX_NAME_LENGTH) {
9925                 XP_ERRORNULL(XPATH_EXPR_ERROR);
9926             }
9927 	    buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9928 	    if (buffer == NULL) {
9929 		XP_ERRORNULL(XPATH_MEMORY_ERROR);
9930 	    }
9931 	    memcpy(buffer, buf, len);
9932 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9933 		   (c == '.') || (c == '-') ||
9934 		   (c == '_') || ((qualified) && (c == ':')) ||
9935 		   (IS_COMBINING(c)) ||
9936 		   (IS_EXTENDER(c))) {
9937 		if (len + 10 > max) {
9938                     xmlChar *tmp;
9939                     if (max > XML_MAX_NAME_LENGTH) {
9940                         xmlFree(buffer);
9941                         XP_ERRORNULL(XPATH_EXPR_ERROR);
9942                     }
9943 		    max *= 2;
9944 		    tmp = (xmlChar *) xmlRealloc(buffer,
9945 			                         max * sizeof(xmlChar));
9946 		    if (tmp == NULL) {
9947                         xmlFree(buffer);
9948 			XP_ERRORNULL(XPATH_MEMORY_ERROR);
9949 		    }
9950                     buffer = tmp;
9951 		}
9952 		COPY_BUF(l,buffer,len,c);
9953 		NEXTL(l);
9954 		c = CUR_CHAR(l);
9955 	    }
9956 	    buffer[len] = 0;
9957 	    return(buffer);
9958 	}
9959     }
9960     if (len == 0)
9961 	return(NULL);
9962     return(xmlStrndup(buf, len));
9963 }
9964 
9965 #define MAX_FRAC 20
9966 
9967 /**
9968  * xmlXPathStringEvalNumber:
9969  * @str:  A string to scan
9970  *
9971  *  [30a]  Float  ::= Number ('e' Digits?)?
9972  *
9973  *  [30]   Number ::=   Digits ('.' Digits?)?
9974  *                    | '.' Digits
9975  *  [31]   Digits ::=   [0-9]+
9976  *
9977  * Compile a Number in the string
9978  * In complement of the Number expression, this function also handles
9979  * negative values : '-' Number.
9980  *
9981  * Returns the double value.
9982  */
9983 double
xmlXPathStringEvalNumber(const xmlChar * str)9984 xmlXPathStringEvalNumber(const xmlChar *str) {
9985     const xmlChar *cur = str;
9986     double ret;
9987     int ok = 0;
9988     int isneg = 0;
9989     int exponent = 0;
9990     int is_exponent_negative = 0;
9991 #ifdef __GNUC__
9992     unsigned long tmp = 0;
9993     double temp;
9994 #endif
9995     if (cur == NULL) return(0);
9996     while (IS_BLANK_CH(*cur)) cur++;
9997     if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9998         return(xmlXPathNAN);
9999     }
10000     if (*cur == '-') {
10001 	isneg = 1;
10002 	cur++;
10003     }
10004 
10005 #ifdef __GNUC__
10006     /*
10007      * tmp/temp is a workaround against a gcc compiler bug
10008      * http://veillard.com/gcc.bug
10009      */
10010     ret = 0;
10011     while ((*cur >= '0') && (*cur <= '9')) {
10012 	ret = ret * 10;
10013 	tmp = (*cur - '0');
10014 	ok = 1;
10015 	cur++;
10016 	temp = (double) tmp;
10017 	ret = ret + temp;
10018     }
10019 #else
10020     ret = 0;
10021     while ((*cur >= '0') && (*cur <= '9')) {
10022 	ret = ret * 10 + (*cur - '0');
10023 	ok = 1;
10024 	cur++;
10025     }
10026 #endif
10027 
10028     if (*cur == '.') {
10029 	int v, frac = 0, max;
10030 	double fraction = 0;
10031 
10032         cur++;
10033 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10034 	    return(xmlXPathNAN);
10035 	}
10036         while (*cur == '0') {
10037 	    frac = frac + 1;
10038 	    cur++;
10039         }
10040         max = frac + MAX_FRAC;
10041 	while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10042 	    v = (*cur - '0');
10043 	    fraction = fraction * 10 + v;
10044 	    frac = frac + 1;
10045 	    cur++;
10046 	}
10047 	fraction /= pow(10.0, frac);
10048 	ret = ret + fraction;
10049 	while ((*cur >= '0') && (*cur <= '9'))
10050 	    cur++;
10051     }
10052     if ((*cur == 'e') || (*cur == 'E')) {
10053       cur++;
10054       if (*cur == '-') {
10055 	is_exponent_negative = 1;
10056 	cur++;
10057       } else if (*cur == '+') {
10058         cur++;
10059       }
10060       while ((*cur >= '0') && (*cur <= '9')) {
10061         if (exponent < 1000000)
10062 	  exponent = exponent * 10 + (*cur - '0');
10063 	cur++;
10064       }
10065     }
10066     while (IS_BLANK_CH(*cur)) cur++;
10067     if (*cur != 0) return(xmlXPathNAN);
10068     if (isneg) ret = -ret;
10069     if (is_exponent_negative) exponent = -exponent;
10070     ret *= pow(10.0, (double)exponent);
10071     return(ret);
10072 }
10073 
10074 /**
10075  * xmlXPathCompNumber:
10076  * @ctxt:  the XPath Parser context
10077  *
10078  *  [30]   Number ::=   Digits ('.' Digits?)?
10079  *                    | '.' Digits
10080  *  [31]   Digits ::=   [0-9]+
10081  *
10082  * Compile a Number, then push it on the stack
10083  *
10084  */
10085 static void
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)10086 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10087 {
10088     double ret = 0.0;
10089     int ok = 0;
10090     int exponent = 0;
10091     int is_exponent_negative = 0;
10092     xmlXPathObjectPtr num;
10093 #ifdef __GNUC__
10094     unsigned long tmp = 0;
10095     double temp;
10096 #endif
10097 
10098     CHECK_ERROR;
10099     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10100         XP_ERROR(XPATH_NUMBER_ERROR);
10101     }
10102 #ifdef __GNUC__
10103     /*
10104      * tmp/temp is a workaround against a gcc compiler bug
10105      * http://veillard.com/gcc.bug
10106      */
10107     ret = 0;
10108     while ((CUR >= '0') && (CUR <= '9')) {
10109 	ret = ret * 10;
10110 	tmp = (CUR - '0');
10111         ok = 1;
10112         NEXT;
10113 	temp = (double) tmp;
10114 	ret = ret + temp;
10115     }
10116 #else
10117     ret = 0;
10118     while ((CUR >= '0') && (CUR <= '9')) {
10119 	ret = ret * 10 + (CUR - '0');
10120 	ok = 1;
10121 	NEXT;
10122     }
10123 #endif
10124     if (CUR == '.') {
10125 	int v, frac = 0, max;
10126 	double fraction = 0;
10127 
10128         NEXT;
10129         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10130             XP_ERROR(XPATH_NUMBER_ERROR);
10131         }
10132         while (CUR == '0') {
10133             frac = frac + 1;
10134             NEXT;
10135         }
10136         max = frac + MAX_FRAC;
10137         while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10138 	    v = (CUR - '0');
10139 	    fraction = fraction * 10 + v;
10140 	    frac = frac + 1;
10141             NEXT;
10142         }
10143         fraction /= pow(10.0, frac);
10144         ret = ret + fraction;
10145         while ((CUR >= '0') && (CUR <= '9'))
10146             NEXT;
10147     }
10148     if ((CUR == 'e') || (CUR == 'E')) {
10149         NEXT;
10150         if (CUR == '-') {
10151             is_exponent_negative = 1;
10152             NEXT;
10153         } else if (CUR == '+') {
10154 	    NEXT;
10155 	}
10156         while ((CUR >= '0') && (CUR <= '9')) {
10157             if (exponent < 1000000)
10158                 exponent = exponent * 10 + (CUR - '0');
10159             NEXT;
10160         }
10161         if (is_exponent_negative)
10162             exponent = -exponent;
10163         ret *= pow(10.0, (double) exponent);
10164     }
10165     num = xmlXPathCacheNewFloat(ctxt->context, ret);
10166     if (num == NULL) {
10167 	ctxt->error = XPATH_MEMORY_ERROR;
10168     } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
10169                               NULL) == -1) {
10170         xmlXPathReleaseObject(ctxt->context, num);
10171     }
10172 }
10173 
10174 /**
10175  * xmlXPathParseLiteral:
10176  * @ctxt:  the XPath Parser context
10177  *
10178  * Parse a Literal
10179  *
10180  *  [29]   Literal ::=   '"' [^"]* '"'
10181  *                    | "'" [^']* "'"
10182  *
10183  * Returns the value found or NULL in case of error
10184  */
10185 static xmlChar *
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt)10186 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10187     const xmlChar *q;
10188     xmlChar *ret = NULL;
10189 
10190     if (CUR == '"') {
10191         NEXT;
10192 	q = CUR_PTR;
10193 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10194 	    NEXT;
10195 	if (!IS_CHAR_CH(CUR)) {
10196 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10197 	} else {
10198 	    ret = xmlStrndup(q, CUR_PTR - q);
10199 	    NEXT;
10200         }
10201     } else if (CUR == '\'') {
10202         NEXT;
10203 	q = CUR_PTR;
10204 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10205 	    NEXT;
10206 	if (!IS_CHAR_CH(CUR)) {
10207 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10208 	} else {
10209 	    ret = xmlStrndup(q, CUR_PTR - q);
10210 	    NEXT;
10211         }
10212     } else {
10213 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10214     }
10215     return(ret);
10216 }
10217 
10218 /**
10219  * xmlXPathCompLiteral:
10220  * @ctxt:  the XPath Parser context
10221  *
10222  * Parse a Literal and push it on the stack.
10223  *
10224  *  [29]   Literal ::=   '"' [^"]* '"'
10225  *                    | "'" [^']* "'"
10226  *
10227  * TODO: xmlXPathCompLiteral memory allocation could be improved.
10228  */
10229 static void
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt)10230 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10231     const xmlChar *q;
10232     xmlChar *ret = NULL;
10233     xmlXPathObjectPtr lit;
10234 
10235     if (CUR == '"') {
10236         NEXT;
10237 	q = CUR_PTR;
10238 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10239 	    NEXT;
10240 	if (!IS_CHAR_CH(CUR)) {
10241 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10242 	} else {
10243 	    ret = xmlStrndup(q, CUR_PTR - q);
10244 	    NEXT;
10245         }
10246     } else if (CUR == '\'') {
10247         NEXT;
10248 	q = CUR_PTR;
10249 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10250 	    NEXT;
10251 	if (!IS_CHAR_CH(CUR)) {
10252 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10253 	} else {
10254 	    ret = xmlStrndup(q, CUR_PTR - q);
10255 	    NEXT;
10256         }
10257     } else {
10258 	XP_ERROR(XPATH_START_LITERAL_ERROR);
10259     }
10260     if (ret == NULL) return;
10261     lit = xmlXPathCacheNewString(ctxt->context, ret);
10262     if (lit == NULL) {
10263 	ctxt->error = XPATH_MEMORY_ERROR;
10264     } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10265                               NULL) == -1) {
10266         xmlXPathReleaseObject(ctxt->context, lit);
10267     }
10268     xmlFree(ret);
10269 }
10270 
10271 /**
10272  * xmlXPathCompVariableReference:
10273  * @ctxt:  the XPath Parser context
10274  *
10275  * Parse a VariableReference, evaluate it and push it on the stack.
10276  *
10277  * The variable bindings consist of a mapping from variable names
10278  * to variable values. The value of a variable is an object, which can be
10279  * of any of the types that are possible for the value of an expression,
10280  * and may also be of additional types not specified here.
10281  *
10282  * Early evaluation is possible since:
10283  * The variable bindings [...] used to evaluate a subexpression are
10284  * always the same as those used to evaluate the containing expression.
10285  *
10286  *  [36]   VariableReference ::=   '$' QName
10287  */
10288 static void
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt)10289 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10290     xmlChar *name;
10291     xmlChar *prefix;
10292 
10293     SKIP_BLANKS;
10294     if (CUR != '$') {
10295 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10296     }
10297     NEXT;
10298     name = xmlXPathParseQName(ctxt, &prefix);
10299     if (name == NULL) {
10300         xmlFree(prefix);
10301 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10302     }
10303     ctxt->comp->last = -1;
10304     if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
10305         xmlFree(prefix);
10306         xmlFree(name);
10307     }
10308     SKIP_BLANKS;
10309     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10310 	XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10311     }
10312 }
10313 
10314 /**
10315  * xmlXPathIsNodeType:
10316  * @name:  a name string
10317  *
10318  * Is the name given a NodeType one.
10319  *
10320  *  [38]   NodeType ::=   'comment'
10321  *                    | 'text'
10322  *                    | 'processing-instruction'
10323  *                    | 'node'
10324  *
10325  * Returns 1 if true 0 otherwise
10326  */
10327 int
xmlXPathIsNodeType(const xmlChar * name)10328 xmlXPathIsNodeType(const xmlChar *name) {
10329     if (name == NULL)
10330 	return(0);
10331 
10332     if (xmlStrEqual(name, BAD_CAST "node"))
10333 	return(1);
10334     if (xmlStrEqual(name, BAD_CAST "text"))
10335 	return(1);
10336     if (xmlStrEqual(name, BAD_CAST "comment"))
10337 	return(1);
10338     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10339 	return(1);
10340     return(0);
10341 }
10342 
10343 /**
10344  * xmlXPathCompFunctionCall:
10345  * @ctxt:  the XPath Parser context
10346  *
10347  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10348  *  [17]   Argument ::=   Expr
10349  *
10350  * Compile a function call, the evaluation of all arguments are
10351  * pushed on the stack
10352  */
10353 static void
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt)10354 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10355     xmlChar *name;
10356     xmlChar *prefix;
10357     int nbargs = 0;
10358     int sort = 1;
10359 
10360     name = xmlXPathParseQName(ctxt, &prefix);
10361     if (name == NULL) {
10362 	xmlFree(prefix);
10363 	XP_ERROR(XPATH_EXPR_ERROR);
10364     }
10365     SKIP_BLANKS;
10366 #ifdef DEBUG_EXPR
10367     if (prefix == NULL)
10368 	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10369 			name);
10370     else
10371 	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10372 			prefix, name);
10373 #endif
10374 
10375     if (CUR != '(') {
10376 	xmlFree(name);
10377 	xmlFree(prefix);
10378 	XP_ERROR(XPATH_EXPR_ERROR);
10379     }
10380     NEXT;
10381     SKIP_BLANKS;
10382 
10383     /*
10384     * Optimization for count(): we don't need the node-set to be sorted.
10385     */
10386     if ((prefix == NULL) && (name[0] == 'c') &&
10387 	xmlStrEqual(name, BAD_CAST "count"))
10388     {
10389 	sort = 0;
10390     }
10391     ctxt->comp->last = -1;
10392     if (CUR != ')') {
10393 	while (CUR != 0) {
10394 	    int op1 = ctxt->comp->last;
10395 	    ctxt->comp->last = -1;
10396 	    xmlXPathCompileExpr(ctxt, sort);
10397 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
10398 		xmlFree(name);
10399 		xmlFree(prefix);
10400 		return;
10401 	    }
10402 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10403 	    nbargs++;
10404 	    if (CUR == ')') break;
10405 	    if (CUR != ',') {
10406 		xmlFree(name);
10407 		xmlFree(prefix);
10408 		XP_ERROR(XPATH_EXPR_ERROR);
10409 	    }
10410 	    NEXT;
10411 	    SKIP_BLANKS;
10412 	}
10413     }
10414     if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
10415         xmlFree(prefix);
10416         xmlFree(name);
10417     }
10418     NEXT;
10419     SKIP_BLANKS;
10420 }
10421 
10422 /**
10423  * xmlXPathCompPrimaryExpr:
10424  * @ctxt:  the XPath Parser context
10425  *
10426  *  [15]   PrimaryExpr ::=   VariableReference
10427  *                | '(' Expr ')'
10428  *                | Literal
10429  *                | Number
10430  *                | FunctionCall
10431  *
10432  * Compile a primary expression.
10433  */
10434 static void
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt)10435 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10436     SKIP_BLANKS;
10437     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10438     else if (CUR == '(') {
10439 	NEXT;
10440 	SKIP_BLANKS;
10441 	xmlXPathCompileExpr(ctxt, 1);
10442 	CHECK_ERROR;
10443 	if (CUR != ')') {
10444 	    XP_ERROR(XPATH_EXPR_ERROR);
10445 	}
10446 	NEXT;
10447 	SKIP_BLANKS;
10448     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10449 	xmlXPathCompNumber(ctxt);
10450     } else if ((CUR == '\'') || (CUR == '"')) {
10451 	xmlXPathCompLiteral(ctxt);
10452     } else {
10453 	xmlXPathCompFunctionCall(ctxt);
10454     }
10455     SKIP_BLANKS;
10456 }
10457 
10458 /**
10459  * xmlXPathCompFilterExpr:
10460  * @ctxt:  the XPath Parser context
10461  *
10462  *  [20]   FilterExpr ::=   PrimaryExpr
10463  *               | FilterExpr Predicate
10464  *
10465  * Compile a filter expression.
10466  * Square brackets are used to filter expressions in the same way that
10467  * they are used in location paths. It is an error if the expression to
10468  * be filtered does not evaluate to a node-set. The context node list
10469  * used for evaluating the expression in square brackets is the node-set
10470  * to be filtered listed in document order.
10471  */
10472 
10473 static void
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt)10474 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10475     xmlXPathCompPrimaryExpr(ctxt);
10476     CHECK_ERROR;
10477     SKIP_BLANKS;
10478 
10479     while (CUR == '[') {
10480 	xmlXPathCompPredicate(ctxt, 1);
10481 	SKIP_BLANKS;
10482     }
10483 
10484 
10485 }
10486 
10487 /**
10488  * xmlXPathScanName:
10489  * @ctxt:  the XPath Parser context
10490  *
10491  * Trickery: parse an XML name but without consuming the input flow
10492  * Needed to avoid insanity in the parser state.
10493  *
10494  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10495  *                  CombiningChar | Extender
10496  *
10497  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10498  *
10499  * [6] Names ::= Name (S Name)*
10500  *
10501  * Returns the Name parsed or NULL
10502  */
10503 
10504 static xmlChar *
xmlXPathScanName(xmlXPathParserContextPtr ctxt)10505 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10506     int len = 0, l;
10507     int c;
10508     const xmlChar *cur;
10509     xmlChar *ret;
10510 
10511     cur = ctxt->cur;
10512 
10513     c = CUR_CHAR(l);
10514     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10515 	(!IS_LETTER(c) && (c != '_') &&
10516          (c != ':'))) {
10517 	return(NULL);
10518     }
10519 
10520     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10521 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10522             (c == '.') || (c == '-') ||
10523 	    (c == '_') || (c == ':') ||
10524 	    (IS_COMBINING(c)) ||
10525 	    (IS_EXTENDER(c)))) {
10526 	len += l;
10527 	NEXTL(l);
10528 	c = CUR_CHAR(l);
10529     }
10530     ret = xmlStrndup(cur, ctxt->cur - cur);
10531     ctxt->cur = cur;
10532     return(ret);
10533 }
10534 
10535 /**
10536  * xmlXPathCompPathExpr:
10537  * @ctxt:  the XPath Parser context
10538  *
10539  *  [19]   PathExpr ::=   LocationPath
10540  *               | FilterExpr
10541  *               | FilterExpr '/' RelativeLocationPath
10542  *               | FilterExpr '//' RelativeLocationPath
10543  *
10544  * Compile a path expression.
10545  * The / operator and // operators combine an arbitrary expression
10546  * and a relative location path. It is an error if the expression
10547  * does not evaluate to a node-set.
10548  * The / operator does composition in the same way as when / is
10549  * used in a location path. As in location paths, // is short for
10550  * /descendant-or-self::node()/.
10551  */
10552 
10553 static void
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt)10554 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10555     int lc = 1;           /* Should we branch to LocationPath ?         */
10556     xmlChar *name = NULL; /* we may have to preparse a name to find out */
10557 
10558     SKIP_BLANKS;
10559     if ((CUR == '$') || (CUR == '(') ||
10560 	(IS_ASCII_DIGIT(CUR)) ||
10561         (CUR == '\'') || (CUR == '"') ||
10562 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10563 	lc = 0;
10564     } else if (CUR == '*') {
10565 	/* relative or absolute location path */
10566 	lc = 1;
10567     } else if (CUR == '/') {
10568 	/* relative or absolute location path */
10569 	lc = 1;
10570     } else if (CUR == '@') {
10571 	/* relative abbreviated attribute location path */
10572 	lc = 1;
10573     } else if (CUR == '.') {
10574 	/* relative abbreviated attribute location path */
10575 	lc = 1;
10576     } else {
10577 	/*
10578 	 * Problem is finding if we have a name here whether it's:
10579 	 *   - a nodetype
10580 	 *   - a function call in which case it's followed by '('
10581 	 *   - an axis in which case it's followed by ':'
10582 	 *   - a element name
10583 	 * We do an a priori analysis here rather than having to
10584 	 * maintain parsed token content through the recursive function
10585 	 * calls. This looks uglier but makes the code easier to
10586 	 * read/write/debug.
10587 	 */
10588 	SKIP_BLANKS;
10589 	name = xmlXPathScanName(ctxt);
10590 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10591 #ifdef DEBUG_STEP
10592 	    xmlGenericError(xmlGenericErrorContext,
10593 		    "PathExpr: Axis\n");
10594 #endif
10595 	    lc = 1;
10596 	    xmlFree(name);
10597 	} else if (name != NULL) {
10598 	    int len =xmlStrlen(name);
10599 
10600 
10601 	    while (NXT(len) != 0) {
10602 		if (NXT(len) == '/') {
10603 		    /* element name */
10604 #ifdef DEBUG_STEP
10605 		    xmlGenericError(xmlGenericErrorContext,
10606 			    "PathExpr: AbbrRelLocation\n");
10607 #endif
10608 		    lc = 1;
10609 		    break;
10610 		} else if (IS_BLANK_CH(NXT(len))) {
10611 		    /* ignore blanks */
10612 		    ;
10613 		} else if (NXT(len) == ':') {
10614 #ifdef DEBUG_STEP
10615 		    xmlGenericError(xmlGenericErrorContext,
10616 			    "PathExpr: AbbrRelLocation\n");
10617 #endif
10618 		    lc = 1;
10619 		    break;
10620 		} else if ((NXT(len) == '(')) {
10621 		    /* Node Type or Function */
10622 		    if (xmlXPathIsNodeType(name)) {
10623 #ifdef DEBUG_STEP
10624 		        xmlGenericError(xmlGenericErrorContext,
10625 				"PathExpr: Type search\n");
10626 #endif
10627 			lc = 1;
10628 #ifdef LIBXML_XPTR_ENABLED
10629                     } else if (ctxt->xptr &&
10630                                xmlStrEqual(name, BAD_CAST "range-to")) {
10631                         lc = 1;
10632 #endif
10633 		    } else {
10634 #ifdef DEBUG_STEP
10635 		        xmlGenericError(xmlGenericErrorContext,
10636 				"PathExpr: function call\n");
10637 #endif
10638 			lc = 0;
10639 		    }
10640                     break;
10641 		} else if ((NXT(len) == '[')) {
10642 		    /* element name */
10643 #ifdef DEBUG_STEP
10644 		    xmlGenericError(xmlGenericErrorContext,
10645 			    "PathExpr: AbbrRelLocation\n");
10646 #endif
10647 		    lc = 1;
10648 		    break;
10649 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10650 			   (NXT(len) == '=')) {
10651 		    lc = 1;
10652 		    break;
10653 		} else {
10654 		    lc = 1;
10655 		    break;
10656 		}
10657 		len++;
10658 	    }
10659 	    if (NXT(len) == 0) {
10660 #ifdef DEBUG_STEP
10661 		xmlGenericError(xmlGenericErrorContext,
10662 			"PathExpr: AbbrRelLocation\n");
10663 #endif
10664 		/* element name */
10665 		lc = 1;
10666 	    }
10667 	    xmlFree(name);
10668 	} else {
10669 	    /* make sure all cases are covered explicitly */
10670 	    XP_ERROR(XPATH_EXPR_ERROR);
10671 	}
10672     }
10673 
10674     if (lc) {
10675 	if (CUR == '/') {
10676 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10677 	} else {
10678 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10679 	}
10680 	xmlXPathCompLocationPath(ctxt);
10681     } else {
10682 	xmlXPathCompFilterExpr(ctxt);
10683 	CHECK_ERROR;
10684 	if ((CUR == '/') && (NXT(1) == '/')) {
10685 	    SKIP(2);
10686 	    SKIP_BLANKS;
10687 
10688 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10689 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10690 
10691 	    xmlXPathCompRelativeLocationPath(ctxt);
10692 	} else if (CUR == '/') {
10693 	    xmlXPathCompRelativeLocationPath(ctxt);
10694 	}
10695     }
10696     SKIP_BLANKS;
10697 }
10698 
10699 /**
10700  * xmlXPathCompUnionExpr:
10701  * @ctxt:  the XPath Parser context
10702  *
10703  *  [18]   UnionExpr ::=   PathExpr
10704  *               | UnionExpr '|' PathExpr
10705  *
10706  * Compile an union expression.
10707  */
10708 
10709 static void
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt)10710 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10711     xmlXPathCompPathExpr(ctxt);
10712     CHECK_ERROR;
10713     SKIP_BLANKS;
10714     while (CUR == '|') {
10715 	int op1 = ctxt->comp->last;
10716 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10717 
10718 	NEXT;
10719 	SKIP_BLANKS;
10720 	xmlXPathCompPathExpr(ctxt);
10721 
10722 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10723 
10724 	SKIP_BLANKS;
10725     }
10726 }
10727 
10728 /**
10729  * xmlXPathCompUnaryExpr:
10730  * @ctxt:  the XPath Parser context
10731  *
10732  *  [27]   UnaryExpr ::=   UnionExpr
10733  *                   | '-' UnaryExpr
10734  *
10735  * Compile an unary expression.
10736  */
10737 
10738 static void
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt)10739 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10740     int minus = 0;
10741     int found = 0;
10742 
10743     SKIP_BLANKS;
10744     while (CUR == '-') {
10745         minus = 1 - minus;
10746 	found = 1;
10747 	NEXT;
10748 	SKIP_BLANKS;
10749     }
10750 
10751     xmlXPathCompUnionExpr(ctxt);
10752     CHECK_ERROR;
10753     if (found) {
10754 	if (minus)
10755 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10756 	else
10757 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10758     }
10759 }
10760 
10761 /**
10762  * xmlXPathCompMultiplicativeExpr:
10763  * @ctxt:  the XPath Parser context
10764  *
10765  *  [26]   MultiplicativeExpr ::=   UnaryExpr
10766  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10767  *                   | MultiplicativeExpr 'div' UnaryExpr
10768  *                   | MultiplicativeExpr 'mod' UnaryExpr
10769  *  [34]   MultiplyOperator ::=   '*'
10770  *
10771  * Compile an Additive expression.
10772  */
10773 
10774 static void
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt)10775 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10776     xmlXPathCompUnaryExpr(ctxt);
10777     CHECK_ERROR;
10778     SKIP_BLANKS;
10779     while ((CUR == '*') ||
10780            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10781            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10782 	int op = -1;
10783 	int op1 = ctxt->comp->last;
10784 
10785         if (CUR == '*') {
10786 	    op = 0;
10787 	    NEXT;
10788 	} else if (CUR == 'd') {
10789 	    op = 1;
10790 	    SKIP(3);
10791 	} else if (CUR == 'm') {
10792 	    op = 2;
10793 	    SKIP(3);
10794 	}
10795 	SKIP_BLANKS;
10796         xmlXPathCompUnaryExpr(ctxt);
10797 	CHECK_ERROR;
10798 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10799 	SKIP_BLANKS;
10800     }
10801 }
10802 
10803 /**
10804  * xmlXPathCompAdditiveExpr:
10805  * @ctxt:  the XPath Parser context
10806  *
10807  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10808  *                   | AdditiveExpr '+' MultiplicativeExpr
10809  *                   | AdditiveExpr '-' MultiplicativeExpr
10810  *
10811  * Compile an Additive expression.
10812  */
10813 
10814 static void
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt)10815 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10816 
10817     xmlXPathCompMultiplicativeExpr(ctxt);
10818     CHECK_ERROR;
10819     SKIP_BLANKS;
10820     while ((CUR == '+') || (CUR == '-')) {
10821 	int plus;
10822 	int op1 = ctxt->comp->last;
10823 
10824         if (CUR == '+') plus = 1;
10825 	else plus = 0;
10826 	NEXT;
10827 	SKIP_BLANKS;
10828         xmlXPathCompMultiplicativeExpr(ctxt);
10829 	CHECK_ERROR;
10830 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10831 	SKIP_BLANKS;
10832     }
10833 }
10834 
10835 /**
10836  * xmlXPathCompRelationalExpr:
10837  * @ctxt:  the XPath Parser context
10838  *
10839  *  [24]   RelationalExpr ::=   AdditiveExpr
10840  *                 | RelationalExpr '<' AdditiveExpr
10841  *                 | RelationalExpr '>' AdditiveExpr
10842  *                 | RelationalExpr '<=' AdditiveExpr
10843  *                 | RelationalExpr '>=' AdditiveExpr
10844  *
10845  *  A <= B > C is allowed ? Answer from James, yes with
10846  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10847  *  which is basically what got implemented.
10848  *
10849  * Compile a Relational expression, then push the result
10850  * on the stack
10851  */
10852 
10853 static void
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt)10854 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10855     xmlXPathCompAdditiveExpr(ctxt);
10856     CHECK_ERROR;
10857     SKIP_BLANKS;
10858     while ((CUR == '<') || (CUR == '>')) {
10859 	int inf, strict;
10860 	int op1 = ctxt->comp->last;
10861 
10862         if (CUR == '<') inf = 1;
10863 	else inf = 0;
10864 	if (NXT(1) == '=') strict = 0;
10865 	else strict = 1;
10866 	NEXT;
10867 	if (!strict) NEXT;
10868 	SKIP_BLANKS;
10869         xmlXPathCompAdditiveExpr(ctxt);
10870 	CHECK_ERROR;
10871 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10872 	SKIP_BLANKS;
10873     }
10874 }
10875 
10876 /**
10877  * xmlXPathCompEqualityExpr:
10878  * @ctxt:  the XPath Parser context
10879  *
10880  *  [23]   EqualityExpr ::=   RelationalExpr
10881  *                 | EqualityExpr '=' RelationalExpr
10882  *                 | EqualityExpr '!=' RelationalExpr
10883  *
10884  *  A != B != C is allowed ? Answer from James, yes with
10885  *  (RelationalExpr = RelationalExpr) = RelationalExpr
10886  *  (RelationalExpr != RelationalExpr) != RelationalExpr
10887  *  which is basically what got implemented.
10888  *
10889  * Compile an Equality expression.
10890  *
10891  */
10892 static void
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt)10893 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10894     xmlXPathCompRelationalExpr(ctxt);
10895     CHECK_ERROR;
10896     SKIP_BLANKS;
10897     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10898 	int eq;
10899 	int op1 = ctxt->comp->last;
10900 
10901         if (CUR == '=') eq = 1;
10902 	else eq = 0;
10903 	NEXT;
10904 	if (!eq) NEXT;
10905 	SKIP_BLANKS;
10906         xmlXPathCompRelationalExpr(ctxt);
10907 	CHECK_ERROR;
10908 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10909 	SKIP_BLANKS;
10910     }
10911 }
10912 
10913 /**
10914  * xmlXPathCompAndExpr:
10915  * @ctxt:  the XPath Parser context
10916  *
10917  *  [22]   AndExpr ::=   EqualityExpr
10918  *                 | AndExpr 'and' EqualityExpr
10919  *
10920  * Compile an AND expression.
10921  *
10922  */
10923 static void
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt)10924 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10925     xmlXPathCompEqualityExpr(ctxt);
10926     CHECK_ERROR;
10927     SKIP_BLANKS;
10928     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10929 	int op1 = ctxt->comp->last;
10930         SKIP(3);
10931 	SKIP_BLANKS;
10932         xmlXPathCompEqualityExpr(ctxt);
10933 	CHECK_ERROR;
10934 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10935 	SKIP_BLANKS;
10936     }
10937 }
10938 
10939 /**
10940  * xmlXPathCompileExpr:
10941  * @ctxt:  the XPath Parser context
10942  *
10943  *  [14]   Expr ::=   OrExpr
10944  *  [21]   OrExpr ::=   AndExpr
10945  *                 | OrExpr 'or' AndExpr
10946  *
10947  * Parse and compile an expression
10948  */
10949 static void
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt,int sort)10950 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10951     xmlXPathContextPtr xpctxt = ctxt->context;
10952 
10953     if (xpctxt != NULL) {
10954         if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10955             XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10956         /*
10957          * Parsing a single '(' pushes about 10 functions on the call stack
10958          * before recursing!
10959          */
10960         xpctxt->depth += 10;
10961     }
10962 
10963     xmlXPathCompAndExpr(ctxt);
10964     CHECK_ERROR;
10965     SKIP_BLANKS;
10966     while ((CUR == 'o') && (NXT(1) == 'r')) {
10967 	int op1 = ctxt->comp->last;
10968         SKIP(2);
10969 	SKIP_BLANKS;
10970         xmlXPathCompAndExpr(ctxt);
10971 	CHECK_ERROR;
10972 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10973 	SKIP_BLANKS;
10974     }
10975     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10976 	/* more ops could be optimized too */
10977 	/*
10978 	* This is the main place to eliminate sorting for
10979 	* operations which don't require a sorted node-set.
10980 	* E.g. count().
10981 	*/
10982 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10983     }
10984 
10985     if (xpctxt != NULL)
10986         xpctxt->depth -= 10;
10987 }
10988 
10989 /**
10990  * xmlXPathCompPredicate:
10991  * @ctxt:  the XPath Parser context
10992  * @filter:  act as a filter
10993  *
10994  *  [8]   Predicate ::=   '[' PredicateExpr ']'
10995  *  [9]   PredicateExpr ::=   Expr
10996  *
10997  * Compile a predicate expression
10998  */
10999 static void
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt,int filter)11000 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11001     int op1 = ctxt->comp->last;
11002 
11003     SKIP_BLANKS;
11004     if (CUR != '[') {
11005 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11006     }
11007     NEXT;
11008     SKIP_BLANKS;
11009 
11010     ctxt->comp->last = -1;
11011     /*
11012     * This call to xmlXPathCompileExpr() will deactivate sorting
11013     * of the predicate result.
11014     * TODO: Sorting is still activated for filters, since I'm not
11015     *  sure if needed. Normally sorting should not be needed, since
11016     *  a filter can only diminish the number of items in a sequence,
11017     *  but won't change its order; so if the initial sequence is sorted,
11018     *  subsequent sorting is not needed.
11019     */
11020     if (! filter)
11021 	xmlXPathCompileExpr(ctxt, 0);
11022     else
11023 	xmlXPathCompileExpr(ctxt, 1);
11024     CHECK_ERROR;
11025 
11026     if (CUR != ']') {
11027 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11028     }
11029 
11030     if (filter)
11031 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11032     else
11033 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11034 
11035     NEXT;
11036     SKIP_BLANKS;
11037 }
11038 
11039 /**
11040  * xmlXPathCompNodeTest:
11041  * @ctxt:  the XPath Parser context
11042  * @test:  pointer to a xmlXPathTestVal
11043  * @type:  pointer to a xmlXPathTypeVal
11044  * @prefix:  placeholder for a possible name prefix
11045  *
11046  * [7] NodeTest ::=   NameTest
11047  *		    | NodeType '(' ')'
11048  *		    | 'processing-instruction' '(' Literal ')'
11049  *
11050  * [37] NameTest ::=  '*'
11051  *		    | NCName ':' '*'
11052  *		    | QName
11053  * [38] NodeType ::= 'comment'
11054  *		   | 'text'
11055  *		   | 'processing-instruction'
11056  *		   | 'node'
11057  *
11058  * Returns the name found and updates @test, @type and @prefix appropriately
11059  */
11060 static xmlChar *
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt,xmlXPathTestVal * test,xmlXPathTypeVal * type,xmlChar ** prefix,xmlChar * name)11061 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11062 	             xmlXPathTypeVal *type, xmlChar **prefix,
11063 		     xmlChar *name) {
11064     int blanks;
11065 
11066     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11067 	STRANGE;
11068 	return(NULL);
11069     }
11070     *type = (xmlXPathTypeVal) 0;
11071     *test = (xmlXPathTestVal) 0;
11072     *prefix = NULL;
11073     SKIP_BLANKS;
11074 
11075     if ((name == NULL) && (CUR == '*')) {
11076 	/*
11077 	 * All elements
11078 	 */
11079 	NEXT;
11080 	*test = NODE_TEST_ALL;
11081 	return(NULL);
11082     }
11083 
11084     if (name == NULL)
11085 	name = xmlXPathParseNCName(ctxt);
11086     if (name == NULL) {
11087 	XP_ERRORNULL(XPATH_EXPR_ERROR);
11088     }
11089 
11090     blanks = IS_BLANK_CH(CUR);
11091     SKIP_BLANKS;
11092     if (CUR == '(') {
11093 	NEXT;
11094 	/*
11095 	 * NodeType or PI search
11096 	 */
11097 	if (xmlStrEqual(name, BAD_CAST "comment"))
11098 	    *type = NODE_TYPE_COMMENT;
11099 	else if (xmlStrEqual(name, BAD_CAST "node"))
11100 	    *type = NODE_TYPE_NODE;
11101 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11102 	    *type = NODE_TYPE_PI;
11103 	else if (xmlStrEqual(name, BAD_CAST "text"))
11104 	    *type = NODE_TYPE_TEXT;
11105 	else {
11106 	    if (name != NULL)
11107 		xmlFree(name);
11108 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11109 	}
11110 
11111 	*test = NODE_TEST_TYPE;
11112 
11113 	SKIP_BLANKS;
11114 	if (*type == NODE_TYPE_PI) {
11115 	    /*
11116 	     * Specific case: search a PI by name.
11117 	     */
11118 	    if (name != NULL)
11119 		xmlFree(name);
11120 	    name = NULL;
11121 	    if (CUR != ')') {
11122 		name = xmlXPathParseLiteral(ctxt);
11123 		CHECK_ERROR NULL;
11124 		*test = NODE_TEST_PI;
11125 		SKIP_BLANKS;
11126 	    }
11127 	}
11128 	if (CUR != ')') {
11129 	    if (name != NULL)
11130 		xmlFree(name);
11131 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11132 	}
11133 	NEXT;
11134 	return(name);
11135     }
11136     *test = NODE_TEST_NAME;
11137     if ((!blanks) && (CUR == ':')) {
11138 	NEXT;
11139 
11140 	/*
11141 	 * Since currently the parser context don't have a
11142 	 * namespace list associated:
11143 	 * The namespace name for this prefix can be computed
11144 	 * only at evaluation time. The compilation is done
11145 	 * outside of any context.
11146 	 */
11147 #if 0
11148 	*prefix = xmlXPathNsLookup(ctxt->context, name);
11149 	if (name != NULL)
11150 	    xmlFree(name);
11151 	if (*prefix == NULL) {
11152 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11153 	}
11154 #else
11155 	*prefix = name;
11156 #endif
11157 
11158 	if (CUR == '*') {
11159 	    /*
11160 	     * All elements
11161 	     */
11162 	    NEXT;
11163 	    *test = NODE_TEST_ALL;
11164 	    return(NULL);
11165 	}
11166 
11167 	name = xmlXPathParseNCName(ctxt);
11168 	if (name == NULL) {
11169 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11170 	}
11171     }
11172     return(name);
11173 }
11174 
11175 /**
11176  * xmlXPathIsAxisName:
11177  * @name:  a preparsed name token
11178  *
11179  * [6] AxisName ::=   'ancestor'
11180  *                  | 'ancestor-or-self'
11181  *                  | 'attribute'
11182  *                  | 'child'
11183  *                  | 'descendant'
11184  *                  | 'descendant-or-self'
11185  *                  | 'following'
11186  *                  | 'following-sibling'
11187  *                  | 'namespace'
11188  *                  | 'parent'
11189  *                  | 'preceding'
11190  *                  | 'preceding-sibling'
11191  *                  | 'self'
11192  *
11193  * Returns the axis or 0
11194  */
11195 static xmlXPathAxisVal
xmlXPathIsAxisName(const xmlChar * name)11196 xmlXPathIsAxisName(const xmlChar *name) {
11197     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11198     switch (name[0]) {
11199 	case 'a':
11200 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
11201 		ret = AXIS_ANCESTOR;
11202 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11203 		ret = AXIS_ANCESTOR_OR_SELF;
11204 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
11205 		ret = AXIS_ATTRIBUTE;
11206 	    break;
11207 	case 'c':
11208 	    if (xmlStrEqual(name, BAD_CAST "child"))
11209 		ret = AXIS_CHILD;
11210 	    break;
11211 	case 'd':
11212 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
11213 		ret = AXIS_DESCENDANT;
11214 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11215 		ret = AXIS_DESCENDANT_OR_SELF;
11216 	    break;
11217 	case 'f':
11218 	    if (xmlStrEqual(name, BAD_CAST "following"))
11219 		ret = AXIS_FOLLOWING;
11220 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11221 		ret = AXIS_FOLLOWING_SIBLING;
11222 	    break;
11223 	case 'n':
11224 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
11225 		ret = AXIS_NAMESPACE;
11226 	    break;
11227 	case 'p':
11228 	    if (xmlStrEqual(name, BAD_CAST "parent"))
11229 		ret = AXIS_PARENT;
11230 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
11231 		ret = AXIS_PRECEDING;
11232 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11233 		ret = AXIS_PRECEDING_SIBLING;
11234 	    break;
11235 	case 's':
11236 	    if (xmlStrEqual(name, BAD_CAST "self"))
11237 		ret = AXIS_SELF;
11238 	    break;
11239     }
11240     return(ret);
11241 }
11242 
11243 /**
11244  * xmlXPathCompStep:
11245  * @ctxt:  the XPath Parser context
11246  *
11247  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11248  *                  | AbbreviatedStep
11249  *
11250  * [12] AbbreviatedStep ::=   '.' | '..'
11251  *
11252  * [5] AxisSpecifier ::= AxisName '::'
11253  *                  | AbbreviatedAxisSpecifier
11254  *
11255  * [13] AbbreviatedAxisSpecifier ::= '@'?
11256  *
11257  * Modified for XPtr range support as:
11258  *
11259  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11260  *                     | AbbreviatedStep
11261  *                     | 'range-to' '(' Expr ')' Predicate*
11262  *
11263  * Compile one step in a Location Path
11264  * A location step of . is short for self::node(). This is
11265  * particularly useful in conjunction with //. For example, the
11266  * location path .//para is short for
11267  * self::node()/descendant-or-self::node()/child::para
11268  * and so will select all para descendant elements of the context
11269  * node.
11270  * Similarly, a location step of .. is short for parent::node().
11271  * For example, ../title is short for parent::node()/child::title
11272  * and so will select the title children of the parent of the context
11273  * node.
11274  */
11275 static void
xmlXPathCompStep(xmlXPathParserContextPtr ctxt)11276 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11277 #ifdef LIBXML_XPTR_ENABLED
11278     int rangeto = 0;
11279     int op2 = -1;
11280 #endif
11281 
11282     SKIP_BLANKS;
11283     if ((CUR == '.') && (NXT(1) == '.')) {
11284 	SKIP(2);
11285 	SKIP_BLANKS;
11286 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11287 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11288     } else if (CUR == '.') {
11289 	NEXT;
11290 	SKIP_BLANKS;
11291     } else {
11292 	xmlChar *name = NULL;
11293 	xmlChar *prefix = NULL;
11294 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
11295 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11296 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11297 	int op1;
11298 
11299 	/*
11300 	 * The modification needed for XPointer change to the production
11301 	 */
11302 #ifdef LIBXML_XPTR_ENABLED
11303 	if (ctxt->xptr) {
11304 	    name = xmlXPathParseNCName(ctxt);
11305 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11306                 op2 = ctxt->comp->last;
11307 		xmlFree(name);
11308 		SKIP_BLANKS;
11309 		if (CUR != '(') {
11310 		    XP_ERROR(XPATH_EXPR_ERROR);
11311 		}
11312 		NEXT;
11313 		SKIP_BLANKS;
11314 
11315 		xmlXPathCompileExpr(ctxt, 1);
11316 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11317 		CHECK_ERROR;
11318 
11319 		SKIP_BLANKS;
11320 		if (CUR != ')') {
11321 		    XP_ERROR(XPATH_EXPR_ERROR);
11322 		}
11323 		NEXT;
11324 		rangeto = 1;
11325 		goto eval_predicates;
11326 	    }
11327 	}
11328 #endif
11329 	if (CUR == '*') {
11330 	    axis = AXIS_CHILD;
11331 	} else {
11332 	    if (name == NULL)
11333 		name = xmlXPathParseNCName(ctxt);
11334 	    if (name != NULL) {
11335 		axis = xmlXPathIsAxisName(name);
11336 		if (axis != 0) {
11337 		    SKIP_BLANKS;
11338 		    if ((CUR == ':') && (NXT(1) == ':')) {
11339 			SKIP(2);
11340 			xmlFree(name);
11341 			name = NULL;
11342 		    } else {
11343 			/* an element name can conflict with an axis one :-\ */
11344 			axis = AXIS_CHILD;
11345 		    }
11346 		} else {
11347 		    axis = AXIS_CHILD;
11348 		}
11349 	    } else if (CUR == '@') {
11350 		NEXT;
11351 		axis = AXIS_ATTRIBUTE;
11352 	    } else {
11353 		axis = AXIS_CHILD;
11354 	    }
11355 	}
11356 
11357         if (ctxt->error != XPATH_EXPRESSION_OK) {
11358             xmlFree(name);
11359             return;
11360         }
11361 
11362 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11363 	if (test == 0)
11364 	    return;
11365 
11366         if ((prefix != NULL) && (ctxt->context != NULL) &&
11367 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11368 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11369 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11370 	    }
11371 	}
11372 #ifdef DEBUG_STEP
11373 	xmlGenericError(xmlGenericErrorContext,
11374 		"Basis : computing new set\n");
11375 #endif
11376 
11377 #ifdef DEBUG_STEP
11378 	xmlGenericError(xmlGenericErrorContext, "Basis : ");
11379 	if (ctxt->value == NULL)
11380 	    xmlGenericError(xmlGenericErrorContext, "no value\n");
11381 	else if (ctxt->value->nodesetval == NULL)
11382 	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
11383 	else
11384 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11385 #endif
11386 
11387 #ifdef LIBXML_XPTR_ENABLED
11388 eval_predicates:
11389 #endif
11390 	op1 = ctxt->comp->last;
11391 	ctxt->comp->last = -1;
11392 
11393 	SKIP_BLANKS;
11394 	while (CUR == '[') {
11395 	    xmlXPathCompPredicate(ctxt, 0);
11396 	}
11397 
11398 #ifdef LIBXML_XPTR_ENABLED
11399 	if (rangeto) {
11400 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11401 	} else
11402 #endif
11403         if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11404                            test, type, (void *)prefix, (void *)name) == -1) {
11405             xmlFree(prefix);
11406             xmlFree(name);
11407         }
11408     }
11409 #ifdef DEBUG_STEP
11410     xmlGenericError(xmlGenericErrorContext, "Step : ");
11411     if (ctxt->value == NULL)
11412 	xmlGenericError(xmlGenericErrorContext, "no value\n");
11413     else if (ctxt->value->nodesetval == NULL)
11414 	xmlGenericError(xmlGenericErrorContext, "Empty\n");
11415     else
11416 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11417 		ctxt->value->nodesetval);
11418 #endif
11419 }
11420 
11421 /**
11422  * xmlXPathCompRelativeLocationPath:
11423  * @ctxt:  the XPath Parser context
11424  *
11425  *  [3]   RelativeLocationPath ::=   Step
11426  *                     | RelativeLocationPath '/' Step
11427  *                     | AbbreviatedRelativeLocationPath
11428  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11429  *
11430  * Compile a relative location path.
11431  */
11432 static void
xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt)11433 xmlXPathCompRelativeLocationPath
11434 (xmlXPathParserContextPtr ctxt) {
11435     SKIP_BLANKS;
11436     if ((CUR == '/') && (NXT(1) == '/')) {
11437 	SKIP(2);
11438 	SKIP_BLANKS;
11439 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11440 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11441     } else if (CUR == '/') {
11442 	    NEXT;
11443 	SKIP_BLANKS;
11444     }
11445     xmlXPathCompStep(ctxt);
11446     CHECK_ERROR;
11447     SKIP_BLANKS;
11448     while (CUR == '/') {
11449 	if ((CUR == '/') && (NXT(1) == '/')) {
11450 	    SKIP(2);
11451 	    SKIP_BLANKS;
11452 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11453 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11454 	    xmlXPathCompStep(ctxt);
11455 	} else if (CUR == '/') {
11456 	    NEXT;
11457 	    SKIP_BLANKS;
11458 	    xmlXPathCompStep(ctxt);
11459 	}
11460 	SKIP_BLANKS;
11461     }
11462 }
11463 
11464 /**
11465  * xmlXPathCompLocationPath:
11466  * @ctxt:  the XPath Parser context
11467  *
11468  *  [1]   LocationPath ::=   RelativeLocationPath
11469  *                     | AbsoluteLocationPath
11470  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11471  *                     | AbbreviatedAbsoluteLocationPath
11472  *  [10]   AbbreviatedAbsoluteLocationPath ::=
11473  *                           '//' RelativeLocationPath
11474  *
11475  * Compile a location path
11476  *
11477  * // is short for /descendant-or-self::node()/. For example,
11478  * //para is short for /descendant-or-self::node()/child::para and
11479  * so will select any para element in the document (even a para element
11480  * that is a document element will be selected by //para since the
11481  * document element node is a child of the root node); div//para is
11482  * short for div/descendant-or-self::node()/child::para and so will
11483  * select all para descendants of div children.
11484  */
11485 static void
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt)11486 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11487     SKIP_BLANKS;
11488     if (CUR != '/') {
11489         xmlXPathCompRelativeLocationPath(ctxt);
11490     } else {
11491 	while (CUR == '/') {
11492 	    if ((CUR == '/') && (NXT(1) == '/')) {
11493 		SKIP(2);
11494 		SKIP_BLANKS;
11495 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11496 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11497 		xmlXPathCompRelativeLocationPath(ctxt);
11498 	    } else if (CUR == '/') {
11499 		NEXT;
11500 		SKIP_BLANKS;
11501 		if ((CUR != 0 ) &&
11502 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11503 		     (CUR == '@') || (CUR == '*')))
11504 		    xmlXPathCompRelativeLocationPath(ctxt);
11505 	    }
11506 	    CHECK_ERROR;
11507 	}
11508     }
11509 }
11510 
11511 /************************************************************************
11512  *									*
11513  *		XPath precompiled expression evaluation			*
11514  *									*
11515  ************************************************************************/
11516 
11517 static int
11518 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11519 
11520 #ifdef DEBUG_STEP
11521 static void
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,int nbNodes)11522 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11523 			  int nbNodes)
11524 {
11525     xmlGenericError(xmlGenericErrorContext, "new step : ");
11526     switch (op->value) {
11527         case AXIS_ANCESTOR:
11528             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11529             break;
11530         case AXIS_ANCESTOR_OR_SELF:
11531             xmlGenericError(xmlGenericErrorContext,
11532                             "axis 'ancestors-or-self' ");
11533             break;
11534         case AXIS_ATTRIBUTE:
11535             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11536             break;
11537         case AXIS_CHILD:
11538             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11539             break;
11540         case AXIS_DESCENDANT:
11541             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11542             break;
11543         case AXIS_DESCENDANT_OR_SELF:
11544             xmlGenericError(xmlGenericErrorContext,
11545                             "axis 'descendant-or-self' ");
11546             break;
11547         case AXIS_FOLLOWING:
11548             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11549             break;
11550         case AXIS_FOLLOWING_SIBLING:
11551             xmlGenericError(xmlGenericErrorContext,
11552                             "axis 'following-siblings' ");
11553             break;
11554         case AXIS_NAMESPACE:
11555             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11556             break;
11557         case AXIS_PARENT:
11558             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11559             break;
11560         case AXIS_PRECEDING:
11561             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11562             break;
11563         case AXIS_PRECEDING_SIBLING:
11564             xmlGenericError(xmlGenericErrorContext,
11565                             "axis 'preceding-sibling' ");
11566             break;
11567         case AXIS_SELF:
11568             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11569             break;
11570     }
11571     xmlGenericError(xmlGenericErrorContext,
11572 	" context contains %d nodes\n", nbNodes);
11573     switch (op->value2) {
11574         case NODE_TEST_NONE:
11575             xmlGenericError(xmlGenericErrorContext,
11576                             "           searching for none !!!\n");
11577             break;
11578         case NODE_TEST_TYPE:
11579             xmlGenericError(xmlGenericErrorContext,
11580                             "           searching for type %d\n", op->value3);
11581             break;
11582         case NODE_TEST_PI:
11583             xmlGenericError(xmlGenericErrorContext,
11584                             "           searching for PI !!!\n");
11585             break;
11586         case NODE_TEST_ALL:
11587             xmlGenericError(xmlGenericErrorContext,
11588                             "           searching for *\n");
11589             break;
11590         case NODE_TEST_NS:
11591             xmlGenericError(xmlGenericErrorContext,
11592                             "           searching for namespace %s\n",
11593                             op->value5);
11594             break;
11595         case NODE_TEST_NAME:
11596             xmlGenericError(xmlGenericErrorContext,
11597                             "           searching for name %s\n", op->value5);
11598             if (op->value4)
11599                 xmlGenericError(xmlGenericErrorContext,
11600                                 "           with namespace %s\n", op->value4);
11601             break;
11602     }
11603     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11604 }
11605 #endif /* DEBUG_STEP */
11606 
11607 /**
11608  * xmlXPathNodeSetFilter:
11609  * @ctxt:  the XPath Parser context
11610  * @set: the node set to filter
11611  * @filterOpIndex: the index of the predicate/filter op
11612  * @minPos: minimum position in the filtered set (1-based)
11613  * @maxPos: maximum position in the filtered set (1-based)
11614  * @hasNsNodes: true if the node set may contain namespace nodes
11615  *
11616  * Filter a node set, keeping only nodes for which the predicate expression
11617  * matches. Afterwards, keep only nodes between minPos and maxPos in the
11618  * filtered result.
11619  */
11620 static void
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,xmlNodeSetPtr set,int filterOpIndex,int minPos,int maxPos,int hasNsNodes)11621 xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11622 		      xmlNodeSetPtr set,
11623 		      int filterOpIndex,
11624                       int minPos, int maxPos,
11625 		      int hasNsNodes)
11626 {
11627     xmlXPathContextPtr xpctxt;
11628     xmlNodePtr oldnode;
11629     xmlDocPtr olddoc;
11630     xmlXPathStepOpPtr filterOp;
11631     int oldcs, oldpp;
11632     int i, j, pos;
11633 
11634     if ((set == NULL) || (set->nodeNr == 0))
11635         return;
11636 
11637     /*
11638     * Check if the node set contains a sufficient number of nodes for
11639     * the requested range.
11640     */
11641     if (set->nodeNr < minPos) {
11642         xmlXPathNodeSetClear(set, hasNsNodes);
11643         return;
11644     }
11645 
11646     xpctxt = ctxt->context;
11647     oldnode = xpctxt->node;
11648     olddoc = xpctxt->doc;
11649     oldcs = xpctxt->contextSize;
11650     oldpp = xpctxt->proximityPosition;
11651     filterOp = &ctxt->comp->steps[filterOpIndex];
11652 
11653     xpctxt->contextSize = set->nodeNr;
11654 
11655     for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11656         xmlNodePtr node = set->nodeTab[i];
11657         int res;
11658 
11659         xpctxt->node = node;
11660         xpctxt->proximityPosition = i + 1;
11661 
11662         /*
11663         * Also set the xpath document in case things like
11664         * key() are evaluated in the predicate.
11665         *
11666         * TODO: Get real doc for namespace nodes.
11667         */
11668         if ((node->type != XML_NAMESPACE_DECL) &&
11669             (node->doc != NULL))
11670             xpctxt->doc = node->doc;
11671 
11672         res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11673 
11674         if (ctxt->error != XPATH_EXPRESSION_OK)
11675             break;
11676         if (res < 0) {
11677             /* Shouldn't happen */
11678             xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11679             break;
11680         }
11681 
11682         if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11683             if (i != j) {
11684                 set->nodeTab[j] = node;
11685                 set->nodeTab[i] = NULL;
11686             }
11687 
11688             j += 1;
11689         } else {
11690             /* Remove the entry from the initial node set. */
11691             set->nodeTab[i] = NULL;
11692             if (node->type == XML_NAMESPACE_DECL)
11693                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11694         }
11695 
11696         if (res != 0) {
11697             if (pos == maxPos) {
11698                 i += 1;
11699                 break;
11700             }
11701 
11702             pos += 1;
11703         }
11704     }
11705 
11706     /* Free remaining nodes. */
11707     if (hasNsNodes) {
11708         for (; i < set->nodeNr; i++) {
11709             xmlNodePtr node = set->nodeTab[i];
11710             if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11711                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11712         }
11713     }
11714 
11715     set->nodeNr = j;
11716 
11717     /* If too many elements were removed, shrink table to preserve memory. */
11718     if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11719         (set->nodeNr < set->nodeMax / 2)) {
11720         xmlNodePtr *tmp;
11721         int nodeMax = set->nodeNr;
11722 
11723         if (nodeMax < XML_NODESET_DEFAULT)
11724             nodeMax = XML_NODESET_DEFAULT;
11725         tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11726                 nodeMax * sizeof(xmlNodePtr));
11727         if (tmp == NULL) {
11728             xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11729         } else {
11730             set->nodeTab = tmp;
11731             set->nodeMax = nodeMax;
11732         }
11733     }
11734 
11735     xpctxt->node = oldnode;
11736     xpctxt->doc = olddoc;
11737     xpctxt->contextSize = oldcs;
11738     xpctxt->proximityPosition = oldpp;
11739 }
11740 
11741 #ifdef LIBXML_XPTR_ENABLED
11742 /**
11743  * xmlXPathLocationSetFilter:
11744  * @ctxt:  the XPath Parser context
11745  * @locset: the location set to filter
11746  * @filterOpIndex: the index of the predicate/filter op
11747  * @minPos: minimum position in the filtered set (1-based)
11748  * @maxPos: maximum position in the filtered set (1-based)
11749  *
11750  * Filter a location set, keeping only nodes for which the predicate
11751  * expression matches. Afterwards, keep only nodes between minPos and maxPos
11752  * in the filtered result.
11753  */
11754 static void
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,xmlLocationSetPtr locset,int filterOpIndex,int minPos,int maxPos)11755 xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11756 		          xmlLocationSetPtr locset,
11757 		          int filterOpIndex,
11758                           int minPos, int maxPos)
11759 {
11760     xmlXPathContextPtr xpctxt;
11761     xmlNodePtr oldnode;
11762     xmlDocPtr olddoc;
11763     xmlXPathStepOpPtr filterOp;
11764     int oldcs, oldpp;
11765     int i, j, pos;
11766 
11767     if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11768         return;
11769 
11770     xpctxt = ctxt->context;
11771     oldnode = xpctxt->node;
11772     olddoc = xpctxt->doc;
11773     oldcs = xpctxt->contextSize;
11774     oldpp = xpctxt->proximityPosition;
11775     filterOp = &ctxt->comp->steps[filterOpIndex];
11776 
11777     xpctxt->contextSize = locset->locNr;
11778 
11779     for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11780         xmlNodePtr contextNode = locset->locTab[i]->user;
11781         int res;
11782 
11783         xpctxt->node = contextNode;
11784         xpctxt->proximityPosition = i + 1;
11785 
11786         /*
11787         * Also set the xpath document in case things like
11788         * key() are evaluated in the predicate.
11789         *
11790         * TODO: Get real doc for namespace nodes.
11791         */
11792         if ((contextNode->type != XML_NAMESPACE_DECL) &&
11793             (contextNode->doc != NULL))
11794             xpctxt->doc = contextNode->doc;
11795 
11796         res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11797 
11798         if (ctxt->error != XPATH_EXPRESSION_OK)
11799             break;
11800         if (res < 0) {
11801             /* Shouldn't happen */
11802             xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11803             break;
11804         }
11805 
11806         if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11807             if (i != j) {
11808                 locset->locTab[j] = locset->locTab[i];
11809                 locset->locTab[i] = NULL;
11810             }
11811 
11812             j += 1;
11813         } else {
11814             /* Remove the entry from the initial location set. */
11815             xmlXPathFreeObject(locset->locTab[i]);
11816             locset->locTab[i] = NULL;
11817         }
11818 
11819         if (res != 0) {
11820             if (pos == maxPos) {
11821                 i += 1;
11822                 break;
11823             }
11824 
11825             pos += 1;
11826         }
11827     }
11828 
11829     /* Free remaining nodes. */
11830     for (; i < locset->locNr; i++)
11831         xmlXPathFreeObject(locset->locTab[i]);
11832 
11833     locset->locNr = j;
11834 
11835     /* If too many elements were removed, shrink table to preserve memory. */
11836     if ((locset->locMax > XML_NODESET_DEFAULT) &&
11837         (locset->locNr < locset->locMax / 2)) {
11838         xmlXPathObjectPtr *tmp;
11839         int locMax = locset->locNr;
11840 
11841         if (locMax < XML_NODESET_DEFAULT)
11842             locMax = XML_NODESET_DEFAULT;
11843         tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11844                 locMax * sizeof(xmlXPathObjectPtr));
11845         if (tmp == NULL) {
11846             xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11847         } else {
11848             locset->locTab = tmp;
11849             locset->locMax = locMax;
11850         }
11851     }
11852 
11853     xpctxt->node = oldnode;
11854     xpctxt->doc = olddoc;
11855     xpctxt->contextSize = oldcs;
11856     xpctxt->proximityPosition = oldpp;
11857 }
11858 #endif /* LIBXML_XPTR_ENABLED */
11859 
11860 /**
11861  * xmlXPathCompOpEvalPredicate:
11862  * @ctxt:  the XPath Parser context
11863  * @op: the predicate op
11864  * @set: the node set to filter
11865  * @minPos: minimum position in the filtered set (1-based)
11866  * @maxPos: maximum position in the filtered set (1-based)
11867  * @hasNsNodes: true if the node set may contain namespace nodes
11868  *
11869  * Filter a node set, keeping only nodes for which the sequence of predicate
11870  * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11871  * in the filtered result.
11872  */
11873 static void
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int minPos,int maxPos,int hasNsNodes)11874 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11875 			    xmlXPathStepOpPtr op,
11876 			    xmlNodeSetPtr set,
11877                             int minPos, int maxPos,
11878 			    int hasNsNodes)
11879 {
11880     if (op->ch1 != -1) {
11881 	xmlXPathCompExprPtr comp = ctxt->comp;
11882 	/*
11883 	* Process inner predicates first.
11884 	*/
11885 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11886             xmlGenericError(xmlGenericErrorContext,
11887                 "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11888             XP_ERROR(XPATH_INVALID_OPERAND);
11889 	}
11890         if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11891             XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11892         ctxt->context->depth += 1;
11893 	xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11894                                     1, set->nodeNr, hasNsNodes);
11895         ctxt->context->depth -= 1;
11896 	CHECK_ERROR;
11897     }
11898 
11899     if (op->ch2 != -1)
11900         xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11901 }
11902 
11903 static int
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int * maxPos)11904 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11905 			    xmlXPathStepOpPtr op,
11906 			    int *maxPos)
11907 {
11908 
11909     xmlXPathStepOpPtr exprOp;
11910 
11911     /*
11912     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11913     */
11914 
11915     /*
11916     * If not -1, then ch1 will point to:
11917     * 1) For predicates (XPATH_OP_PREDICATE):
11918     *    - an inner predicate operator
11919     * 2) For filters (XPATH_OP_FILTER):
11920     *    - an inner filter operator OR
11921     *    - an expression selecting the node set.
11922     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11923     */
11924     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11925 	return(0);
11926 
11927     if (op->ch2 != -1) {
11928 	exprOp = &ctxt->comp->steps[op->ch2];
11929     } else
11930 	return(0);
11931 
11932     if ((exprOp != NULL) &&
11933 	(exprOp->op == XPATH_OP_VALUE) &&
11934 	(exprOp->value4 != NULL) &&
11935 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11936     {
11937         double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11938 
11939 	/*
11940 	* We have a "[n]" predicate here.
11941 	* TODO: Unfortunately this simplistic test here is not
11942 	* able to detect a position() predicate in compound
11943 	* expressions like "[@attr = 'a" and position() = 1],
11944 	* and even not the usage of position() in
11945 	* "[position() = 1]"; thus - obviously - a position-range,
11946 	* like it "[position() < 5]", is also not detected.
11947 	* Maybe we could rewrite the AST to ease the optimization.
11948 	*/
11949 
11950         if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11951 	    *maxPos = (int) floatval;
11952             if (floatval == (double) *maxPos)
11953                 return(1);
11954         }
11955     }
11956     return(0);
11957 }
11958 
11959 static int
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first,xmlNodePtr * last,int toBool)11960 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11961                            xmlXPathStepOpPtr op,
11962 			   xmlNodePtr * first, xmlNodePtr * last,
11963 			   int toBool)
11964 {
11965 
11966 #define XP_TEST_HIT \
11967     if (hasAxisRange != 0) { \
11968 	if (++pos == maxPos) { \
11969 	    if (addNode(seq, cur) < 0) \
11970 	        ctxt->error = XPATH_MEMORY_ERROR; \
11971 	    goto axis_range_end; } \
11972     } else { \
11973 	if (addNode(seq, cur) < 0) \
11974 	    ctxt->error = XPATH_MEMORY_ERROR; \
11975 	if (breakOnFirstHit) goto first_hit; }
11976 
11977 #define XP_TEST_HIT_NS \
11978     if (hasAxisRange != 0) { \
11979 	if (++pos == maxPos) { \
11980 	    hasNsNodes = 1; \
11981 	    if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11982 	        ctxt->error = XPATH_MEMORY_ERROR; \
11983 	goto axis_range_end; } \
11984     } else { \
11985 	hasNsNodes = 1; \
11986 	if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11987 	    ctxt->error = XPATH_MEMORY_ERROR; \
11988 	if (breakOnFirstHit) goto first_hit; }
11989 
11990     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11991     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11992     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11993     const xmlChar *prefix = op->value4;
11994     const xmlChar *name = op->value5;
11995     const xmlChar *URI = NULL;
11996 
11997 #ifdef DEBUG_STEP
11998     int nbMatches = 0, prevMatches = 0;
11999 #endif
12000     int total = 0, hasNsNodes = 0;
12001     /* The popped object holding the context nodes */
12002     xmlXPathObjectPtr obj;
12003     /* The set of context nodes for the node tests */
12004     xmlNodeSetPtr contextSeq;
12005     int contextIdx;
12006     xmlNodePtr contextNode;
12007     /* The final resulting node set wrt to all context nodes */
12008     xmlNodeSetPtr outSeq;
12009     /*
12010     * The temporary resulting node set wrt 1 context node.
12011     * Used to feed predicate evaluation.
12012     */
12013     xmlNodeSetPtr seq;
12014     xmlNodePtr cur;
12015     /* First predicate operator */
12016     xmlXPathStepOpPtr predOp;
12017     int maxPos; /* The requested position() (when a "[n]" predicate) */
12018     int hasPredicateRange, hasAxisRange, pos;
12019     int breakOnFirstHit;
12020 
12021     xmlXPathTraversalFunction next = NULL;
12022     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12023     xmlXPathNodeSetMergeFunction mergeAndClear;
12024     xmlNodePtr oldContextNode;
12025     xmlXPathContextPtr xpctxt = ctxt->context;
12026 
12027 
12028     CHECK_TYPE0(XPATH_NODESET);
12029     obj = valuePop(ctxt);
12030     /*
12031     * Setup namespaces.
12032     */
12033     if (prefix != NULL) {
12034         URI = xmlXPathNsLookup(xpctxt, prefix);
12035         if (URI == NULL) {
12036 	    xmlXPathReleaseObject(xpctxt, obj);
12037             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12038 	}
12039     }
12040     /*
12041     * Setup axis.
12042     *
12043     * MAYBE FUTURE TODO: merging optimizations:
12044     * - If the nodes to be traversed wrt to the initial nodes and
12045     *   the current axis cannot overlap, then we could avoid searching
12046     *   for duplicates during the merge.
12047     *   But the question is how/when to evaluate if they cannot overlap.
12048     *   Example: if we know that for two initial nodes, the one is
12049     *   not in the ancestor-or-self axis of the other, then we could safely
12050     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12051     *   the descendant-or-self axis.
12052     */
12053     mergeAndClear = xmlXPathNodeSetMergeAndClear;
12054     switch (axis) {
12055         case AXIS_ANCESTOR:
12056             first = NULL;
12057             next = xmlXPathNextAncestor;
12058             break;
12059         case AXIS_ANCESTOR_OR_SELF:
12060             first = NULL;
12061             next = xmlXPathNextAncestorOrSelf;
12062             break;
12063         case AXIS_ATTRIBUTE:
12064             first = NULL;
12065 	    last = NULL;
12066             next = xmlXPathNextAttribute;
12067 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12068             break;
12069         case AXIS_CHILD:
12070 	    last = NULL;
12071 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12072 		(type == NODE_TYPE_NODE))
12073 	    {
12074 		/*
12075 		* Optimization if an element node type is 'element'.
12076 		*/
12077 		next = xmlXPathNextChildElement;
12078 	    } else
12079 		next = xmlXPathNextChild;
12080 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12081             break;
12082         case AXIS_DESCENDANT:
12083 	    last = NULL;
12084             next = xmlXPathNextDescendant;
12085             break;
12086         case AXIS_DESCENDANT_OR_SELF:
12087 	    last = NULL;
12088             next = xmlXPathNextDescendantOrSelf;
12089             break;
12090         case AXIS_FOLLOWING:
12091 	    last = NULL;
12092             next = xmlXPathNextFollowing;
12093             break;
12094         case AXIS_FOLLOWING_SIBLING:
12095 	    last = NULL;
12096             next = xmlXPathNextFollowingSibling;
12097             break;
12098         case AXIS_NAMESPACE:
12099             first = NULL;
12100 	    last = NULL;
12101             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12102 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12103             break;
12104         case AXIS_PARENT:
12105             first = NULL;
12106             next = xmlXPathNextParent;
12107             break;
12108         case AXIS_PRECEDING:
12109             first = NULL;
12110             next = xmlXPathNextPrecedingInternal;
12111             break;
12112         case AXIS_PRECEDING_SIBLING:
12113             first = NULL;
12114             next = xmlXPathNextPrecedingSibling;
12115             break;
12116         case AXIS_SELF:
12117             first = NULL;
12118 	    last = NULL;
12119             next = xmlXPathNextSelf;
12120 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12121             break;
12122     }
12123 
12124 #ifdef DEBUG_STEP
12125     xmlXPathDebugDumpStepAxis(op,
12126 	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12127 #endif
12128 
12129     if (next == NULL) {
12130 	xmlXPathReleaseObject(xpctxt, obj);
12131         return(0);
12132     }
12133     contextSeq = obj->nodesetval;
12134     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12135 	xmlXPathReleaseObject(xpctxt, obj);
12136         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12137         return(0);
12138     }
12139     /*
12140     * Predicate optimization ---------------------------------------------
12141     * If this step has a last predicate, which contains a position(),
12142     * then we'll optimize (although not exactly "position()", but only
12143     * the  short-hand form, i.e., "[n]".
12144     *
12145     * Example - expression "/foo[parent::bar][1]":
12146     *
12147     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12148     *   ROOT                               -- op->ch1
12149     *   PREDICATE                          -- op->ch2 (predOp)
12150     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12151     *       SORT
12152     *         COLLECT  'parent' 'name' 'node' bar
12153     *           NODE
12154     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12155     *
12156     */
12157     maxPos = 0;
12158     predOp = NULL;
12159     hasPredicateRange = 0;
12160     hasAxisRange = 0;
12161     if (op->ch2 != -1) {
12162 	/*
12163 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
12164 	*/
12165 	predOp = &ctxt->comp->steps[op->ch2];
12166 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12167 	    if (predOp->ch1 != -1) {
12168 		/*
12169 		* Use the next inner predicate operator.
12170 		*/
12171 		predOp = &ctxt->comp->steps[predOp->ch1];
12172 		hasPredicateRange = 1;
12173 	    } else {
12174 		/*
12175 		* There's no other predicate than the [n] predicate.
12176 		*/
12177 		predOp = NULL;
12178 		hasAxisRange = 1;
12179 	    }
12180 	}
12181     }
12182     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12183     /*
12184     * Axis traversal -----------------------------------------------------
12185     */
12186     /*
12187      * 2.3 Node Tests
12188      *  - For the attribute axis, the principal node type is attribute.
12189      *  - For the namespace axis, the principal node type is namespace.
12190      *  - For other axes, the principal node type is element.
12191      *
12192      * A node test * is true for any node of the
12193      * principal node type. For example, child::* will
12194      * select all element children of the context node
12195      */
12196     oldContextNode = xpctxt->node;
12197     addNode = xmlXPathNodeSetAddUnique;
12198     outSeq = NULL;
12199     seq = NULL;
12200     contextNode = NULL;
12201     contextIdx = 0;
12202 
12203 
12204     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12205            (ctxt->error == XPATH_EXPRESSION_OK)) {
12206 	xpctxt->node = contextSeq->nodeTab[contextIdx++];
12207 
12208 	if (seq == NULL) {
12209 	    seq = xmlXPathNodeSetCreate(NULL);
12210 	    if (seq == NULL) {
12211                 /* TODO: Propagate memory error. */
12212 		total = 0;
12213 		goto error;
12214 	    }
12215 	}
12216 	/*
12217 	* Traverse the axis and test the nodes.
12218 	*/
12219 	pos = 0;
12220 	cur = NULL;
12221 	hasNsNodes = 0;
12222         do {
12223             if (OP_LIMIT_EXCEEDED(ctxt, 1))
12224                 goto error;
12225 
12226             cur = next(ctxt, cur);
12227             if (cur == NULL)
12228                 break;
12229 
12230 	    /*
12231 	    * QUESTION TODO: What does the "first" and "last" stuff do?
12232 	    */
12233             if ((first != NULL) && (*first != NULL)) {
12234 		if (*first == cur)
12235 		    break;
12236 		if (((total % 256) == 0) &&
12237 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12238 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12239 #else
12240 		    (xmlXPathCmpNodes(*first, cur) >= 0))
12241 #endif
12242 		{
12243 		    break;
12244 		}
12245 	    }
12246 	    if ((last != NULL) && (*last != NULL)) {
12247 		if (*last == cur)
12248 		    break;
12249 		if (((total % 256) == 0) &&
12250 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12251 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12252 #else
12253 		    (xmlXPathCmpNodes(cur, *last) >= 0))
12254 #endif
12255 		{
12256 		    break;
12257 		}
12258 	    }
12259 
12260             total++;
12261 
12262 #ifdef DEBUG_STEP
12263             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12264 #endif
12265 
12266 	    switch (test) {
12267                 case NODE_TEST_NONE:
12268 		    total = 0;
12269                     STRANGE
12270 		    goto error;
12271                 case NODE_TEST_TYPE:
12272 		    if (type == NODE_TYPE_NODE) {
12273 			switch (cur->type) {
12274 			    case XML_DOCUMENT_NODE:
12275 			    case XML_HTML_DOCUMENT_NODE:
12276 #ifdef LIBXML_DOCB_ENABLED
12277 			    case XML_DOCB_DOCUMENT_NODE:
12278 #endif
12279 			    case XML_ELEMENT_NODE:
12280 			    case XML_ATTRIBUTE_NODE:
12281 			    case XML_PI_NODE:
12282 			    case XML_COMMENT_NODE:
12283 			    case XML_CDATA_SECTION_NODE:
12284 			    case XML_TEXT_NODE:
12285 				XP_TEST_HIT
12286 				break;
12287 			    case XML_NAMESPACE_DECL: {
12288 				if (axis == AXIS_NAMESPACE) {
12289 				    XP_TEST_HIT_NS
12290 				} else {
12291 	                            hasNsNodes = 1;
12292 				    XP_TEST_HIT
12293 				}
12294 				break;
12295                             }
12296 			    default:
12297 				break;
12298 			}
12299 		    } else if (cur->type == (xmlElementType) type) {
12300 			if (cur->type == XML_NAMESPACE_DECL)
12301 			    XP_TEST_HIT_NS
12302 			else
12303 			    XP_TEST_HIT
12304 		    } else if ((type == NODE_TYPE_TEXT) &&
12305 			 (cur->type == XML_CDATA_SECTION_NODE))
12306 		    {
12307 			XP_TEST_HIT
12308 		    }
12309 		    break;
12310                 case NODE_TEST_PI:
12311                     if ((cur->type == XML_PI_NODE) &&
12312                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12313 		    {
12314 			XP_TEST_HIT
12315                     }
12316                     break;
12317                 case NODE_TEST_ALL:
12318                     if (axis == AXIS_ATTRIBUTE) {
12319                         if (cur->type == XML_ATTRIBUTE_NODE)
12320 			{
12321                             if (prefix == NULL)
12322 			    {
12323 				XP_TEST_HIT
12324                             } else if ((cur->ns != NULL) &&
12325 				(xmlStrEqual(URI, cur->ns->href)))
12326 			    {
12327 				XP_TEST_HIT
12328                             }
12329                         }
12330                     } else if (axis == AXIS_NAMESPACE) {
12331                         if (cur->type == XML_NAMESPACE_DECL)
12332 			{
12333 			    XP_TEST_HIT_NS
12334                         }
12335                     } else {
12336                         if (cur->type == XML_ELEMENT_NODE) {
12337                             if (prefix == NULL)
12338 			    {
12339 				XP_TEST_HIT
12340 
12341                             } else if ((cur->ns != NULL) &&
12342 				(xmlStrEqual(URI, cur->ns->href)))
12343 			    {
12344 				XP_TEST_HIT
12345                             }
12346                         }
12347                     }
12348                     break;
12349                 case NODE_TEST_NS:{
12350                         TODO;
12351                         break;
12352                     }
12353                 case NODE_TEST_NAME:
12354                     if (axis == AXIS_ATTRIBUTE) {
12355                         if (cur->type != XML_ATTRIBUTE_NODE)
12356 			    break;
12357 		    } else if (axis == AXIS_NAMESPACE) {
12358                         if (cur->type != XML_NAMESPACE_DECL)
12359 			    break;
12360 		    } else {
12361 		        if (cur->type != XML_ELEMENT_NODE)
12362 			    break;
12363 		    }
12364                     switch (cur->type) {
12365                         case XML_ELEMENT_NODE:
12366                             if (xmlStrEqual(name, cur->name)) {
12367                                 if (prefix == NULL) {
12368                                     if (cur->ns == NULL)
12369 				    {
12370 					XP_TEST_HIT
12371                                     }
12372                                 } else {
12373                                     if ((cur->ns != NULL) &&
12374                                         (xmlStrEqual(URI, cur->ns->href)))
12375 				    {
12376 					XP_TEST_HIT
12377                                     }
12378                                 }
12379                             }
12380                             break;
12381                         case XML_ATTRIBUTE_NODE:{
12382                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12383 
12384                                 if (xmlStrEqual(name, attr->name)) {
12385                                     if (prefix == NULL) {
12386                                         if ((attr->ns == NULL) ||
12387                                             (attr->ns->prefix == NULL))
12388 					{
12389 					    XP_TEST_HIT
12390                                         }
12391                                     } else {
12392                                         if ((attr->ns != NULL) &&
12393                                             (xmlStrEqual(URI,
12394 					      attr->ns->href)))
12395 					{
12396 					    XP_TEST_HIT
12397                                         }
12398                                     }
12399                                 }
12400                                 break;
12401                             }
12402                         case XML_NAMESPACE_DECL:
12403                             if (cur->type == XML_NAMESPACE_DECL) {
12404                                 xmlNsPtr ns = (xmlNsPtr) cur;
12405 
12406                                 if ((ns->prefix != NULL) && (name != NULL)
12407                                     && (xmlStrEqual(ns->prefix, name)))
12408 				{
12409 				    XP_TEST_HIT_NS
12410                                 }
12411                             }
12412                             break;
12413                         default:
12414                             break;
12415                     }
12416                     break;
12417 	    } /* switch(test) */
12418         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12419 
12420 	goto apply_predicates;
12421 
12422 axis_range_end: /* ----------------------------------------------------- */
12423 	/*
12424 	* We have a "/foo[n]", and position() = n was reached.
12425 	* Note that we can have as well "/foo/::parent::foo[1]", so
12426 	* a duplicate-aware merge is still needed.
12427 	* Merge with the result.
12428 	*/
12429 	if (outSeq == NULL) {
12430 	    outSeq = seq;
12431 	    seq = NULL;
12432 	} else
12433             /* TODO: Check memory error. */
12434 	    outSeq = mergeAndClear(outSeq, seq);
12435 	/*
12436 	* Break if only a true/false result was requested.
12437 	*/
12438 	if (toBool)
12439 	    break;
12440 	continue;
12441 
12442 first_hit: /* ---------------------------------------------------------- */
12443 	/*
12444 	* Break if only a true/false result was requested and
12445 	* no predicates existed and a node test succeeded.
12446 	*/
12447 	if (outSeq == NULL) {
12448 	    outSeq = seq;
12449 	    seq = NULL;
12450 	} else
12451             /* TODO: Check memory error. */
12452 	    outSeq = mergeAndClear(outSeq, seq);
12453 	break;
12454 
12455 #ifdef DEBUG_STEP
12456 	if (seq != NULL)
12457 	    nbMatches += seq->nodeNr;
12458 #endif
12459 
12460 apply_predicates: /* --------------------------------------------------- */
12461         if (ctxt->error != XPATH_EXPRESSION_OK)
12462 	    goto error;
12463 
12464         /*
12465 	* Apply predicates.
12466 	*/
12467         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12468 	    /*
12469 	    * E.g. when we have a "/foo[some expression][n]".
12470 	    */
12471 	    /*
12472 	    * QUESTION TODO: The old predicate evaluation took into
12473 	    *  account location-sets.
12474 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12475 	    *  Do we expect such a set here?
12476 	    *  All what I learned now from the evaluation semantics
12477 	    *  does not indicate that a location-set will be processed
12478 	    *  here, so this looks OK.
12479 	    */
12480 	    /*
12481 	    * Iterate over all predicates, starting with the outermost
12482 	    * predicate.
12483 	    * TODO: Problem: we cannot execute the inner predicates first
12484 	    *  since we cannot go back *up* the operator tree!
12485 	    *  Options we have:
12486 	    *  1) Use of recursive functions (like is it currently done
12487 	    *     via xmlXPathCompOpEval())
12488 	    *  2) Add a predicate evaluation information stack to the
12489 	    *     context struct
12490 	    *  3) Change the way the operators are linked; we need a
12491 	    *     "parent" field on xmlXPathStepOp
12492 	    *
12493 	    * For the moment, I'll try to solve this with a recursive
12494 	    * function: xmlXPathCompOpEvalPredicate().
12495 	    */
12496 	    if (hasPredicateRange != 0)
12497 		xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12498 					    hasNsNodes);
12499 	    else
12500 		xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12501 					    hasNsNodes);
12502 
12503 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12504 		total = 0;
12505 		goto error;
12506 	    }
12507         }
12508 
12509         if (seq->nodeNr > 0) {
12510 	    /*
12511 	    * Add to result set.
12512 	    */
12513 	    if (outSeq == NULL) {
12514 		outSeq = seq;
12515 		seq = NULL;
12516 	    } else {
12517                 /* TODO: Check memory error. */
12518 		outSeq = mergeAndClear(outSeq, seq);
12519 	    }
12520 
12521             if (toBool)
12522                 break;
12523 	}
12524     }
12525 
12526 error:
12527     if ((obj->boolval) && (obj->user != NULL)) {
12528 	/*
12529 	* QUESTION TODO: What does this do and why?
12530 	* TODO: Do we have to do this also for the "error"
12531 	* cleanup further down?
12532 	*/
12533 	ctxt->value->boolval = 1;
12534 	ctxt->value->user = obj->user;
12535 	obj->user = NULL;
12536 	obj->boolval = 0;
12537     }
12538     xmlXPathReleaseObject(xpctxt, obj);
12539 
12540     /*
12541     * Ensure we return at least an empty set.
12542     */
12543     if (outSeq == NULL) {
12544 	if ((seq != NULL) && (seq->nodeNr == 0))
12545 	    outSeq = seq;
12546 	else
12547             /* TODO: Check memory error. */
12548 	    outSeq = xmlXPathNodeSetCreate(NULL);
12549     }
12550     if ((seq != NULL) && (seq != outSeq)) {
12551 	 xmlXPathFreeNodeSet(seq);
12552     }
12553     /*
12554     * Hand over the result. Better to push the set also in
12555     * case of errors.
12556     */
12557     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12558     /*
12559     * Reset the context node.
12560     */
12561     xpctxt->node = oldContextNode;
12562     /*
12563     * When traversing the namespace axis in "toBool" mode, it's
12564     * possible that tmpNsList wasn't freed.
12565     */
12566     if (xpctxt->tmpNsList != NULL) {
12567         xmlFree(xpctxt->tmpNsList);
12568         xpctxt->tmpNsList = NULL;
12569     }
12570 
12571 #ifdef DEBUG_STEP
12572     xmlGenericError(xmlGenericErrorContext,
12573 	"\nExamined %d nodes, found %d nodes at that step\n",
12574 	total, nbMatches);
12575 #endif
12576 
12577     return(total);
12578 }
12579 
12580 static int
12581 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12582 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12583 
12584 /**
12585  * xmlXPathCompOpEvalFirst:
12586  * @ctxt:  the XPath parser context with the compiled expression
12587  * @op:  an XPath compiled operation
12588  * @first:  the first elem found so far
12589  *
12590  * Evaluate the Precompiled XPath operation searching only the first
12591  * element in document order
12592  *
12593  * Returns the number of examined objects.
12594  */
12595 static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12596 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12597                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12598 {
12599     int total = 0, cur;
12600     xmlXPathCompExprPtr comp;
12601     xmlXPathObjectPtr arg1, arg2;
12602 
12603     CHECK_ERROR0;
12604     if (OP_LIMIT_EXCEEDED(ctxt, 1))
12605         return(0);
12606     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12607         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12608     ctxt->context->depth += 1;
12609     comp = ctxt->comp;
12610     switch (op->op) {
12611         case XPATH_OP_END:
12612             break;
12613         case XPATH_OP_UNION:
12614             total =
12615                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12616                                         first);
12617 	    CHECK_ERROR0;
12618             if ((ctxt->value != NULL)
12619                 && (ctxt->value->type == XPATH_NODESET)
12620                 && (ctxt->value->nodesetval != NULL)
12621                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12622                 /*
12623                  * limit tree traversing to first node in the result
12624                  */
12625 		/*
12626 		* OPTIMIZE TODO: This implicitly sorts
12627 		*  the result, even if not needed. E.g. if the argument
12628 		*  of the count() function, no sorting is needed.
12629 		* OPTIMIZE TODO: How do we know if the node-list wasn't
12630 		*  already sorted?
12631 		*/
12632 		if (ctxt->value->nodesetval->nodeNr > 1)
12633 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12634                 *first = ctxt->value->nodesetval->nodeTab[0];
12635             }
12636             cur =
12637                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12638                                         first);
12639 	    CHECK_ERROR0;
12640 
12641             arg2 = valuePop(ctxt);
12642             arg1 = valuePop(ctxt);
12643             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12644                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12645 	        xmlXPathReleaseObject(ctxt->context, arg1);
12646 	        xmlXPathReleaseObject(ctxt->context, arg2);
12647                 XP_ERROR0(XPATH_INVALID_TYPE);
12648             }
12649             if ((ctxt->context->opLimit != 0) &&
12650                 (((arg1->nodesetval != NULL) &&
12651                   (xmlXPathCheckOpLimit(ctxt,
12652                                         arg1->nodesetval->nodeNr) < 0)) ||
12653                  ((arg2->nodesetval != NULL) &&
12654                   (xmlXPathCheckOpLimit(ctxt,
12655                                         arg2->nodesetval->nodeNr) < 0)))) {
12656 	        xmlXPathReleaseObject(ctxt->context, arg1);
12657 	        xmlXPathReleaseObject(ctxt->context, arg2);
12658                 break;
12659             }
12660 
12661             /* TODO: Check memory error. */
12662             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12663                                                     arg2->nodesetval);
12664             valuePush(ctxt, arg1);
12665 	    xmlXPathReleaseObject(ctxt->context, arg2);
12666             /* optimizer */
12667 	    if (total > cur)
12668 		xmlXPathCompSwap(op);
12669             total += cur;
12670             break;
12671         case XPATH_OP_ROOT:
12672             xmlXPathRoot(ctxt);
12673             break;
12674         case XPATH_OP_NODE:
12675             if (op->ch1 != -1)
12676                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12677 	    CHECK_ERROR0;
12678             if (op->ch2 != -1)
12679                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12680 	    CHECK_ERROR0;
12681 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12682 		ctxt->context->node));
12683             break;
12684         case XPATH_OP_COLLECT:{
12685                 if (op->ch1 == -1)
12686                     break;
12687 
12688                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12689 		CHECK_ERROR0;
12690 
12691                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12692                 break;
12693             }
12694         case XPATH_OP_VALUE:
12695             valuePush(ctxt,
12696                       xmlXPathCacheObjectCopy(ctxt->context,
12697 			(xmlXPathObjectPtr) op->value4));
12698             break;
12699         case XPATH_OP_SORT:
12700             if (op->ch1 != -1)
12701                 total +=
12702                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12703                                             first);
12704 	    CHECK_ERROR0;
12705             if ((ctxt->value != NULL)
12706                 && (ctxt->value->type == XPATH_NODESET)
12707                 && (ctxt->value->nodesetval != NULL)
12708 		&& (ctxt->value->nodesetval->nodeNr > 1))
12709                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12710             break;
12711 #ifdef XP_OPTIMIZED_FILTER_FIRST
12712 	case XPATH_OP_FILTER:
12713                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12714             break;
12715 #endif
12716         default:
12717             total += xmlXPathCompOpEval(ctxt, op);
12718             break;
12719     }
12720 
12721     ctxt->context->depth -= 1;
12722     return(total);
12723 }
12724 
12725 /**
12726  * xmlXPathCompOpEvalLast:
12727  * @ctxt:  the XPath parser context with the compiled expression
12728  * @op:  an XPath compiled operation
12729  * @last:  the last elem found so far
12730  *
12731  * Evaluate the Precompiled XPath operation searching only the last
12732  * element in document order
12733  *
12734  * Returns the number of nodes traversed
12735  */
12736 static int
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * last)12737 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12738                        xmlNodePtr * last)
12739 {
12740     int total = 0, cur;
12741     xmlXPathCompExprPtr comp;
12742     xmlXPathObjectPtr arg1, arg2;
12743 
12744     CHECK_ERROR0;
12745     if (OP_LIMIT_EXCEEDED(ctxt, 1))
12746         return(0);
12747     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12748         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12749     ctxt->context->depth += 1;
12750     comp = ctxt->comp;
12751     switch (op->op) {
12752         case XPATH_OP_END:
12753             break;
12754         case XPATH_OP_UNION:
12755             total =
12756                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12757 	    CHECK_ERROR0;
12758             if ((ctxt->value != NULL)
12759                 && (ctxt->value->type == XPATH_NODESET)
12760                 && (ctxt->value->nodesetval != NULL)
12761                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12762                 /*
12763                  * limit tree traversing to first node in the result
12764                  */
12765 		if (ctxt->value->nodesetval->nodeNr > 1)
12766 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12767                 *last =
12768                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12769                                                      nodesetval->nodeNr -
12770                                                      1];
12771             }
12772             cur =
12773                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12774 	    CHECK_ERROR0;
12775             if ((ctxt->value != NULL)
12776                 && (ctxt->value->type == XPATH_NODESET)
12777                 && (ctxt->value->nodesetval != NULL)
12778                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12779             }
12780 
12781             arg2 = valuePop(ctxt);
12782             arg1 = valuePop(ctxt);
12783             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12784                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12785 	        xmlXPathReleaseObject(ctxt->context, arg1);
12786 	        xmlXPathReleaseObject(ctxt->context, arg2);
12787                 XP_ERROR0(XPATH_INVALID_TYPE);
12788             }
12789             if ((ctxt->context->opLimit != 0) &&
12790                 (((arg1->nodesetval != NULL) &&
12791                   (xmlXPathCheckOpLimit(ctxt,
12792                                         arg1->nodesetval->nodeNr) < 0)) ||
12793                  ((arg2->nodesetval != NULL) &&
12794                   (xmlXPathCheckOpLimit(ctxt,
12795                                         arg2->nodesetval->nodeNr) < 0)))) {
12796 	        xmlXPathReleaseObject(ctxt->context, arg1);
12797 	        xmlXPathReleaseObject(ctxt->context, arg2);
12798                 break;
12799             }
12800 
12801             /* TODO: Check memory error. */
12802             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12803                                                     arg2->nodesetval);
12804             valuePush(ctxt, arg1);
12805 	    xmlXPathReleaseObject(ctxt->context, arg2);
12806             /* optimizer */
12807 	    if (total > cur)
12808 		xmlXPathCompSwap(op);
12809             total += cur;
12810             break;
12811         case XPATH_OP_ROOT:
12812             xmlXPathRoot(ctxt);
12813             break;
12814         case XPATH_OP_NODE:
12815             if (op->ch1 != -1)
12816                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12817 	    CHECK_ERROR0;
12818             if (op->ch2 != -1)
12819                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12820 	    CHECK_ERROR0;
12821 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12822 		ctxt->context->node));
12823             break;
12824         case XPATH_OP_COLLECT:{
12825                 if (op->ch1 == -1)
12826                     break;
12827 
12828                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12829 		CHECK_ERROR0;
12830 
12831                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12832                 break;
12833             }
12834         case XPATH_OP_VALUE:
12835             valuePush(ctxt,
12836                       xmlXPathCacheObjectCopy(ctxt->context,
12837 			(xmlXPathObjectPtr) op->value4));
12838             break;
12839         case XPATH_OP_SORT:
12840             if (op->ch1 != -1)
12841                 total +=
12842                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12843                                            last);
12844 	    CHECK_ERROR0;
12845             if ((ctxt->value != NULL)
12846                 && (ctxt->value->type == XPATH_NODESET)
12847                 && (ctxt->value->nodesetval != NULL)
12848 		&& (ctxt->value->nodesetval->nodeNr > 1))
12849                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12850             break;
12851         default:
12852             total += xmlXPathCompOpEval(ctxt, op);
12853             break;
12854     }
12855 
12856     ctxt->context->depth -= 1;
12857     return (total);
12858 }
12859 
12860 #ifdef XP_OPTIMIZED_FILTER_FIRST
12861 static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12862 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12863 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
12864 {
12865     int total = 0;
12866     xmlXPathCompExprPtr comp;
12867     xmlNodeSetPtr set;
12868 
12869     CHECK_ERROR0;
12870     comp = ctxt->comp;
12871     /*
12872     * Optimization for ()[last()] selection i.e. the last elem
12873     */
12874     if ((op->ch1 != -1) && (op->ch2 != -1) &&
12875 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12876 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12877 	int f = comp->steps[op->ch2].ch1;
12878 
12879 	if ((f != -1) &&
12880 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12881 	    (comp->steps[f].value5 == NULL) &&
12882 	    (comp->steps[f].value == 0) &&
12883 	    (comp->steps[f].value4 != NULL) &&
12884 	    (xmlStrEqual
12885 	    (comp->steps[f].value4, BAD_CAST "last"))) {
12886 	    xmlNodePtr last = NULL;
12887 
12888 	    total +=
12889 		xmlXPathCompOpEvalLast(ctxt,
12890 		    &comp->steps[op->ch1],
12891 		    &last);
12892 	    CHECK_ERROR0;
12893 	    /*
12894 	    * The nodeset should be in document order,
12895 	    * Keep only the last value
12896 	    */
12897 	    if ((ctxt->value != NULL) &&
12898 		(ctxt->value->type == XPATH_NODESET) &&
12899 		(ctxt->value->nodesetval != NULL) &&
12900 		(ctxt->value->nodesetval->nodeTab != NULL) &&
12901 		(ctxt->value->nodesetval->nodeNr > 1)) {
12902                 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12903 		*first = *(ctxt->value->nodesetval->nodeTab);
12904 	    }
12905 	    return (total);
12906 	}
12907     }
12908 
12909     if (op->ch1 != -1)
12910 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12911     CHECK_ERROR0;
12912     if (op->ch2 == -1)
12913 	return (total);
12914     if (ctxt->value == NULL)
12915 	return (total);
12916 
12917 #ifdef LIBXML_XPTR_ENABLED
12918     /*
12919     * Hum are we filtering the result of an XPointer expression
12920     */
12921     if (ctxt->value->type == XPATH_LOCATIONSET) {
12922         xmlLocationSetPtr locset = ctxt->value->user;
12923 
12924         if (locset != NULL) {
12925             xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12926             if (locset->locNr > 0)
12927                 *first = (xmlNodePtr) locset->locTab[0]->user;
12928         }
12929 
12930 	return (total);
12931     }
12932 #endif /* LIBXML_XPTR_ENABLED */
12933 
12934     CHECK_TYPE0(XPATH_NODESET);
12935     set = ctxt->value->nodesetval;
12936     if (set != NULL) {
12937         xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12938         if (set->nodeNr > 0)
12939             *first = set->nodeTab[0];
12940     }
12941 
12942     return (total);
12943 }
12944 #endif /* XP_OPTIMIZED_FILTER_FIRST */
12945 
12946 /**
12947  * xmlXPathCompOpEval:
12948  * @ctxt:  the XPath parser context with the compiled expression
12949  * @op:  an XPath compiled operation
12950  *
12951  * Evaluate the Precompiled XPath operation
12952  * Returns the number of nodes traversed
12953  */
12954 static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op)12955 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12956 {
12957     int total = 0;
12958     int equal, ret;
12959     xmlXPathCompExprPtr comp;
12960     xmlXPathObjectPtr arg1, arg2;
12961 
12962     CHECK_ERROR0;
12963     if (OP_LIMIT_EXCEEDED(ctxt, 1))
12964         return(0);
12965     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12966         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12967     ctxt->context->depth += 1;
12968     comp = ctxt->comp;
12969     switch (op->op) {
12970         case XPATH_OP_END:
12971             break;
12972         case XPATH_OP_AND:
12973             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12974 	    CHECK_ERROR0;
12975             xmlXPathBooleanFunction(ctxt, 1);
12976             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12977                 break;
12978             arg2 = valuePop(ctxt);
12979             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12980 	    if (ctxt->error) {
12981 		xmlXPathFreeObject(arg2);
12982 		break;
12983 	    }
12984             xmlXPathBooleanFunction(ctxt, 1);
12985             if (ctxt->value != NULL)
12986                 ctxt->value->boolval &= arg2->boolval;
12987 	    xmlXPathReleaseObject(ctxt->context, arg2);
12988             break;
12989         case XPATH_OP_OR:
12990             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12991 	    CHECK_ERROR0;
12992             xmlXPathBooleanFunction(ctxt, 1);
12993             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12994                 break;
12995             arg2 = valuePop(ctxt);
12996             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12997 	    if (ctxt->error) {
12998 		xmlXPathFreeObject(arg2);
12999 		break;
13000 	    }
13001             xmlXPathBooleanFunction(ctxt, 1);
13002             if (ctxt->value != NULL)
13003                 ctxt->value->boolval |= arg2->boolval;
13004 	    xmlXPathReleaseObject(ctxt->context, arg2);
13005             break;
13006         case XPATH_OP_EQUAL:
13007             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13008 	    CHECK_ERROR0;
13009             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13010 	    CHECK_ERROR0;
13011 	    if (op->value)
13012 		equal = xmlXPathEqualValues(ctxt);
13013 	    else
13014 		equal = xmlXPathNotEqualValues(ctxt);
13015 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13016             break;
13017         case XPATH_OP_CMP:
13018             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13019 	    CHECK_ERROR0;
13020             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13021 	    CHECK_ERROR0;
13022             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13023 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13024             break;
13025         case XPATH_OP_PLUS:
13026             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13027 	    CHECK_ERROR0;
13028             if (op->ch2 != -1) {
13029                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13030 	    }
13031 	    CHECK_ERROR0;
13032             if (op->value == 0)
13033                 xmlXPathSubValues(ctxt);
13034             else if (op->value == 1)
13035                 xmlXPathAddValues(ctxt);
13036             else if (op->value == 2)
13037                 xmlXPathValueFlipSign(ctxt);
13038             else if (op->value == 3) {
13039                 CAST_TO_NUMBER;
13040                 CHECK_TYPE0(XPATH_NUMBER);
13041             }
13042             break;
13043         case XPATH_OP_MULT:
13044             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13045 	    CHECK_ERROR0;
13046             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13047 	    CHECK_ERROR0;
13048             if (op->value == 0)
13049                 xmlXPathMultValues(ctxt);
13050             else if (op->value == 1)
13051                 xmlXPathDivValues(ctxt);
13052             else if (op->value == 2)
13053                 xmlXPathModValues(ctxt);
13054             break;
13055         case XPATH_OP_UNION:
13056             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13057 	    CHECK_ERROR0;
13058             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13059 	    CHECK_ERROR0;
13060 
13061             arg2 = valuePop(ctxt);
13062             arg1 = valuePop(ctxt);
13063             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13064                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13065 	        xmlXPathReleaseObject(ctxt->context, arg1);
13066 	        xmlXPathReleaseObject(ctxt->context, arg2);
13067                 XP_ERROR0(XPATH_INVALID_TYPE);
13068             }
13069             if ((ctxt->context->opLimit != 0) &&
13070                 (((arg1->nodesetval != NULL) &&
13071                   (xmlXPathCheckOpLimit(ctxt,
13072                                         arg1->nodesetval->nodeNr) < 0)) ||
13073                  ((arg2->nodesetval != NULL) &&
13074                   (xmlXPathCheckOpLimit(ctxt,
13075                                         arg2->nodesetval->nodeNr) < 0)))) {
13076 	        xmlXPathReleaseObject(ctxt->context, arg1);
13077 	        xmlXPathReleaseObject(ctxt->context, arg2);
13078                 break;
13079             }
13080 
13081 	    if ((arg1->nodesetval == NULL) ||
13082 		((arg2->nodesetval != NULL) &&
13083 		 (arg2->nodesetval->nodeNr != 0)))
13084 	    {
13085                 /* TODO: Check memory error. */
13086 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13087 							arg2->nodesetval);
13088 	    }
13089 
13090             valuePush(ctxt, arg1);
13091 	    xmlXPathReleaseObject(ctxt->context, arg2);
13092             break;
13093         case XPATH_OP_ROOT:
13094             xmlXPathRoot(ctxt);
13095             break;
13096         case XPATH_OP_NODE:
13097             if (op->ch1 != -1)
13098                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13099 	    CHECK_ERROR0;
13100             if (op->ch2 != -1)
13101                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13102 	    CHECK_ERROR0;
13103 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13104 		ctxt->context->node));
13105             break;
13106         case XPATH_OP_COLLECT:{
13107                 if (op->ch1 == -1)
13108                     break;
13109 
13110                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13111 		CHECK_ERROR0;
13112 
13113                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13114                 break;
13115             }
13116         case XPATH_OP_VALUE:
13117             valuePush(ctxt,
13118                       xmlXPathCacheObjectCopy(ctxt->context,
13119 			(xmlXPathObjectPtr) op->value4));
13120             break;
13121         case XPATH_OP_VARIABLE:{
13122 		xmlXPathObjectPtr val;
13123 
13124                 if (op->ch1 != -1)
13125                     total +=
13126                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13127                 if (op->value5 == NULL) {
13128 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13129 		    if (val == NULL)
13130 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13131                     valuePush(ctxt, val);
13132 		} else {
13133                     const xmlChar *URI;
13134 
13135                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13136                     if (URI == NULL) {
13137                         xmlGenericError(xmlGenericErrorContext,
13138             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13139                                     (char *) op->value4, (char *)op->value5);
13140                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13141                         break;
13142                     }
13143 		    val = xmlXPathVariableLookupNS(ctxt->context,
13144                                                        op->value4, URI);
13145 		    if (val == NULL)
13146 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13147                     valuePush(ctxt, val);
13148                 }
13149                 break;
13150             }
13151         case XPATH_OP_FUNCTION:{
13152                 xmlXPathFunction func;
13153                 const xmlChar *oldFunc, *oldFuncURI;
13154 		int i;
13155                 int frame;
13156 
13157                 frame = xmlXPathSetFrame(ctxt);
13158                 if (op->ch1 != -1) {
13159                     total +=
13160                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13161                     if (ctxt->error != XPATH_EXPRESSION_OK) {
13162                         xmlXPathPopFrame(ctxt, frame);
13163                         break;
13164                     }
13165                 }
13166 		if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13167 		    xmlGenericError(xmlGenericErrorContext,
13168 			    "xmlXPathCompOpEval: parameter error\n");
13169 		    ctxt->error = XPATH_INVALID_OPERAND;
13170                     xmlXPathPopFrame(ctxt, frame);
13171 		    break;
13172 		}
13173 		for (i = 0; i < op->value; i++) {
13174 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13175 			xmlGenericError(xmlGenericErrorContext,
13176 				"xmlXPathCompOpEval: parameter error\n");
13177 			ctxt->error = XPATH_INVALID_OPERAND;
13178                         xmlXPathPopFrame(ctxt, frame);
13179 			break;
13180 		    }
13181                 }
13182                 if (op->cache != NULL)
13183                     func = op->cache;
13184                 else {
13185                     const xmlChar *URI = NULL;
13186 
13187                     if (op->value5 == NULL)
13188                         func =
13189                             xmlXPathFunctionLookup(ctxt->context,
13190                                                    op->value4);
13191                     else {
13192                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
13193                         if (URI == NULL) {
13194                             xmlGenericError(xmlGenericErrorContext,
13195             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13196                                     (char *)op->value4, (char *)op->value5);
13197                             xmlXPathPopFrame(ctxt, frame);
13198                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13199                             break;
13200                         }
13201                         func = xmlXPathFunctionLookupNS(ctxt->context,
13202                                                         op->value4, URI);
13203                     }
13204                     if (func == NULL) {
13205                         xmlGenericError(xmlGenericErrorContext,
13206                                 "xmlXPathCompOpEval: function %s not found\n",
13207                                         (char *)op->value4);
13208                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13209                     }
13210                     op->cache = func;
13211                     op->cacheURI = (void *) URI;
13212                 }
13213                 oldFunc = ctxt->context->function;
13214                 oldFuncURI = ctxt->context->functionURI;
13215                 ctxt->context->function = op->value4;
13216                 ctxt->context->functionURI = op->cacheURI;
13217                 func(ctxt, op->value);
13218                 ctxt->context->function = oldFunc;
13219                 ctxt->context->functionURI = oldFuncURI;
13220                 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13221                     (ctxt->valueNr != ctxt->valueFrame + 1))
13222                     XP_ERROR0(XPATH_STACK_ERROR);
13223                 xmlXPathPopFrame(ctxt, frame);
13224                 break;
13225             }
13226         case XPATH_OP_ARG:
13227             if (op->ch1 != -1) {
13228                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13229 	        CHECK_ERROR0;
13230             }
13231             if (op->ch2 != -1) {
13232                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13233 	        CHECK_ERROR0;
13234 	    }
13235             break;
13236         case XPATH_OP_PREDICATE:
13237         case XPATH_OP_FILTER:{
13238                 xmlNodeSetPtr set;
13239 
13240                 /*
13241                  * Optimization for ()[1] selection i.e. the first elem
13242                  */
13243                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13244 #ifdef XP_OPTIMIZED_FILTER_FIRST
13245 		    /*
13246 		    * FILTER TODO: Can we assume that the inner processing
13247 		    *  will result in an ordered list if we have an
13248 		    *  XPATH_OP_FILTER?
13249 		    *  What about an additional field or flag on
13250 		    *  xmlXPathObject like @sorted ? This way we wouldn't need
13251 		    *  to assume anything, so it would be more robust and
13252 		    *  easier to optimize.
13253 		    */
13254                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13255 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13256 #else
13257 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13258 #endif
13259                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13260                     xmlXPathObjectPtr val;
13261 
13262                     val = comp->steps[op->ch2].value4;
13263                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13264                         (val->floatval == 1.0)) {
13265                         xmlNodePtr first = NULL;
13266 
13267                         total +=
13268                             xmlXPathCompOpEvalFirst(ctxt,
13269                                                     &comp->steps[op->ch1],
13270                                                     &first);
13271 			CHECK_ERROR0;
13272                         /*
13273                          * The nodeset should be in document order,
13274                          * Keep only the first value
13275                          */
13276                         if ((ctxt->value != NULL) &&
13277                             (ctxt->value->type == XPATH_NODESET) &&
13278                             (ctxt->value->nodesetval != NULL) &&
13279                             (ctxt->value->nodesetval->nodeNr > 1))
13280                             xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13281                                                         1, 1);
13282                         break;
13283                     }
13284                 }
13285                 /*
13286                  * Optimization for ()[last()] selection i.e. the last elem
13287                  */
13288                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13289                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13290                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13291                     int f = comp->steps[op->ch2].ch1;
13292 
13293                     if ((f != -1) &&
13294                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13295                         (comp->steps[f].value5 == NULL) &&
13296                         (comp->steps[f].value == 0) &&
13297                         (comp->steps[f].value4 != NULL) &&
13298                         (xmlStrEqual
13299                          (comp->steps[f].value4, BAD_CAST "last"))) {
13300                         xmlNodePtr last = NULL;
13301 
13302                         total +=
13303                             xmlXPathCompOpEvalLast(ctxt,
13304                                                    &comp->steps[op->ch1],
13305                                                    &last);
13306 			CHECK_ERROR0;
13307                         /*
13308                          * The nodeset should be in document order,
13309                          * Keep only the last value
13310                          */
13311                         if ((ctxt->value != NULL) &&
13312                             (ctxt->value->type == XPATH_NODESET) &&
13313                             (ctxt->value->nodesetval != NULL) &&
13314                             (ctxt->value->nodesetval->nodeTab != NULL) &&
13315                             (ctxt->value->nodesetval->nodeNr > 1))
13316                             xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13317                         break;
13318                     }
13319                 }
13320 		/*
13321 		* Process inner predicates first.
13322 		* Example "index[parent::book][1]":
13323 		* ...
13324 		*   PREDICATE   <-- we are here "[1]"
13325 		*     PREDICATE <-- process "[parent::book]" first
13326 		*       SORT
13327 		*         COLLECT  'parent' 'name' 'node' book
13328 		*           NODE
13329 		*     ELEM Object is a number : 1
13330 		*/
13331                 if (op->ch1 != -1)
13332                     total +=
13333                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13334 		CHECK_ERROR0;
13335                 if (op->ch2 == -1)
13336                     break;
13337                 if (ctxt->value == NULL)
13338                     break;
13339 
13340 #ifdef LIBXML_XPTR_ENABLED
13341                 /*
13342                  * Hum are we filtering the result of an XPointer expression
13343                  */
13344                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13345                     xmlLocationSetPtr locset = ctxt->value->user;
13346                     xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13347                                               1, locset->locNr);
13348                     break;
13349                 }
13350 #endif /* LIBXML_XPTR_ENABLED */
13351 
13352                 CHECK_TYPE0(XPATH_NODESET);
13353                 set = ctxt->value->nodesetval;
13354                 if (set != NULL)
13355                     xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13356                                           1, set->nodeNr, 1);
13357                 break;
13358             }
13359         case XPATH_OP_SORT:
13360             if (op->ch1 != -1)
13361                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13362 	    CHECK_ERROR0;
13363             if ((ctxt->value != NULL) &&
13364                 (ctxt->value->type == XPATH_NODESET) &&
13365                 (ctxt->value->nodesetval != NULL) &&
13366 		(ctxt->value->nodesetval->nodeNr > 1))
13367 	    {
13368                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13369 	    }
13370             break;
13371 #ifdef LIBXML_XPTR_ENABLED
13372         case XPATH_OP_RANGETO:{
13373                 xmlXPathObjectPtr range;
13374                 xmlXPathObjectPtr res, obj;
13375                 xmlXPathObjectPtr tmp;
13376                 xmlLocationSetPtr newlocset = NULL;
13377 		    xmlLocationSetPtr oldlocset;
13378                 xmlNodeSetPtr oldset;
13379                 xmlNodePtr oldnode = ctxt->context->node;
13380                 int oldcs = ctxt->context->contextSize;
13381                 int oldpp = ctxt->context->proximityPosition;
13382                 int i, j;
13383 
13384                 if (op->ch1 != -1) {
13385                     total +=
13386                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13387                     CHECK_ERROR0;
13388                 }
13389                 if (ctxt->value == NULL) {
13390                     XP_ERROR0(XPATH_INVALID_OPERAND);
13391                 }
13392                 if (op->ch2 == -1)
13393                     break;
13394 
13395                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13396                     /*
13397                      * Extract the old locset, and then evaluate the result of the
13398                      * expression for all the element in the locset. use it to grow
13399                      * up a new locset.
13400                      */
13401                     CHECK_TYPE0(XPATH_LOCATIONSET);
13402 
13403                     if ((ctxt->value->user == NULL) ||
13404                         (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13405                         break;
13406 
13407                     obj = valuePop(ctxt);
13408                     oldlocset = obj->user;
13409 
13410                     newlocset = xmlXPtrLocationSetCreate(NULL);
13411 
13412                     for (i = 0; i < oldlocset->locNr; i++) {
13413                         /*
13414                          * Run the evaluation with a node list made of a
13415                          * single item in the nodelocset.
13416                          */
13417                         ctxt->context->node = oldlocset->locTab[i]->user;
13418                         ctxt->context->contextSize = oldlocset->locNr;
13419                         ctxt->context->proximityPosition = i + 1;
13420 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13421 			    ctxt->context->node);
13422                         valuePush(ctxt, tmp);
13423 
13424                         if (op->ch2 != -1)
13425                             total +=
13426                                 xmlXPathCompOpEval(ctxt,
13427                                                    &comp->steps[op->ch2]);
13428 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13429                             xmlXPtrFreeLocationSet(newlocset);
13430                             goto rangeto_error;
13431 			}
13432 
13433                         res = valuePop(ctxt);
13434 			if (res->type == XPATH_LOCATIONSET) {
13435 			    xmlLocationSetPtr rloc =
13436 			        (xmlLocationSetPtr)res->user;
13437 			    for (j=0; j<rloc->locNr; j++) {
13438 			        range = xmlXPtrNewRange(
13439 				  oldlocset->locTab[i]->user,
13440 				  oldlocset->locTab[i]->index,
13441 				  rloc->locTab[j]->user2,
13442 				  rloc->locTab[j]->index2);
13443 				if (range != NULL) {
13444 				    xmlXPtrLocationSetAdd(newlocset, range);
13445 				}
13446 			    }
13447 			} else {
13448 			    range = xmlXPtrNewRangeNodeObject(
13449 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
13450                             if (range != NULL) {
13451                                 xmlXPtrLocationSetAdd(newlocset,range);
13452 			    }
13453                         }
13454 
13455                         /*
13456                          * Cleanup
13457                          */
13458                         if (res != NULL) {
13459 			    xmlXPathReleaseObject(ctxt->context, res);
13460 			}
13461                         if (ctxt->value == tmp) {
13462                             res = valuePop(ctxt);
13463 			    xmlXPathReleaseObject(ctxt->context, res);
13464                         }
13465                     }
13466 		} else {	/* Not a location set */
13467                     CHECK_TYPE0(XPATH_NODESET);
13468                     obj = valuePop(ctxt);
13469                     oldset = obj->nodesetval;
13470 
13471                     newlocset = xmlXPtrLocationSetCreate(NULL);
13472 
13473                     if (oldset != NULL) {
13474                         for (i = 0; i < oldset->nodeNr; i++) {
13475                             /*
13476                              * Run the evaluation with a node list made of a single item
13477                              * in the nodeset.
13478                              */
13479                             ctxt->context->node = oldset->nodeTab[i];
13480 			    /*
13481 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
13482 			    */
13483 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13484 				ctxt->context->node);
13485                             valuePush(ctxt, tmp);
13486 
13487                             if (op->ch2 != -1)
13488                                 total +=
13489                                     xmlXPathCompOpEval(ctxt,
13490                                                    &comp->steps[op->ch2]);
13491 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
13492                                 xmlXPtrFreeLocationSet(newlocset);
13493                                 goto rangeto_error;
13494 			    }
13495 
13496                             res = valuePop(ctxt);
13497                             range =
13498                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13499                                                       res);
13500                             if (range != NULL) {
13501                                 xmlXPtrLocationSetAdd(newlocset, range);
13502                             }
13503 
13504                             /*
13505                              * Cleanup
13506                              */
13507                             if (res != NULL) {
13508 				xmlXPathReleaseObject(ctxt->context, res);
13509 			    }
13510                             if (ctxt->value == tmp) {
13511                                 res = valuePop(ctxt);
13512 				xmlXPathReleaseObject(ctxt->context, res);
13513                             }
13514                         }
13515                     }
13516                 }
13517 
13518                 /*
13519                  * The result is used as the new evaluation set.
13520                  */
13521                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13522 rangeto_error:
13523 		xmlXPathReleaseObject(ctxt->context, obj);
13524                 ctxt->context->node = oldnode;
13525                 ctxt->context->contextSize = oldcs;
13526                 ctxt->context->proximityPosition = oldpp;
13527                 break;
13528             }
13529 #endif /* LIBXML_XPTR_ENABLED */
13530         default:
13531             xmlGenericError(xmlGenericErrorContext,
13532                             "XPath: unknown precompiled operation %d\n", op->op);
13533             ctxt->error = XPATH_INVALID_OPERAND;
13534             break;
13535     }
13536 
13537     ctxt->context->depth -= 1;
13538     return (total);
13539 }
13540 
13541 /**
13542  * xmlXPathCompOpEvalToBoolean:
13543  * @ctxt:  the XPath parser context
13544  *
13545  * Evaluates if the expression evaluates to true.
13546  *
13547  * Returns 1 if true, 0 if false and -1 on API or internal errors.
13548  */
13549 static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int isPredicate)13550 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13551 			    xmlXPathStepOpPtr op,
13552 			    int isPredicate)
13553 {
13554     xmlXPathObjectPtr resObj = NULL;
13555 
13556 start:
13557     if (OP_LIMIT_EXCEEDED(ctxt, 1))
13558         return(0);
13559     /* comp = ctxt->comp; */
13560     switch (op->op) {
13561         case XPATH_OP_END:
13562             return (0);
13563 	case XPATH_OP_VALUE:
13564 	    resObj = (xmlXPathObjectPtr) op->value4;
13565 	    if (isPredicate)
13566 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13567 	    return(xmlXPathCastToBoolean(resObj));
13568 	case XPATH_OP_SORT:
13569 	    /*
13570 	    * We don't need sorting for boolean results. Skip this one.
13571 	    */
13572             if (op->ch1 != -1) {
13573 		op = &ctxt->comp->steps[op->ch1];
13574 		goto start;
13575 	    }
13576 	    return(0);
13577 	case XPATH_OP_COLLECT:
13578 	    if (op->ch1 == -1)
13579 		return(0);
13580 
13581             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13582 	    if (ctxt->error != XPATH_EXPRESSION_OK)
13583 		return(-1);
13584 
13585             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13586 	    if (ctxt->error != XPATH_EXPRESSION_OK)
13587 		return(-1);
13588 
13589 	    resObj = valuePop(ctxt);
13590 	    if (resObj == NULL)
13591 		return(-1);
13592 	    break;
13593 	default:
13594 	    /*
13595 	    * Fallback to call xmlXPathCompOpEval().
13596 	    */
13597 	    xmlXPathCompOpEval(ctxt, op);
13598 	    if (ctxt->error != XPATH_EXPRESSION_OK)
13599 		return(-1);
13600 
13601 	    resObj = valuePop(ctxt);
13602 	    if (resObj == NULL)
13603 		return(-1);
13604 	    break;
13605     }
13606 
13607     if (resObj) {
13608 	int res;
13609 
13610 	if (resObj->type == XPATH_BOOLEAN) {
13611 	    res = resObj->boolval;
13612 	} else if (isPredicate) {
13613 	    /*
13614 	    * For predicates a result of type "number" is handled
13615 	    * differently:
13616 	    * SPEC XPath 1.0:
13617 	    * "If the result is a number, the result will be converted
13618 	    *  to true if the number is equal to the context position
13619 	    *  and will be converted to false otherwise;"
13620 	    */
13621 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13622 	} else {
13623 	    res = xmlXPathCastToBoolean(resObj);
13624 	}
13625 	xmlXPathReleaseObject(ctxt->context, resObj);
13626 	return(res);
13627     }
13628 
13629     return(0);
13630 }
13631 
13632 #ifdef XPATH_STREAMING
13633 /**
13634  * xmlXPathRunStreamEval:
13635  * @ctxt:  the XPath parser context with the compiled expression
13636  *
13637  * Evaluate the Precompiled Streamable XPath expression in the given context.
13638  */
13639 static int
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt,xmlPatternPtr comp,xmlXPathObjectPtr * resultSeq,int toBool)13640 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13641 		      xmlXPathObjectPtr *resultSeq, int toBool)
13642 {
13643     int max_depth, min_depth;
13644     int from_root;
13645     int ret, depth;
13646     int eval_all_nodes;
13647     xmlNodePtr cur = NULL, limit = NULL;
13648     xmlStreamCtxtPtr patstream = NULL;
13649 
13650     int nb_nodes = 0;
13651 
13652     if ((ctxt == NULL) || (comp == NULL))
13653         return(-1);
13654     max_depth = xmlPatternMaxDepth(comp);
13655     if (max_depth == -1)
13656         return(-1);
13657     if (max_depth == -2)
13658         max_depth = 10000;
13659     min_depth = xmlPatternMinDepth(comp);
13660     if (min_depth == -1)
13661         return(-1);
13662     from_root = xmlPatternFromRoot(comp);
13663     if (from_root < 0)
13664         return(-1);
13665 #if 0
13666     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13667 #endif
13668 
13669     if (! toBool) {
13670 	if (resultSeq == NULL)
13671 	    return(-1);
13672 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13673 	if (*resultSeq == NULL)
13674 	    return(-1);
13675     }
13676 
13677     /*
13678      * handle the special cases of "/" amd "." being matched
13679      */
13680     if (min_depth == 0) {
13681 	if (from_root) {
13682 	    /* Select "/" */
13683 	    if (toBool)
13684 		return(1);
13685             /* TODO: Check memory error. */
13686 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
13687 		                     (xmlNodePtr) ctxt->doc);
13688 	} else {
13689 	    /* Select "self::node()" */
13690 	    if (toBool)
13691 		return(1);
13692             /* TODO: Check memory error. */
13693 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13694 	}
13695     }
13696     if (max_depth == 0) {
13697 	return(0);
13698     }
13699 
13700     if (from_root) {
13701         cur = (xmlNodePtr)ctxt->doc;
13702     } else if (ctxt->node != NULL) {
13703         switch (ctxt->node->type) {
13704             case XML_ELEMENT_NODE:
13705             case XML_DOCUMENT_NODE:
13706             case XML_DOCUMENT_FRAG_NODE:
13707             case XML_HTML_DOCUMENT_NODE:
13708 #ifdef LIBXML_DOCB_ENABLED
13709             case XML_DOCB_DOCUMENT_NODE:
13710 #endif
13711 	        cur = ctxt->node;
13712 		break;
13713             case XML_ATTRIBUTE_NODE:
13714             case XML_TEXT_NODE:
13715             case XML_CDATA_SECTION_NODE:
13716             case XML_ENTITY_REF_NODE:
13717             case XML_ENTITY_NODE:
13718             case XML_PI_NODE:
13719             case XML_COMMENT_NODE:
13720             case XML_NOTATION_NODE:
13721             case XML_DTD_NODE:
13722             case XML_DOCUMENT_TYPE_NODE:
13723             case XML_ELEMENT_DECL:
13724             case XML_ATTRIBUTE_DECL:
13725             case XML_ENTITY_DECL:
13726             case XML_NAMESPACE_DECL:
13727             case XML_XINCLUDE_START:
13728             case XML_XINCLUDE_END:
13729 		break;
13730 	}
13731 	limit = cur;
13732     }
13733     if (cur == NULL) {
13734         return(0);
13735     }
13736 
13737     patstream = xmlPatternGetStreamCtxt(comp);
13738     if (patstream == NULL) {
13739 	/*
13740 	* QUESTION TODO: Is this an error?
13741 	*/
13742 	return(0);
13743     }
13744 
13745     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13746 
13747     if (from_root) {
13748 	ret = xmlStreamPush(patstream, NULL, NULL);
13749 	if (ret < 0) {
13750 	} else if (ret == 1) {
13751 	    if (toBool)
13752 		goto return_1;
13753             /* TODO: Check memory error. */
13754 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13755 	}
13756     }
13757     depth = 0;
13758     goto scan_children;
13759 next_node:
13760     do {
13761         if (ctxt->opLimit != 0) {
13762             if (ctxt->opCount >= ctxt->opLimit) {
13763                 xmlGenericError(xmlGenericErrorContext,
13764                         "XPath operation limit exceeded\n");
13765                 xmlFreeStreamCtxt(patstream);
13766                 return(-1);
13767             }
13768             ctxt->opCount++;
13769         }
13770 
13771         nb_nodes++;
13772 
13773 	switch (cur->type) {
13774 	    case XML_ELEMENT_NODE:
13775 	    case XML_TEXT_NODE:
13776 	    case XML_CDATA_SECTION_NODE:
13777 	    case XML_COMMENT_NODE:
13778 	    case XML_PI_NODE:
13779 		if (cur->type == XML_ELEMENT_NODE) {
13780 		    ret = xmlStreamPush(patstream, cur->name,
13781 				(cur->ns ? cur->ns->href : NULL));
13782 		} else if (eval_all_nodes)
13783 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13784 		else
13785 		    break;
13786 
13787 		if (ret < 0) {
13788 		    /* NOP. */
13789 		} else if (ret == 1) {
13790 		    if (toBool)
13791 			goto return_1;
13792 		    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13793 		        < 0) {
13794 			ctxt->lastError.domain = XML_FROM_XPATH;
13795 			ctxt->lastError.code = XML_ERR_NO_MEMORY;
13796 		    }
13797 		}
13798 		if ((cur->children == NULL) || (depth >= max_depth)) {
13799 		    ret = xmlStreamPop(patstream);
13800 		    while (cur->next != NULL) {
13801 			cur = cur->next;
13802 			if ((cur->type != XML_ENTITY_DECL) &&
13803 			    (cur->type != XML_DTD_NODE))
13804 			    goto next_node;
13805 		    }
13806 		}
13807 	    default:
13808 		break;
13809 	}
13810 
13811 scan_children:
13812 	if (cur->type == XML_NAMESPACE_DECL) break;
13813 	if ((cur->children != NULL) && (depth < max_depth)) {
13814 	    /*
13815 	     * Do not descend on entities declarations
13816 	     */
13817 	    if (cur->children->type != XML_ENTITY_DECL) {
13818 		cur = cur->children;
13819 		depth++;
13820 		/*
13821 		 * Skip DTDs
13822 		 */
13823 		if (cur->type != XML_DTD_NODE)
13824 		    continue;
13825 	    }
13826 	}
13827 
13828 	if (cur == limit)
13829 	    break;
13830 
13831 	while (cur->next != NULL) {
13832 	    cur = cur->next;
13833 	    if ((cur->type != XML_ENTITY_DECL) &&
13834 		(cur->type != XML_DTD_NODE))
13835 		goto next_node;
13836 	}
13837 
13838 	do {
13839 	    cur = cur->parent;
13840 	    depth--;
13841 	    if ((cur == NULL) || (cur == limit) ||
13842                 (cur->type == XML_DOCUMENT_NODE))
13843 	        goto done;
13844 	    if (cur->type == XML_ELEMENT_NODE) {
13845 		ret = xmlStreamPop(patstream);
13846 	    } else if ((eval_all_nodes) &&
13847 		((cur->type == XML_TEXT_NODE) ||
13848 		 (cur->type == XML_CDATA_SECTION_NODE) ||
13849 		 (cur->type == XML_COMMENT_NODE) ||
13850 		 (cur->type == XML_PI_NODE)))
13851 	    {
13852 		ret = xmlStreamPop(patstream);
13853 	    }
13854 	    if (cur->next != NULL) {
13855 		cur = cur->next;
13856 		break;
13857 	    }
13858 	} while (cur != NULL);
13859 
13860     } while ((cur != NULL) && (depth >= 0));
13861 
13862 done:
13863 
13864 #if 0
13865     printf("stream eval: checked %d nodes selected %d\n",
13866            nb_nodes, retObj->nodesetval->nodeNr);
13867 #endif
13868 
13869     if (patstream)
13870 	xmlFreeStreamCtxt(patstream);
13871     return(0);
13872 
13873 return_1:
13874     if (patstream)
13875 	xmlFreeStreamCtxt(patstream);
13876     return(1);
13877 }
13878 #endif /* XPATH_STREAMING */
13879 
13880 /**
13881  * xmlXPathRunEval:
13882  * @ctxt:  the XPath parser context with the compiled expression
13883  * @toBool:  evaluate to a boolean result
13884  *
13885  * Evaluate the Precompiled XPath expression in the given context.
13886  */
13887 static int
xmlXPathRunEval(xmlXPathParserContextPtr ctxt,int toBool)13888 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13889 {
13890     xmlXPathCompExprPtr comp;
13891 
13892     if ((ctxt == NULL) || (ctxt->comp == NULL))
13893 	return(-1);
13894 
13895     ctxt->context->depth = 0;
13896 
13897     if (ctxt->valueTab == NULL) {
13898 	/* Allocate the value stack */
13899 	ctxt->valueTab = (xmlXPathObjectPtr *)
13900 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13901 	if (ctxt->valueTab == NULL) {
13902 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13903 	    xmlFree(ctxt);
13904 	}
13905 	ctxt->valueNr = 0;
13906 	ctxt->valueMax = 10;
13907 	ctxt->value = NULL;
13908         ctxt->valueFrame = 0;
13909     }
13910 #ifdef XPATH_STREAMING
13911     if (ctxt->comp->stream) {
13912 	int res;
13913 
13914 	if (toBool) {
13915 	    /*
13916 	    * Evaluation to boolean result.
13917 	    */
13918 	    res = xmlXPathRunStreamEval(ctxt->context,
13919 		ctxt->comp->stream, NULL, 1);
13920 	    if (res != -1)
13921 		return(res);
13922 	} else {
13923 	    xmlXPathObjectPtr resObj = NULL;
13924 
13925 	    /*
13926 	    * Evaluation to a sequence.
13927 	    */
13928 	    res = xmlXPathRunStreamEval(ctxt->context,
13929 		ctxt->comp->stream, &resObj, 0);
13930 
13931 	    if ((res != -1) && (resObj != NULL)) {
13932 		valuePush(ctxt, resObj);
13933 		return(0);
13934 	    }
13935 	    if (resObj != NULL)
13936 		xmlXPathReleaseObject(ctxt->context, resObj);
13937 	}
13938 	/*
13939 	* QUESTION TODO: This falls back to normal XPath evaluation
13940 	* if res == -1. Is this intended?
13941 	*/
13942     }
13943 #endif
13944     comp = ctxt->comp;
13945     if (comp->last < 0) {
13946 	xmlGenericError(xmlGenericErrorContext,
13947 	    "xmlXPathRunEval: last is less than zero\n");
13948 	return(-1);
13949     }
13950     if (toBool)
13951 	return(xmlXPathCompOpEvalToBoolean(ctxt,
13952 	    &comp->steps[comp->last], 0));
13953     else
13954 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13955 
13956     return(0);
13957 }
13958 
13959 /************************************************************************
13960  *									*
13961  *			Public interfaces				*
13962  *									*
13963  ************************************************************************/
13964 
13965 /**
13966  * xmlXPathEvalPredicate:
13967  * @ctxt:  the XPath context
13968  * @res:  the Predicate Expression evaluation result
13969  *
13970  * Evaluate a predicate result for the current node.
13971  * A PredicateExpr is evaluated by evaluating the Expr and converting
13972  * the result to a boolean. If the result is a number, the result will
13973  * be converted to true if the number is equal to the position of the
13974  * context node in the context node list (as returned by the position
13975  * function) and will be converted to false otherwise; if the result
13976  * is not a number, then the result will be converted as if by a call
13977  * to the boolean function.
13978  *
13979  * Returns 1 if predicate is true, 0 otherwise
13980  */
13981 int
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt,xmlXPathObjectPtr res)13982 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13983     if ((ctxt == NULL) || (res == NULL)) return(0);
13984     switch (res->type) {
13985         case XPATH_BOOLEAN:
13986 	    return(res->boolval);
13987         case XPATH_NUMBER:
13988 	    return(res->floatval == ctxt->proximityPosition);
13989         case XPATH_NODESET:
13990         case XPATH_XSLT_TREE:
13991 	    if (res->nodesetval == NULL)
13992 		return(0);
13993 	    return(res->nodesetval->nodeNr != 0);
13994         case XPATH_STRING:
13995 	    return((res->stringval != NULL) &&
13996 	           (xmlStrlen(res->stringval) != 0));
13997         default:
13998 	    STRANGE
13999     }
14000     return(0);
14001 }
14002 
14003 /**
14004  * xmlXPathEvaluatePredicateResult:
14005  * @ctxt:  the XPath Parser context
14006  * @res:  the Predicate Expression evaluation result
14007  *
14008  * Evaluate a predicate result for the current node.
14009  * A PredicateExpr is evaluated by evaluating the Expr and converting
14010  * the result to a boolean. If the result is a number, the result will
14011  * be converted to true if the number is equal to the position of the
14012  * context node in the context node list (as returned by the position
14013  * function) and will be converted to false otherwise; if the result
14014  * is not a number, then the result will be converted as if by a call
14015  * to the boolean function.
14016  *
14017  * Returns 1 if predicate is true, 0 otherwise
14018  */
14019 int
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr res)14020 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14021                                 xmlXPathObjectPtr res) {
14022     if ((ctxt == NULL) || (res == NULL)) return(0);
14023     switch (res->type) {
14024         case XPATH_BOOLEAN:
14025 	    return(res->boolval);
14026         case XPATH_NUMBER:
14027 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14028 	    return((res->floatval == ctxt->context->proximityPosition) &&
14029 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14030 #else
14031 	    return(res->floatval == ctxt->context->proximityPosition);
14032 #endif
14033         case XPATH_NODESET:
14034         case XPATH_XSLT_TREE:
14035 	    if (res->nodesetval == NULL)
14036 		return(0);
14037 	    return(res->nodesetval->nodeNr != 0);
14038         case XPATH_STRING:
14039 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
14040 #ifdef LIBXML_XPTR_ENABLED
14041 	case XPATH_LOCATIONSET:{
14042 	    xmlLocationSetPtr ptr = res->user;
14043 	    if (ptr == NULL)
14044 	        return(0);
14045 	    return (ptr->locNr != 0);
14046 	    }
14047 #endif
14048         default:
14049 	    STRANGE
14050     }
14051     return(0);
14052 }
14053 
14054 #ifdef XPATH_STREAMING
14055 /**
14056  * xmlXPathTryStreamCompile:
14057  * @ctxt: an XPath context
14058  * @str:  the XPath expression
14059  *
14060  * Try to compile the XPath expression as a streamable subset.
14061  *
14062  * Returns the compiled expression or NULL if failed to compile.
14063  */
14064 static xmlXPathCompExprPtr
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14065 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14066     /*
14067      * Optimization: use streaming patterns when the XPath expression can
14068      * be compiled to a stream lookup
14069      */
14070     xmlPatternPtr stream;
14071     xmlXPathCompExprPtr comp;
14072     xmlDictPtr dict = NULL;
14073     const xmlChar **namespaces = NULL;
14074     xmlNsPtr ns;
14075     int i, j;
14076 
14077     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14078         (!xmlStrchr(str, '@'))) {
14079 	const xmlChar *tmp;
14080 
14081 	/*
14082 	 * We don't try to handle expressions using the verbose axis
14083 	 * specifiers ("::"), just the simplified form at this point.
14084 	 * Additionally, if there is no list of namespaces available and
14085 	 *  there's a ":" in the expression, indicating a prefixed QName,
14086 	 *  then we won't try to compile either. xmlPatterncompile() needs
14087 	 *  to have a list of namespaces at compilation time in order to
14088 	 *  compile prefixed name tests.
14089 	 */
14090 	tmp = xmlStrchr(str, ':');
14091 	if ((tmp != NULL) &&
14092 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14093 	    return(NULL);
14094 
14095 	if (ctxt != NULL) {
14096 	    dict = ctxt->dict;
14097 	    if (ctxt->nsNr > 0) {
14098 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14099 		if (namespaces == NULL) {
14100 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14101 		    return(NULL);
14102 		}
14103 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14104 		    ns = ctxt->namespaces[j];
14105 		    namespaces[i++] = ns->href;
14106 		    namespaces[i++] = ns->prefix;
14107 		}
14108 		namespaces[i++] = NULL;
14109 		namespaces[i] = NULL;
14110 	    }
14111 	}
14112 
14113 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14114 	if (namespaces != NULL) {
14115 	    xmlFree((xmlChar **)namespaces);
14116 	}
14117 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14118 	    comp = xmlXPathNewCompExpr();
14119 	    if (comp == NULL) {
14120 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14121 		return(NULL);
14122 	    }
14123 	    comp->stream = stream;
14124 	    comp->dict = dict;
14125 	    if (comp->dict)
14126 		xmlDictReference(comp->dict);
14127 	    return(comp);
14128 	}
14129 	xmlFreePattern(stream);
14130     }
14131     return(NULL);
14132 }
14133 #endif /* XPATH_STREAMING */
14134 
14135 static void
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,xmlXPathStepOpPtr op)14136 xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14137                            xmlXPathStepOpPtr op)
14138 {
14139     xmlXPathCompExprPtr comp = pctxt->comp;
14140     xmlXPathContextPtr ctxt;
14141 
14142     /*
14143     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14144     * internal representation.
14145     */
14146 
14147     if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14148         (op->ch1 != -1) &&
14149         (op->ch2 == -1 /* no predicate */))
14150     {
14151         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14152 
14153         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14154             ((xmlXPathAxisVal) prevop->value ==
14155                 AXIS_DESCENDANT_OR_SELF) &&
14156             (prevop->ch2 == -1) &&
14157             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14158             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14159         {
14160             /*
14161             * This is a "descendant-or-self::node()" without predicates.
14162             * Try to eliminate it.
14163             */
14164 
14165             switch ((xmlXPathAxisVal) op->value) {
14166                 case AXIS_CHILD:
14167                 case AXIS_DESCENDANT:
14168                     /*
14169                     * Convert "descendant-or-self::node()/child::" or
14170                     * "descendant-or-self::node()/descendant::" to
14171                     * "descendant::"
14172                     */
14173                     op->ch1   = prevop->ch1;
14174                     op->value = AXIS_DESCENDANT;
14175                     break;
14176                 case AXIS_SELF:
14177                 case AXIS_DESCENDANT_OR_SELF:
14178                     /*
14179                     * Convert "descendant-or-self::node()/self::" or
14180                     * "descendant-or-self::node()/descendant-or-self::" to
14181                     * to "descendant-or-self::"
14182                     */
14183                     op->ch1   = prevop->ch1;
14184                     op->value = AXIS_DESCENDANT_OR_SELF;
14185                     break;
14186                 default:
14187                     break;
14188             }
14189 	}
14190     }
14191 
14192     /* OP_VALUE has invalid ch1. */
14193     if (op->op == XPATH_OP_VALUE)
14194         return;
14195 
14196     /* Recurse */
14197     ctxt = pctxt->context;
14198     if (ctxt != NULL) {
14199         if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14200             return;
14201         ctxt->depth += 1;
14202     }
14203     if (op->ch1 != -1)
14204         xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14205     if (op->ch2 != -1)
14206 	xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14207     if (ctxt != NULL)
14208         ctxt->depth -= 1;
14209 }
14210 
14211 /**
14212  * xmlXPathCtxtCompile:
14213  * @ctxt: an XPath context
14214  * @str:  the XPath expression
14215  *
14216  * Compile an XPath expression
14217  *
14218  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14219  *         the caller has to free the object.
14220  */
14221 xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14222 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14223     xmlXPathParserContextPtr pctxt;
14224     xmlXPathCompExprPtr comp;
14225 
14226 #ifdef XPATH_STREAMING
14227     comp = xmlXPathTryStreamCompile(ctxt, str);
14228     if (comp != NULL)
14229         return(comp);
14230 #endif
14231 
14232     xmlInitParser();
14233 
14234     pctxt = xmlXPathNewParserContext(str, ctxt);
14235     if (pctxt == NULL)
14236         return NULL;
14237     if (ctxt != NULL)
14238         ctxt->depth = 0;
14239     xmlXPathCompileExpr(pctxt, 1);
14240 
14241     if( pctxt->error != XPATH_EXPRESSION_OK )
14242     {
14243         xmlXPathFreeParserContext(pctxt);
14244         return(NULL);
14245     }
14246 
14247     if (*pctxt->cur != 0) {
14248 	/*
14249 	 * aleksey: in some cases this line prints *second* error message
14250 	 * (see bug #78858) and probably this should be fixed.
14251 	 * However, we are not sure that all error messages are printed
14252 	 * out in other places. It's not critical so we leave it as-is for now
14253 	 */
14254 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14255 	comp = NULL;
14256     } else {
14257 	comp = pctxt->comp;
14258 	if ((comp->nbStep > 1) && (comp->last >= 0)) {
14259             if (ctxt != NULL)
14260                 ctxt->depth = 0;
14261 	    xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14262 	}
14263 	pctxt->comp = NULL;
14264     }
14265     xmlXPathFreeParserContext(pctxt);
14266 
14267     if (comp != NULL) {
14268 	comp->expr = xmlStrdup(str);
14269 #ifdef DEBUG_EVAL_COUNTS
14270 	comp->string = xmlStrdup(str);
14271 	comp->nb = 0;
14272 #endif
14273     }
14274     return(comp);
14275 }
14276 
14277 /**
14278  * xmlXPathCompile:
14279  * @str:  the XPath expression
14280  *
14281  * Compile an XPath expression
14282  *
14283  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14284  *         the caller has to free the object.
14285  */
14286 xmlXPathCompExprPtr
xmlXPathCompile(const xmlChar * str)14287 xmlXPathCompile(const xmlChar *str) {
14288     return(xmlXPathCtxtCompile(NULL, str));
14289 }
14290 
14291 /**
14292  * xmlXPathCompiledEvalInternal:
14293  * @comp:  the compiled XPath expression
14294  * @ctxt:  the XPath context
14295  * @resObj: the resulting XPath object or NULL
14296  * @toBool: 1 if only a boolean result is requested
14297  *
14298  * Evaluate the Precompiled XPath expression in the given context.
14299  * The caller has to free @resObj.
14300  *
14301  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14302  *         the caller has to free the object.
14303  */
14304 static int
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt,xmlXPathObjectPtr * resObjPtr,int toBool)14305 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14306 			     xmlXPathContextPtr ctxt,
14307 			     xmlXPathObjectPtr *resObjPtr,
14308 			     int toBool)
14309 {
14310     xmlXPathParserContextPtr pctxt;
14311     xmlXPathObjectPtr resObj;
14312 #ifndef LIBXML_THREAD_ENABLED
14313     static int reentance = 0;
14314 #endif
14315     int res;
14316 
14317     CHECK_CTXT_NEG(ctxt)
14318 
14319     if (comp == NULL)
14320 	return(-1);
14321     xmlInitParser();
14322 
14323 #ifndef LIBXML_THREAD_ENABLED
14324     reentance++;
14325     if (reentance > 1)
14326 	xmlXPathDisableOptimizer = 1;
14327 #endif
14328 
14329 #ifdef DEBUG_EVAL_COUNTS
14330     comp->nb++;
14331     if ((comp->string != NULL) && (comp->nb > 100)) {
14332 	fprintf(stderr, "100 x %s\n", comp->string);
14333 	comp->nb = 0;
14334     }
14335 #endif
14336     pctxt = xmlXPathCompParserContext(comp, ctxt);
14337     res = xmlXPathRunEval(pctxt, toBool);
14338 
14339     if (pctxt->error != XPATH_EXPRESSION_OK) {
14340         resObj = NULL;
14341     } else {
14342         resObj = valuePop(pctxt);
14343         if (resObj == NULL) {
14344             if (!toBool)
14345                 xmlGenericError(xmlGenericErrorContext,
14346                     "xmlXPathCompiledEval: No result on the stack.\n");
14347         } else if (pctxt->valueNr > 0) {
14348             xmlGenericError(xmlGenericErrorContext,
14349                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14350                 pctxt->valueNr);
14351         }
14352     }
14353 
14354     if (resObjPtr)
14355         *resObjPtr = resObj;
14356     else
14357         xmlXPathReleaseObject(ctxt, resObj);
14358 
14359     pctxt->comp = NULL;
14360     xmlXPathFreeParserContext(pctxt);
14361 #ifndef LIBXML_THREAD_ENABLED
14362     reentance--;
14363 #endif
14364 
14365     return(res);
14366 }
14367 
14368 /**
14369  * xmlXPathCompiledEval:
14370  * @comp:  the compiled XPath expression
14371  * @ctx:  the XPath context
14372  *
14373  * Evaluate the Precompiled XPath expression in the given context.
14374  *
14375  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14376  *         the caller has to free the object.
14377  */
14378 xmlXPathObjectPtr
xmlXPathCompiledEval(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctx)14379 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14380 {
14381     xmlXPathObjectPtr res = NULL;
14382 
14383     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14384     return(res);
14385 }
14386 
14387 /**
14388  * xmlXPathCompiledEvalToBoolean:
14389  * @comp:  the compiled XPath expression
14390  * @ctxt:  the XPath context
14391  *
14392  * Applies the XPath boolean() function on the result of the given
14393  * compiled expression.
14394  *
14395  * Returns 1 if the expression evaluated to true, 0 if to false and
14396  *         -1 in API and internal errors.
14397  */
14398 int
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)14399 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14400 			      xmlXPathContextPtr ctxt)
14401 {
14402     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14403 }
14404 
14405 /**
14406  * xmlXPathEvalExpr:
14407  * @ctxt:  the XPath Parser context
14408  *
14409  * Parse and evaluate an XPath expression in the given context,
14410  * then push the result on the context stack
14411  */
14412 void
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt)14413 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14414 #ifdef XPATH_STREAMING
14415     xmlXPathCompExprPtr comp;
14416 #endif
14417 
14418     if (ctxt == NULL) return;
14419 
14420 #ifdef XPATH_STREAMING
14421     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14422     if (comp != NULL) {
14423         if (ctxt->comp != NULL)
14424 	    xmlXPathFreeCompExpr(ctxt->comp);
14425         ctxt->comp = comp;
14426     } else
14427 #endif
14428     {
14429         if (ctxt->context != NULL)
14430             ctxt->context->depth = 0;
14431 	xmlXPathCompileExpr(ctxt, 1);
14432         CHECK_ERROR;
14433 
14434         /* Check for trailing characters. */
14435         if (*ctxt->cur != 0)
14436             XP_ERROR(XPATH_EXPR_ERROR);
14437 
14438 	if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14439             if (ctxt->context != NULL)
14440                 ctxt->context->depth = 0;
14441 	    xmlXPathOptimizeExpression(ctxt,
14442 		&ctxt->comp->steps[ctxt->comp->last]);
14443         }
14444     }
14445 
14446     xmlXPathRunEval(ctxt, 0);
14447 }
14448 
14449 /**
14450  * xmlXPathEval:
14451  * @str:  the XPath expression
14452  * @ctx:  the XPath context
14453  *
14454  * Evaluate the XPath Location Path in the given context.
14455  *
14456  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14457  *         the caller has to free the object.
14458  */
14459 xmlXPathObjectPtr
xmlXPathEval(const xmlChar * str,xmlXPathContextPtr ctx)14460 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14461     xmlXPathParserContextPtr ctxt;
14462     xmlXPathObjectPtr res;
14463 
14464     CHECK_CTXT(ctx)
14465 
14466     xmlInitParser();
14467 
14468     ctxt = xmlXPathNewParserContext(str, ctx);
14469     if (ctxt == NULL)
14470         return NULL;
14471     xmlXPathEvalExpr(ctxt);
14472 
14473     if (ctxt->error != XPATH_EXPRESSION_OK) {
14474 	res = NULL;
14475     } else {
14476 	res = valuePop(ctxt);
14477         if (res == NULL) {
14478             xmlGenericError(xmlGenericErrorContext,
14479                 "xmlXPathCompiledEval: No result on the stack.\n");
14480         } else if (ctxt->valueNr > 0) {
14481             xmlGenericError(xmlGenericErrorContext,
14482                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14483                 ctxt->valueNr);
14484         }
14485     }
14486 
14487     xmlXPathFreeParserContext(ctxt);
14488     return(res);
14489 }
14490 
14491 /**
14492  * xmlXPathSetContextNode:
14493  * @node: the node to to use as the context node
14494  * @ctx:  the XPath context
14495  *
14496  * Sets 'node' as the context node. The node must be in the same
14497  * document as that associated with the context.
14498  *
14499  * Returns -1 in case of error or 0 if successful
14500  */
14501 int
xmlXPathSetContextNode(xmlNodePtr node,xmlXPathContextPtr ctx)14502 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14503     if ((node == NULL) || (ctx == NULL))
14504         return(-1);
14505 
14506     if (node->doc == ctx->doc) {
14507         ctx->node = node;
14508 	return(0);
14509     }
14510     return(-1);
14511 }
14512 
14513 /**
14514  * xmlXPathNodeEval:
14515  * @node: the node to to use as the context node
14516  * @str:  the XPath expression
14517  * @ctx:  the XPath context
14518  *
14519  * Evaluate the XPath Location Path in the given context. The node 'node'
14520  * is set as the context node. The context node is not restored.
14521  *
14522  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14523  *         the caller has to free the object.
14524  */
14525 xmlXPathObjectPtr
xmlXPathNodeEval(xmlNodePtr node,const xmlChar * str,xmlXPathContextPtr ctx)14526 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14527     if (str == NULL)
14528         return(NULL);
14529     if (xmlXPathSetContextNode(node, ctx) < 0)
14530         return(NULL);
14531     return(xmlXPathEval(str, ctx));
14532 }
14533 
14534 /**
14535  * xmlXPathEvalExpression:
14536  * @str:  the XPath expression
14537  * @ctxt:  the XPath context
14538  *
14539  * Alias for xmlXPathEval().
14540  *
14541  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14542  *         the caller has to free the object.
14543  */
14544 xmlXPathObjectPtr
xmlXPathEvalExpression(const xmlChar * str,xmlXPathContextPtr ctxt)14545 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14546     return(xmlXPathEval(str, ctxt));
14547 }
14548 
14549 /************************************************************************
14550  *									*
14551  *	Extra functions not pertaining to the XPath spec		*
14552  *									*
14553  ************************************************************************/
14554 /**
14555  * xmlXPathEscapeUriFunction:
14556  * @ctxt:  the XPath Parser context
14557  * @nargs:  the number of arguments
14558  *
14559  * Implement the escape-uri() XPath function
14560  *    string escape-uri(string $str, bool $escape-reserved)
14561  *
14562  * This function applies the URI escaping rules defined in section 2 of [RFC
14563  * 2396] to the string supplied as $uri-part, which typically represents all
14564  * or part of a URI. The effect of the function is to replace any special
14565  * character in the string by an escape sequence of the form %xx%yy...,
14566  * where xxyy... is the hexadecimal representation of the octets used to
14567  * represent the character in UTF-8.
14568  *
14569  * The set of characters that are escaped depends on the setting of the
14570  * boolean argument $escape-reserved.
14571  *
14572  * If $escape-reserved is true, all characters are escaped other than lower
14573  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14574  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14575  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14576  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14577  * A-F).
14578  *
14579  * If $escape-reserved is false, the behavior differs in that characters
14580  * referred to in [RFC 2396] as reserved characters are not escaped. These
14581  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14582  *
14583  * [RFC 2396] does not define whether escaped URIs should use lower case or
14584  * upper case for hexadecimal digits. To ensure that escaped URIs can be
14585  * compared using string comparison functions, this function must always use
14586  * the upper-case letters A-F.
14587  *
14588  * Generally, $escape-reserved should be set to true when escaping a string
14589  * that is to form a single part of a URI, and to false when escaping an
14590  * entire URI or URI reference.
14591  *
14592  * In the case of non-ascii characters, the string is encoded according to
14593  * utf-8 and then converted according to RFC 2396.
14594  *
14595  * Examples
14596  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14597  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14598  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14599  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14600  *
14601  */
14602 static void
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt,int nargs)14603 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14604     xmlXPathObjectPtr str;
14605     int escape_reserved;
14606     xmlBufPtr target;
14607     xmlChar *cptr;
14608     xmlChar escape[4];
14609 
14610     CHECK_ARITY(2);
14611 
14612     escape_reserved = xmlXPathPopBoolean(ctxt);
14613 
14614     CAST_TO_STRING;
14615     str = valuePop(ctxt);
14616 
14617     target = xmlBufCreate();
14618 
14619     escape[0] = '%';
14620     escape[3] = 0;
14621 
14622     if (target) {
14623 	for (cptr = str->stringval; *cptr; cptr++) {
14624 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
14625 		(*cptr >= 'a' && *cptr <= 'z') ||
14626 		(*cptr >= '0' && *cptr <= '9') ||
14627 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
14628 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
14629 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14630 		(*cptr == '%' &&
14631 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14632 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14633 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
14634 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14635 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14636 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14637 		(!escape_reserved &&
14638 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14639 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14640 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14641 		  *cptr == ','))) {
14642 		xmlBufAdd(target, cptr, 1);
14643 	    } else {
14644 		if ((*cptr >> 4) < 10)
14645 		    escape[1] = '0' + (*cptr >> 4);
14646 		else
14647 		    escape[1] = 'A' - 10 + (*cptr >> 4);
14648 		if ((*cptr & 0xF) < 10)
14649 		    escape[2] = '0' + (*cptr & 0xF);
14650 		else
14651 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
14652 
14653 		xmlBufAdd(target, &escape[0], 3);
14654 	    }
14655 	}
14656     }
14657     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14658 	xmlBufContent(target)));
14659     xmlBufFree(target);
14660     xmlXPathReleaseObject(ctxt->context, str);
14661 }
14662 
14663 /**
14664  * xmlXPathRegisterAllFunctions:
14665  * @ctxt:  the XPath context
14666  *
14667  * Registers all default XPath functions in this context
14668  */
14669 void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)14670 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14671 {
14672     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14673                          xmlXPathBooleanFunction);
14674     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14675                          xmlXPathCeilingFunction);
14676     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14677                          xmlXPathCountFunction);
14678     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14679                          xmlXPathConcatFunction);
14680     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14681                          xmlXPathContainsFunction);
14682     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14683                          xmlXPathIdFunction);
14684     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14685                          xmlXPathFalseFunction);
14686     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14687                          xmlXPathFloorFunction);
14688     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14689                          xmlXPathLastFunction);
14690     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14691                          xmlXPathLangFunction);
14692     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14693                          xmlXPathLocalNameFunction);
14694     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14695                          xmlXPathNotFunction);
14696     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14697                          xmlXPathNameFunction);
14698     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14699                          xmlXPathNamespaceURIFunction);
14700     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14701                          xmlXPathNormalizeFunction);
14702     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14703                          xmlXPathNumberFunction);
14704     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14705                          xmlXPathPositionFunction);
14706     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14707                          xmlXPathRoundFunction);
14708     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14709                          xmlXPathStringFunction);
14710     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14711                          xmlXPathStringLengthFunction);
14712     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14713                          xmlXPathStartsWithFunction);
14714     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14715                          xmlXPathSubstringFunction);
14716     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14717                          xmlXPathSubstringBeforeFunction);
14718     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14719                          xmlXPathSubstringAfterFunction);
14720     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14721                          xmlXPathSumFunction);
14722     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14723                          xmlXPathTrueFunction);
14724     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14725                          xmlXPathTranslateFunction);
14726 
14727     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14728 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14729                          xmlXPathEscapeUriFunction);
14730 }
14731 
14732 #endif /* LIBXML_XPATH_ENABLED */
14733 #define bottom_xpath
14734 #include "elfgcchack.h"
14735