• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * xpath.c: XML Path Language implementation
3  *          XPath is a language for addressing parts of an XML document,
4  *          designed to be used by both XSLT and XPointer
5  *
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                 if (name == NULL) {
11124 	            XP_ERRORNULL(XPATH_EXPR_ERROR);
11125                 }
11126 		*test = NODE_TEST_PI;
11127 		SKIP_BLANKS;
11128 	    }
11129 	}
11130 	if (CUR != ')') {
11131 	    if (name != NULL)
11132 		xmlFree(name);
11133 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11134 	}
11135 	NEXT;
11136 	return(name);
11137     }
11138     *test = NODE_TEST_NAME;
11139     if ((!blanks) && (CUR == ':')) {
11140 	NEXT;
11141 
11142 	/*
11143 	 * Since currently the parser context don't have a
11144 	 * namespace list associated:
11145 	 * The namespace name for this prefix can be computed
11146 	 * only at evaluation time. The compilation is done
11147 	 * outside of any context.
11148 	 */
11149 #if 0
11150 	*prefix = xmlXPathNsLookup(ctxt->context, name);
11151 	if (name != NULL)
11152 	    xmlFree(name);
11153 	if (*prefix == NULL) {
11154 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11155 	}
11156 #else
11157 	*prefix = name;
11158 #endif
11159 
11160 	if (CUR == '*') {
11161 	    /*
11162 	     * All elements
11163 	     */
11164 	    NEXT;
11165 	    *test = NODE_TEST_ALL;
11166 	    return(NULL);
11167 	}
11168 
11169 	name = xmlXPathParseNCName(ctxt);
11170 	if (name == NULL) {
11171 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
11172 	}
11173     }
11174     return(name);
11175 }
11176 
11177 /**
11178  * xmlXPathIsAxisName:
11179  * @name:  a preparsed name token
11180  *
11181  * [6] AxisName ::=   'ancestor'
11182  *                  | 'ancestor-or-self'
11183  *                  | 'attribute'
11184  *                  | 'child'
11185  *                  | 'descendant'
11186  *                  | 'descendant-or-self'
11187  *                  | 'following'
11188  *                  | 'following-sibling'
11189  *                  | 'namespace'
11190  *                  | 'parent'
11191  *                  | 'preceding'
11192  *                  | 'preceding-sibling'
11193  *                  | 'self'
11194  *
11195  * Returns the axis or 0
11196  */
11197 static xmlXPathAxisVal
xmlXPathIsAxisName(const xmlChar * name)11198 xmlXPathIsAxisName(const xmlChar *name) {
11199     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11200     switch (name[0]) {
11201 	case 'a':
11202 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
11203 		ret = AXIS_ANCESTOR;
11204 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11205 		ret = AXIS_ANCESTOR_OR_SELF;
11206 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
11207 		ret = AXIS_ATTRIBUTE;
11208 	    break;
11209 	case 'c':
11210 	    if (xmlStrEqual(name, BAD_CAST "child"))
11211 		ret = AXIS_CHILD;
11212 	    break;
11213 	case 'd':
11214 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
11215 		ret = AXIS_DESCENDANT;
11216 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11217 		ret = AXIS_DESCENDANT_OR_SELF;
11218 	    break;
11219 	case 'f':
11220 	    if (xmlStrEqual(name, BAD_CAST "following"))
11221 		ret = AXIS_FOLLOWING;
11222 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11223 		ret = AXIS_FOLLOWING_SIBLING;
11224 	    break;
11225 	case 'n':
11226 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
11227 		ret = AXIS_NAMESPACE;
11228 	    break;
11229 	case 'p':
11230 	    if (xmlStrEqual(name, BAD_CAST "parent"))
11231 		ret = AXIS_PARENT;
11232 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
11233 		ret = AXIS_PRECEDING;
11234 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11235 		ret = AXIS_PRECEDING_SIBLING;
11236 	    break;
11237 	case 's':
11238 	    if (xmlStrEqual(name, BAD_CAST "self"))
11239 		ret = AXIS_SELF;
11240 	    break;
11241     }
11242     return(ret);
11243 }
11244 
11245 /**
11246  * xmlXPathCompStep:
11247  * @ctxt:  the XPath Parser context
11248  *
11249  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11250  *                  | AbbreviatedStep
11251  *
11252  * [12] AbbreviatedStep ::=   '.' | '..'
11253  *
11254  * [5] AxisSpecifier ::= AxisName '::'
11255  *                  | AbbreviatedAxisSpecifier
11256  *
11257  * [13] AbbreviatedAxisSpecifier ::= '@'?
11258  *
11259  * Modified for XPtr range support as:
11260  *
11261  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11262  *                     | AbbreviatedStep
11263  *                     | 'range-to' '(' Expr ')' Predicate*
11264  *
11265  * Compile one step in a Location Path
11266  * A location step of . is short for self::node(). This is
11267  * particularly useful in conjunction with //. For example, the
11268  * location path .//para is short for
11269  * self::node()/descendant-or-self::node()/child::para
11270  * and so will select all para descendant elements of the context
11271  * node.
11272  * Similarly, a location step of .. is short for parent::node().
11273  * For example, ../title is short for parent::node()/child::title
11274  * and so will select the title children of the parent of the context
11275  * node.
11276  */
11277 static void
xmlXPathCompStep(xmlXPathParserContextPtr ctxt)11278 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11279 #ifdef LIBXML_XPTR_ENABLED
11280     int rangeto = 0;
11281     int op2 = -1;
11282 #endif
11283 
11284     SKIP_BLANKS;
11285     if ((CUR == '.') && (NXT(1) == '.')) {
11286 	SKIP(2);
11287 	SKIP_BLANKS;
11288 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11289 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11290     } else if (CUR == '.') {
11291 	NEXT;
11292 	SKIP_BLANKS;
11293     } else {
11294 	xmlChar *name = NULL;
11295 	xmlChar *prefix = NULL;
11296 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
11297 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11298 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11299 	int op1;
11300 
11301 	/*
11302 	 * The modification needed for XPointer change to the production
11303 	 */
11304 #ifdef LIBXML_XPTR_ENABLED
11305 	if (ctxt->xptr) {
11306 	    name = xmlXPathParseNCName(ctxt);
11307 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11308                 op2 = ctxt->comp->last;
11309 		xmlFree(name);
11310 		SKIP_BLANKS;
11311 		if (CUR != '(') {
11312 		    XP_ERROR(XPATH_EXPR_ERROR);
11313 		}
11314 		NEXT;
11315 		SKIP_BLANKS;
11316 
11317 		xmlXPathCompileExpr(ctxt, 1);
11318 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11319 		CHECK_ERROR;
11320 
11321 		SKIP_BLANKS;
11322 		if (CUR != ')') {
11323 		    XP_ERROR(XPATH_EXPR_ERROR);
11324 		}
11325 		NEXT;
11326 		rangeto = 1;
11327 		goto eval_predicates;
11328 	    }
11329 	}
11330 #endif
11331 	if (CUR == '*') {
11332 	    axis = AXIS_CHILD;
11333 	} else {
11334 	    if (name == NULL)
11335 		name = xmlXPathParseNCName(ctxt);
11336 	    if (name != NULL) {
11337 		axis = xmlXPathIsAxisName(name);
11338 		if (axis != 0) {
11339 		    SKIP_BLANKS;
11340 		    if ((CUR == ':') && (NXT(1) == ':')) {
11341 			SKIP(2);
11342 			xmlFree(name);
11343 			name = NULL;
11344 		    } else {
11345 			/* an element name can conflict with an axis one :-\ */
11346 			axis = AXIS_CHILD;
11347 		    }
11348 		} else {
11349 		    axis = AXIS_CHILD;
11350 		}
11351 	    } else if (CUR == '@') {
11352 		NEXT;
11353 		axis = AXIS_ATTRIBUTE;
11354 	    } else {
11355 		axis = AXIS_CHILD;
11356 	    }
11357 	}
11358 
11359         if (ctxt->error != XPATH_EXPRESSION_OK) {
11360             xmlFree(name);
11361             return;
11362         }
11363 
11364 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11365 	if (test == 0)
11366 	    return;
11367 
11368         if ((prefix != NULL) && (ctxt->context != NULL) &&
11369 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11370 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11371 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11372 	    }
11373 	}
11374 #ifdef DEBUG_STEP
11375 	xmlGenericError(xmlGenericErrorContext,
11376 		"Basis : computing new set\n");
11377 #endif
11378 
11379 #ifdef DEBUG_STEP
11380 	xmlGenericError(xmlGenericErrorContext, "Basis : ");
11381 	if (ctxt->value == NULL)
11382 	    xmlGenericError(xmlGenericErrorContext, "no value\n");
11383 	else if (ctxt->value->nodesetval == NULL)
11384 	    xmlGenericError(xmlGenericErrorContext, "Empty\n");
11385 	else
11386 	    xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11387 #endif
11388 
11389 #ifdef LIBXML_XPTR_ENABLED
11390 eval_predicates:
11391 #endif
11392 	op1 = ctxt->comp->last;
11393 	ctxt->comp->last = -1;
11394 
11395 	SKIP_BLANKS;
11396 	while (CUR == '[') {
11397 	    xmlXPathCompPredicate(ctxt, 0);
11398 	}
11399 
11400 #ifdef LIBXML_XPTR_ENABLED
11401 	if (rangeto) {
11402 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11403 	} else
11404 #endif
11405         if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11406                            test, type, (void *)prefix, (void *)name) == -1) {
11407             xmlFree(prefix);
11408             xmlFree(name);
11409         }
11410     }
11411 #ifdef DEBUG_STEP
11412     xmlGenericError(xmlGenericErrorContext, "Step : ");
11413     if (ctxt->value == NULL)
11414 	xmlGenericError(xmlGenericErrorContext, "no value\n");
11415     else if (ctxt->value->nodesetval == NULL)
11416 	xmlGenericError(xmlGenericErrorContext, "Empty\n");
11417     else
11418 	xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11419 		ctxt->value->nodesetval);
11420 #endif
11421 }
11422 
11423 /**
11424  * xmlXPathCompRelativeLocationPath:
11425  * @ctxt:  the XPath Parser context
11426  *
11427  *  [3]   RelativeLocationPath ::=   Step
11428  *                     | RelativeLocationPath '/' Step
11429  *                     | AbbreviatedRelativeLocationPath
11430  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11431  *
11432  * Compile a relative location path.
11433  */
11434 static void
xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt)11435 xmlXPathCompRelativeLocationPath
11436 (xmlXPathParserContextPtr ctxt) {
11437     SKIP_BLANKS;
11438     if ((CUR == '/') && (NXT(1) == '/')) {
11439 	SKIP(2);
11440 	SKIP_BLANKS;
11441 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11442 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11443     } else if (CUR == '/') {
11444 	    NEXT;
11445 	SKIP_BLANKS;
11446     }
11447     xmlXPathCompStep(ctxt);
11448     CHECK_ERROR;
11449     SKIP_BLANKS;
11450     while (CUR == '/') {
11451 	if ((CUR == '/') && (NXT(1) == '/')) {
11452 	    SKIP(2);
11453 	    SKIP_BLANKS;
11454 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11455 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11456 	    xmlXPathCompStep(ctxt);
11457 	} else if (CUR == '/') {
11458 	    NEXT;
11459 	    SKIP_BLANKS;
11460 	    xmlXPathCompStep(ctxt);
11461 	}
11462 	SKIP_BLANKS;
11463     }
11464 }
11465 
11466 /**
11467  * xmlXPathCompLocationPath:
11468  * @ctxt:  the XPath Parser context
11469  *
11470  *  [1]   LocationPath ::=   RelativeLocationPath
11471  *                     | AbsoluteLocationPath
11472  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11473  *                     | AbbreviatedAbsoluteLocationPath
11474  *  [10]   AbbreviatedAbsoluteLocationPath ::=
11475  *                           '//' RelativeLocationPath
11476  *
11477  * Compile a location path
11478  *
11479  * // is short for /descendant-or-self::node()/. For example,
11480  * //para is short for /descendant-or-self::node()/child::para and
11481  * so will select any para element in the document (even a para element
11482  * that is a document element will be selected by //para since the
11483  * document element node is a child of the root node); div//para is
11484  * short for div/descendant-or-self::node()/child::para and so will
11485  * select all para descendants of div children.
11486  */
11487 static void
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt)11488 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11489     SKIP_BLANKS;
11490     if (CUR != '/') {
11491         xmlXPathCompRelativeLocationPath(ctxt);
11492     } else {
11493 	while (CUR == '/') {
11494 	    if ((CUR == '/') && (NXT(1) == '/')) {
11495 		SKIP(2);
11496 		SKIP_BLANKS;
11497 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11498 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11499 		xmlXPathCompRelativeLocationPath(ctxt);
11500 	    } else if (CUR == '/') {
11501 		NEXT;
11502 		SKIP_BLANKS;
11503 		if ((CUR != 0 ) &&
11504 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11505 		     (CUR == '@') || (CUR == '*')))
11506 		    xmlXPathCompRelativeLocationPath(ctxt);
11507 	    }
11508 	    CHECK_ERROR;
11509 	}
11510     }
11511 }
11512 
11513 /************************************************************************
11514  *									*
11515  *		XPath precompiled expression evaluation			*
11516  *									*
11517  ************************************************************************/
11518 
11519 static int
11520 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11521 
11522 #ifdef DEBUG_STEP
11523 static void
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,int nbNodes)11524 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11525 			  int nbNodes)
11526 {
11527     xmlGenericError(xmlGenericErrorContext, "new step : ");
11528     switch (op->value) {
11529         case AXIS_ANCESTOR:
11530             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11531             break;
11532         case AXIS_ANCESTOR_OR_SELF:
11533             xmlGenericError(xmlGenericErrorContext,
11534                             "axis 'ancestors-or-self' ");
11535             break;
11536         case AXIS_ATTRIBUTE:
11537             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11538             break;
11539         case AXIS_CHILD:
11540             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11541             break;
11542         case AXIS_DESCENDANT:
11543             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11544             break;
11545         case AXIS_DESCENDANT_OR_SELF:
11546             xmlGenericError(xmlGenericErrorContext,
11547                             "axis 'descendant-or-self' ");
11548             break;
11549         case AXIS_FOLLOWING:
11550             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11551             break;
11552         case AXIS_FOLLOWING_SIBLING:
11553             xmlGenericError(xmlGenericErrorContext,
11554                             "axis 'following-siblings' ");
11555             break;
11556         case AXIS_NAMESPACE:
11557             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11558             break;
11559         case AXIS_PARENT:
11560             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11561             break;
11562         case AXIS_PRECEDING:
11563             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11564             break;
11565         case AXIS_PRECEDING_SIBLING:
11566             xmlGenericError(xmlGenericErrorContext,
11567                             "axis 'preceding-sibling' ");
11568             break;
11569         case AXIS_SELF:
11570             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11571             break;
11572     }
11573     xmlGenericError(xmlGenericErrorContext,
11574 	" context contains %d nodes\n", nbNodes);
11575     switch (op->value2) {
11576         case NODE_TEST_NONE:
11577             xmlGenericError(xmlGenericErrorContext,
11578                             "           searching for none !!!\n");
11579             break;
11580         case NODE_TEST_TYPE:
11581             xmlGenericError(xmlGenericErrorContext,
11582                             "           searching for type %d\n", op->value3);
11583             break;
11584         case NODE_TEST_PI:
11585             xmlGenericError(xmlGenericErrorContext,
11586                             "           searching for PI !!!\n");
11587             break;
11588         case NODE_TEST_ALL:
11589             xmlGenericError(xmlGenericErrorContext,
11590                             "           searching for *\n");
11591             break;
11592         case NODE_TEST_NS:
11593             xmlGenericError(xmlGenericErrorContext,
11594                             "           searching for namespace %s\n",
11595                             op->value5);
11596             break;
11597         case NODE_TEST_NAME:
11598             xmlGenericError(xmlGenericErrorContext,
11599                             "           searching for name %s\n", op->value5);
11600             if (op->value4)
11601                 xmlGenericError(xmlGenericErrorContext,
11602                                 "           with namespace %s\n", op->value4);
11603             break;
11604     }
11605     xmlGenericError(xmlGenericErrorContext, "Testing : ");
11606 }
11607 #endif /* DEBUG_STEP */
11608 
11609 /**
11610  * xmlXPathNodeSetFilter:
11611  * @ctxt:  the XPath Parser context
11612  * @set: the node set to filter
11613  * @filterOpIndex: the index of the predicate/filter op
11614  * @minPos: minimum position in the filtered set (1-based)
11615  * @maxPos: maximum position in the filtered set (1-based)
11616  * @hasNsNodes: true if the node set may contain namespace nodes
11617  *
11618  * Filter a node set, keeping only nodes for which the predicate expression
11619  * matches. Afterwards, keep only nodes between minPos and maxPos in the
11620  * filtered result.
11621  */
11622 static void
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,xmlNodeSetPtr set,int filterOpIndex,int minPos,int maxPos,int hasNsNodes)11623 xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11624 		      xmlNodeSetPtr set,
11625 		      int filterOpIndex,
11626                       int minPos, int maxPos,
11627 		      int hasNsNodes)
11628 {
11629     xmlXPathContextPtr xpctxt;
11630     xmlNodePtr oldnode;
11631     xmlDocPtr olddoc;
11632     xmlXPathStepOpPtr filterOp;
11633     int oldcs, oldpp;
11634     int i, j, pos;
11635 
11636     if ((set == NULL) || (set->nodeNr == 0))
11637         return;
11638 
11639     /*
11640     * Check if the node set contains a sufficient number of nodes for
11641     * the requested range.
11642     */
11643     if (set->nodeNr < minPos) {
11644         xmlXPathNodeSetClear(set, hasNsNodes);
11645         return;
11646     }
11647 
11648     xpctxt = ctxt->context;
11649     oldnode = xpctxt->node;
11650     olddoc = xpctxt->doc;
11651     oldcs = xpctxt->contextSize;
11652     oldpp = xpctxt->proximityPosition;
11653     filterOp = &ctxt->comp->steps[filterOpIndex];
11654 
11655     xpctxt->contextSize = set->nodeNr;
11656 
11657     for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11658         xmlNodePtr node = set->nodeTab[i];
11659         int res;
11660 
11661         xpctxt->node = node;
11662         xpctxt->proximityPosition = i + 1;
11663 
11664         /*
11665         * Also set the xpath document in case things like
11666         * key() are evaluated in the predicate.
11667         *
11668         * TODO: Get real doc for namespace nodes.
11669         */
11670         if ((node->type != XML_NAMESPACE_DECL) &&
11671             (node->doc != NULL))
11672             xpctxt->doc = node->doc;
11673 
11674         res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11675 
11676         if (ctxt->error != XPATH_EXPRESSION_OK)
11677             break;
11678         if (res < 0) {
11679             /* Shouldn't happen */
11680             xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11681             break;
11682         }
11683 
11684         if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11685             if (i != j) {
11686                 set->nodeTab[j] = node;
11687                 set->nodeTab[i] = NULL;
11688             }
11689 
11690             j += 1;
11691         } else {
11692             /* Remove the entry from the initial node set. */
11693             set->nodeTab[i] = NULL;
11694             if (node->type == XML_NAMESPACE_DECL)
11695                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11696         }
11697 
11698         if (res != 0) {
11699             if (pos == maxPos) {
11700                 i += 1;
11701                 break;
11702             }
11703 
11704             pos += 1;
11705         }
11706     }
11707 
11708     /* Free remaining nodes. */
11709     if (hasNsNodes) {
11710         for (; i < set->nodeNr; i++) {
11711             xmlNodePtr node = set->nodeTab[i];
11712             if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11713                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11714         }
11715     }
11716 
11717     set->nodeNr = j;
11718 
11719     /* If too many elements were removed, shrink table to preserve memory. */
11720     if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11721         (set->nodeNr < set->nodeMax / 2)) {
11722         xmlNodePtr *tmp;
11723         int nodeMax = set->nodeNr;
11724 
11725         if (nodeMax < XML_NODESET_DEFAULT)
11726             nodeMax = XML_NODESET_DEFAULT;
11727         tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11728                 nodeMax * sizeof(xmlNodePtr));
11729         if (tmp == NULL) {
11730             xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11731         } else {
11732             set->nodeTab = tmp;
11733             set->nodeMax = nodeMax;
11734         }
11735     }
11736 
11737     xpctxt->node = oldnode;
11738     xpctxt->doc = olddoc;
11739     xpctxt->contextSize = oldcs;
11740     xpctxt->proximityPosition = oldpp;
11741 }
11742 
11743 #ifdef LIBXML_XPTR_ENABLED
11744 /**
11745  * xmlXPathLocationSetFilter:
11746  * @ctxt:  the XPath Parser context
11747  * @locset: the location set to filter
11748  * @filterOpIndex: the index of the predicate/filter op
11749  * @minPos: minimum position in the filtered set (1-based)
11750  * @maxPos: maximum position in the filtered set (1-based)
11751  *
11752  * Filter a location set, keeping only nodes for which the predicate
11753  * expression matches. Afterwards, keep only nodes between minPos and maxPos
11754  * in the filtered result.
11755  */
11756 static void
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,xmlLocationSetPtr locset,int filterOpIndex,int minPos,int maxPos)11757 xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11758 		          xmlLocationSetPtr locset,
11759 		          int filterOpIndex,
11760                           int minPos, int maxPos)
11761 {
11762     xmlXPathContextPtr xpctxt;
11763     xmlNodePtr oldnode;
11764     xmlDocPtr olddoc;
11765     xmlXPathStepOpPtr filterOp;
11766     int oldcs, oldpp;
11767     int i, j, pos;
11768 
11769     if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11770         return;
11771 
11772     xpctxt = ctxt->context;
11773     oldnode = xpctxt->node;
11774     olddoc = xpctxt->doc;
11775     oldcs = xpctxt->contextSize;
11776     oldpp = xpctxt->proximityPosition;
11777     filterOp = &ctxt->comp->steps[filterOpIndex];
11778 
11779     xpctxt->contextSize = locset->locNr;
11780 
11781     for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11782         xmlNodePtr contextNode = locset->locTab[i]->user;
11783         int res;
11784 
11785         xpctxt->node = contextNode;
11786         xpctxt->proximityPosition = i + 1;
11787 
11788         /*
11789         * Also set the xpath document in case things like
11790         * key() are evaluated in the predicate.
11791         *
11792         * TODO: Get real doc for namespace nodes.
11793         */
11794         if ((contextNode->type != XML_NAMESPACE_DECL) &&
11795             (contextNode->doc != NULL))
11796             xpctxt->doc = contextNode->doc;
11797 
11798         res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11799 
11800         if (ctxt->error != XPATH_EXPRESSION_OK)
11801             break;
11802         if (res < 0) {
11803             /* Shouldn't happen */
11804             xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11805             break;
11806         }
11807 
11808         if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11809             if (i != j) {
11810                 locset->locTab[j] = locset->locTab[i];
11811                 locset->locTab[i] = NULL;
11812             }
11813 
11814             j += 1;
11815         } else {
11816             /* Remove the entry from the initial location set. */
11817             xmlXPathFreeObject(locset->locTab[i]);
11818             locset->locTab[i] = NULL;
11819         }
11820 
11821         if (res != 0) {
11822             if (pos == maxPos) {
11823                 i += 1;
11824                 break;
11825             }
11826 
11827             pos += 1;
11828         }
11829     }
11830 
11831     /* Free remaining nodes. */
11832     for (; i < locset->locNr; i++)
11833         xmlXPathFreeObject(locset->locTab[i]);
11834 
11835     locset->locNr = j;
11836 
11837     /* If too many elements were removed, shrink table to preserve memory. */
11838     if ((locset->locMax > XML_NODESET_DEFAULT) &&
11839         (locset->locNr < locset->locMax / 2)) {
11840         xmlXPathObjectPtr *tmp;
11841         int locMax = locset->locNr;
11842 
11843         if (locMax < XML_NODESET_DEFAULT)
11844             locMax = XML_NODESET_DEFAULT;
11845         tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11846                 locMax * sizeof(xmlXPathObjectPtr));
11847         if (tmp == NULL) {
11848             xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11849         } else {
11850             locset->locTab = tmp;
11851             locset->locMax = locMax;
11852         }
11853     }
11854 
11855     xpctxt->node = oldnode;
11856     xpctxt->doc = olddoc;
11857     xpctxt->contextSize = oldcs;
11858     xpctxt->proximityPosition = oldpp;
11859 }
11860 #endif /* LIBXML_XPTR_ENABLED */
11861 
11862 /**
11863  * xmlXPathCompOpEvalPredicate:
11864  * @ctxt:  the XPath Parser context
11865  * @op: the predicate op
11866  * @set: the node set to filter
11867  * @minPos: minimum position in the filtered set (1-based)
11868  * @maxPos: maximum position in the filtered set (1-based)
11869  * @hasNsNodes: true if the node set may contain namespace nodes
11870  *
11871  * Filter a node set, keeping only nodes for which the sequence of predicate
11872  * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11873  * in the filtered result.
11874  */
11875 static void
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int minPos,int maxPos,int hasNsNodes)11876 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11877 			    xmlXPathStepOpPtr op,
11878 			    xmlNodeSetPtr set,
11879                             int minPos, int maxPos,
11880 			    int hasNsNodes)
11881 {
11882     if (op->ch1 != -1) {
11883 	xmlXPathCompExprPtr comp = ctxt->comp;
11884 	/*
11885 	* Process inner predicates first.
11886 	*/
11887 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11888             xmlGenericError(xmlGenericErrorContext,
11889                 "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11890             XP_ERROR(XPATH_INVALID_OPERAND);
11891 	}
11892         if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11893             XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11894         ctxt->context->depth += 1;
11895 	xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11896                                     1, set->nodeNr, hasNsNodes);
11897         ctxt->context->depth -= 1;
11898 	CHECK_ERROR;
11899     }
11900 
11901     if (op->ch2 != -1)
11902         xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11903 }
11904 
11905 static int
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int * maxPos)11906 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11907 			    xmlXPathStepOpPtr op,
11908 			    int *maxPos)
11909 {
11910 
11911     xmlXPathStepOpPtr exprOp;
11912 
11913     /*
11914     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11915     */
11916 
11917     /*
11918     * If not -1, then ch1 will point to:
11919     * 1) For predicates (XPATH_OP_PREDICATE):
11920     *    - an inner predicate operator
11921     * 2) For filters (XPATH_OP_FILTER):
11922     *    - an inner filter operator OR
11923     *    - an expression selecting the node set.
11924     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11925     */
11926     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11927 	return(0);
11928 
11929     if (op->ch2 != -1) {
11930 	exprOp = &ctxt->comp->steps[op->ch2];
11931     } else
11932 	return(0);
11933 
11934     if ((exprOp != NULL) &&
11935 	(exprOp->op == XPATH_OP_VALUE) &&
11936 	(exprOp->value4 != NULL) &&
11937 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11938     {
11939         double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11940 
11941 	/*
11942 	* We have a "[n]" predicate here.
11943 	* TODO: Unfortunately this simplistic test here is not
11944 	* able to detect a position() predicate in compound
11945 	* expressions like "[@attr = 'a" and position() = 1],
11946 	* and even not the usage of position() in
11947 	* "[position() = 1]"; thus - obviously - a position-range,
11948 	* like it "[position() < 5]", is also not detected.
11949 	* Maybe we could rewrite the AST to ease the optimization.
11950 	*/
11951 
11952         if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11953 	    *maxPos = (int) floatval;
11954             if (floatval == (double) *maxPos)
11955                 return(1);
11956         }
11957     }
11958     return(0);
11959 }
11960 
11961 static int
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first,xmlNodePtr * last,int toBool)11962 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11963                            xmlXPathStepOpPtr op,
11964 			   xmlNodePtr * first, xmlNodePtr * last,
11965 			   int toBool)
11966 {
11967 
11968 #define XP_TEST_HIT \
11969     if (hasAxisRange != 0) { \
11970 	if (++pos == maxPos) { \
11971 	    if (addNode(seq, cur) < 0) \
11972 	        ctxt->error = XPATH_MEMORY_ERROR; \
11973 	    goto axis_range_end; } \
11974     } else { \
11975 	if (addNode(seq, cur) < 0) \
11976 	    ctxt->error = XPATH_MEMORY_ERROR; \
11977 	if (breakOnFirstHit) goto first_hit; }
11978 
11979 #define XP_TEST_HIT_NS \
11980     if (hasAxisRange != 0) { \
11981 	if (++pos == maxPos) { \
11982 	    hasNsNodes = 1; \
11983 	    if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11984 	        ctxt->error = XPATH_MEMORY_ERROR; \
11985 	goto axis_range_end; } \
11986     } else { \
11987 	hasNsNodes = 1; \
11988 	if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11989 	    ctxt->error = XPATH_MEMORY_ERROR; \
11990 	if (breakOnFirstHit) goto first_hit; }
11991 
11992     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11993     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11994     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11995     const xmlChar *prefix = op->value4;
11996     const xmlChar *name = op->value5;
11997     const xmlChar *URI = NULL;
11998 
11999 #ifdef DEBUG_STEP
12000     int nbMatches = 0, prevMatches = 0;
12001 #endif
12002     int total = 0, hasNsNodes = 0;
12003     /* The popped object holding the context nodes */
12004     xmlXPathObjectPtr obj;
12005     /* The set of context nodes for the node tests */
12006     xmlNodeSetPtr contextSeq;
12007     int contextIdx;
12008     xmlNodePtr contextNode;
12009     /* The final resulting node set wrt to all context nodes */
12010     xmlNodeSetPtr outSeq;
12011     /*
12012     * The temporary resulting node set wrt 1 context node.
12013     * Used to feed predicate evaluation.
12014     */
12015     xmlNodeSetPtr seq;
12016     xmlNodePtr cur;
12017     /* First predicate operator */
12018     xmlXPathStepOpPtr predOp;
12019     int maxPos; /* The requested position() (when a "[n]" predicate) */
12020     int hasPredicateRange, hasAxisRange, pos;
12021     int breakOnFirstHit;
12022 
12023     xmlXPathTraversalFunction next = NULL;
12024     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12025     xmlXPathNodeSetMergeFunction mergeAndClear;
12026     xmlNodePtr oldContextNode;
12027     xmlXPathContextPtr xpctxt = ctxt->context;
12028 
12029 
12030     CHECK_TYPE0(XPATH_NODESET);
12031     obj = valuePop(ctxt);
12032     /*
12033     * Setup namespaces.
12034     */
12035     if (prefix != NULL) {
12036         URI = xmlXPathNsLookup(xpctxt, prefix);
12037         if (URI == NULL) {
12038 	    xmlXPathReleaseObject(xpctxt, obj);
12039             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12040 	}
12041     }
12042     /*
12043     * Setup axis.
12044     *
12045     * MAYBE FUTURE TODO: merging optimizations:
12046     * - If the nodes to be traversed wrt to the initial nodes and
12047     *   the current axis cannot overlap, then we could avoid searching
12048     *   for duplicates during the merge.
12049     *   But the question is how/when to evaluate if they cannot overlap.
12050     *   Example: if we know that for two initial nodes, the one is
12051     *   not in the ancestor-or-self axis of the other, then we could safely
12052     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12053     *   the descendant-or-self axis.
12054     */
12055     mergeAndClear = xmlXPathNodeSetMergeAndClear;
12056     switch (axis) {
12057         case AXIS_ANCESTOR:
12058             first = NULL;
12059             next = xmlXPathNextAncestor;
12060             break;
12061         case AXIS_ANCESTOR_OR_SELF:
12062             first = NULL;
12063             next = xmlXPathNextAncestorOrSelf;
12064             break;
12065         case AXIS_ATTRIBUTE:
12066             first = NULL;
12067 	    last = NULL;
12068             next = xmlXPathNextAttribute;
12069 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12070             break;
12071         case AXIS_CHILD:
12072 	    last = NULL;
12073 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12074 		(type == NODE_TYPE_NODE))
12075 	    {
12076 		/*
12077 		* Optimization if an element node type is 'element'.
12078 		*/
12079 		next = xmlXPathNextChildElement;
12080 	    } else
12081 		next = xmlXPathNextChild;
12082 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12083             break;
12084         case AXIS_DESCENDANT:
12085 	    last = NULL;
12086             next = xmlXPathNextDescendant;
12087             break;
12088         case AXIS_DESCENDANT_OR_SELF:
12089 	    last = NULL;
12090             next = xmlXPathNextDescendantOrSelf;
12091             break;
12092         case AXIS_FOLLOWING:
12093 	    last = NULL;
12094             next = xmlXPathNextFollowing;
12095             break;
12096         case AXIS_FOLLOWING_SIBLING:
12097 	    last = NULL;
12098             next = xmlXPathNextFollowingSibling;
12099             break;
12100         case AXIS_NAMESPACE:
12101             first = NULL;
12102 	    last = NULL;
12103             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12104 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12105             break;
12106         case AXIS_PARENT:
12107             first = NULL;
12108             next = xmlXPathNextParent;
12109             break;
12110         case AXIS_PRECEDING:
12111             first = NULL;
12112             next = xmlXPathNextPrecedingInternal;
12113             break;
12114         case AXIS_PRECEDING_SIBLING:
12115             first = NULL;
12116             next = xmlXPathNextPrecedingSibling;
12117             break;
12118         case AXIS_SELF:
12119             first = NULL;
12120 	    last = NULL;
12121             next = xmlXPathNextSelf;
12122 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12123             break;
12124     }
12125 
12126 #ifdef DEBUG_STEP
12127     xmlXPathDebugDumpStepAxis(op,
12128 	(obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12129 #endif
12130 
12131     if (next == NULL) {
12132 	xmlXPathReleaseObject(xpctxt, obj);
12133         return(0);
12134     }
12135     contextSeq = obj->nodesetval;
12136     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12137 	xmlXPathReleaseObject(xpctxt, obj);
12138         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12139         return(0);
12140     }
12141     /*
12142     * Predicate optimization ---------------------------------------------
12143     * If this step has a last predicate, which contains a position(),
12144     * then we'll optimize (although not exactly "position()", but only
12145     * the  short-hand form, i.e., "[n]".
12146     *
12147     * Example - expression "/foo[parent::bar][1]":
12148     *
12149     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12150     *   ROOT                               -- op->ch1
12151     *   PREDICATE                          -- op->ch2 (predOp)
12152     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12153     *       SORT
12154     *         COLLECT  'parent' 'name' 'node' bar
12155     *           NODE
12156     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12157     *
12158     */
12159     maxPos = 0;
12160     predOp = NULL;
12161     hasPredicateRange = 0;
12162     hasAxisRange = 0;
12163     if (op->ch2 != -1) {
12164 	/*
12165 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
12166 	*/
12167 	predOp = &ctxt->comp->steps[op->ch2];
12168 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12169 	    if (predOp->ch1 != -1) {
12170 		/*
12171 		* Use the next inner predicate operator.
12172 		*/
12173 		predOp = &ctxt->comp->steps[predOp->ch1];
12174 		hasPredicateRange = 1;
12175 	    } else {
12176 		/*
12177 		* There's no other predicate than the [n] predicate.
12178 		*/
12179 		predOp = NULL;
12180 		hasAxisRange = 1;
12181 	    }
12182 	}
12183     }
12184     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12185     /*
12186     * Axis traversal -----------------------------------------------------
12187     */
12188     /*
12189      * 2.3 Node Tests
12190      *  - For the attribute axis, the principal node type is attribute.
12191      *  - For the namespace axis, the principal node type is namespace.
12192      *  - For other axes, the principal node type is element.
12193      *
12194      * A node test * is true for any node of the
12195      * principal node type. For example, child::* will
12196      * select all element children of the context node
12197      */
12198     oldContextNode = xpctxt->node;
12199     addNode = xmlXPathNodeSetAddUnique;
12200     outSeq = NULL;
12201     seq = NULL;
12202     contextNode = NULL;
12203     contextIdx = 0;
12204 
12205 
12206     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12207            (ctxt->error == XPATH_EXPRESSION_OK)) {
12208 	xpctxt->node = contextSeq->nodeTab[contextIdx++];
12209 
12210 	if (seq == NULL) {
12211 	    seq = xmlXPathNodeSetCreate(NULL);
12212 	    if (seq == NULL) {
12213                 /* TODO: Propagate memory error. */
12214 		total = 0;
12215 		goto error;
12216 	    }
12217 	}
12218 	/*
12219 	* Traverse the axis and test the nodes.
12220 	*/
12221 	pos = 0;
12222 	cur = NULL;
12223 	hasNsNodes = 0;
12224         do {
12225             if (OP_LIMIT_EXCEEDED(ctxt, 1))
12226                 goto error;
12227 
12228             cur = next(ctxt, cur);
12229             if (cur == NULL)
12230                 break;
12231 
12232 	    /*
12233 	    * QUESTION TODO: What does the "first" and "last" stuff do?
12234 	    */
12235             if ((first != NULL) && (*first != NULL)) {
12236 		if (*first == cur)
12237 		    break;
12238 		if (((total % 256) == 0) &&
12239 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12240 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
12241 #else
12242 		    (xmlXPathCmpNodes(*first, cur) >= 0))
12243 #endif
12244 		{
12245 		    break;
12246 		}
12247 	    }
12248 	    if ((last != NULL) && (*last != NULL)) {
12249 		if (*last == cur)
12250 		    break;
12251 		if (((total % 256) == 0) &&
12252 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12253 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
12254 #else
12255 		    (xmlXPathCmpNodes(cur, *last) >= 0))
12256 #endif
12257 		{
12258 		    break;
12259 		}
12260 	    }
12261 
12262             total++;
12263 
12264 #ifdef DEBUG_STEP
12265             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12266 #endif
12267 
12268 	    switch (test) {
12269                 case NODE_TEST_NONE:
12270 		    total = 0;
12271                     STRANGE
12272 		    goto error;
12273                 case NODE_TEST_TYPE:
12274 		    if (type == NODE_TYPE_NODE) {
12275 			switch (cur->type) {
12276 			    case XML_DOCUMENT_NODE:
12277 			    case XML_HTML_DOCUMENT_NODE:
12278 #ifdef LIBXML_DOCB_ENABLED
12279 			    case XML_DOCB_DOCUMENT_NODE:
12280 #endif
12281 			    case XML_ELEMENT_NODE:
12282 			    case XML_ATTRIBUTE_NODE:
12283 			    case XML_PI_NODE:
12284 			    case XML_COMMENT_NODE:
12285 			    case XML_CDATA_SECTION_NODE:
12286 			    case XML_TEXT_NODE:
12287 				XP_TEST_HIT
12288 				break;
12289 			    case XML_NAMESPACE_DECL: {
12290 				if (axis == AXIS_NAMESPACE) {
12291 				    XP_TEST_HIT_NS
12292 				} else {
12293 	                            hasNsNodes = 1;
12294 				    XP_TEST_HIT
12295 				}
12296 				break;
12297                             }
12298 			    default:
12299 				break;
12300 			}
12301 		    } else if (cur->type == (xmlElementType) type) {
12302 			if (cur->type == XML_NAMESPACE_DECL)
12303 			    XP_TEST_HIT_NS
12304 			else
12305 			    XP_TEST_HIT
12306 		    } else if ((type == NODE_TYPE_TEXT) &&
12307 			 (cur->type == XML_CDATA_SECTION_NODE))
12308 		    {
12309 			XP_TEST_HIT
12310 		    }
12311 		    break;
12312                 case NODE_TEST_PI:
12313                     if ((cur->type == XML_PI_NODE) &&
12314                         ((name == NULL) || xmlStrEqual(name, cur->name)))
12315 		    {
12316 			XP_TEST_HIT
12317                     }
12318                     break;
12319                 case NODE_TEST_ALL:
12320                     if (axis == AXIS_ATTRIBUTE) {
12321                         if (cur->type == XML_ATTRIBUTE_NODE)
12322 			{
12323                             if (prefix == NULL)
12324 			    {
12325 				XP_TEST_HIT
12326                             } else if ((cur->ns != NULL) &&
12327 				(xmlStrEqual(URI, cur->ns->href)))
12328 			    {
12329 				XP_TEST_HIT
12330                             }
12331                         }
12332                     } else if (axis == AXIS_NAMESPACE) {
12333                         if (cur->type == XML_NAMESPACE_DECL)
12334 			{
12335 			    XP_TEST_HIT_NS
12336                         }
12337                     } else {
12338                         if (cur->type == XML_ELEMENT_NODE) {
12339                             if (prefix == NULL)
12340 			    {
12341 				XP_TEST_HIT
12342 
12343                             } else if ((cur->ns != NULL) &&
12344 				(xmlStrEqual(URI, cur->ns->href)))
12345 			    {
12346 				XP_TEST_HIT
12347                             }
12348                         }
12349                     }
12350                     break;
12351                 case NODE_TEST_NS:{
12352                         TODO;
12353                         break;
12354                     }
12355                 case NODE_TEST_NAME:
12356                     if (axis == AXIS_ATTRIBUTE) {
12357                         if (cur->type != XML_ATTRIBUTE_NODE)
12358 			    break;
12359 		    } else if (axis == AXIS_NAMESPACE) {
12360                         if (cur->type != XML_NAMESPACE_DECL)
12361 			    break;
12362 		    } else {
12363 		        if (cur->type != XML_ELEMENT_NODE)
12364 			    break;
12365 		    }
12366                     switch (cur->type) {
12367                         case XML_ELEMENT_NODE:
12368                             if (xmlStrEqual(name, cur->name)) {
12369                                 if (prefix == NULL) {
12370                                     if (cur->ns == NULL)
12371 				    {
12372 					XP_TEST_HIT
12373                                     }
12374                                 } else {
12375                                     if ((cur->ns != NULL) &&
12376                                         (xmlStrEqual(URI, cur->ns->href)))
12377 				    {
12378 					XP_TEST_HIT
12379                                     }
12380                                 }
12381                             }
12382                             break;
12383                         case XML_ATTRIBUTE_NODE:{
12384                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
12385 
12386                                 if (xmlStrEqual(name, attr->name)) {
12387                                     if (prefix == NULL) {
12388                                         if ((attr->ns == NULL) ||
12389                                             (attr->ns->prefix == NULL))
12390 					{
12391 					    XP_TEST_HIT
12392                                         }
12393                                     } else {
12394                                         if ((attr->ns != NULL) &&
12395                                             (xmlStrEqual(URI,
12396 					      attr->ns->href)))
12397 					{
12398 					    XP_TEST_HIT
12399                                         }
12400                                     }
12401                                 }
12402                                 break;
12403                             }
12404                         case XML_NAMESPACE_DECL:
12405                             if (cur->type == XML_NAMESPACE_DECL) {
12406                                 xmlNsPtr ns = (xmlNsPtr) cur;
12407 
12408                                 if ((ns->prefix != NULL) && (name != NULL)
12409                                     && (xmlStrEqual(ns->prefix, name)))
12410 				{
12411 				    XP_TEST_HIT_NS
12412                                 }
12413                             }
12414                             break;
12415                         default:
12416                             break;
12417                     }
12418                     break;
12419 	    } /* switch(test) */
12420         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12421 
12422 	goto apply_predicates;
12423 
12424 axis_range_end: /* ----------------------------------------------------- */
12425 	/*
12426 	* We have a "/foo[n]", and position() = n was reached.
12427 	* Note that we can have as well "/foo/::parent::foo[1]", so
12428 	* a duplicate-aware merge is still needed.
12429 	* Merge with the result.
12430 	*/
12431 	if (outSeq == NULL) {
12432 	    outSeq = seq;
12433 	    seq = NULL;
12434 	} else
12435             /* TODO: Check memory error. */
12436 	    outSeq = mergeAndClear(outSeq, seq);
12437 	/*
12438 	* Break if only a true/false result was requested.
12439 	*/
12440 	if (toBool)
12441 	    break;
12442 	continue;
12443 
12444 first_hit: /* ---------------------------------------------------------- */
12445 	/*
12446 	* Break if only a true/false result was requested and
12447 	* no predicates existed and a node test succeeded.
12448 	*/
12449 	if (outSeq == NULL) {
12450 	    outSeq = seq;
12451 	    seq = NULL;
12452 	} else
12453             /* TODO: Check memory error. */
12454 	    outSeq = mergeAndClear(outSeq, seq);
12455 	break;
12456 
12457 #ifdef DEBUG_STEP
12458 	if (seq != NULL)
12459 	    nbMatches += seq->nodeNr;
12460 #endif
12461 
12462 apply_predicates: /* --------------------------------------------------- */
12463         if (ctxt->error != XPATH_EXPRESSION_OK)
12464 	    goto error;
12465 
12466         /*
12467 	* Apply predicates.
12468 	*/
12469         if ((predOp != NULL) && (seq->nodeNr > 0)) {
12470 	    /*
12471 	    * E.g. when we have a "/foo[some expression][n]".
12472 	    */
12473 	    /*
12474 	    * QUESTION TODO: The old predicate evaluation took into
12475 	    *  account location-sets.
12476 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12477 	    *  Do we expect such a set here?
12478 	    *  All what I learned now from the evaluation semantics
12479 	    *  does not indicate that a location-set will be processed
12480 	    *  here, so this looks OK.
12481 	    */
12482 	    /*
12483 	    * Iterate over all predicates, starting with the outermost
12484 	    * predicate.
12485 	    * TODO: Problem: we cannot execute the inner predicates first
12486 	    *  since we cannot go back *up* the operator tree!
12487 	    *  Options we have:
12488 	    *  1) Use of recursive functions (like is it currently done
12489 	    *     via xmlXPathCompOpEval())
12490 	    *  2) Add a predicate evaluation information stack to the
12491 	    *     context struct
12492 	    *  3) Change the way the operators are linked; we need a
12493 	    *     "parent" field on xmlXPathStepOp
12494 	    *
12495 	    * For the moment, I'll try to solve this with a recursive
12496 	    * function: xmlXPathCompOpEvalPredicate().
12497 	    */
12498 	    if (hasPredicateRange != 0)
12499 		xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12500 					    hasNsNodes);
12501 	    else
12502 		xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12503 					    hasNsNodes);
12504 
12505 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
12506 		total = 0;
12507 		goto error;
12508 	    }
12509         }
12510 
12511         if (seq->nodeNr > 0) {
12512 	    /*
12513 	    * Add to result set.
12514 	    */
12515 	    if (outSeq == NULL) {
12516 		outSeq = seq;
12517 		seq = NULL;
12518 	    } else {
12519                 /* TODO: Check memory error. */
12520 		outSeq = mergeAndClear(outSeq, seq);
12521 	    }
12522 
12523             if (toBool)
12524                 break;
12525 	}
12526     }
12527 
12528 error:
12529     if ((obj->boolval) && (obj->user != NULL)) {
12530 	/*
12531 	* QUESTION TODO: What does this do and why?
12532 	* TODO: Do we have to do this also for the "error"
12533 	* cleanup further down?
12534 	*/
12535 	ctxt->value->boolval = 1;
12536 	ctxt->value->user = obj->user;
12537 	obj->user = NULL;
12538 	obj->boolval = 0;
12539     }
12540     xmlXPathReleaseObject(xpctxt, obj);
12541 
12542     /*
12543     * Ensure we return at least an empty set.
12544     */
12545     if (outSeq == NULL) {
12546 	if ((seq != NULL) && (seq->nodeNr == 0))
12547 	    outSeq = seq;
12548 	else
12549             /* TODO: Check memory error. */
12550 	    outSeq = xmlXPathNodeSetCreate(NULL);
12551     }
12552     if ((seq != NULL) && (seq != outSeq)) {
12553 	 xmlXPathFreeNodeSet(seq);
12554     }
12555     /*
12556     * Hand over the result. Better to push the set also in
12557     * case of errors.
12558     */
12559     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12560     /*
12561     * Reset the context node.
12562     */
12563     xpctxt->node = oldContextNode;
12564     /*
12565     * When traversing the namespace axis in "toBool" mode, it's
12566     * possible that tmpNsList wasn't freed.
12567     */
12568     if (xpctxt->tmpNsList != NULL) {
12569         xmlFree(xpctxt->tmpNsList);
12570         xpctxt->tmpNsList = NULL;
12571     }
12572 
12573 #ifdef DEBUG_STEP
12574     xmlGenericError(xmlGenericErrorContext,
12575 	"\nExamined %d nodes, found %d nodes at that step\n",
12576 	total, nbMatches);
12577 #endif
12578 
12579     return(total);
12580 }
12581 
12582 static int
12583 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12584 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
12585 
12586 /**
12587  * xmlXPathCompOpEvalFirst:
12588  * @ctxt:  the XPath parser context with the compiled expression
12589  * @op:  an XPath compiled operation
12590  * @first:  the first elem found so far
12591  *
12592  * Evaluate the Precompiled XPath operation searching only the first
12593  * element in document order
12594  *
12595  * Returns the number of examined objects.
12596  */
12597 static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12598 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12599                         xmlXPathStepOpPtr op, xmlNodePtr * first)
12600 {
12601     int total = 0, cur;
12602     xmlXPathCompExprPtr comp;
12603     xmlXPathObjectPtr arg1, arg2;
12604 
12605     CHECK_ERROR0;
12606     if (OP_LIMIT_EXCEEDED(ctxt, 1))
12607         return(0);
12608     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12609         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12610     ctxt->context->depth += 1;
12611     comp = ctxt->comp;
12612     switch (op->op) {
12613         case XPATH_OP_END:
12614             break;
12615         case XPATH_OP_UNION:
12616             total =
12617                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12618                                         first);
12619 	    CHECK_ERROR0;
12620             if ((ctxt->value != NULL)
12621                 && (ctxt->value->type == XPATH_NODESET)
12622                 && (ctxt->value->nodesetval != NULL)
12623                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12624                 /*
12625                  * limit tree traversing to first node in the result
12626                  */
12627 		/*
12628 		* OPTIMIZE TODO: This implicitly sorts
12629 		*  the result, even if not needed. E.g. if the argument
12630 		*  of the count() function, no sorting is needed.
12631 		* OPTIMIZE TODO: How do we know if the node-list wasn't
12632 		*  already sorted?
12633 		*/
12634 		if (ctxt->value->nodesetval->nodeNr > 1)
12635 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12636                 *first = ctxt->value->nodesetval->nodeTab[0];
12637             }
12638             cur =
12639                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12640                                         first);
12641 	    CHECK_ERROR0;
12642 
12643             arg2 = valuePop(ctxt);
12644             arg1 = valuePop(ctxt);
12645             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12646                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12647 	        xmlXPathReleaseObject(ctxt->context, arg1);
12648 	        xmlXPathReleaseObject(ctxt->context, arg2);
12649                 XP_ERROR0(XPATH_INVALID_TYPE);
12650             }
12651             if ((ctxt->context->opLimit != 0) &&
12652                 (((arg1->nodesetval != NULL) &&
12653                   (xmlXPathCheckOpLimit(ctxt,
12654                                         arg1->nodesetval->nodeNr) < 0)) ||
12655                  ((arg2->nodesetval != NULL) &&
12656                   (xmlXPathCheckOpLimit(ctxt,
12657                                         arg2->nodesetval->nodeNr) < 0)))) {
12658 	        xmlXPathReleaseObject(ctxt->context, arg1);
12659 	        xmlXPathReleaseObject(ctxt->context, arg2);
12660                 break;
12661             }
12662 
12663             /* TODO: Check memory error. */
12664             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12665                                                     arg2->nodesetval);
12666             valuePush(ctxt, arg1);
12667 	    xmlXPathReleaseObject(ctxt->context, arg2);
12668             /* optimizer */
12669 	    if (total > cur)
12670 		xmlXPathCompSwap(op);
12671             total += cur;
12672             break;
12673         case XPATH_OP_ROOT:
12674             xmlXPathRoot(ctxt);
12675             break;
12676         case XPATH_OP_NODE:
12677             if (op->ch1 != -1)
12678                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12679 	    CHECK_ERROR0;
12680             if (op->ch2 != -1)
12681                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12682 	    CHECK_ERROR0;
12683 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12684 		ctxt->context->node));
12685             break;
12686         case XPATH_OP_COLLECT:{
12687                 if (op->ch1 == -1)
12688                     break;
12689 
12690                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12691 		CHECK_ERROR0;
12692 
12693                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12694                 break;
12695             }
12696         case XPATH_OP_VALUE:
12697             valuePush(ctxt,
12698                       xmlXPathCacheObjectCopy(ctxt->context,
12699 			(xmlXPathObjectPtr) op->value4));
12700             break;
12701         case XPATH_OP_SORT:
12702             if (op->ch1 != -1)
12703                 total +=
12704                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12705                                             first);
12706 	    CHECK_ERROR0;
12707             if ((ctxt->value != NULL)
12708                 && (ctxt->value->type == XPATH_NODESET)
12709                 && (ctxt->value->nodesetval != NULL)
12710 		&& (ctxt->value->nodesetval->nodeNr > 1))
12711                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12712             break;
12713 #ifdef XP_OPTIMIZED_FILTER_FIRST
12714 	case XPATH_OP_FILTER:
12715                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12716             break;
12717 #endif
12718         default:
12719             total += xmlXPathCompOpEval(ctxt, op);
12720             break;
12721     }
12722 
12723     ctxt->context->depth -= 1;
12724     return(total);
12725 }
12726 
12727 /**
12728  * xmlXPathCompOpEvalLast:
12729  * @ctxt:  the XPath parser context with the compiled expression
12730  * @op:  an XPath compiled operation
12731  * @last:  the last elem found so far
12732  *
12733  * Evaluate the Precompiled XPath operation searching only the last
12734  * element in document order
12735  *
12736  * Returns the number of nodes traversed
12737  */
12738 static int
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * last)12739 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12740                        xmlNodePtr * last)
12741 {
12742     int total = 0, cur;
12743     xmlXPathCompExprPtr comp;
12744     xmlXPathObjectPtr arg1, arg2;
12745 
12746     CHECK_ERROR0;
12747     if (OP_LIMIT_EXCEEDED(ctxt, 1))
12748         return(0);
12749     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12750         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12751     ctxt->context->depth += 1;
12752     comp = ctxt->comp;
12753     switch (op->op) {
12754         case XPATH_OP_END:
12755             break;
12756         case XPATH_OP_UNION:
12757             total =
12758                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12759 	    CHECK_ERROR0;
12760             if ((ctxt->value != NULL)
12761                 && (ctxt->value->type == XPATH_NODESET)
12762                 && (ctxt->value->nodesetval != NULL)
12763                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12764                 /*
12765                  * limit tree traversing to first node in the result
12766                  */
12767 		if (ctxt->value->nodesetval->nodeNr > 1)
12768 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
12769                 *last =
12770                     ctxt->value->nodesetval->nodeTab[ctxt->value->
12771                                                      nodesetval->nodeNr -
12772                                                      1];
12773             }
12774             cur =
12775                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12776 	    CHECK_ERROR0;
12777             if ((ctxt->value != NULL)
12778                 && (ctxt->value->type == XPATH_NODESET)
12779                 && (ctxt->value->nodesetval != NULL)
12780                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12781             }
12782 
12783             arg2 = valuePop(ctxt);
12784             arg1 = valuePop(ctxt);
12785             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12786                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12787 	        xmlXPathReleaseObject(ctxt->context, arg1);
12788 	        xmlXPathReleaseObject(ctxt->context, arg2);
12789                 XP_ERROR0(XPATH_INVALID_TYPE);
12790             }
12791             if ((ctxt->context->opLimit != 0) &&
12792                 (((arg1->nodesetval != NULL) &&
12793                   (xmlXPathCheckOpLimit(ctxt,
12794                                         arg1->nodesetval->nodeNr) < 0)) ||
12795                  ((arg2->nodesetval != NULL) &&
12796                   (xmlXPathCheckOpLimit(ctxt,
12797                                         arg2->nodesetval->nodeNr) < 0)))) {
12798 	        xmlXPathReleaseObject(ctxt->context, arg1);
12799 	        xmlXPathReleaseObject(ctxt->context, arg2);
12800                 break;
12801             }
12802 
12803             /* TODO: Check memory error. */
12804             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12805                                                     arg2->nodesetval);
12806             valuePush(ctxt, arg1);
12807 	    xmlXPathReleaseObject(ctxt->context, arg2);
12808             /* optimizer */
12809 	    if (total > cur)
12810 		xmlXPathCompSwap(op);
12811             total += cur;
12812             break;
12813         case XPATH_OP_ROOT:
12814             xmlXPathRoot(ctxt);
12815             break;
12816         case XPATH_OP_NODE:
12817             if (op->ch1 != -1)
12818                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12819 	    CHECK_ERROR0;
12820             if (op->ch2 != -1)
12821                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12822 	    CHECK_ERROR0;
12823 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12824 		ctxt->context->node));
12825             break;
12826         case XPATH_OP_COLLECT:{
12827                 if (op->ch1 == -1)
12828                     break;
12829 
12830                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12831 		CHECK_ERROR0;
12832 
12833                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12834                 break;
12835             }
12836         case XPATH_OP_VALUE:
12837             valuePush(ctxt,
12838                       xmlXPathCacheObjectCopy(ctxt->context,
12839 			(xmlXPathObjectPtr) op->value4));
12840             break;
12841         case XPATH_OP_SORT:
12842             if (op->ch1 != -1)
12843                 total +=
12844                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12845                                            last);
12846 	    CHECK_ERROR0;
12847             if ((ctxt->value != NULL)
12848                 && (ctxt->value->type == XPATH_NODESET)
12849                 && (ctxt->value->nodesetval != NULL)
12850 		&& (ctxt->value->nodesetval->nodeNr > 1))
12851                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12852             break;
12853         default:
12854             total += xmlXPathCompOpEval(ctxt, op);
12855             break;
12856     }
12857 
12858     ctxt->context->depth -= 1;
12859     return (total);
12860 }
12861 
12862 #ifdef XP_OPTIMIZED_FILTER_FIRST
12863 static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12864 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12865 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
12866 {
12867     int total = 0;
12868     xmlXPathCompExprPtr comp;
12869     xmlNodeSetPtr set;
12870 
12871     CHECK_ERROR0;
12872     comp = ctxt->comp;
12873     /*
12874     * Optimization for ()[last()] selection i.e. the last elem
12875     */
12876     if ((op->ch1 != -1) && (op->ch2 != -1) &&
12877 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12878 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12879 	int f = comp->steps[op->ch2].ch1;
12880 
12881 	if ((f != -1) &&
12882 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12883 	    (comp->steps[f].value5 == NULL) &&
12884 	    (comp->steps[f].value == 0) &&
12885 	    (comp->steps[f].value4 != NULL) &&
12886 	    (xmlStrEqual
12887 	    (comp->steps[f].value4, BAD_CAST "last"))) {
12888 	    xmlNodePtr last = NULL;
12889 
12890 	    total +=
12891 		xmlXPathCompOpEvalLast(ctxt,
12892 		    &comp->steps[op->ch1],
12893 		    &last);
12894 	    CHECK_ERROR0;
12895 	    /*
12896 	    * The nodeset should be in document order,
12897 	    * Keep only the last value
12898 	    */
12899 	    if ((ctxt->value != NULL) &&
12900 		(ctxt->value->type == XPATH_NODESET) &&
12901 		(ctxt->value->nodesetval != NULL) &&
12902 		(ctxt->value->nodesetval->nodeTab != NULL) &&
12903 		(ctxt->value->nodesetval->nodeNr > 1)) {
12904                 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12905 		*first = *(ctxt->value->nodesetval->nodeTab);
12906 	    }
12907 	    return (total);
12908 	}
12909     }
12910 
12911     if (op->ch1 != -1)
12912 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12913     CHECK_ERROR0;
12914     if (op->ch2 == -1)
12915 	return (total);
12916     if (ctxt->value == NULL)
12917 	return (total);
12918 
12919 #ifdef LIBXML_XPTR_ENABLED
12920     /*
12921     * Hum are we filtering the result of an XPointer expression
12922     */
12923     if (ctxt->value->type == XPATH_LOCATIONSET) {
12924         xmlLocationSetPtr locset = ctxt->value->user;
12925 
12926         if (locset != NULL) {
12927             xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12928             if (locset->locNr > 0)
12929                 *first = (xmlNodePtr) locset->locTab[0]->user;
12930         }
12931 
12932 	return (total);
12933     }
12934 #endif /* LIBXML_XPTR_ENABLED */
12935 
12936     CHECK_TYPE0(XPATH_NODESET);
12937     set = ctxt->value->nodesetval;
12938     if (set != NULL) {
12939         xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12940         if (set->nodeNr > 0)
12941             *first = set->nodeTab[0];
12942     }
12943 
12944     return (total);
12945 }
12946 #endif /* XP_OPTIMIZED_FILTER_FIRST */
12947 
12948 /**
12949  * xmlXPathCompOpEval:
12950  * @ctxt:  the XPath parser context with the compiled expression
12951  * @op:  an XPath compiled operation
12952  *
12953  * Evaluate the Precompiled XPath operation
12954  * Returns the number of nodes traversed
12955  */
12956 static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op)12957 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12958 {
12959     int total = 0;
12960     int equal, ret;
12961     xmlXPathCompExprPtr comp;
12962     xmlXPathObjectPtr arg1, arg2;
12963 
12964     CHECK_ERROR0;
12965     if (OP_LIMIT_EXCEEDED(ctxt, 1))
12966         return(0);
12967     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12968         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12969     ctxt->context->depth += 1;
12970     comp = ctxt->comp;
12971     switch (op->op) {
12972         case XPATH_OP_END:
12973             break;
12974         case XPATH_OP_AND:
12975             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12976 	    CHECK_ERROR0;
12977             xmlXPathBooleanFunction(ctxt, 1);
12978             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12979                 break;
12980             arg2 = valuePop(ctxt);
12981             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12982 	    if (ctxt->error) {
12983 		xmlXPathFreeObject(arg2);
12984 		break;
12985 	    }
12986             xmlXPathBooleanFunction(ctxt, 1);
12987             if (ctxt->value != NULL)
12988                 ctxt->value->boolval &= arg2->boolval;
12989 	    xmlXPathReleaseObject(ctxt->context, arg2);
12990             break;
12991         case XPATH_OP_OR:
12992             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12993 	    CHECK_ERROR0;
12994             xmlXPathBooleanFunction(ctxt, 1);
12995             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12996                 break;
12997             arg2 = valuePop(ctxt);
12998             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12999 	    if (ctxt->error) {
13000 		xmlXPathFreeObject(arg2);
13001 		break;
13002 	    }
13003             xmlXPathBooleanFunction(ctxt, 1);
13004             if (ctxt->value != NULL)
13005                 ctxt->value->boolval |= arg2->boolval;
13006 	    xmlXPathReleaseObject(ctxt->context, arg2);
13007             break;
13008         case XPATH_OP_EQUAL:
13009             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13010 	    CHECK_ERROR0;
13011             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13012 	    CHECK_ERROR0;
13013 	    if (op->value)
13014 		equal = xmlXPathEqualValues(ctxt);
13015 	    else
13016 		equal = xmlXPathNotEqualValues(ctxt);
13017 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13018             break;
13019         case XPATH_OP_CMP:
13020             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13021 	    CHECK_ERROR0;
13022             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13023 	    CHECK_ERROR0;
13024             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13025 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13026             break;
13027         case XPATH_OP_PLUS:
13028             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13029 	    CHECK_ERROR0;
13030             if (op->ch2 != -1) {
13031                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13032 	    }
13033 	    CHECK_ERROR0;
13034             if (op->value == 0)
13035                 xmlXPathSubValues(ctxt);
13036             else if (op->value == 1)
13037                 xmlXPathAddValues(ctxt);
13038             else if (op->value == 2)
13039                 xmlXPathValueFlipSign(ctxt);
13040             else if (op->value == 3) {
13041                 CAST_TO_NUMBER;
13042                 CHECK_TYPE0(XPATH_NUMBER);
13043             }
13044             break;
13045         case XPATH_OP_MULT:
13046             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13047 	    CHECK_ERROR0;
13048             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13049 	    CHECK_ERROR0;
13050             if (op->value == 0)
13051                 xmlXPathMultValues(ctxt);
13052             else if (op->value == 1)
13053                 xmlXPathDivValues(ctxt);
13054             else if (op->value == 2)
13055                 xmlXPathModValues(ctxt);
13056             break;
13057         case XPATH_OP_UNION:
13058             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13059 	    CHECK_ERROR0;
13060             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13061 	    CHECK_ERROR0;
13062 
13063             arg2 = valuePop(ctxt);
13064             arg1 = valuePop(ctxt);
13065             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13066                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13067 	        xmlXPathReleaseObject(ctxt->context, arg1);
13068 	        xmlXPathReleaseObject(ctxt->context, arg2);
13069                 XP_ERROR0(XPATH_INVALID_TYPE);
13070             }
13071             if ((ctxt->context->opLimit != 0) &&
13072                 (((arg1->nodesetval != NULL) &&
13073                   (xmlXPathCheckOpLimit(ctxt,
13074                                         arg1->nodesetval->nodeNr) < 0)) ||
13075                  ((arg2->nodesetval != NULL) &&
13076                   (xmlXPathCheckOpLimit(ctxt,
13077                                         arg2->nodesetval->nodeNr) < 0)))) {
13078 	        xmlXPathReleaseObject(ctxt->context, arg1);
13079 	        xmlXPathReleaseObject(ctxt->context, arg2);
13080                 break;
13081             }
13082 
13083 	    if ((arg1->nodesetval == NULL) ||
13084 		((arg2->nodesetval != NULL) &&
13085 		 (arg2->nodesetval->nodeNr != 0)))
13086 	    {
13087                 /* TODO: Check memory error. */
13088 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13089 							arg2->nodesetval);
13090 	    }
13091 
13092             valuePush(ctxt, arg1);
13093 	    xmlXPathReleaseObject(ctxt->context, arg2);
13094             break;
13095         case XPATH_OP_ROOT:
13096             xmlXPathRoot(ctxt);
13097             break;
13098         case XPATH_OP_NODE:
13099             if (op->ch1 != -1)
13100                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13101 	    CHECK_ERROR0;
13102             if (op->ch2 != -1)
13103                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13104 	    CHECK_ERROR0;
13105 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13106 		ctxt->context->node));
13107             break;
13108         case XPATH_OP_COLLECT:{
13109                 if (op->ch1 == -1)
13110                     break;
13111 
13112                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13113 		CHECK_ERROR0;
13114 
13115                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13116                 break;
13117             }
13118         case XPATH_OP_VALUE:
13119             valuePush(ctxt,
13120                       xmlXPathCacheObjectCopy(ctxt->context,
13121 			(xmlXPathObjectPtr) op->value4));
13122             break;
13123         case XPATH_OP_VARIABLE:{
13124 		xmlXPathObjectPtr val;
13125 
13126                 if (op->ch1 != -1)
13127                     total +=
13128                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13129                 if (op->value5 == NULL) {
13130 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
13131 		    if (val == NULL)
13132 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13133                     valuePush(ctxt, val);
13134 		} else {
13135                     const xmlChar *URI;
13136 
13137                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
13138                     if (URI == NULL) {
13139                         xmlGenericError(xmlGenericErrorContext,
13140             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13141                                     (char *) op->value4, (char *)op->value5);
13142                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13143                         break;
13144                     }
13145 		    val = xmlXPathVariableLookupNS(ctxt->context,
13146                                                        op->value4, URI);
13147 		    if (val == NULL)
13148 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13149                     valuePush(ctxt, val);
13150                 }
13151                 break;
13152             }
13153         case XPATH_OP_FUNCTION:{
13154                 xmlXPathFunction func;
13155                 const xmlChar *oldFunc, *oldFuncURI;
13156 		int i;
13157                 int frame;
13158 
13159                 frame = xmlXPathSetFrame(ctxt);
13160                 if (op->ch1 != -1) {
13161                     total +=
13162                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13163                     if (ctxt->error != XPATH_EXPRESSION_OK) {
13164                         xmlXPathPopFrame(ctxt, frame);
13165                         break;
13166                     }
13167                 }
13168 		if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13169 		    xmlGenericError(xmlGenericErrorContext,
13170 			    "xmlXPathCompOpEval: parameter error\n");
13171 		    ctxt->error = XPATH_INVALID_OPERAND;
13172                     xmlXPathPopFrame(ctxt, frame);
13173 		    break;
13174 		}
13175 		for (i = 0; i < op->value; i++) {
13176 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13177 			xmlGenericError(xmlGenericErrorContext,
13178 				"xmlXPathCompOpEval: parameter error\n");
13179 			ctxt->error = XPATH_INVALID_OPERAND;
13180                         xmlXPathPopFrame(ctxt, frame);
13181 			break;
13182 		    }
13183                 }
13184                 if (op->cache != NULL)
13185                     func = op->cache;
13186                 else {
13187                     const xmlChar *URI = NULL;
13188 
13189                     if (op->value5 == NULL)
13190                         func =
13191                             xmlXPathFunctionLookup(ctxt->context,
13192                                                    op->value4);
13193                     else {
13194                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
13195                         if (URI == NULL) {
13196                             xmlGenericError(xmlGenericErrorContext,
13197             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13198                                     (char *)op->value4, (char *)op->value5);
13199                             xmlXPathPopFrame(ctxt, frame);
13200                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13201                             break;
13202                         }
13203                         func = xmlXPathFunctionLookupNS(ctxt->context,
13204                                                         op->value4, URI);
13205                     }
13206                     if (func == NULL) {
13207                         xmlGenericError(xmlGenericErrorContext,
13208                                 "xmlXPathCompOpEval: function %s not found\n",
13209                                         (char *)op->value4);
13210                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13211                     }
13212                     op->cache = func;
13213                     op->cacheURI = (void *) URI;
13214                 }
13215                 oldFunc = ctxt->context->function;
13216                 oldFuncURI = ctxt->context->functionURI;
13217                 ctxt->context->function = op->value4;
13218                 ctxt->context->functionURI = op->cacheURI;
13219                 func(ctxt, op->value);
13220                 ctxt->context->function = oldFunc;
13221                 ctxt->context->functionURI = oldFuncURI;
13222                 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13223                     (ctxt->valueNr != ctxt->valueFrame + 1))
13224                     XP_ERROR0(XPATH_STACK_ERROR);
13225                 xmlXPathPopFrame(ctxt, frame);
13226                 break;
13227             }
13228         case XPATH_OP_ARG:
13229             if (op->ch1 != -1) {
13230                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13231 	        CHECK_ERROR0;
13232             }
13233             if (op->ch2 != -1) {
13234                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13235 	        CHECK_ERROR0;
13236 	    }
13237             break;
13238         case XPATH_OP_PREDICATE:
13239         case XPATH_OP_FILTER:{
13240                 xmlNodeSetPtr set;
13241 
13242                 /*
13243                  * Optimization for ()[1] selection i.e. the first elem
13244                  */
13245                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13246 #ifdef XP_OPTIMIZED_FILTER_FIRST
13247 		    /*
13248 		    * FILTER TODO: Can we assume that the inner processing
13249 		    *  will result in an ordered list if we have an
13250 		    *  XPATH_OP_FILTER?
13251 		    *  What about an additional field or flag on
13252 		    *  xmlXPathObject like @sorted ? This way we wouldn't need
13253 		    *  to assume anything, so it would be more robust and
13254 		    *  easier to optimize.
13255 		    */
13256                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13257 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13258 #else
13259 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13260 #endif
13261                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13262                     xmlXPathObjectPtr val;
13263 
13264                     val = comp->steps[op->ch2].value4;
13265                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13266                         (val->floatval == 1.0)) {
13267                         xmlNodePtr first = NULL;
13268 
13269                         total +=
13270                             xmlXPathCompOpEvalFirst(ctxt,
13271                                                     &comp->steps[op->ch1],
13272                                                     &first);
13273 			CHECK_ERROR0;
13274                         /*
13275                          * The nodeset should be in document order,
13276                          * Keep only the first value
13277                          */
13278                         if ((ctxt->value != NULL) &&
13279                             (ctxt->value->type == XPATH_NODESET) &&
13280                             (ctxt->value->nodesetval != NULL) &&
13281                             (ctxt->value->nodesetval->nodeNr > 1))
13282                             xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13283                                                         1, 1);
13284                         break;
13285                     }
13286                 }
13287                 /*
13288                  * Optimization for ()[last()] selection i.e. the last elem
13289                  */
13290                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13291                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13292                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13293                     int f = comp->steps[op->ch2].ch1;
13294 
13295                     if ((f != -1) &&
13296                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13297                         (comp->steps[f].value5 == NULL) &&
13298                         (comp->steps[f].value == 0) &&
13299                         (comp->steps[f].value4 != NULL) &&
13300                         (xmlStrEqual
13301                          (comp->steps[f].value4, BAD_CAST "last"))) {
13302                         xmlNodePtr last = NULL;
13303 
13304                         total +=
13305                             xmlXPathCompOpEvalLast(ctxt,
13306                                                    &comp->steps[op->ch1],
13307                                                    &last);
13308 			CHECK_ERROR0;
13309                         /*
13310                          * The nodeset should be in document order,
13311                          * Keep only the last value
13312                          */
13313                         if ((ctxt->value != NULL) &&
13314                             (ctxt->value->type == XPATH_NODESET) &&
13315                             (ctxt->value->nodesetval != NULL) &&
13316                             (ctxt->value->nodesetval->nodeTab != NULL) &&
13317                             (ctxt->value->nodesetval->nodeNr > 1))
13318                             xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13319                         break;
13320                     }
13321                 }
13322 		/*
13323 		* Process inner predicates first.
13324 		* Example "index[parent::book][1]":
13325 		* ...
13326 		*   PREDICATE   <-- we are here "[1]"
13327 		*     PREDICATE <-- process "[parent::book]" first
13328 		*       SORT
13329 		*         COLLECT  'parent' 'name' 'node' book
13330 		*           NODE
13331 		*     ELEM Object is a number : 1
13332 		*/
13333                 if (op->ch1 != -1)
13334                     total +=
13335                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13336 		CHECK_ERROR0;
13337                 if (op->ch2 == -1)
13338                     break;
13339                 if (ctxt->value == NULL)
13340                     break;
13341 
13342 #ifdef LIBXML_XPTR_ENABLED
13343                 /*
13344                  * Hum are we filtering the result of an XPointer expression
13345                  */
13346                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13347                     xmlLocationSetPtr locset = ctxt->value->user;
13348                     xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13349                                               1, locset->locNr);
13350                     break;
13351                 }
13352 #endif /* LIBXML_XPTR_ENABLED */
13353 
13354                 CHECK_TYPE0(XPATH_NODESET);
13355                 set = ctxt->value->nodesetval;
13356                 if (set != NULL)
13357                     xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13358                                           1, set->nodeNr, 1);
13359                 break;
13360             }
13361         case XPATH_OP_SORT:
13362             if (op->ch1 != -1)
13363                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13364 	    CHECK_ERROR0;
13365             if ((ctxt->value != NULL) &&
13366                 (ctxt->value->type == XPATH_NODESET) &&
13367                 (ctxt->value->nodesetval != NULL) &&
13368 		(ctxt->value->nodesetval->nodeNr > 1))
13369 	    {
13370                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13371 	    }
13372             break;
13373 #ifdef LIBXML_XPTR_ENABLED
13374         case XPATH_OP_RANGETO:{
13375                 xmlXPathObjectPtr range;
13376                 xmlXPathObjectPtr res, obj;
13377                 xmlXPathObjectPtr tmp;
13378                 xmlLocationSetPtr newlocset = NULL;
13379 		    xmlLocationSetPtr oldlocset;
13380                 xmlNodeSetPtr oldset;
13381                 xmlNodePtr oldnode = ctxt->context->node;
13382                 int oldcs = ctxt->context->contextSize;
13383                 int oldpp = ctxt->context->proximityPosition;
13384                 int i, j;
13385 
13386                 if (op->ch1 != -1) {
13387                     total +=
13388                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13389                     CHECK_ERROR0;
13390                 }
13391                 if (ctxt->value == NULL) {
13392                     XP_ERROR0(XPATH_INVALID_OPERAND);
13393                 }
13394                 if (op->ch2 == -1)
13395                     break;
13396 
13397                 if (ctxt->value->type == XPATH_LOCATIONSET) {
13398                     /*
13399                      * Extract the old locset, and then evaluate the result of the
13400                      * expression for all the element in the locset. use it to grow
13401                      * up a new locset.
13402                      */
13403                     CHECK_TYPE0(XPATH_LOCATIONSET);
13404 
13405                     if ((ctxt->value->user == NULL) ||
13406                         (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13407                         break;
13408 
13409                     obj = valuePop(ctxt);
13410                     oldlocset = obj->user;
13411 
13412                     newlocset = xmlXPtrLocationSetCreate(NULL);
13413 
13414                     for (i = 0; i < oldlocset->locNr; i++) {
13415                         /*
13416                          * Run the evaluation with a node list made of a
13417                          * single item in the nodelocset.
13418                          */
13419                         ctxt->context->node = oldlocset->locTab[i]->user;
13420                         ctxt->context->contextSize = oldlocset->locNr;
13421                         ctxt->context->proximityPosition = i + 1;
13422 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13423 			    ctxt->context->node);
13424                         valuePush(ctxt, tmp);
13425 
13426                         if (op->ch2 != -1)
13427                             total +=
13428                                 xmlXPathCompOpEval(ctxt,
13429                                                    &comp->steps[op->ch2]);
13430 			if (ctxt->error != XPATH_EXPRESSION_OK) {
13431                             xmlXPtrFreeLocationSet(newlocset);
13432                             goto rangeto_error;
13433 			}
13434 
13435                         res = valuePop(ctxt);
13436 			if (res->type == XPATH_LOCATIONSET) {
13437 			    xmlLocationSetPtr rloc =
13438 			        (xmlLocationSetPtr)res->user;
13439 			    for (j=0; j<rloc->locNr; j++) {
13440 			        range = xmlXPtrNewRange(
13441 				  oldlocset->locTab[i]->user,
13442 				  oldlocset->locTab[i]->index,
13443 				  rloc->locTab[j]->user2,
13444 				  rloc->locTab[j]->index2);
13445 				if (range != NULL) {
13446 				    xmlXPtrLocationSetAdd(newlocset, range);
13447 				}
13448 			    }
13449 			} else {
13450 			    range = xmlXPtrNewRangeNodeObject(
13451 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
13452                             if (range != NULL) {
13453                                 xmlXPtrLocationSetAdd(newlocset,range);
13454 			    }
13455                         }
13456 
13457                         /*
13458                          * Cleanup
13459                          */
13460                         if (res != NULL) {
13461 			    xmlXPathReleaseObject(ctxt->context, res);
13462 			}
13463                         if (ctxt->value == tmp) {
13464                             res = valuePop(ctxt);
13465 			    xmlXPathReleaseObject(ctxt->context, res);
13466                         }
13467                     }
13468 		} else {	/* Not a location set */
13469                     CHECK_TYPE0(XPATH_NODESET);
13470                     obj = valuePop(ctxt);
13471                     oldset = obj->nodesetval;
13472 
13473                     newlocset = xmlXPtrLocationSetCreate(NULL);
13474 
13475                     if (oldset != NULL) {
13476                         for (i = 0; i < oldset->nodeNr; i++) {
13477                             /*
13478                              * Run the evaluation with a node list made of a single item
13479                              * in the nodeset.
13480                              */
13481                             ctxt->context->node = oldset->nodeTab[i];
13482 			    /*
13483 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
13484 			    */
13485 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13486 				ctxt->context->node);
13487                             valuePush(ctxt, tmp);
13488 
13489                             if (op->ch2 != -1)
13490                                 total +=
13491                                     xmlXPathCompOpEval(ctxt,
13492                                                    &comp->steps[op->ch2]);
13493 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
13494                                 xmlXPtrFreeLocationSet(newlocset);
13495                                 goto rangeto_error;
13496 			    }
13497 
13498                             res = valuePop(ctxt);
13499                             range =
13500                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13501                                                       res);
13502                             if (range != NULL) {
13503                                 xmlXPtrLocationSetAdd(newlocset, range);
13504                             }
13505 
13506                             /*
13507                              * Cleanup
13508                              */
13509                             if (res != NULL) {
13510 				xmlXPathReleaseObject(ctxt->context, res);
13511 			    }
13512                             if (ctxt->value == tmp) {
13513                                 res = valuePop(ctxt);
13514 				xmlXPathReleaseObject(ctxt->context, res);
13515                             }
13516                         }
13517                     }
13518                 }
13519 
13520                 /*
13521                  * The result is used as the new evaluation set.
13522                  */
13523                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13524 rangeto_error:
13525 		xmlXPathReleaseObject(ctxt->context, obj);
13526                 ctxt->context->node = oldnode;
13527                 ctxt->context->contextSize = oldcs;
13528                 ctxt->context->proximityPosition = oldpp;
13529                 break;
13530             }
13531 #endif /* LIBXML_XPTR_ENABLED */
13532         default:
13533             xmlGenericError(xmlGenericErrorContext,
13534                             "XPath: unknown precompiled operation %d\n", op->op);
13535             ctxt->error = XPATH_INVALID_OPERAND;
13536             break;
13537     }
13538 
13539     ctxt->context->depth -= 1;
13540     return (total);
13541 }
13542 
13543 /**
13544  * xmlXPathCompOpEvalToBoolean:
13545  * @ctxt:  the XPath parser context
13546  *
13547  * Evaluates if the expression evaluates to true.
13548  *
13549  * Returns 1 if true, 0 if false and -1 on API or internal errors.
13550  */
13551 static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int isPredicate)13552 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13553 			    xmlXPathStepOpPtr op,
13554 			    int isPredicate)
13555 {
13556     xmlXPathObjectPtr resObj = NULL;
13557 
13558 start:
13559     if (OP_LIMIT_EXCEEDED(ctxt, 1))
13560         return(0);
13561     /* comp = ctxt->comp; */
13562     switch (op->op) {
13563         case XPATH_OP_END:
13564             return (0);
13565 	case XPATH_OP_VALUE:
13566 	    resObj = (xmlXPathObjectPtr) op->value4;
13567 	    if (isPredicate)
13568 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13569 	    return(xmlXPathCastToBoolean(resObj));
13570 	case XPATH_OP_SORT:
13571 	    /*
13572 	    * We don't need sorting for boolean results. Skip this one.
13573 	    */
13574             if (op->ch1 != -1) {
13575 		op = &ctxt->comp->steps[op->ch1];
13576 		goto start;
13577 	    }
13578 	    return(0);
13579 	case XPATH_OP_COLLECT:
13580 	    if (op->ch1 == -1)
13581 		return(0);
13582 
13583             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13584 	    if (ctxt->error != XPATH_EXPRESSION_OK)
13585 		return(-1);
13586 
13587             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13588 	    if (ctxt->error != XPATH_EXPRESSION_OK)
13589 		return(-1);
13590 
13591 	    resObj = valuePop(ctxt);
13592 	    if (resObj == NULL)
13593 		return(-1);
13594 	    break;
13595 	default:
13596 	    /*
13597 	    * Fallback to call xmlXPathCompOpEval().
13598 	    */
13599 	    xmlXPathCompOpEval(ctxt, op);
13600 	    if (ctxt->error != XPATH_EXPRESSION_OK)
13601 		return(-1);
13602 
13603 	    resObj = valuePop(ctxt);
13604 	    if (resObj == NULL)
13605 		return(-1);
13606 	    break;
13607     }
13608 
13609     if (resObj) {
13610 	int res;
13611 
13612 	if (resObj->type == XPATH_BOOLEAN) {
13613 	    res = resObj->boolval;
13614 	} else if (isPredicate) {
13615 	    /*
13616 	    * For predicates a result of type "number" is handled
13617 	    * differently:
13618 	    * SPEC XPath 1.0:
13619 	    * "If the result is a number, the result will be converted
13620 	    *  to true if the number is equal to the context position
13621 	    *  and will be converted to false otherwise;"
13622 	    */
13623 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13624 	} else {
13625 	    res = xmlXPathCastToBoolean(resObj);
13626 	}
13627 	xmlXPathReleaseObject(ctxt->context, resObj);
13628 	return(res);
13629     }
13630 
13631     return(0);
13632 }
13633 
13634 #ifdef XPATH_STREAMING
13635 /**
13636  * xmlXPathRunStreamEval:
13637  * @ctxt:  the XPath parser context with the compiled expression
13638  *
13639  * Evaluate the Precompiled Streamable XPath expression in the given context.
13640  */
13641 static int
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt,xmlPatternPtr comp,xmlXPathObjectPtr * resultSeq,int toBool)13642 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13643 		      xmlXPathObjectPtr *resultSeq, int toBool)
13644 {
13645     int max_depth, min_depth;
13646     int from_root;
13647     int ret, depth;
13648     int eval_all_nodes;
13649     xmlNodePtr cur = NULL, limit = NULL;
13650     xmlStreamCtxtPtr patstream = NULL;
13651 
13652     int nb_nodes = 0;
13653 
13654     if ((ctxt == NULL) || (comp == NULL))
13655         return(-1);
13656     max_depth = xmlPatternMaxDepth(comp);
13657     if (max_depth == -1)
13658         return(-1);
13659     if (max_depth == -2)
13660         max_depth = 10000;
13661     min_depth = xmlPatternMinDepth(comp);
13662     if (min_depth == -1)
13663         return(-1);
13664     from_root = xmlPatternFromRoot(comp);
13665     if (from_root < 0)
13666         return(-1);
13667 #if 0
13668     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13669 #endif
13670 
13671     if (! toBool) {
13672 	if (resultSeq == NULL)
13673 	    return(-1);
13674 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13675 	if (*resultSeq == NULL)
13676 	    return(-1);
13677     }
13678 
13679     /*
13680      * handle the special cases of "/" amd "." being matched
13681      */
13682     if (min_depth == 0) {
13683 	if (from_root) {
13684 	    /* Select "/" */
13685 	    if (toBool)
13686 		return(1);
13687             /* TODO: Check memory error. */
13688 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
13689 		                     (xmlNodePtr) ctxt->doc);
13690 	} else {
13691 	    /* Select "self::node()" */
13692 	    if (toBool)
13693 		return(1);
13694             /* TODO: Check memory error. */
13695 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13696 	}
13697     }
13698     if (max_depth == 0) {
13699 	return(0);
13700     }
13701 
13702     if (from_root) {
13703         cur = (xmlNodePtr)ctxt->doc;
13704     } else if (ctxt->node != NULL) {
13705         switch (ctxt->node->type) {
13706             case XML_ELEMENT_NODE:
13707             case XML_DOCUMENT_NODE:
13708             case XML_DOCUMENT_FRAG_NODE:
13709             case XML_HTML_DOCUMENT_NODE:
13710 #ifdef LIBXML_DOCB_ENABLED
13711             case XML_DOCB_DOCUMENT_NODE:
13712 #endif
13713 	        cur = ctxt->node;
13714 		break;
13715             case XML_ATTRIBUTE_NODE:
13716             case XML_TEXT_NODE:
13717             case XML_CDATA_SECTION_NODE:
13718             case XML_ENTITY_REF_NODE:
13719             case XML_ENTITY_NODE:
13720             case XML_PI_NODE:
13721             case XML_COMMENT_NODE:
13722             case XML_NOTATION_NODE:
13723             case XML_DTD_NODE:
13724             case XML_DOCUMENT_TYPE_NODE:
13725             case XML_ELEMENT_DECL:
13726             case XML_ATTRIBUTE_DECL:
13727             case XML_ENTITY_DECL:
13728             case XML_NAMESPACE_DECL:
13729             case XML_XINCLUDE_START:
13730             case XML_XINCLUDE_END:
13731 		break;
13732 	}
13733 	limit = cur;
13734     }
13735     if (cur == NULL) {
13736         return(0);
13737     }
13738 
13739     patstream = xmlPatternGetStreamCtxt(comp);
13740     if (patstream == NULL) {
13741 	/*
13742 	* QUESTION TODO: Is this an error?
13743 	*/
13744 	return(0);
13745     }
13746 
13747     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13748 
13749     if (from_root) {
13750 	ret = xmlStreamPush(patstream, NULL, NULL);
13751 	if (ret < 0) {
13752 	} else if (ret == 1) {
13753 	    if (toBool)
13754 		goto return_1;
13755             /* TODO: Check memory error. */
13756 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13757 	}
13758     }
13759     depth = 0;
13760     goto scan_children;
13761 next_node:
13762     do {
13763         if (ctxt->opLimit != 0) {
13764             if (ctxt->opCount >= ctxt->opLimit) {
13765                 xmlGenericError(xmlGenericErrorContext,
13766                         "XPath operation limit exceeded\n");
13767                 xmlFreeStreamCtxt(patstream);
13768                 return(-1);
13769             }
13770             ctxt->opCount++;
13771         }
13772 
13773         nb_nodes++;
13774 
13775 	switch (cur->type) {
13776 	    case XML_ELEMENT_NODE:
13777 	    case XML_TEXT_NODE:
13778 	    case XML_CDATA_SECTION_NODE:
13779 	    case XML_COMMENT_NODE:
13780 	    case XML_PI_NODE:
13781 		if (cur->type == XML_ELEMENT_NODE) {
13782 		    ret = xmlStreamPush(patstream, cur->name,
13783 				(cur->ns ? cur->ns->href : NULL));
13784 		} else if (eval_all_nodes)
13785 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13786 		else
13787 		    break;
13788 
13789 		if (ret < 0) {
13790 		    /* NOP. */
13791 		} else if (ret == 1) {
13792 		    if (toBool)
13793 			goto return_1;
13794 		    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13795 		        < 0) {
13796 			ctxt->lastError.domain = XML_FROM_XPATH;
13797 			ctxt->lastError.code = XML_ERR_NO_MEMORY;
13798 		    }
13799 		}
13800 		if ((cur->children == NULL) || (depth >= max_depth)) {
13801 		    ret = xmlStreamPop(patstream);
13802 		    while (cur->next != NULL) {
13803 			cur = cur->next;
13804 			if ((cur->type != XML_ENTITY_DECL) &&
13805 			    (cur->type != XML_DTD_NODE))
13806 			    goto next_node;
13807 		    }
13808 		}
13809 	    default:
13810 		break;
13811 	}
13812 
13813 scan_children:
13814 	if (cur->type == XML_NAMESPACE_DECL) break;
13815 	if ((cur->children != NULL) && (depth < max_depth)) {
13816 	    /*
13817 	     * Do not descend on entities declarations
13818 	     */
13819 	    if (cur->children->type != XML_ENTITY_DECL) {
13820 		cur = cur->children;
13821 		depth++;
13822 		/*
13823 		 * Skip DTDs
13824 		 */
13825 		if (cur->type != XML_DTD_NODE)
13826 		    continue;
13827 	    }
13828 	}
13829 
13830 	if (cur == limit)
13831 	    break;
13832 
13833 	while (cur->next != NULL) {
13834 	    cur = cur->next;
13835 	    if ((cur->type != XML_ENTITY_DECL) &&
13836 		(cur->type != XML_DTD_NODE))
13837 		goto next_node;
13838 	}
13839 
13840 	do {
13841 	    cur = cur->parent;
13842 	    depth--;
13843 	    if ((cur == NULL) || (cur == limit) ||
13844                 (cur->type == XML_DOCUMENT_NODE))
13845 	        goto done;
13846 	    if (cur->type == XML_ELEMENT_NODE) {
13847 		ret = xmlStreamPop(patstream);
13848 	    } else if ((eval_all_nodes) &&
13849 		((cur->type == XML_TEXT_NODE) ||
13850 		 (cur->type == XML_CDATA_SECTION_NODE) ||
13851 		 (cur->type == XML_COMMENT_NODE) ||
13852 		 (cur->type == XML_PI_NODE)))
13853 	    {
13854 		ret = xmlStreamPop(patstream);
13855 	    }
13856 	    if (cur->next != NULL) {
13857 		cur = cur->next;
13858 		break;
13859 	    }
13860 	} while (cur != NULL);
13861 
13862     } while ((cur != NULL) && (depth >= 0));
13863 
13864 done:
13865 
13866 #if 0
13867     printf("stream eval: checked %d nodes selected %d\n",
13868            nb_nodes, retObj->nodesetval->nodeNr);
13869 #endif
13870 
13871     if (patstream)
13872 	xmlFreeStreamCtxt(patstream);
13873     return(0);
13874 
13875 return_1:
13876     if (patstream)
13877 	xmlFreeStreamCtxt(patstream);
13878     return(1);
13879 }
13880 #endif /* XPATH_STREAMING */
13881 
13882 /**
13883  * xmlXPathRunEval:
13884  * @ctxt:  the XPath parser context with the compiled expression
13885  * @toBool:  evaluate to a boolean result
13886  *
13887  * Evaluate the Precompiled XPath expression in the given context.
13888  */
13889 static int
xmlXPathRunEval(xmlXPathParserContextPtr ctxt,int toBool)13890 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13891 {
13892     xmlXPathCompExprPtr comp;
13893 
13894     if ((ctxt == NULL) || (ctxt->comp == NULL))
13895 	return(-1);
13896 
13897     ctxt->context->depth = 0;
13898 
13899     if (ctxt->valueTab == NULL) {
13900 	/* Allocate the value stack */
13901 	ctxt->valueTab = (xmlXPathObjectPtr *)
13902 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13903 	if (ctxt->valueTab == NULL) {
13904 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13905 	    xmlFree(ctxt);
13906 	}
13907 	ctxt->valueNr = 0;
13908 	ctxt->valueMax = 10;
13909 	ctxt->value = NULL;
13910         ctxt->valueFrame = 0;
13911     }
13912 #ifdef XPATH_STREAMING
13913     if (ctxt->comp->stream) {
13914 	int res;
13915 
13916 	if (toBool) {
13917 	    /*
13918 	    * Evaluation to boolean result.
13919 	    */
13920 	    res = xmlXPathRunStreamEval(ctxt->context,
13921 		ctxt->comp->stream, NULL, 1);
13922 	    if (res != -1)
13923 		return(res);
13924 	} else {
13925 	    xmlXPathObjectPtr resObj = NULL;
13926 
13927 	    /*
13928 	    * Evaluation to a sequence.
13929 	    */
13930 	    res = xmlXPathRunStreamEval(ctxt->context,
13931 		ctxt->comp->stream, &resObj, 0);
13932 
13933 	    if ((res != -1) && (resObj != NULL)) {
13934 		valuePush(ctxt, resObj);
13935 		return(0);
13936 	    }
13937 	    if (resObj != NULL)
13938 		xmlXPathReleaseObject(ctxt->context, resObj);
13939 	}
13940 	/*
13941 	* QUESTION TODO: This falls back to normal XPath evaluation
13942 	* if res == -1. Is this intended?
13943 	*/
13944     }
13945 #endif
13946     comp = ctxt->comp;
13947     if (comp->last < 0) {
13948 	xmlGenericError(xmlGenericErrorContext,
13949 	    "xmlXPathRunEval: last is less than zero\n");
13950 	return(-1);
13951     }
13952     if (toBool)
13953 	return(xmlXPathCompOpEvalToBoolean(ctxt,
13954 	    &comp->steps[comp->last], 0));
13955     else
13956 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13957 
13958     return(0);
13959 }
13960 
13961 /************************************************************************
13962  *									*
13963  *			Public interfaces				*
13964  *									*
13965  ************************************************************************/
13966 
13967 /**
13968  * xmlXPathEvalPredicate:
13969  * @ctxt:  the XPath context
13970  * @res:  the Predicate Expression evaluation result
13971  *
13972  * Evaluate a predicate result for the current node.
13973  * A PredicateExpr is evaluated by evaluating the Expr and converting
13974  * the result to a boolean. If the result is a number, the result will
13975  * be converted to true if the number is equal to the position of the
13976  * context node in the context node list (as returned by the position
13977  * function) and will be converted to false otherwise; if the result
13978  * is not a number, then the result will be converted as if by a call
13979  * to the boolean function.
13980  *
13981  * Returns 1 if predicate is true, 0 otherwise
13982  */
13983 int
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt,xmlXPathObjectPtr res)13984 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13985     if ((ctxt == NULL) || (res == NULL)) return(0);
13986     switch (res->type) {
13987         case XPATH_BOOLEAN:
13988 	    return(res->boolval);
13989         case XPATH_NUMBER:
13990 	    return(res->floatval == ctxt->proximityPosition);
13991         case XPATH_NODESET:
13992         case XPATH_XSLT_TREE:
13993 	    if (res->nodesetval == NULL)
13994 		return(0);
13995 	    return(res->nodesetval->nodeNr != 0);
13996         case XPATH_STRING:
13997 	    return((res->stringval != NULL) &&
13998 	           (xmlStrlen(res->stringval) != 0));
13999         default:
14000 	    STRANGE
14001     }
14002     return(0);
14003 }
14004 
14005 /**
14006  * xmlXPathEvaluatePredicateResult:
14007  * @ctxt:  the XPath Parser context
14008  * @res:  the Predicate Expression evaluation result
14009  *
14010  * Evaluate a predicate result for the current node.
14011  * A PredicateExpr is evaluated by evaluating the Expr and converting
14012  * the result to a boolean. If the result is a number, the result will
14013  * be converted to true if the number is equal to the position of the
14014  * context node in the context node list (as returned by the position
14015  * function) and will be converted to false otherwise; if the result
14016  * is not a number, then the result will be converted as if by a call
14017  * to the boolean function.
14018  *
14019  * Returns 1 if predicate is true, 0 otherwise
14020  */
14021 int
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr res)14022 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14023                                 xmlXPathObjectPtr res) {
14024     if ((ctxt == NULL) || (res == NULL)) return(0);
14025     switch (res->type) {
14026         case XPATH_BOOLEAN:
14027 	    return(res->boolval);
14028         case XPATH_NUMBER:
14029 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14030 	    return((res->floatval == ctxt->context->proximityPosition) &&
14031 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14032 #else
14033 	    return(res->floatval == ctxt->context->proximityPosition);
14034 #endif
14035         case XPATH_NODESET:
14036         case XPATH_XSLT_TREE:
14037 	    if (res->nodesetval == NULL)
14038 		return(0);
14039 	    return(res->nodesetval->nodeNr != 0);
14040         case XPATH_STRING:
14041 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
14042 #ifdef LIBXML_XPTR_ENABLED
14043 	case XPATH_LOCATIONSET:{
14044 	    xmlLocationSetPtr ptr = res->user;
14045 	    if (ptr == NULL)
14046 	        return(0);
14047 	    return (ptr->locNr != 0);
14048 	    }
14049 #endif
14050         default:
14051 	    STRANGE
14052     }
14053     return(0);
14054 }
14055 
14056 #ifdef XPATH_STREAMING
14057 /**
14058  * xmlXPathTryStreamCompile:
14059  * @ctxt: an XPath context
14060  * @str:  the XPath expression
14061  *
14062  * Try to compile the XPath expression as a streamable subset.
14063  *
14064  * Returns the compiled expression or NULL if failed to compile.
14065  */
14066 static xmlXPathCompExprPtr
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14067 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14068     /*
14069      * Optimization: use streaming patterns when the XPath expression can
14070      * be compiled to a stream lookup
14071      */
14072     xmlPatternPtr stream;
14073     xmlXPathCompExprPtr comp;
14074     xmlDictPtr dict = NULL;
14075     const xmlChar **namespaces = NULL;
14076     xmlNsPtr ns;
14077     int i, j;
14078 
14079     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14080         (!xmlStrchr(str, '@'))) {
14081 	const xmlChar *tmp;
14082 
14083 	/*
14084 	 * We don't try to handle expressions using the verbose axis
14085 	 * specifiers ("::"), just the simplified form at this point.
14086 	 * Additionally, if there is no list of namespaces available and
14087 	 *  there's a ":" in the expression, indicating a prefixed QName,
14088 	 *  then we won't try to compile either. xmlPatterncompile() needs
14089 	 *  to have a list of namespaces at compilation time in order to
14090 	 *  compile prefixed name tests.
14091 	 */
14092 	tmp = xmlStrchr(str, ':');
14093 	if ((tmp != NULL) &&
14094 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14095 	    return(NULL);
14096 
14097 	if (ctxt != NULL) {
14098 	    dict = ctxt->dict;
14099 	    if (ctxt->nsNr > 0) {
14100 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14101 		if (namespaces == NULL) {
14102 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14103 		    return(NULL);
14104 		}
14105 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14106 		    ns = ctxt->namespaces[j];
14107 		    namespaces[i++] = ns->href;
14108 		    namespaces[i++] = ns->prefix;
14109 		}
14110 		namespaces[i++] = NULL;
14111 		namespaces[i] = NULL;
14112 	    }
14113 	}
14114 
14115 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14116 	if (namespaces != NULL) {
14117 	    xmlFree((xmlChar **)namespaces);
14118 	}
14119 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14120 	    comp = xmlXPathNewCompExpr();
14121 	    if (comp == NULL) {
14122 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14123 		return(NULL);
14124 	    }
14125 	    comp->stream = stream;
14126 	    comp->dict = dict;
14127 	    if (comp->dict)
14128 		xmlDictReference(comp->dict);
14129 	    return(comp);
14130 	}
14131 	xmlFreePattern(stream);
14132     }
14133     return(NULL);
14134 }
14135 #endif /* XPATH_STREAMING */
14136 
14137 static void
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,xmlXPathStepOpPtr op)14138 xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14139                            xmlXPathStepOpPtr op)
14140 {
14141     xmlXPathCompExprPtr comp = pctxt->comp;
14142     xmlXPathContextPtr ctxt;
14143 
14144     /*
14145     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14146     * internal representation.
14147     */
14148 
14149     if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14150         (op->ch1 != -1) &&
14151         (op->ch2 == -1 /* no predicate */))
14152     {
14153         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14154 
14155         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14156             ((xmlXPathAxisVal) prevop->value ==
14157                 AXIS_DESCENDANT_OR_SELF) &&
14158             (prevop->ch2 == -1) &&
14159             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14160             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14161         {
14162             /*
14163             * This is a "descendant-or-self::node()" without predicates.
14164             * Try to eliminate it.
14165             */
14166 
14167             switch ((xmlXPathAxisVal) op->value) {
14168                 case AXIS_CHILD:
14169                 case AXIS_DESCENDANT:
14170                     /*
14171                     * Convert "descendant-or-self::node()/child::" or
14172                     * "descendant-or-self::node()/descendant::" to
14173                     * "descendant::"
14174                     */
14175                     op->ch1   = prevop->ch1;
14176                     op->value = AXIS_DESCENDANT;
14177                     break;
14178                 case AXIS_SELF:
14179                 case AXIS_DESCENDANT_OR_SELF:
14180                     /*
14181                     * Convert "descendant-or-self::node()/self::" or
14182                     * "descendant-or-self::node()/descendant-or-self::" to
14183                     * to "descendant-or-self::"
14184                     */
14185                     op->ch1   = prevop->ch1;
14186                     op->value = AXIS_DESCENDANT_OR_SELF;
14187                     break;
14188                 default:
14189                     break;
14190             }
14191 	}
14192     }
14193 
14194     /* OP_VALUE has invalid ch1. */
14195     if (op->op == XPATH_OP_VALUE)
14196         return;
14197 
14198     /* Recurse */
14199     ctxt = pctxt->context;
14200     if (ctxt != NULL) {
14201         if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14202             return;
14203         ctxt->depth += 1;
14204     }
14205     if (op->ch1 != -1)
14206         xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14207     if (op->ch2 != -1)
14208 	xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14209     if (ctxt != NULL)
14210         ctxt->depth -= 1;
14211 }
14212 
14213 /**
14214  * xmlXPathCtxtCompile:
14215  * @ctxt: an XPath context
14216  * @str:  the XPath expression
14217  *
14218  * Compile an XPath expression
14219  *
14220  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14221  *         the caller has to free the object.
14222  */
14223 xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14224 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14225     xmlXPathParserContextPtr pctxt;
14226     xmlXPathCompExprPtr comp;
14227 
14228 #ifdef XPATH_STREAMING
14229     comp = xmlXPathTryStreamCompile(ctxt, str);
14230     if (comp != NULL)
14231         return(comp);
14232 #endif
14233 
14234     xmlInitParser();
14235 
14236     pctxt = xmlXPathNewParserContext(str, ctxt);
14237     if (pctxt == NULL)
14238         return NULL;
14239     if (ctxt != NULL)
14240         ctxt->depth = 0;
14241     xmlXPathCompileExpr(pctxt, 1);
14242 
14243     if( pctxt->error != XPATH_EXPRESSION_OK )
14244     {
14245         xmlXPathFreeParserContext(pctxt);
14246         return(NULL);
14247     }
14248 
14249     if (*pctxt->cur != 0) {
14250 	/*
14251 	 * aleksey: in some cases this line prints *second* error message
14252 	 * (see bug #78858) and probably this should be fixed.
14253 	 * However, we are not sure that all error messages are printed
14254 	 * out in other places. It's not critical so we leave it as-is for now
14255 	 */
14256 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14257 	comp = NULL;
14258     } else {
14259 	comp = pctxt->comp;
14260 	if ((comp->nbStep > 1) && (comp->last >= 0)) {
14261             if (ctxt != NULL)
14262                 ctxt->depth = 0;
14263 	    xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14264 	}
14265 	pctxt->comp = NULL;
14266     }
14267     xmlXPathFreeParserContext(pctxt);
14268 
14269     if (comp != NULL) {
14270 	comp->expr = xmlStrdup(str);
14271 #ifdef DEBUG_EVAL_COUNTS
14272 	comp->string = xmlStrdup(str);
14273 	comp->nb = 0;
14274 #endif
14275     }
14276     return(comp);
14277 }
14278 
14279 /**
14280  * xmlXPathCompile:
14281  * @str:  the XPath expression
14282  *
14283  * Compile an XPath expression
14284  *
14285  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14286  *         the caller has to free the object.
14287  */
14288 xmlXPathCompExprPtr
xmlXPathCompile(const xmlChar * str)14289 xmlXPathCompile(const xmlChar *str) {
14290     return(xmlXPathCtxtCompile(NULL, str));
14291 }
14292 
14293 /**
14294  * xmlXPathCompiledEvalInternal:
14295  * @comp:  the compiled XPath expression
14296  * @ctxt:  the XPath context
14297  * @resObj: the resulting XPath object or NULL
14298  * @toBool: 1 if only a boolean result is requested
14299  *
14300  * Evaluate the Precompiled XPath expression in the given context.
14301  * The caller has to free @resObj.
14302  *
14303  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14304  *         the caller has to free the object.
14305  */
14306 static int
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt,xmlXPathObjectPtr * resObjPtr,int toBool)14307 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14308 			     xmlXPathContextPtr ctxt,
14309 			     xmlXPathObjectPtr *resObjPtr,
14310 			     int toBool)
14311 {
14312     xmlXPathParserContextPtr pctxt;
14313     xmlXPathObjectPtr resObj;
14314 #ifndef LIBXML_THREAD_ENABLED
14315     static int reentance = 0;
14316 #endif
14317     int res;
14318 
14319     CHECK_CTXT_NEG(ctxt)
14320 
14321     if (comp == NULL)
14322 	return(-1);
14323     xmlInitParser();
14324 
14325 #ifndef LIBXML_THREAD_ENABLED
14326     reentance++;
14327     if (reentance > 1)
14328 	xmlXPathDisableOptimizer = 1;
14329 #endif
14330 
14331 #ifdef DEBUG_EVAL_COUNTS
14332     comp->nb++;
14333     if ((comp->string != NULL) && (comp->nb > 100)) {
14334 	fprintf(stderr, "100 x %s\n", comp->string);
14335 	comp->nb = 0;
14336     }
14337 #endif
14338     pctxt = xmlXPathCompParserContext(comp, ctxt);
14339     res = xmlXPathRunEval(pctxt, toBool);
14340 
14341     if (pctxt->error != XPATH_EXPRESSION_OK) {
14342         resObj = NULL;
14343     } else {
14344         resObj = valuePop(pctxt);
14345         if (resObj == NULL) {
14346             if (!toBool)
14347                 xmlGenericError(xmlGenericErrorContext,
14348                     "xmlXPathCompiledEval: No result on the stack.\n");
14349         } else if (pctxt->valueNr > 0) {
14350             xmlGenericError(xmlGenericErrorContext,
14351                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14352                 pctxt->valueNr);
14353         }
14354     }
14355 
14356     if (resObjPtr)
14357         *resObjPtr = resObj;
14358     else
14359         xmlXPathReleaseObject(ctxt, resObj);
14360 
14361     pctxt->comp = NULL;
14362     xmlXPathFreeParserContext(pctxt);
14363 #ifndef LIBXML_THREAD_ENABLED
14364     reentance--;
14365 #endif
14366 
14367     return(res);
14368 }
14369 
14370 /**
14371  * xmlXPathCompiledEval:
14372  * @comp:  the compiled XPath expression
14373  * @ctx:  the XPath context
14374  *
14375  * Evaluate the Precompiled XPath expression in the given context.
14376  *
14377  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14378  *         the caller has to free the object.
14379  */
14380 xmlXPathObjectPtr
xmlXPathCompiledEval(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctx)14381 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14382 {
14383     xmlXPathObjectPtr res = NULL;
14384 
14385     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14386     return(res);
14387 }
14388 
14389 /**
14390  * xmlXPathCompiledEvalToBoolean:
14391  * @comp:  the compiled XPath expression
14392  * @ctxt:  the XPath context
14393  *
14394  * Applies the XPath boolean() function on the result of the given
14395  * compiled expression.
14396  *
14397  * Returns 1 if the expression evaluated to true, 0 if to false and
14398  *         -1 in API and internal errors.
14399  */
14400 int
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)14401 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14402 			      xmlXPathContextPtr ctxt)
14403 {
14404     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14405 }
14406 
14407 /**
14408  * xmlXPathEvalExpr:
14409  * @ctxt:  the XPath Parser context
14410  *
14411  * Parse and evaluate an XPath expression in the given context,
14412  * then push the result on the context stack
14413  */
14414 void
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt)14415 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14416 #ifdef XPATH_STREAMING
14417     xmlXPathCompExprPtr comp;
14418 #endif
14419 
14420     if (ctxt == NULL) return;
14421 
14422 #ifdef XPATH_STREAMING
14423     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14424     if (comp != NULL) {
14425         if (ctxt->comp != NULL)
14426 	    xmlXPathFreeCompExpr(ctxt->comp);
14427         ctxt->comp = comp;
14428     } else
14429 #endif
14430     {
14431         if (ctxt->context != NULL)
14432             ctxt->context->depth = 0;
14433 	xmlXPathCompileExpr(ctxt, 1);
14434         CHECK_ERROR;
14435 
14436         /* Check for trailing characters. */
14437         if (*ctxt->cur != 0)
14438             XP_ERROR(XPATH_EXPR_ERROR);
14439 
14440 	if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14441             if (ctxt->context != NULL)
14442                 ctxt->context->depth = 0;
14443 	    xmlXPathOptimizeExpression(ctxt,
14444 		&ctxt->comp->steps[ctxt->comp->last]);
14445         }
14446     }
14447 
14448     xmlXPathRunEval(ctxt, 0);
14449 }
14450 
14451 /**
14452  * xmlXPathEval:
14453  * @str:  the XPath expression
14454  * @ctx:  the XPath context
14455  *
14456  * Evaluate the XPath Location Path in the given context.
14457  *
14458  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14459  *         the caller has to free the object.
14460  */
14461 xmlXPathObjectPtr
xmlXPathEval(const xmlChar * str,xmlXPathContextPtr ctx)14462 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14463     xmlXPathParserContextPtr ctxt;
14464     xmlXPathObjectPtr res;
14465 
14466     CHECK_CTXT(ctx)
14467 
14468     xmlInitParser();
14469 
14470     ctxt = xmlXPathNewParserContext(str, ctx);
14471     if (ctxt == NULL)
14472         return NULL;
14473     xmlXPathEvalExpr(ctxt);
14474 
14475     if (ctxt->error != XPATH_EXPRESSION_OK) {
14476 	res = NULL;
14477     } else {
14478 	res = valuePop(ctxt);
14479         if (res == NULL) {
14480             xmlGenericError(xmlGenericErrorContext,
14481                 "xmlXPathCompiledEval: No result on the stack.\n");
14482         } else if (ctxt->valueNr > 0) {
14483             xmlGenericError(xmlGenericErrorContext,
14484                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14485                 ctxt->valueNr);
14486         }
14487     }
14488 
14489     xmlXPathFreeParserContext(ctxt);
14490     return(res);
14491 }
14492 
14493 /**
14494  * xmlXPathSetContextNode:
14495  * @node: the node to to use as the context node
14496  * @ctx:  the XPath context
14497  *
14498  * Sets 'node' as the context node. The node must be in the same
14499  * document as that associated with the context.
14500  *
14501  * Returns -1 in case of error or 0 if successful
14502  */
14503 int
xmlXPathSetContextNode(xmlNodePtr node,xmlXPathContextPtr ctx)14504 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14505     if ((node == NULL) || (ctx == NULL))
14506         return(-1);
14507 
14508     if (node->doc == ctx->doc) {
14509         ctx->node = node;
14510 	return(0);
14511     }
14512     return(-1);
14513 }
14514 
14515 /**
14516  * xmlXPathNodeEval:
14517  * @node: the node to to use as the context node
14518  * @str:  the XPath expression
14519  * @ctx:  the XPath context
14520  *
14521  * Evaluate the XPath Location Path in the given context. The node 'node'
14522  * is set as the context node. The context node is not restored.
14523  *
14524  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14525  *         the caller has to free the object.
14526  */
14527 xmlXPathObjectPtr
xmlXPathNodeEval(xmlNodePtr node,const xmlChar * str,xmlXPathContextPtr ctx)14528 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14529     if (str == NULL)
14530         return(NULL);
14531     if (xmlXPathSetContextNode(node, ctx) < 0)
14532         return(NULL);
14533     return(xmlXPathEval(str, ctx));
14534 }
14535 
14536 /**
14537  * xmlXPathEvalExpression:
14538  * @str:  the XPath expression
14539  * @ctxt:  the XPath context
14540  *
14541  * Alias for xmlXPathEval().
14542  *
14543  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14544  *         the caller has to free the object.
14545  */
14546 xmlXPathObjectPtr
xmlXPathEvalExpression(const xmlChar * str,xmlXPathContextPtr ctxt)14547 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14548     return(xmlXPathEval(str, ctxt));
14549 }
14550 
14551 /************************************************************************
14552  *									*
14553  *	Extra functions not pertaining to the XPath spec		*
14554  *									*
14555  ************************************************************************/
14556 /**
14557  * xmlXPathEscapeUriFunction:
14558  * @ctxt:  the XPath Parser context
14559  * @nargs:  the number of arguments
14560  *
14561  * Implement the escape-uri() XPath function
14562  *    string escape-uri(string $str, bool $escape-reserved)
14563  *
14564  * This function applies the URI escaping rules defined in section 2 of [RFC
14565  * 2396] to the string supplied as $uri-part, which typically represents all
14566  * or part of a URI. The effect of the function is to replace any special
14567  * character in the string by an escape sequence of the form %xx%yy...,
14568  * where xxyy... is the hexadecimal representation of the octets used to
14569  * represent the character in UTF-8.
14570  *
14571  * The set of characters that are escaped depends on the setting of the
14572  * boolean argument $escape-reserved.
14573  *
14574  * If $escape-reserved is true, all characters are escaped other than lower
14575  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14576  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14577  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14578  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14579  * A-F).
14580  *
14581  * If $escape-reserved is false, the behavior differs in that characters
14582  * referred to in [RFC 2396] as reserved characters are not escaped. These
14583  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14584  *
14585  * [RFC 2396] does not define whether escaped URIs should use lower case or
14586  * upper case for hexadecimal digits. To ensure that escaped URIs can be
14587  * compared using string comparison functions, this function must always use
14588  * the upper-case letters A-F.
14589  *
14590  * Generally, $escape-reserved should be set to true when escaping a string
14591  * that is to form a single part of a URI, and to false when escaping an
14592  * entire URI or URI reference.
14593  *
14594  * In the case of non-ascii characters, the string is encoded according to
14595  * utf-8 and then converted according to RFC 2396.
14596  *
14597  * Examples
14598  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14599  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14600  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14601  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14602  *
14603  */
14604 static void
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt,int nargs)14605 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14606     xmlXPathObjectPtr str;
14607     int escape_reserved;
14608     xmlBufPtr target;
14609     xmlChar *cptr;
14610     xmlChar escape[4];
14611 
14612     CHECK_ARITY(2);
14613 
14614     escape_reserved = xmlXPathPopBoolean(ctxt);
14615 
14616     CAST_TO_STRING;
14617     str = valuePop(ctxt);
14618 
14619     target = xmlBufCreate();
14620 
14621     escape[0] = '%';
14622     escape[3] = 0;
14623 
14624     if (target) {
14625 	for (cptr = str->stringval; *cptr; cptr++) {
14626 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
14627 		(*cptr >= 'a' && *cptr <= 'z') ||
14628 		(*cptr >= '0' && *cptr <= '9') ||
14629 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
14630 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
14631 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14632 		(*cptr == '%' &&
14633 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14634 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14635 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
14636 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14637 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14638 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14639 		(!escape_reserved &&
14640 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14641 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14642 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14643 		  *cptr == ','))) {
14644 		xmlBufAdd(target, cptr, 1);
14645 	    } else {
14646 		if ((*cptr >> 4) < 10)
14647 		    escape[1] = '0' + (*cptr >> 4);
14648 		else
14649 		    escape[1] = 'A' - 10 + (*cptr >> 4);
14650 		if ((*cptr & 0xF) < 10)
14651 		    escape[2] = '0' + (*cptr & 0xF);
14652 		else
14653 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
14654 
14655 		xmlBufAdd(target, &escape[0], 3);
14656 	    }
14657 	}
14658     }
14659     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14660 	xmlBufContent(target)));
14661     xmlBufFree(target);
14662     xmlXPathReleaseObject(ctxt->context, str);
14663 }
14664 
14665 /**
14666  * xmlXPathRegisterAllFunctions:
14667  * @ctxt:  the XPath context
14668  *
14669  * Registers all default XPath functions in this context
14670  */
14671 void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)14672 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14673 {
14674     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14675                          xmlXPathBooleanFunction);
14676     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14677                          xmlXPathCeilingFunction);
14678     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14679                          xmlXPathCountFunction);
14680     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14681                          xmlXPathConcatFunction);
14682     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14683                          xmlXPathContainsFunction);
14684     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14685                          xmlXPathIdFunction);
14686     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14687                          xmlXPathFalseFunction);
14688     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14689                          xmlXPathFloorFunction);
14690     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14691                          xmlXPathLastFunction);
14692     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14693                          xmlXPathLangFunction);
14694     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14695                          xmlXPathLocalNameFunction);
14696     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14697                          xmlXPathNotFunction);
14698     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14699                          xmlXPathNameFunction);
14700     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14701                          xmlXPathNamespaceURIFunction);
14702     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14703                          xmlXPathNormalizeFunction);
14704     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14705                          xmlXPathNumberFunction);
14706     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14707                          xmlXPathPositionFunction);
14708     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14709                          xmlXPathRoundFunction);
14710     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14711                          xmlXPathStringFunction);
14712     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14713                          xmlXPathStringLengthFunction);
14714     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14715                          xmlXPathStartsWithFunction);
14716     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14717                          xmlXPathSubstringFunction);
14718     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14719                          xmlXPathSubstringBeforeFunction);
14720     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14721                          xmlXPathSubstringAfterFunction);
14722     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14723                          xmlXPathSumFunction);
14724     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14725                          xmlXPathTrueFunction);
14726     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14727                          xmlXPathTranslateFunction);
14728 
14729     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14730 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14731                          xmlXPathEscapeUriFunction);
14732 }
14733 
14734 #endif /* LIBXML_XPATH_ENABLED */
14735 #define bottom_xpath
14736 #include "elfgcchack.h"
14737