• 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 #include <math.h>
29 #include <float.h>
30 #include <ctype.h>
31 
32 #include <libxml/xmlmemory.h>
33 #include <libxml/tree.h>
34 #include <libxml/xpath.h>
35 #include <libxml/xpathInternals.h>
36 #include <libxml/parserInternals.h>
37 #include <libxml/hash.h>
38 #ifdef LIBXML_XPTR_LOCS_ENABLED
39 #include <libxml/xpointer.h>
40 #endif
41 #ifdef LIBXML_DEBUG_ENABLED
42 #include <libxml/debugXML.h>
43 #endif
44 #include <libxml/xmlerror.h>
45 #include <libxml/threads.h>
46 #ifdef LIBXML_PATTERN_ENABLED
47 #include <libxml/pattern.h>
48 #endif
49 
50 #include "private/buf.h"
51 #include "private/error.h"
52 #include "private/xpath.h"
53 
54 #ifdef LIBXML_PATTERN_ENABLED
55 #define XPATH_STREAMING
56 #endif
57 
58 #define TODO								\
59     xmlGenericError(xmlGenericErrorContext,				\
60 	    "Unimplemented block at %s:%d\n",				\
61             __FILE__, __LINE__);
62 
63 /**
64  * WITH_TIM_SORT:
65  *
66  * Use the Timsort algorithm provided in timsort.h to sort
67  * nodeset as this is a great improvement over the old Shell sort
68  * used in xmlXPathNodeSetSort()
69  */
70 #define WITH_TIM_SORT
71 
72 /*
73 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
74 * If defined, this will use xmlXPathCmpNodesExt() instead of
75 * xmlXPathCmpNodes(). The new function is optimized comparison of
76 * non-element nodes; actually it will speed up comparison only if
77 * xmlXPathOrderDocElems() was called in order to index the elements of
78 * a tree in document order; Libxslt does such an indexing, thus it will
79 * benefit from this optimization.
80 */
81 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
82 
83 /*
84 * XP_OPTIMIZED_FILTER_FIRST:
85 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
86 * in a way, that it stop evaluation at the first node.
87 */
88 #define XP_OPTIMIZED_FILTER_FIRST
89 
90 /*
91  * XPATH_MAX_STEPS:
92  * when compiling an XPath expression we arbitrary limit the maximum
93  * number of step operation in the compiled expression. 1000000 is
94  * an insanely large value which should never be reached under normal
95  * circumstances
96  */
97 #define XPATH_MAX_STEPS 1000000
98 
99 /*
100  * XPATH_MAX_STACK_DEPTH:
101  * when evaluating an XPath expression we arbitrary limit the maximum
102  * number of object allowed to be pushed on the stack. 1000000 is
103  * an insanely large value which should never be reached under normal
104  * circumstances
105  */
106 #define XPATH_MAX_STACK_DEPTH 1000000
107 
108 /*
109  * XPATH_MAX_NODESET_LENGTH:
110  * when evaluating an XPath expression nodesets are created and we
111  * arbitrary limit the maximum length of those node set. 10000000 is
112  * an insanely large value which should never be reached under normal
113  * circumstances, one would first need to construct an in memory tree
114  * with more than 10 millions nodes.
115  */
116 #define XPATH_MAX_NODESET_LENGTH 10000000
117 
118 /*
119  * XPATH_MAX_RECRUSION_DEPTH:
120  * Maximum amount of nested functions calls when parsing or evaluating
121  * expressions
122  */
123 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
124 #define XPATH_MAX_RECURSION_DEPTH 500
125 #elif defined(_WIN32)
126 /* Windows typically limits stack size to 1MB. */
127 #define XPATH_MAX_RECURSION_DEPTH 1000
128 #else
129 #define XPATH_MAX_RECURSION_DEPTH 5000
130 #endif
131 
132 /*
133  * TODO:
134  * There are a few spots where some tests are done which depend upon ascii
135  * data.  These should be enhanced for full UTF8 support (see particularly
136  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
137  */
138 
139 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
140 
141 /************************************************************************
142  *									*
143  *			Floating point stuff				*
144  *									*
145  ************************************************************************/
146 
147 double xmlXPathNAN = 0.0;
148 double xmlXPathPINF = 0.0;
149 double xmlXPathNINF = 0.0;
150 
151 /**
152  * xmlXPathInit:
153  *
154  * DEPRECATED: Alias for xmlInitParser.
155  */
156 void
xmlXPathInit(void)157 xmlXPathInit(void) {
158     xmlInitParser();
159 }
160 
161 /**
162  * xmlInitXPathInternal:
163  *
164  * Initialize the XPath environment
165  */
166 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
167 void
xmlInitXPathInternal(void)168 xmlInitXPathInternal(void) {
169 #if defined(NAN) && defined(INFINITY)
170     xmlXPathNAN = NAN;
171     xmlXPathPINF = INFINITY;
172     xmlXPathNINF = -INFINITY;
173 #else
174     /* MSVC doesn't allow division by zero in constant expressions. */
175     double zero = 0.0;
176     xmlXPathNAN = 0.0 / zero;
177     xmlXPathPINF = 1.0 / zero;
178     xmlXPathNINF = -xmlXPathPINF;
179 #endif
180 }
181 
182 /**
183  * xmlXPathIsNaN:
184  * @val:  a double value
185  *
186  * Checks whether a double is a NaN.
187  *
188  * Returns 1 if the value is a NaN, 0 otherwise
189  */
190 int
xmlXPathIsNaN(double val)191 xmlXPathIsNaN(double val) {
192 #ifdef isnan
193     return isnan(val);
194 #else
195     return !(val == val);
196 #endif
197 }
198 
199 /**
200  * xmlXPathIsInf:
201  * @val:  a double value
202  *
203  * Checks whether a double is an infinity.
204  *
205  * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
206  */
207 int
xmlXPathIsInf(double val)208 xmlXPathIsInf(double val) {
209 #ifdef isinf
210     return isinf(val) ? (val > 0 ? 1 : -1) : 0;
211 #else
212     if (val >= xmlXPathPINF)
213         return 1;
214     if (val <= -xmlXPathPINF)
215         return -1;
216     return 0;
217 #endif
218 }
219 
220 #endif /* SCHEMAS or XPATH */
221 
222 #ifdef LIBXML_XPATH_ENABLED
223 
224 /*
225  * TODO: when compatibility allows remove all "fake node libxslt" strings
226  *       the test should just be name[0] = ' '
227  */
228 
229 static xmlNs xmlXPathXMLNamespaceStruct = {
230     NULL,
231     XML_NAMESPACE_DECL,
232     XML_XML_NAMESPACE,
233     BAD_CAST "xml",
234     NULL,
235     NULL
236 };
237 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
238 #ifndef LIBXML_THREAD_ENABLED
239 /*
240  * Optimizer is disabled only when threaded apps are detected while
241  * the library ain't compiled for thread safety.
242  */
243 static int xmlXPathDisableOptimizer = 0;
244 #endif
245 
246 static void
247 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes);
248 
249 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
250 /**
251  * xmlXPathCmpNodesExt:
252  * @node1:  the first node
253  * @node2:  the second node
254  *
255  * Compare two nodes w.r.t document order.
256  * This one is optimized for handling of non-element nodes.
257  *
258  * Returns -2 in case of error 1 if first point < second point, 0 if
259  *         it's the same node, -1 otherwise
260  */
261 static int
xmlXPathCmpNodesExt(xmlNodePtr node1,xmlNodePtr node2)262 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
263     int depth1, depth2;
264     int misc = 0, precedence1 = 0, precedence2 = 0;
265     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
266     xmlNodePtr cur, root;
267     ptrdiff_t l1, l2;
268 
269     if ((node1 == NULL) || (node2 == NULL))
270 	return(-2);
271 
272     if (node1 == node2)
273 	return(0);
274 
275     /*
276      * a couple of optimizations which will avoid computations in most cases
277      */
278     switch (node1->type) {
279 	case XML_ELEMENT_NODE:
280 	    if (node2->type == XML_ELEMENT_NODE) {
281 		if ((0 > (ptrdiff_t) node1->content) &&
282 		    (0 > (ptrdiff_t) node2->content) &&
283 		    (node1->doc == node2->doc))
284 		{
285 		    l1 = -((ptrdiff_t) node1->content);
286 		    l2 = -((ptrdiff_t) node2->content);
287 		    if (l1 < l2)
288 			return(1);
289 		    if (l1 > l2)
290 			return(-1);
291 		} else
292 		    goto turtle_comparison;
293 	    }
294 	    break;
295 	case XML_ATTRIBUTE_NODE:
296 	    precedence1 = 1; /* element is owner */
297 	    miscNode1 = node1;
298 	    node1 = node1->parent;
299 	    misc = 1;
300 	    break;
301 	case XML_TEXT_NODE:
302 	case XML_CDATA_SECTION_NODE:
303 	case XML_COMMENT_NODE:
304 	case XML_PI_NODE: {
305 	    miscNode1 = node1;
306 	    /*
307 	    * Find nearest element node.
308 	    */
309 	    if (node1->prev != NULL) {
310 		do {
311 		    node1 = node1->prev;
312 		    if (node1->type == XML_ELEMENT_NODE) {
313 			precedence1 = 3; /* element in prev-sibl axis */
314 			break;
315 		    }
316 		    if (node1->prev == NULL) {
317 			precedence1 = 2; /* element is parent */
318 			/*
319 			* URGENT TODO: Are there any cases, where the
320 			* parent of such a node is not an element node?
321 			*/
322 			node1 = node1->parent;
323 			break;
324 		    }
325 		} while (1);
326 	    } else {
327 		precedence1 = 2; /* element is parent */
328 		node1 = node1->parent;
329 	    }
330 	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
331 		(0 <= (ptrdiff_t) node1->content)) {
332 		/*
333 		* Fallback for whatever case.
334 		*/
335 		node1 = miscNode1;
336 		precedence1 = 0;
337 	    } else
338 		misc = 1;
339 	}
340 	    break;
341 	case XML_NAMESPACE_DECL:
342 	    /*
343 	    * TODO: why do we return 1 for namespace nodes?
344 	    */
345 	    return(1);
346 	default:
347 	    break;
348     }
349     switch (node2->type) {
350 	case XML_ELEMENT_NODE:
351 	    break;
352 	case XML_ATTRIBUTE_NODE:
353 	    precedence2 = 1; /* element is owner */
354 	    miscNode2 = node2;
355 	    node2 = node2->parent;
356 	    misc = 1;
357 	    break;
358 	case XML_TEXT_NODE:
359 	case XML_CDATA_SECTION_NODE:
360 	case XML_COMMENT_NODE:
361 	case XML_PI_NODE: {
362 	    miscNode2 = node2;
363 	    if (node2->prev != NULL) {
364 		do {
365 		    node2 = node2->prev;
366 		    if (node2->type == XML_ELEMENT_NODE) {
367 			precedence2 = 3; /* element in prev-sibl axis */
368 			break;
369 		    }
370 		    if (node2->prev == NULL) {
371 			precedence2 = 2; /* element is parent */
372 			node2 = node2->parent;
373 			break;
374 		    }
375 		} while (1);
376 	    } else {
377 		precedence2 = 2; /* element is parent */
378 		node2 = node2->parent;
379 	    }
380 	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
381 		(0 <= (ptrdiff_t) node2->content))
382 	    {
383 		node2 = miscNode2;
384 		precedence2 = 0;
385 	    } else
386 		misc = 1;
387 	}
388 	    break;
389 	case XML_NAMESPACE_DECL:
390 	    return(1);
391 	default:
392 	    break;
393     }
394     if (misc) {
395 	if (node1 == node2) {
396 	    if (precedence1 == precedence2) {
397 		/*
398 		* The ugly case; but normally there aren't many
399 		* adjacent non-element nodes around.
400 		*/
401 		cur = miscNode2->prev;
402 		while (cur != NULL) {
403 		    if (cur == miscNode1)
404 			return(1);
405 		    if (cur->type == XML_ELEMENT_NODE)
406 			return(-1);
407 		    cur = cur->prev;
408 		}
409 		return (-1);
410 	    } else {
411 		/*
412 		* Evaluate based on higher precedence wrt to the element.
413 		* TODO: This assumes attributes are sorted before content.
414 		*   Is this 100% correct?
415 		*/
416 		if (precedence1 < precedence2)
417 		    return(1);
418 		else
419 		    return(-1);
420 	    }
421 	}
422 	/*
423 	* Special case: One of the helper-elements is contained by the other.
424 	* <foo>
425 	*   <node2>
426 	*     <node1>Text-1(precedence1 == 2)</node1>
427 	*   </node2>
428 	*   Text-6(precedence2 == 3)
429 	* </foo>
430 	*/
431 	if ((precedence2 == 3) && (precedence1 > 1)) {
432 	    cur = node1->parent;
433 	    while (cur) {
434 		if (cur == node2)
435 		    return(1);
436 		cur = cur->parent;
437 	    }
438 	}
439 	if ((precedence1 == 3) && (precedence2 > 1)) {
440 	    cur = node2->parent;
441 	    while (cur) {
442 		if (cur == node1)
443 		    return(-1);
444 		cur = cur->parent;
445 	    }
446 	}
447     }
448 
449     /*
450      * Speedup using document order if available.
451      */
452     if ((node1->type == XML_ELEMENT_NODE) &&
453 	(node2->type == XML_ELEMENT_NODE) &&
454 	(0 > (ptrdiff_t) node1->content) &&
455 	(0 > (ptrdiff_t) node2->content) &&
456 	(node1->doc == node2->doc)) {
457 
458 	l1 = -((ptrdiff_t) node1->content);
459 	l2 = -((ptrdiff_t) node2->content);
460 	if (l1 < l2)
461 	    return(1);
462 	if (l1 > l2)
463 	    return(-1);
464     }
465 
466 turtle_comparison:
467 
468     if (node1 == node2->prev)
469 	return(1);
470     if (node1 == node2->next)
471 	return(-1);
472     /*
473      * compute depth to root
474      */
475     for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
476 	if (cur->parent == node1)
477 	    return(1);
478 	depth2++;
479     }
480     root = cur;
481     for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
482 	if (cur->parent == node2)
483 	    return(-1);
484 	depth1++;
485     }
486     /*
487      * Distinct document (or distinct entities :-( ) case.
488      */
489     if (root != cur) {
490 	return(-2);
491     }
492     /*
493      * get the nearest common ancestor.
494      */
495     while (depth1 > depth2) {
496 	depth1--;
497 	node1 = node1->parent;
498     }
499     while (depth2 > depth1) {
500 	depth2--;
501 	node2 = node2->parent;
502     }
503     while (node1->parent != node2->parent) {
504 	node1 = node1->parent;
505 	node2 = node2->parent;
506 	/* should not happen but just in case ... */
507 	if ((node1 == NULL) || (node2 == NULL))
508 	    return(-2);
509     }
510     /*
511      * Find who's first.
512      */
513     if (node1 == node2->prev)
514 	return(1);
515     if (node1 == node2->next)
516 	return(-1);
517     /*
518      * Speedup using document order if available.
519      */
520     if ((node1->type == XML_ELEMENT_NODE) &&
521 	(node2->type == XML_ELEMENT_NODE) &&
522 	(0 > (ptrdiff_t) node1->content) &&
523 	(0 > (ptrdiff_t) node2->content) &&
524 	(node1->doc == node2->doc)) {
525 
526 	l1 = -((ptrdiff_t) node1->content);
527 	l2 = -((ptrdiff_t) node2->content);
528 	if (l1 < l2)
529 	    return(1);
530 	if (l1 > l2)
531 	    return(-1);
532     }
533 
534     for (cur = node1->next;cur != NULL;cur = cur->next)
535 	if (cur == node2)
536 	    return(1);
537     return(-1); /* assume there is no sibling list corruption */
538 }
539 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
540 
541 /*
542  * Wrapper for the Timsort algorithm from timsort.h
543  */
544 #ifdef WITH_TIM_SORT
545 #define SORT_NAME libxml_domnode
546 #define SORT_TYPE xmlNodePtr
547 /**
548  * wrap_cmp:
549  * @x: a node
550  * @y: another node
551  *
552  * Comparison function for the Timsort implementation
553  *
554  * Returns -2 in case of error -1 if first point < second point, 0 if
555  *         it's the same node, +1 otherwise
556  */
557 static
558 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
559 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
wrap_cmp(xmlNodePtr x,xmlNodePtr y)560     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
561     {
562         int res = xmlXPathCmpNodesExt(x, y);
563         return res == -2 ? res : -res;
564     }
565 #else
wrap_cmp(xmlNodePtr x,xmlNodePtr y)566     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
567     {
568         int res = xmlXPathCmpNodes(x, y);
569         return res == -2 ? res : -res;
570     }
571 #endif
572 #define SORT_CMP(x, y)  (wrap_cmp(x, y))
573 #include "timsort.h"
574 #endif /* WITH_TIM_SORT */
575 
576 /************************************************************************
577  *									*
578  *			Error handling routines				*
579  *									*
580  ************************************************************************/
581 
582 /**
583  * XP_ERRORNULL:
584  * @X:  the error code
585  *
586  * Macro to raise an XPath error and return NULL.
587  */
588 #define XP_ERRORNULL(X)							\
589     { xmlXPathErr(ctxt, X); return(NULL); }
590 
591 /*
592  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
593  */
594 static const char* const xmlXPathErrorMessages[] = {
595     "Ok\n",
596     "Number encoding\n",
597     "Unfinished literal\n",
598     "Start of literal\n",
599     "Expected $ for variable reference\n",
600     "Undefined variable\n",
601     "Invalid predicate\n",
602     "Invalid expression\n",
603     "Missing closing curly brace\n",
604     "Unregistered function\n",
605     "Invalid operand\n",
606     "Invalid type\n",
607     "Invalid number of arguments\n",
608     "Invalid context size\n",
609     "Invalid context position\n",
610     "Memory allocation error\n",
611     "Syntax error\n",
612     "Resource error\n",
613     "Sub resource error\n",
614     "Undefined namespace prefix\n",
615     "Encoding error\n",
616     "Char out of XML range\n",
617     "Invalid or incomplete context\n",
618     "Stack usage error\n",
619     "Forbidden variable\n",
620     "Operation limit exceeded\n",
621     "Recursion limit exceeded\n",
622     "?? Unknown error ??\n"	/* Must be last in the list! */
623 };
624 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
625 		   sizeof(xmlXPathErrorMessages[0])) - 1)
626 /**
627  * xmlXPathErrMemory:
628  * @ctxt:  an XPath context
629  * @extra:  extra information
630  *
631  * Handle a redefinition of attribute error
632  */
633 static void
xmlXPathErrMemory(xmlXPathContextPtr ctxt,const char * extra)634 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
635 {
636     if (ctxt != NULL) {
637         xmlResetError(&ctxt->lastError);
638         if (extra) {
639             xmlChar buf[200];
640 
641             xmlStrPrintf(buf, 200,
642                          "Memory allocation failed : %s\n",
643                          extra);
644             ctxt->lastError.message = (char *) xmlStrdup(buf);
645         } else {
646             ctxt->lastError.message = (char *)
647 	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
648         }
649         ctxt->lastError.domain = XML_FROM_XPATH;
650         ctxt->lastError.code = XML_ERR_NO_MEMORY;
651 	if (ctxt->error != NULL)
652 	    ctxt->error(ctxt->userData, &ctxt->lastError);
653     } else {
654         if (extra)
655             __xmlRaiseError(NULL, NULL, NULL,
656                             NULL, NULL, XML_FROM_XPATH,
657                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
658                             extra, NULL, NULL, 0, 0,
659                             "Memory allocation failed : %s\n", extra);
660         else
661             __xmlRaiseError(NULL, NULL, NULL,
662                             NULL, NULL, XML_FROM_XPATH,
663                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
664                             NULL, NULL, NULL, 0, 0,
665                             "Memory allocation failed\n");
666     }
667 }
668 
669 /**
670  * xmlXPathPErrMemory:
671  * @ctxt:  an XPath parser context
672  * @extra:  extra information
673  *
674  * Handle a redefinition of attribute error
675  */
676 static void
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt,const char * extra)677 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
678 {
679     if (ctxt == NULL)
680 	xmlXPathErrMemory(NULL, extra);
681     else {
682 	ctxt->error = XPATH_MEMORY_ERROR;
683 	xmlXPathErrMemory(ctxt->context, extra);
684     }
685 }
686 
687 /**
688  * xmlXPathErr:
689  * @ctxt:  a XPath parser context
690  * @error:  the error code
691  *
692  * Handle an XPath error
693  */
694 void
xmlXPathErr(xmlXPathParserContextPtr ctxt,int error)695 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
696 {
697     if ((error < 0) || (error > MAXERRNO))
698 	error = MAXERRNO;
699     if (ctxt == NULL) {
700 	__xmlRaiseError(NULL, NULL, NULL,
701 			NULL, NULL, XML_FROM_XPATH,
702 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
703 			XML_ERR_ERROR, NULL, 0,
704 			NULL, NULL, NULL, 0, 0,
705 			"%s", xmlXPathErrorMessages[error]);
706 	return;
707     }
708     /* Only report the first error */
709     if (ctxt->error != 0)
710         return;
711     ctxt->error = error;
712     if (ctxt->context == NULL) {
713 	__xmlRaiseError(NULL, NULL, NULL,
714 			NULL, NULL, XML_FROM_XPATH,
715 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
716 			XML_ERR_ERROR, NULL, 0,
717 			(const char *) ctxt->base, NULL, NULL,
718 			ctxt->cur - ctxt->base, 0,
719 			"%s", xmlXPathErrorMessages[error]);
720 	return;
721     }
722 
723     /* cleanup current last error */
724     xmlResetError(&ctxt->context->lastError);
725 
726     ctxt->context->lastError.domain = XML_FROM_XPATH;
727     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
728                            XPATH_EXPRESSION_OK;
729     ctxt->context->lastError.level = XML_ERR_ERROR;
730     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
731     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
732     ctxt->context->lastError.node = ctxt->context->debugNode;
733     if (ctxt->context->error != NULL) {
734 	ctxt->context->error(ctxt->context->userData,
735 	                     &ctxt->context->lastError);
736     } else {
737 	__xmlRaiseError(NULL, NULL, NULL,
738 			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
739 			error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
740 			XML_ERR_ERROR, NULL, 0,
741 			(const char *) ctxt->base, NULL, NULL,
742 			ctxt->cur - ctxt->base, 0,
743 			"%s", xmlXPathErrorMessages[error]);
744     }
745 
746 }
747 
748 /**
749  * xmlXPatherror:
750  * @ctxt:  the XPath Parser context
751  * @file:  the file name
752  * @line:  the line number
753  * @no:  the error number
754  *
755  * Formats an error message.
756  */
757 void
xmlXPatherror(xmlXPathParserContextPtr ctxt,const char * file ATTRIBUTE_UNUSED,int line ATTRIBUTE_UNUSED,int no)758 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
759               int line ATTRIBUTE_UNUSED, int no) {
760     xmlXPathErr(ctxt, no);
761 }
762 
763 /**
764  * xmlXPathCheckOpLimit:
765  * @ctxt:  the XPath Parser context
766  * @opCount:  the number of operations to be added
767  *
768  * Adds opCount to the running total of operations and returns -1 if the
769  * operation limit is exceeded. Returns 0 otherwise.
770  */
771 static int
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt,unsigned long opCount)772 xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
773     xmlXPathContextPtr xpctxt = ctxt->context;
774 
775     if ((opCount > xpctxt->opLimit) ||
776         (xpctxt->opCount > xpctxt->opLimit - opCount)) {
777         xpctxt->opCount = xpctxt->opLimit;
778         xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
779         return(-1);
780     }
781 
782     xpctxt->opCount += opCount;
783     return(0);
784 }
785 
786 #define OP_LIMIT_EXCEEDED(ctxt, n) \
787     ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
788 
789 /************************************************************************
790  *									*
791  *			Utilities					*
792  *									*
793  ************************************************************************/
794 
795 /**
796  * xsltPointerList:
797  *
798  * Pointer-list for various purposes.
799  */
800 typedef struct _xmlPointerList xmlPointerList;
801 typedef xmlPointerList *xmlPointerListPtr;
802 struct _xmlPointerList {
803     void **items;
804     int number;
805     int size;
806 };
807 /*
808 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
809 * and here, we should make the functions public.
810 */
811 static int
xmlPointerListAddSize(xmlPointerListPtr list,void * item,int initialSize)812 xmlPointerListAddSize(xmlPointerListPtr list,
813 		       void *item,
814 		       int initialSize)
815 {
816     if (list->size <= list->number) {
817         void **tmp;
818         size_t newSize;
819 
820         if (list->size == 0) {
821             if (initialSize <= 0)
822                 initialSize = 1;
823             newSize = initialSize;
824         } else {
825             if (list->size > 50000000) {
826                 xmlXPathErrMemory(NULL,
827                     "xmlPointerListAddSize: re-allocating item\n");
828                 return(-1);
829             }
830 	    newSize = list->size * 2;
831         }
832 	tmp = (void **) xmlRealloc(list->items, newSize * sizeof(void *));
833 	if (tmp == NULL) {
834 	    xmlXPathErrMemory(NULL,
835 		"xmlPointerListAddSize: re-allocating item\n");
836 	    return(-1);
837 	}
838         list->items = tmp;
839         list->size = newSize;
840     }
841     list->items[list->number++] = item;
842     return(0);
843 }
844 
845 /**
846  * xsltPointerListCreate:
847  *
848  * Creates an xsltPointerList structure.
849  *
850  * Returns a xsltPointerList structure or NULL in case of an error.
851  */
852 static xmlPointerListPtr
xmlPointerListCreate(int initialSize)853 xmlPointerListCreate(int initialSize)
854 {
855     xmlPointerListPtr ret;
856 
857     ret = xmlMalloc(sizeof(xmlPointerList));
858     if (ret == NULL) {
859 	xmlXPathErrMemory(NULL,
860 	    "xmlPointerListCreate: allocating item\n");
861 	return (NULL);
862     }
863     memset(ret, 0, sizeof(xmlPointerList));
864     if (initialSize > 0) {
865 	xmlPointerListAddSize(ret, NULL, initialSize);
866 	ret->number = 0;
867     }
868     return (ret);
869 }
870 
871 /**
872  * xsltPointerListFree:
873  *
874  * Frees the xsltPointerList structure. This does not free
875  * the content of the list.
876  */
877 static void
xmlPointerListFree(xmlPointerListPtr list)878 xmlPointerListFree(xmlPointerListPtr list)
879 {
880     if (list == NULL)
881 	return;
882     if (list->items != NULL)
883 	xmlFree(list->items);
884     xmlFree(list);
885 }
886 
887 /************************************************************************
888  *									*
889  *			Parser Types					*
890  *									*
891  ************************************************************************/
892 
893 /*
894  * Types are private:
895  */
896 
897 typedef enum {
898     XPATH_OP_END=0,
899     XPATH_OP_AND,
900     XPATH_OP_OR,
901     XPATH_OP_EQUAL,
902     XPATH_OP_CMP,
903     XPATH_OP_PLUS,
904     XPATH_OP_MULT,
905     XPATH_OP_UNION,
906     XPATH_OP_ROOT,
907     XPATH_OP_NODE,
908     XPATH_OP_COLLECT,
909     XPATH_OP_VALUE, /* 11 */
910     XPATH_OP_VARIABLE,
911     XPATH_OP_FUNCTION,
912     XPATH_OP_ARG,
913     XPATH_OP_PREDICATE,
914     XPATH_OP_FILTER, /* 16 */
915     XPATH_OP_SORT /* 17 */
916 #ifdef LIBXML_XPTR_LOCS_ENABLED
917     ,XPATH_OP_RANGETO
918 #endif
919 } xmlXPathOp;
920 
921 typedef enum {
922     AXIS_ANCESTOR = 1,
923     AXIS_ANCESTOR_OR_SELF,
924     AXIS_ATTRIBUTE,
925     AXIS_CHILD,
926     AXIS_DESCENDANT,
927     AXIS_DESCENDANT_OR_SELF,
928     AXIS_FOLLOWING,
929     AXIS_FOLLOWING_SIBLING,
930     AXIS_NAMESPACE,
931     AXIS_PARENT,
932     AXIS_PRECEDING,
933     AXIS_PRECEDING_SIBLING,
934     AXIS_SELF
935 } xmlXPathAxisVal;
936 
937 typedef enum {
938     NODE_TEST_NONE = 0,
939     NODE_TEST_TYPE = 1,
940     NODE_TEST_PI = 2,
941     NODE_TEST_ALL = 3,
942     NODE_TEST_NS = 4,
943     NODE_TEST_NAME = 5
944 } xmlXPathTestVal;
945 
946 typedef enum {
947     NODE_TYPE_NODE = 0,
948     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
949     NODE_TYPE_TEXT = XML_TEXT_NODE,
950     NODE_TYPE_PI = XML_PI_NODE
951 } xmlXPathTypeVal;
952 
953 typedef struct _xmlXPathStepOp xmlXPathStepOp;
954 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
955 struct _xmlXPathStepOp {
956     xmlXPathOp op;		/* The identifier of the operation */
957     int ch1;			/* First child */
958     int ch2;			/* Second child */
959     int value;
960     int value2;
961     int value3;
962     void *value4;
963     void *value5;
964     xmlXPathFunction cache;
965     void *cacheURI;
966 };
967 
968 struct _xmlXPathCompExpr {
969     int nbStep;			/* Number of steps in this expression */
970     int maxStep;		/* Maximum number of steps allocated */
971     xmlXPathStepOp *steps;	/* ops for computation of this expression */
972     int last;			/* index of last step in expression */
973     xmlChar *expr;		/* the expression being computed */
974     xmlDictPtr dict;		/* the dictionary to use if any */
975 #ifdef XPATH_STREAMING
976     xmlPatternPtr stream;
977 #endif
978 };
979 
980 /************************************************************************
981  *									*
982  *			Forward declarations				*
983  *									*
984  ************************************************************************/
985 static void
986 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
987 static void
988 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
989 static int
990 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
991                         xmlXPathStepOpPtr op, xmlNodePtr *first);
992 static int
993 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
994 			    xmlXPathStepOpPtr op,
995 			    int isPredicate);
996 static void
997 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
998 
999 /************************************************************************
1000  *									*
1001  *			Parser Type functions				*
1002  *									*
1003  ************************************************************************/
1004 
1005 /**
1006  * xmlXPathNewCompExpr:
1007  *
1008  * Create a new Xpath component
1009  *
1010  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1011  */
1012 static xmlXPathCompExprPtr
xmlXPathNewCompExpr(void)1013 xmlXPathNewCompExpr(void) {
1014     xmlXPathCompExprPtr cur;
1015 
1016     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1017     if (cur == NULL) {
1018         xmlXPathErrMemory(NULL, "allocating component\n");
1019 	return(NULL);
1020     }
1021     memset(cur, 0, sizeof(xmlXPathCompExpr));
1022     cur->maxStep = 10;
1023     cur->nbStep = 0;
1024     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1025 	                                   sizeof(xmlXPathStepOp));
1026     if (cur->steps == NULL) {
1027         xmlXPathErrMemory(NULL, "allocating steps\n");
1028 	xmlFree(cur);
1029 	return(NULL);
1030     }
1031     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1032     cur->last = -1;
1033     return(cur);
1034 }
1035 
1036 /**
1037  * xmlXPathFreeCompExpr:
1038  * @comp:  an XPATH comp
1039  *
1040  * Free up the memory allocated by @comp
1041  */
1042 void
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)1043 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1044 {
1045     xmlXPathStepOpPtr op;
1046     int i;
1047 
1048     if (comp == NULL)
1049         return;
1050     if (comp->dict == NULL) {
1051 	for (i = 0; i < comp->nbStep; i++) {
1052 	    op = &comp->steps[i];
1053 	    if (op->value4 != NULL) {
1054 		if (op->op == XPATH_OP_VALUE)
1055 		    xmlXPathFreeObject(op->value4);
1056 		else
1057 		    xmlFree(op->value4);
1058 	    }
1059 	    if (op->value5 != NULL)
1060 		xmlFree(op->value5);
1061 	}
1062     } else {
1063 	for (i = 0; i < comp->nbStep; i++) {
1064 	    op = &comp->steps[i];
1065 	    if (op->value4 != NULL) {
1066 		if (op->op == XPATH_OP_VALUE)
1067 		    xmlXPathFreeObject(op->value4);
1068 	    }
1069 	}
1070         xmlDictFree(comp->dict);
1071     }
1072     if (comp->steps != NULL) {
1073         xmlFree(comp->steps);
1074     }
1075 #ifdef XPATH_STREAMING
1076     if (comp->stream != NULL) {
1077         xmlFreePatternList(comp->stream);
1078     }
1079 #endif
1080     if (comp->expr != NULL) {
1081         xmlFree(comp->expr);
1082     }
1083 
1084     xmlFree(comp);
1085 }
1086 
1087 /**
1088  * xmlXPathCompExprAdd:
1089  * @comp:  the compiled expression
1090  * @ch1: first child index
1091  * @ch2: second child index
1092  * @op:  an op
1093  * @value:  the first int value
1094  * @value2:  the second int value
1095  * @value3:  the third int value
1096  * @value4:  the first string value
1097  * @value5:  the second string value
1098  *
1099  * Add a step to an XPath Compiled Expression
1100  *
1101  * Returns -1 in case of failure, the index otherwise
1102  */
1103 static int
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt,int ch1,int ch2,xmlXPathOp op,int value,int value2,int value3,void * value4,void * value5)1104 xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1105    xmlXPathOp op, int value,
1106    int value2, int value3, void *value4, void *value5) {
1107     xmlXPathCompExprPtr comp = ctxt->comp;
1108     if (comp->nbStep >= comp->maxStep) {
1109 	xmlXPathStepOp *real;
1110 
1111         if (comp->maxStep >= XPATH_MAX_STEPS) {
1112 	    xmlXPathPErrMemory(ctxt, "adding step\n");
1113 	    return(-1);
1114         }
1115 	comp->maxStep *= 2;
1116 	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1117 		                      comp->maxStep * sizeof(xmlXPathStepOp));
1118 	if (real == NULL) {
1119 	    comp->maxStep /= 2;
1120 	    xmlXPathPErrMemory(ctxt, "adding step\n");
1121 	    return(-1);
1122 	}
1123 	comp->steps = real;
1124     }
1125     comp->last = comp->nbStep;
1126     comp->steps[comp->nbStep].ch1 = ch1;
1127     comp->steps[comp->nbStep].ch2 = ch2;
1128     comp->steps[comp->nbStep].op = op;
1129     comp->steps[comp->nbStep].value = value;
1130     comp->steps[comp->nbStep].value2 = value2;
1131     comp->steps[comp->nbStep].value3 = value3;
1132     if ((comp->dict != NULL) &&
1133         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1134 	 (op == XPATH_OP_COLLECT))) {
1135         if (value4 != NULL) {
1136 	    comp->steps[comp->nbStep].value4 = (xmlChar *)
1137 	        (void *)xmlDictLookup(comp->dict, value4, -1);
1138 	    xmlFree(value4);
1139 	} else
1140 	    comp->steps[comp->nbStep].value4 = NULL;
1141         if (value5 != NULL) {
1142 	    comp->steps[comp->nbStep].value5 = (xmlChar *)
1143 	        (void *)xmlDictLookup(comp->dict, value5, -1);
1144 	    xmlFree(value5);
1145 	} else
1146 	    comp->steps[comp->nbStep].value5 = NULL;
1147     } else {
1148 	comp->steps[comp->nbStep].value4 = value4;
1149 	comp->steps[comp->nbStep].value5 = value5;
1150     }
1151     comp->steps[comp->nbStep].cache = NULL;
1152     return(comp->nbStep++);
1153 }
1154 
1155 /**
1156  * xmlXPathCompSwap:
1157  * @comp:  the compiled expression
1158  * @op: operation index
1159  *
1160  * Swaps 2 operations in the compiled expression
1161  */
1162 static void
xmlXPathCompSwap(xmlXPathStepOpPtr op)1163 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1164     int tmp;
1165 
1166 #ifndef LIBXML_THREAD_ENABLED
1167     /*
1168      * Since this manipulates possibly shared variables, this is
1169      * disabled if one detects that the library is used in a multithreaded
1170      * application
1171      */
1172     if (xmlXPathDisableOptimizer)
1173 	return;
1174 #endif
1175 
1176     tmp = op->ch1;
1177     op->ch1 = op->ch2;
1178     op->ch2 = tmp;
1179 }
1180 
1181 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
1182     xmlXPathCompExprAdd(ctxt, (op1), (op2),			\
1183 	                (op), (val), (val2), (val3), (val4), (val5))
1184 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
1185     xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,		\
1186 	                (op), (val), (val2), (val3), (val4), (val5))
1187 
1188 #define PUSH_LEAVE_EXPR(op, val, val2)					\
1189 xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1190 
1191 #define PUSH_UNARY_EXPR(op, ch, val, val2)				\
1192 xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1193 
1194 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
1195 xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),			\
1196 			(val), (val2), 0 ,NULL ,NULL)
1197 
1198 /************************************************************************
1199  *									*
1200  *		XPath object cache structures				*
1201  *									*
1202  ************************************************************************/
1203 
1204 /* #define XP_DEFAULT_CACHE_ON */
1205 
1206 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1207 
1208 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1209 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1210 struct _xmlXPathContextCache {
1211     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1212     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1213     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1214     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1215     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1216     int maxNodeset;
1217     int maxString;
1218     int maxBoolean;
1219     int maxNumber;
1220     int maxMisc;
1221 };
1222 
1223 /************************************************************************
1224  *									*
1225  *		Debugging related functions				*
1226  *									*
1227  ************************************************************************/
1228 
1229 #define STRANGE							\
1230     xmlGenericError(xmlGenericErrorContext,				\
1231 	    "Internal error at %s:%d\n",				\
1232             __FILE__, __LINE__);
1233 
1234 #ifdef LIBXML_DEBUG_ENABLED
1235 static void
xmlXPathDebugDumpNode(FILE * output,xmlNodePtr cur,int depth)1236 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1237     int i;
1238     char shift[100];
1239 
1240     for (i = 0;((i < depth) && (i < 25));i++)
1241         shift[2 * i] = shift[2 * i + 1] = ' ';
1242     shift[2 * i] = shift[2 * i + 1] = 0;
1243     if (cur == NULL) {
1244 	fprintf(output, "%s", shift);
1245 	fprintf(output, "Node is NULL !\n");
1246 	return;
1247 
1248     }
1249 
1250     if ((cur->type == XML_DOCUMENT_NODE) ||
1251 	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
1252 	fprintf(output, "%s", shift);
1253 	fprintf(output, " /\n");
1254     } else if (cur->type == XML_ATTRIBUTE_NODE)
1255 	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1256     else
1257 	xmlDebugDumpOneNode(output, cur, depth);
1258 }
1259 static void
xmlXPathDebugDumpNodeList(FILE * output,xmlNodePtr cur,int depth)1260 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1261     xmlNodePtr tmp;
1262     int i;
1263     char shift[100];
1264 
1265     for (i = 0;((i < depth) && (i < 25));i++)
1266         shift[2 * i] = shift[2 * i + 1] = ' ';
1267     shift[2 * i] = shift[2 * i + 1] = 0;
1268     if (cur == NULL) {
1269 	fprintf(output, "%s", shift);
1270 	fprintf(output, "Node is NULL !\n");
1271 	return;
1272 
1273     }
1274 
1275     while (cur != NULL) {
1276 	tmp = cur;
1277 	cur = cur->next;
1278 	xmlDebugDumpOneNode(output, tmp, depth);
1279     }
1280 }
1281 
1282 static void
xmlXPathDebugDumpNodeSet(FILE * output,xmlNodeSetPtr cur,int depth)1283 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1284     int i;
1285     char shift[100];
1286 
1287     for (i = 0;((i < depth) && (i < 25));i++)
1288         shift[2 * i] = shift[2 * i + 1] = ' ';
1289     shift[2 * i] = shift[2 * i + 1] = 0;
1290 
1291     if (cur == NULL) {
1292 	fprintf(output, "%s", shift);
1293 	fprintf(output, "NodeSet is NULL !\n");
1294 	return;
1295 
1296     }
1297 
1298     if (cur != NULL) {
1299 	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1300 	for (i = 0;i < cur->nodeNr;i++) {
1301 	    fprintf(output, "%s", shift);
1302 	    fprintf(output, "%d", i + 1);
1303 	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1304 	}
1305     }
1306 }
1307 
1308 static void
xmlXPathDebugDumpValueTree(FILE * output,xmlNodeSetPtr cur,int depth)1309 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1310     int i;
1311     char shift[100];
1312 
1313     for (i = 0;((i < depth) && (i < 25));i++)
1314         shift[2 * i] = shift[2 * i + 1] = ' ';
1315     shift[2 * i] = shift[2 * i + 1] = 0;
1316 
1317     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1318 	fprintf(output, "%s", shift);
1319 	fprintf(output, "Value Tree is NULL !\n");
1320 	return;
1321 
1322     }
1323 
1324     fprintf(output, "%s", shift);
1325     fprintf(output, "%d", i + 1);
1326     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1327 }
1328 #if defined(LIBXML_XPTR_LOCS_ENABLED)
1329 static void
xmlXPathDebugDumpLocationSet(FILE * output,xmlLocationSetPtr cur,int depth)1330 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1331     int i;
1332     char shift[100];
1333 
1334     for (i = 0;((i < depth) && (i < 25));i++)
1335         shift[2 * i] = shift[2 * i + 1] = ' ';
1336     shift[2 * i] = shift[2 * i + 1] = 0;
1337 
1338     if (cur == NULL) {
1339 	fprintf(output, "%s", shift);
1340 	fprintf(output, "LocationSet is NULL !\n");
1341 	return;
1342 
1343     }
1344 
1345     for (i = 0;i < cur->locNr;i++) {
1346 	fprintf(output, "%s", shift);
1347         fprintf(output, "%d : ", i + 1);
1348 	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1349     }
1350 }
1351 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1352 
1353 /**
1354  * xmlXPathDebugDumpObject:
1355  * @output:  the FILE * to dump the output
1356  * @cur:  the object to inspect
1357  * @depth:  indentation level
1358  *
1359  * Dump the content of the object for debugging purposes
1360  */
1361 void
xmlXPathDebugDumpObject(FILE * output,xmlXPathObjectPtr cur,int depth)1362 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1363     int i;
1364     char shift[100];
1365 
1366     if (output == NULL) return;
1367 
1368     for (i = 0;((i < depth) && (i < 25));i++)
1369         shift[2 * i] = shift[2 * i + 1] = ' ';
1370     shift[2 * i] = shift[2 * i + 1] = 0;
1371 
1372 
1373     fprintf(output, "%s", shift);
1374 
1375     if (cur == NULL) {
1376         fprintf(output, "Object is empty (NULL)\n");
1377 	return;
1378     }
1379     switch(cur->type) {
1380         case XPATH_UNDEFINED:
1381 	    fprintf(output, "Object is uninitialized\n");
1382 	    break;
1383         case XPATH_NODESET:
1384 	    fprintf(output, "Object is a Node Set :\n");
1385 	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1386 	    break;
1387 	case XPATH_XSLT_TREE:
1388 	    fprintf(output, "Object is an XSLT value tree :\n");
1389 	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1390 	    break;
1391         case XPATH_BOOLEAN:
1392 	    fprintf(output, "Object is a Boolean : ");
1393 	    if (cur->boolval) fprintf(output, "true\n");
1394 	    else fprintf(output, "false\n");
1395 	    break;
1396         case XPATH_NUMBER:
1397 	    switch (xmlXPathIsInf(cur->floatval)) {
1398 	    case 1:
1399 		fprintf(output, "Object is a number : Infinity\n");
1400 		break;
1401 	    case -1:
1402 		fprintf(output, "Object is a number : -Infinity\n");
1403 		break;
1404 	    default:
1405 		if (xmlXPathIsNaN(cur->floatval)) {
1406 		    fprintf(output, "Object is a number : NaN\n");
1407 		} else if (cur->floatval == 0) {
1408                     /* Omit sign for negative zero. */
1409 		    fprintf(output, "Object is a number : 0\n");
1410 		} else {
1411 		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
1412 		}
1413 	    }
1414 	    break;
1415         case XPATH_STRING:
1416 	    fprintf(output, "Object is a string : ");
1417 	    xmlDebugDumpString(output, cur->stringval);
1418 	    fprintf(output, "\n");
1419 	    break;
1420 #ifdef LIBXML_XPTR_LOCS_ENABLED
1421 	case XPATH_POINT:
1422 	    fprintf(output, "Object is a point : index %d in node", cur->index);
1423 	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1424 	    fprintf(output, "\n");
1425 	    break;
1426 	case XPATH_RANGE:
1427 	    if ((cur->user2 == NULL) ||
1428 		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1429 		fprintf(output, "Object is a collapsed range :\n");
1430 		fprintf(output, "%s", shift);
1431 		if (cur->index >= 0)
1432 		    fprintf(output, "index %d in ", cur->index);
1433 		fprintf(output, "node\n");
1434 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1435 			              depth + 1);
1436 	    } else  {
1437 		fprintf(output, "Object is a range :\n");
1438 		fprintf(output, "%s", shift);
1439 		fprintf(output, "From ");
1440 		if (cur->index >= 0)
1441 		    fprintf(output, "index %d in ", cur->index);
1442 		fprintf(output, "node\n");
1443 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1444 			              depth + 1);
1445 		fprintf(output, "%s", shift);
1446 		fprintf(output, "To ");
1447 		if (cur->index2 >= 0)
1448 		    fprintf(output, "index %d in ", cur->index2);
1449 		fprintf(output, "node\n");
1450 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1451 			              depth + 1);
1452 		fprintf(output, "\n");
1453 	    }
1454 	    break;
1455 	case XPATH_LOCATIONSET:
1456 	    fprintf(output, "Object is a Location Set:\n");
1457 	    xmlXPathDebugDumpLocationSet(output,
1458 		    (xmlLocationSetPtr) cur->user, depth);
1459 	    break;
1460 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1461 	case XPATH_USERS:
1462 	    fprintf(output, "Object is user defined\n");
1463 	    break;
1464     }
1465 }
1466 
1467 static void
xmlXPathDebugDumpStepOp(FILE * output,xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op,int depth)1468 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1469 	                     xmlXPathStepOpPtr op, int depth) {
1470     int i;
1471     char shift[100];
1472 
1473     for (i = 0;((i < depth) && (i < 25));i++)
1474         shift[2 * i] = shift[2 * i + 1] = ' ';
1475     shift[2 * i] = shift[2 * i + 1] = 0;
1476 
1477     fprintf(output, "%s", shift);
1478     if (op == NULL) {
1479 	fprintf(output, "Step is NULL\n");
1480 	return;
1481     }
1482     switch (op->op) {
1483         case XPATH_OP_END:
1484 	    fprintf(output, "END"); break;
1485         case XPATH_OP_AND:
1486 	    fprintf(output, "AND"); break;
1487         case XPATH_OP_OR:
1488 	    fprintf(output, "OR"); break;
1489         case XPATH_OP_EQUAL:
1490 	     if (op->value)
1491 		 fprintf(output, "EQUAL =");
1492 	     else
1493 		 fprintf(output, "EQUAL !=");
1494 	     break;
1495         case XPATH_OP_CMP:
1496 	     if (op->value)
1497 		 fprintf(output, "CMP <");
1498 	     else
1499 		 fprintf(output, "CMP >");
1500 	     if (!op->value2)
1501 		 fprintf(output, "=");
1502 	     break;
1503         case XPATH_OP_PLUS:
1504 	     if (op->value == 0)
1505 		 fprintf(output, "PLUS -");
1506 	     else if (op->value == 1)
1507 		 fprintf(output, "PLUS +");
1508 	     else if (op->value == 2)
1509 		 fprintf(output, "PLUS unary -");
1510 	     else if (op->value == 3)
1511 		 fprintf(output, "PLUS unary - -");
1512 	     break;
1513         case XPATH_OP_MULT:
1514 	     if (op->value == 0)
1515 		 fprintf(output, "MULT *");
1516 	     else if (op->value == 1)
1517 		 fprintf(output, "MULT div");
1518 	     else
1519 		 fprintf(output, "MULT mod");
1520 	     break;
1521         case XPATH_OP_UNION:
1522 	     fprintf(output, "UNION"); break;
1523         case XPATH_OP_ROOT:
1524 	     fprintf(output, "ROOT"); break;
1525         case XPATH_OP_NODE:
1526 	     fprintf(output, "NODE"); break;
1527         case XPATH_OP_SORT:
1528 	     fprintf(output, "SORT"); break;
1529         case XPATH_OP_COLLECT: {
1530 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1531 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1532 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1533 	    const xmlChar *prefix = op->value4;
1534 	    const xmlChar *name = op->value5;
1535 
1536 	    fprintf(output, "COLLECT ");
1537 	    switch (axis) {
1538 		case AXIS_ANCESTOR:
1539 		    fprintf(output, " 'ancestors' "); break;
1540 		case AXIS_ANCESTOR_OR_SELF:
1541 		    fprintf(output, " 'ancestors-or-self' "); break;
1542 		case AXIS_ATTRIBUTE:
1543 		    fprintf(output, " 'attributes' "); break;
1544 		case AXIS_CHILD:
1545 		    fprintf(output, " 'child' "); break;
1546 		case AXIS_DESCENDANT:
1547 		    fprintf(output, " 'descendant' "); break;
1548 		case AXIS_DESCENDANT_OR_SELF:
1549 		    fprintf(output, " 'descendant-or-self' "); break;
1550 		case AXIS_FOLLOWING:
1551 		    fprintf(output, " 'following' "); break;
1552 		case AXIS_FOLLOWING_SIBLING:
1553 		    fprintf(output, " 'following-siblings' "); break;
1554 		case AXIS_NAMESPACE:
1555 		    fprintf(output, " 'namespace' "); break;
1556 		case AXIS_PARENT:
1557 		    fprintf(output, " 'parent' "); break;
1558 		case AXIS_PRECEDING:
1559 		    fprintf(output, " 'preceding' "); break;
1560 		case AXIS_PRECEDING_SIBLING:
1561 		    fprintf(output, " 'preceding-sibling' "); break;
1562 		case AXIS_SELF:
1563 		    fprintf(output, " 'self' "); break;
1564 	    }
1565 	    switch (test) {
1566                 case NODE_TEST_NONE:
1567 		    fprintf(output, "'none' "); break;
1568                 case NODE_TEST_TYPE:
1569 		    fprintf(output, "'type' "); break;
1570                 case NODE_TEST_PI:
1571 		    fprintf(output, "'PI' "); break;
1572                 case NODE_TEST_ALL:
1573 		    fprintf(output, "'all' "); break;
1574                 case NODE_TEST_NS:
1575 		    fprintf(output, "'namespace' "); break;
1576                 case NODE_TEST_NAME:
1577 		    fprintf(output, "'name' "); break;
1578 	    }
1579 	    switch (type) {
1580                 case NODE_TYPE_NODE:
1581 		    fprintf(output, "'node' "); break;
1582                 case NODE_TYPE_COMMENT:
1583 		    fprintf(output, "'comment' "); break;
1584                 case NODE_TYPE_TEXT:
1585 		    fprintf(output, "'text' "); break;
1586                 case NODE_TYPE_PI:
1587 		    fprintf(output, "'PI' "); break;
1588 	    }
1589 	    if (prefix != NULL)
1590 		fprintf(output, "%s:", prefix);
1591 	    if (name != NULL)
1592 		fprintf(output, "%s", (const char *) name);
1593 	    break;
1594 
1595         }
1596 	case XPATH_OP_VALUE: {
1597 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1598 
1599 	    fprintf(output, "ELEM ");
1600 	    xmlXPathDebugDumpObject(output, object, 0);
1601 	    goto finish;
1602 	}
1603 	case XPATH_OP_VARIABLE: {
1604 	    const xmlChar *prefix = op->value5;
1605 	    const xmlChar *name = op->value4;
1606 
1607 	    if (prefix != NULL)
1608 		fprintf(output, "VARIABLE %s:%s", prefix, name);
1609 	    else
1610 		fprintf(output, "VARIABLE %s", name);
1611 	    break;
1612 	}
1613 	case XPATH_OP_FUNCTION: {
1614 	    int nbargs = op->value;
1615 	    const xmlChar *prefix = op->value5;
1616 	    const xmlChar *name = op->value4;
1617 
1618 	    if (prefix != NULL)
1619 		fprintf(output, "FUNCTION %s:%s(%d args)",
1620 			prefix, name, nbargs);
1621 	    else
1622 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1623 	    break;
1624 	}
1625         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1626         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1627         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1628 #ifdef LIBXML_XPTR_LOCS_ENABLED
1629         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1630 #endif
1631 	default:
1632         fprintf(output, "UNKNOWN %d\n", op->op); return;
1633     }
1634     fprintf(output, "\n");
1635 finish:
1636     if (op->ch1 >= 0)
1637 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1638     if (op->ch2 >= 0)
1639 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1640 }
1641 
1642 /**
1643  * xmlXPathDebugDumpCompExpr:
1644  * @output:  the FILE * for the output
1645  * @comp:  the precompiled XPath expression
1646  * @depth:  the indentation level.
1647  *
1648  * Dumps the tree of the compiled XPath expression.
1649  */
1650 void
xmlXPathDebugDumpCompExpr(FILE * output,xmlXPathCompExprPtr comp,int depth)1651 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1652 	                  int depth) {
1653     int i;
1654     char shift[100];
1655 
1656     if ((output == NULL) || (comp == NULL)) return;
1657 
1658     for (i = 0;((i < depth) && (i < 25));i++)
1659         shift[2 * i] = shift[2 * i + 1] = ' ';
1660     shift[2 * i] = shift[2 * i + 1] = 0;
1661 
1662     fprintf(output, "%s", shift);
1663 
1664 #ifdef XPATH_STREAMING
1665     if (comp->stream) {
1666         fprintf(output, "Streaming Expression\n");
1667     } else
1668 #endif
1669     {
1670         fprintf(output, "Compiled Expression : %d elements\n",
1671                 comp->nbStep);
1672         i = comp->last;
1673         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1674     }
1675 }
1676 
1677 #endif /* LIBXML_DEBUG_ENABLED */
1678 
1679 /************************************************************************
1680  *									*
1681  *			XPath object caching				*
1682  *									*
1683  ************************************************************************/
1684 
1685 /**
1686  * xmlXPathNewCache:
1687  *
1688  * Create a new object cache
1689  *
1690  * Returns the xmlXPathCache just allocated.
1691  */
1692 static xmlXPathContextCachePtr
xmlXPathNewCache(void)1693 xmlXPathNewCache(void)
1694 {
1695     xmlXPathContextCachePtr ret;
1696 
1697     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1698     if (ret == NULL) {
1699         xmlXPathErrMemory(NULL, "creating object cache\n");
1700 	return(NULL);
1701     }
1702     memset(ret, 0 , sizeof(xmlXPathContextCache));
1703     ret->maxNodeset = 100;
1704     ret->maxString = 100;
1705     ret->maxBoolean = 100;
1706     ret->maxNumber = 100;
1707     ret->maxMisc = 100;
1708     return(ret);
1709 }
1710 
1711 static void
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)1712 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
1713 {
1714     int i;
1715     xmlXPathObjectPtr obj;
1716 
1717     if (list == NULL)
1718 	return;
1719 
1720     for (i = 0; i < list->number; i++) {
1721 	obj = list->items[i];
1722 	/*
1723 	* Note that it is already assured that we don't need to
1724 	* look out for namespace nodes in the node-set.
1725 	*/
1726 	if (obj->nodesetval != NULL) {
1727 	    if (obj->nodesetval->nodeTab != NULL)
1728 		xmlFree(obj->nodesetval->nodeTab);
1729 	    xmlFree(obj->nodesetval);
1730 	}
1731 	xmlFree(obj);
1732     }
1733     xmlPointerListFree(list);
1734 }
1735 
1736 static void
xmlXPathFreeCache(xmlXPathContextCachePtr cache)1737 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1738 {
1739     if (cache == NULL)
1740 	return;
1741     if (cache->nodesetObjs)
1742 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1743     if (cache->stringObjs)
1744 	xmlXPathCacheFreeObjectList(cache->stringObjs);
1745     if (cache->booleanObjs)
1746 	xmlXPathCacheFreeObjectList(cache->booleanObjs);
1747     if (cache->numberObjs)
1748 	xmlXPathCacheFreeObjectList(cache->numberObjs);
1749     if (cache->miscObjs)
1750 	xmlXPathCacheFreeObjectList(cache->miscObjs);
1751     xmlFree(cache);
1752 }
1753 
1754 /**
1755  * xmlXPathContextSetCache:
1756  *
1757  * @ctxt:  the XPath context
1758  * @active: enables/disables (creates/frees) the cache
1759  * @value: a value with semantics dependent on @options
1760  * @options: options (currently only the value 0 is used)
1761  *
1762  * Creates/frees an object cache on the XPath context.
1763  * If activates XPath objects (xmlXPathObject) will be cached internally
1764  * to be reused.
1765  * @options:
1766  *   0: This will set the XPath object caching:
1767  *      @value:
1768  *        This will set the maximum number of XPath objects
1769  *        to be cached per slot
1770  *        There are 5 slots for: node-set, string, number, boolean, and
1771  *        misc objects. Use <0 for the default number (100).
1772  *   Other values for @options have currently no effect.
1773  *
1774  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1775  */
1776 int
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,int active,int value,int options)1777 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1778 			int active,
1779 			int value,
1780 			int options)
1781 {
1782     if (ctxt == NULL)
1783 	return(-1);
1784     if (active) {
1785 	xmlXPathContextCachePtr cache;
1786 
1787 	if (ctxt->cache == NULL) {
1788 	    ctxt->cache = xmlXPathNewCache();
1789 	    if (ctxt->cache == NULL)
1790 		return(-1);
1791 	}
1792 	cache = (xmlXPathContextCachePtr) ctxt->cache;
1793 	if (options == 0) {
1794 	    if (value < 0)
1795 		value = 100;
1796 	    cache->maxNodeset = value;
1797 	    cache->maxString = value;
1798 	    cache->maxNumber = value;
1799 	    cache->maxBoolean = value;
1800 	    cache->maxMisc = value;
1801 	}
1802     } else if (ctxt->cache != NULL) {
1803 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1804 	ctxt->cache = NULL;
1805     }
1806     return(0);
1807 }
1808 
1809 /**
1810  * xmlXPathCacheWrapNodeSet:
1811  * @ctxt: the XPath context
1812  * @val:  the NodePtr value
1813  *
1814  * This is the cached version of xmlXPathWrapNodeSet().
1815  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1816  *
1817  * Returns the created or reused object.
1818  *
1819  * In case of error the node set is destroyed and NULL is returned.
1820  */
1821 static xmlXPathObjectPtr
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt,xmlNodeSetPtr val)1822 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1823 {
1824     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1825 	xmlXPathContextCachePtr cache =
1826 	    (xmlXPathContextCachePtr) ctxt->cache;
1827 
1828 	if ((cache->miscObjs != NULL) &&
1829 	    (cache->miscObjs->number != 0))
1830 	{
1831 	    xmlXPathObjectPtr ret;
1832 
1833 	    ret = (xmlXPathObjectPtr)
1834 		cache->miscObjs->items[--cache->miscObjs->number];
1835 	    ret->type = XPATH_NODESET;
1836 	    ret->nodesetval = val;
1837 	    return(ret);
1838 	}
1839     }
1840 
1841     return(xmlXPathWrapNodeSet(val));
1842 
1843 }
1844 
1845 /**
1846  * xmlXPathCacheWrapString:
1847  * @ctxt: the XPath context
1848  * @val:  the xmlChar * value
1849  *
1850  * This is the cached version of xmlXPathWrapString().
1851  * Wraps the @val string into an XPath object.
1852  *
1853  * Returns the created or reused object.
1854  */
1855 static xmlXPathObjectPtr
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt,xmlChar * val)1856 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1857 {
1858     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1859 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1860 
1861 	if ((cache->stringObjs != NULL) &&
1862 	    (cache->stringObjs->number != 0))
1863 	{
1864 
1865 	    xmlXPathObjectPtr ret;
1866 
1867 	    ret = (xmlXPathObjectPtr)
1868 		cache->stringObjs->items[--cache->stringObjs->number];
1869 	    ret->type = XPATH_STRING;
1870 	    ret->stringval = val;
1871 	    return(ret);
1872 	} else if ((cache->miscObjs != NULL) &&
1873 	    (cache->miscObjs->number != 0))
1874 	{
1875 	    xmlXPathObjectPtr ret;
1876 	    /*
1877 	    * Fallback to misc-cache.
1878 	    */
1879 	    ret = (xmlXPathObjectPtr)
1880 		cache->miscObjs->items[--cache->miscObjs->number];
1881 
1882 	    ret->type = XPATH_STRING;
1883 	    ret->stringval = val;
1884 	    return(ret);
1885 	}
1886     }
1887     return(xmlXPathWrapString(val));
1888 }
1889 
1890 /**
1891  * xmlXPathCacheNewNodeSet:
1892  * @ctxt: the XPath context
1893  * @val:  the NodePtr value
1894  *
1895  * This is the cached version of xmlXPathNewNodeSet().
1896  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
1897  * it with the single Node @val
1898  *
1899  * Returns the created or reused object.
1900  */
1901 static xmlXPathObjectPtr
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt,xmlNodePtr val)1902 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
1903 {
1904     if ((ctxt != NULL) && (ctxt->cache)) {
1905 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1906 
1907 	if ((cache->nodesetObjs != NULL) &&
1908 	    (cache->nodesetObjs->number != 0))
1909 	{
1910 	    xmlXPathObjectPtr ret;
1911 	    /*
1912 	    * Use the nodeset-cache.
1913 	    */
1914 	    ret = (xmlXPathObjectPtr)
1915 		cache->nodesetObjs->items[--cache->nodesetObjs->number];
1916 	    ret->type = XPATH_NODESET;
1917 	    ret->boolval = 0;
1918 	    if (val) {
1919 		if ((ret->nodesetval->nodeMax == 0) ||
1920 		    (val->type == XML_NAMESPACE_DECL))
1921 		{
1922                     /* TODO: Check memory error. */
1923 		    xmlXPathNodeSetAddUnique(ret->nodesetval, val);
1924 		} else {
1925 		    ret->nodesetval->nodeTab[0] = val;
1926 		    ret->nodesetval->nodeNr = 1;
1927 		}
1928 	    }
1929 	    return(ret);
1930 	} else if ((cache->miscObjs != NULL) &&
1931 	    (cache->miscObjs->number != 0))
1932 	{
1933 	    xmlXPathObjectPtr ret;
1934             xmlNodeSetPtr set;
1935 	    /*
1936 	    * Fallback to misc-cache.
1937 	    */
1938 
1939 	    set = xmlXPathNodeSetCreate(val);
1940 	    if (set == NULL) {
1941 		ctxt->lastError.domain = XML_FROM_XPATH;
1942 		ctxt->lastError.code = XML_ERR_NO_MEMORY;
1943 		return(NULL);
1944 	    }
1945 
1946 	    ret = (xmlXPathObjectPtr)
1947 		cache->miscObjs->items[--cache->miscObjs->number];
1948 
1949 	    ret->type = XPATH_NODESET;
1950 	    ret->boolval = 0;
1951 	    ret->nodesetval = set;
1952 	    return(ret);
1953 	}
1954     }
1955     return(xmlXPathNewNodeSet(val));
1956 }
1957 
1958 /**
1959  * xmlXPathCacheNewString:
1960  * @ctxt: the XPath context
1961  * @val:  the xmlChar * value
1962  *
1963  * This is the cached version of xmlXPathNewString().
1964  * Acquire an xmlXPathObjectPtr of type string and of value @val
1965  *
1966  * Returns the created or reused object.
1967  */
1968 static xmlXPathObjectPtr
xmlXPathCacheNewString(xmlXPathContextPtr ctxt,const xmlChar * val)1969 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
1970 {
1971     if ((ctxt != NULL) && (ctxt->cache)) {
1972 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1973 
1974 	if ((cache->stringObjs != NULL) &&
1975 	    (cache->stringObjs->number != 0))
1976 	{
1977 	    xmlXPathObjectPtr ret;
1978             xmlChar *copy;
1979 
1980             if (val == NULL)
1981                 val = BAD_CAST "";
1982             copy = xmlStrdup(val);
1983             if (copy == NULL) {
1984                 xmlXPathErrMemory(ctxt, NULL);
1985                 return(NULL);
1986             }
1987 
1988 	    ret = (xmlXPathObjectPtr)
1989 		cache->stringObjs->items[--cache->stringObjs->number];
1990 	    ret->type = XPATH_STRING;
1991             ret->stringval = copy;
1992 	    return(ret);
1993 	} else if ((cache->miscObjs != NULL) &&
1994 	    (cache->miscObjs->number != 0))
1995 	{
1996 	    xmlXPathObjectPtr ret;
1997             xmlChar *copy;
1998 
1999             if (val == NULL)
2000                 val = BAD_CAST "";
2001             copy = xmlStrdup(val);
2002             if (copy == NULL) {
2003                 xmlXPathErrMemory(ctxt, NULL);
2004                 return(NULL);
2005             }
2006 
2007 	    ret = (xmlXPathObjectPtr)
2008 		cache->miscObjs->items[--cache->miscObjs->number];
2009 
2010 	    ret->type = XPATH_STRING;
2011             ret->stringval = copy;
2012 	    return(ret);
2013 	}
2014     }
2015     return(xmlXPathNewString(val));
2016 }
2017 
2018 /**
2019  * xmlXPathCacheNewCString:
2020  * @ctxt: the XPath context
2021  * @val:  the char * value
2022  *
2023  * This is the cached version of xmlXPathNewCString().
2024  * Acquire an xmlXPathObjectPtr of type string and of value @val
2025  *
2026  * Returns the created or reused object.
2027  */
2028 static xmlXPathObjectPtr
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt,const char * val)2029 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2030 {
2031     return xmlXPathCacheNewString(ctxt, BAD_CAST val);
2032 }
2033 
2034 /**
2035  * xmlXPathCacheNewBoolean:
2036  * @ctxt: the XPath context
2037  * @val:  the boolean value
2038  *
2039  * This is the cached version of xmlXPathNewBoolean().
2040  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2041  *
2042  * Returns the created or reused object.
2043  */
2044 static xmlXPathObjectPtr
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt,int val)2045 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2046 {
2047     if ((ctxt != NULL) && (ctxt->cache)) {
2048 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2049 
2050 	if ((cache->booleanObjs != NULL) &&
2051 	    (cache->booleanObjs->number != 0))
2052 	{
2053 	    xmlXPathObjectPtr ret;
2054 
2055 	    ret = (xmlXPathObjectPtr)
2056 		cache->booleanObjs->items[--cache->booleanObjs->number];
2057 	    ret->type = XPATH_BOOLEAN;
2058 	    ret->boolval = (val != 0);
2059 	    return(ret);
2060 	} else if ((cache->miscObjs != NULL) &&
2061 	    (cache->miscObjs->number != 0))
2062 	{
2063 	    xmlXPathObjectPtr ret;
2064 
2065 	    ret = (xmlXPathObjectPtr)
2066 		cache->miscObjs->items[--cache->miscObjs->number];
2067 
2068 	    ret->type = XPATH_BOOLEAN;
2069 	    ret->boolval = (val != 0);
2070 	    return(ret);
2071 	}
2072     }
2073     return(xmlXPathNewBoolean(val));
2074 }
2075 
2076 /**
2077  * xmlXPathCacheNewFloat:
2078  * @ctxt: the XPath context
2079  * @val:  the double value
2080  *
2081  * This is the cached version of xmlXPathNewFloat().
2082  * Acquires an xmlXPathObjectPtr of type double and of value @val
2083  *
2084  * Returns the created or reused object.
2085  */
2086 static xmlXPathObjectPtr
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt,double val)2087 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2088 {
2089      if ((ctxt != NULL) && (ctxt->cache)) {
2090 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2091 
2092 	if ((cache->numberObjs != NULL) &&
2093 	    (cache->numberObjs->number != 0))
2094 	{
2095 	    xmlXPathObjectPtr ret;
2096 
2097 	    ret = (xmlXPathObjectPtr)
2098 		cache->numberObjs->items[--cache->numberObjs->number];
2099 	    ret->type = XPATH_NUMBER;
2100 	    ret->floatval = val;
2101 	    return(ret);
2102 	} else if ((cache->miscObjs != NULL) &&
2103 	    (cache->miscObjs->number != 0))
2104 	{
2105 	    xmlXPathObjectPtr ret;
2106 
2107 	    ret = (xmlXPathObjectPtr)
2108 		cache->miscObjs->items[--cache->miscObjs->number];
2109 
2110 	    ret->type = XPATH_NUMBER;
2111 	    ret->floatval = val;
2112 	    return(ret);
2113 	}
2114     }
2115     return(xmlXPathNewFloat(val));
2116 }
2117 
2118 /**
2119  * xmlXPathCacheConvertString:
2120  * @ctxt: the XPath context
2121  * @val:  an XPath object
2122  *
2123  * This is the cached version of xmlXPathConvertString().
2124  * Converts an existing object to its string() equivalent
2125  *
2126  * Returns a created or reused object, the old one is freed (cached)
2127  *         (or the operation is done directly on @val)
2128  */
2129 
2130 static xmlXPathObjectPtr
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2131 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2132     xmlChar *res = NULL;
2133 
2134     if (val == NULL)
2135 	return(xmlXPathCacheNewCString(ctxt, ""));
2136 
2137     switch (val->type) {
2138     case XPATH_UNDEFINED:
2139 	break;
2140     case XPATH_NODESET:
2141     case XPATH_XSLT_TREE:
2142 	res = xmlXPathCastNodeSetToString(val->nodesetval);
2143 	break;
2144     case XPATH_STRING:
2145 	return(val);
2146     case XPATH_BOOLEAN:
2147 	res = xmlXPathCastBooleanToString(val->boolval);
2148 	break;
2149     case XPATH_NUMBER:
2150 	res = xmlXPathCastNumberToString(val->floatval);
2151 	break;
2152     case XPATH_USERS:
2153 #ifdef LIBXML_XPTR_LOCS_ENABLED
2154     case XPATH_POINT:
2155     case XPATH_RANGE:
2156     case XPATH_LOCATIONSET:
2157 #endif /* LIBXML_XPTR_LOCS_ENABLED */
2158 	TODO;
2159 	break;
2160     }
2161     xmlXPathReleaseObject(ctxt, val);
2162     if (res == NULL)
2163 	return(xmlXPathCacheNewCString(ctxt, ""));
2164     return(xmlXPathCacheWrapString(ctxt, res));
2165 }
2166 
2167 /**
2168  * xmlXPathCacheObjectCopy:
2169  * @ctxt: the XPath context
2170  * @val:  the original object
2171  *
2172  * This is the cached version of xmlXPathObjectCopy().
2173  * Acquire a copy of a given object
2174  *
2175  * Returns a created or reused created object.
2176  */
2177 static xmlXPathObjectPtr
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2178 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2179 {
2180     if (val == NULL)
2181 	return(NULL);
2182 
2183     if (XP_HAS_CACHE(ctxt)) {
2184 	switch (val->type) {
2185 	    case XPATH_NODESET:
2186 		return(xmlXPathCacheWrapNodeSet(ctxt,
2187 		    xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2188 	    case XPATH_STRING:
2189 		return(xmlXPathCacheNewString(ctxt, val->stringval));
2190 	    case XPATH_BOOLEAN:
2191 		return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2192 	    case XPATH_NUMBER:
2193 		return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2194 	    default:
2195 		break;
2196 	}
2197     }
2198     return(xmlXPathObjectCopy(val));
2199 }
2200 
2201 /**
2202  * xmlXPathCacheConvertBoolean:
2203  * @ctxt: the XPath context
2204  * @val:  an XPath object
2205  *
2206  * This is the cached version of xmlXPathConvertBoolean().
2207  * Converts an existing object to its boolean() equivalent
2208  *
2209  * Returns a created or reused object, the old one is freed (or the operation
2210  *         is done directly on @val)
2211  */
2212 static xmlXPathObjectPtr
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2213 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2214     xmlXPathObjectPtr ret;
2215 
2216     if (val == NULL)
2217 	return(xmlXPathCacheNewBoolean(ctxt, 0));
2218     if (val->type == XPATH_BOOLEAN)
2219 	return(val);
2220     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2221     xmlXPathReleaseObject(ctxt, val);
2222     return(ret);
2223 }
2224 
2225 /**
2226  * xmlXPathCacheConvertNumber:
2227  * @ctxt: the XPath context
2228  * @val:  an XPath object
2229  *
2230  * This is the cached version of xmlXPathConvertNumber().
2231  * Converts an existing object to its number() equivalent
2232  *
2233  * Returns a created or reused object, the old one is freed (or the operation
2234  *         is done directly on @val)
2235  */
2236 static xmlXPathObjectPtr
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2237 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2238     xmlXPathObjectPtr ret;
2239 
2240     if (val == NULL)
2241 	return(xmlXPathCacheNewFloat(ctxt, 0.0));
2242     if (val->type == XPATH_NUMBER)
2243 	return(val);
2244     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2245     xmlXPathReleaseObject(ctxt, val);
2246     return(ret);
2247 }
2248 
2249 /************************************************************************
2250  *									*
2251  *		Parser stacks related functions and macros		*
2252  *									*
2253  ************************************************************************/
2254 
2255 /**
2256  * valuePop:
2257  * @ctxt: an XPath evaluation context
2258  *
2259  * Pops the top XPath object from the value stack
2260  *
2261  * Returns the XPath object just removed
2262  */
2263 xmlXPathObjectPtr
valuePop(xmlXPathParserContextPtr ctxt)2264 valuePop(xmlXPathParserContextPtr ctxt)
2265 {
2266     xmlXPathObjectPtr ret;
2267 
2268     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2269         return (NULL);
2270 
2271     ctxt->valueNr--;
2272     if (ctxt->valueNr > 0)
2273         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2274     else
2275         ctxt->value = NULL;
2276     ret = ctxt->valueTab[ctxt->valueNr];
2277     ctxt->valueTab[ctxt->valueNr] = NULL;
2278     return (ret);
2279 }
2280 /**
2281  * valuePush:
2282  * @ctxt:  an XPath evaluation context
2283  * @value:  the XPath object
2284  *
2285  * Pushes a new XPath object on top of the value stack. If value is NULL,
2286  * a memory error is recorded in the parser context.
2287  *
2288  * Returns the number of items on the value stack, or -1 in case of error.
2289  *
2290  * The object is destroyed in case of error.
2291  */
2292 int
valuePush(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr value)2293 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2294 {
2295     if (ctxt == NULL) return(-1);
2296     if (value == NULL) {
2297         /*
2298          * A NULL value typically indicates that a memory allocation failed,
2299          * so we set ctxt->error here to propagate the error.
2300          */
2301 	ctxt->error = XPATH_MEMORY_ERROR;
2302         return(-1);
2303     }
2304     if (ctxt->valueNr >= ctxt->valueMax) {
2305         xmlXPathObjectPtr *tmp;
2306 
2307         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2308             xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2309             xmlXPathFreeObject(value);
2310             return (-1);
2311         }
2312         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2313                                              2 * ctxt->valueMax *
2314                                              sizeof(ctxt->valueTab[0]));
2315         if (tmp == NULL) {
2316             xmlXPathPErrMemory(ctxt, "pushing value\n");
2317             xmlXPathFreeObject(value);
2318             return (-1);
2319         }
2320         ctxt->valueMax *= 2;
2321 	ctxt->valueTab = tmp;
2322     }
2323     ctxt->valueTab[ctxt->valueNr] = value;
2324     ctxt->value = value;
2325     return (ctxt->valueNr++);
2326 }
2327 
2328 /**
2329  * xmlXPathPopBoolean:
2330  * @ctxt:  an XPath parser context
2331  *
2332  * Pops a boolean from the stack, handling conversion if needed.
2333  * Check error with #xmlXPathCheckError.
2334  *
2335  * Returns the boolean
2336  */
2337 int
xmlXPathPopBoolean(xmlXPathParserContextPtr ctxt)2338 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2339     xmlXPathObjectPtr obj;
2340     int ret;
2341 
2342     obj = valuePop(ctxt);
2343     if (obj == NULL) {
2344 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2345 	return(0);
2346     }
2347     if (obj->type != XPATH_BOOLEAN)
2348 	ret = xmlXPathCastToBoolean(obj);
2349     else
2350         ret = obj->boolval;
2351     xmlXPathReleaseObject(ctxt->context, obj);
2352     return(ret);
2353 }
2354 
2355 /**
2356  * xmlXPathPopNumber:
2357  * @ctxt:  an XPath parser context
2358  *
2359  * Pops a number from the stack, handling conversion if needed.
2360  * Check error with #xmlXPathCheckError.
2361  *
2362  * Returns the number
2363  */
2364 double
xmlXPathPopNumber(xmlXPathParserContextPtr ctxt)2365 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2366     xmlXPathObjectPtr obj;
2367     double ret;
2368 
2369     obj = valuePop(ctxt);
2370     if (obj == NULL) {
2371 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2372 	return(0);
2373     }
2374     if (obj->type != XPATH_NUMBER)
2375 	ret = xmlXPathCastToNumber(obj);
2376     else
2377         ret = obj->floatval;
2378     xmlXPathReleaseObject(ctxt->context, obj);
2379     return(ret);
2380 }
2381 
2382 /**
2383  * xmlXPathPopString:
2384  * @ctxt:  an XPath parser context
2385  *
2386  * Pops a string from the stack, handling conversion if needed.
2387  * Check error with #xmlXPathCheckError.
2388  *
2389  * Returns the string
2390  */
2391 xmlChar *
xmlXPathPopString(xmlXPathParserContextPtr ctxt)2392 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2393     xmlXPathObjectPtr obj;
2394     xmlChar * ret;
2395 
2396     obj = valuePop(ctxt);
2397     if (obj == NULL) {
2398 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2399 	return(NULL);
2400     }
2401     ret = xmlXPathCastToString(obj);	/* this does required strdup */
2402     /* TODO: needs refactoring somewhere else */
2403     if (obj->stringval == ret)
2404 	obj->stringval = NULL;
2405     xmlXPathReleaseObject(ctxt->context, obj);
2406     return(ret);
2407 }
2408 
2409 /**
2410  * xmlXPathPopNodeSet:
2411  * @ctxt:  an XPath parser context
2412  *
2413  * Pops a node-set from the stack, handling conversion if needed.
2414  * Check error with #xmlXPathCheckError.
2415  *
2416  * Returns the node-set
2417  */
2418 xmlNodeSetPtr
xmlXPathPopNodeSet(xmlXPathParserContextPtr ctxt)2419 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2420     xmlXPathObjectPtr obj;
2421     xmlNodeSetPtr ret;
2422 
2423     if (ctxt == NULL) return(NULL);
2424     if (ctxt->value == NULL) {
2425 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2426 	return(NULL);
2427     }
2428     if (!xmlXPathStackIsNodeSet(ctxt)) {
2429 	xmlXPathSetTypeError(ctxt);
2430 	return(NULL);
2431     }
2432     obj = valuePop(ctxt);
2433     ret = obj->nodesetval;
2434 #if 0
2435     /* to fix memory leak of not clearing obj->user */
2436     if (obj->boolval && obj->user != NULL)
2437         xmlFreeNodeList((xmlNodePtr) obj->user);
2438 #endif
2439     obj->nodesetval = NULL;
2440     xmlXPathReleaseObject(ctxt->context, obj);
2441     return(ret);
2442 }
2443 
2444 /**
2445  * xmlXPathPopExternal:
2446  * @ctxt:  an XPath parser context
2447  *
2448  * Pops an external object from the stack, handling conversion if needed.
2449  * Check error with #xmlXPathCheckError.
2450  *
2451  * Returns the object
2452  */
2453 void *
xmlXPathPopExternal(xmlXPathParserContextPtr ctxt)2454 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2455     xmlXPathObjectPtr obj;
2456     void * ret;
2457 
2458     if ((ctxt == NULL) || (ctxt->value == NULL)) {
2459 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2460 	return(NULL);
2461     }
2462     if (ctxt->value->type != XPATH_USERS) {
2463 	xmlXPathSetTypeError(ctxt);
2464 	return(NULL);
2465     }
2466     obj = valuePop(ctxt);
2467     ret = obj->user;
2468     obj->user = NULL;
2469     xmlXPathReleaseObject(ctxt->context, obj);
2470     return(ret);
2471 }
2472 
2473 /*
2474  * Macros for accessing the content. Those should be used only by the parser,
2475  * and not exported.
2476  *
2477  * Dirty macros, i.e. one need to make assumption on the context to use them
2478  *
2479  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2480  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2481  *           in ISO-Latin or UTF-8.
2482  *           This should be used internally by the parser
2483  *           only to compare to ASCII values otherwise it would break when
2484  *           running with UTF-8 encoding.
2485  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2486  *           to compare on ASCII based substring.
2487  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2488  *           strings within the parser.
2489  *   CURRENT Returns the current char value, with the full decoding of
2490  *           UTF-8 if we are using this mode. It returns an int.
2491  *   NEXT    Skip to the next character, this does the proper decoding
2492  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2493  *           It returns the pointer to the current xmlChar.
2494  */
2495 
2496 #define CUR (*ctxt->cur)
2497 #define SKIP(val) ctxt->cur += (val)
2498 #define NXT(val) ctxt->cur[(val)]
2499 #define CUR_PTR ctxt->cur
2500 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2501 
2502 #define COPY_BUF(l,b,i,v)                                              \
2503     if (l == 1) b[i++] = v;                                            \
2504     else i += xmlCopyChar(l,&b[i],v)
2505 
2506 #define NEXTL(l)  ctxt->cur += l
2507 
2508 #define SKIP_BLANKS							\
2509     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2510 
2511 #define CURRENT (*ctxt->cur)
2512 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
2513 
2514 
2515 #ifndef DBL_DIG
2516 #define DBL_DIG 16
2517 #endif
2518 #ifndef DBL_EPSILON
2519 #define DBL_EPSILON 1E-9
2520 #endif
2521 
2522 #define UPPER_DOUBLE 1E9
2523 #define LOWER_DOUBLE 1E-5
2524 #define	LOWER_DOUBLE_EXP 5
2525 
2526 #define INTEGER_DIGITS DBL_DIG
2527 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2528 #define EXPONENT_DIGITS (3 + 2)
2529 
2530 /**
2531  * xmlXPathFormatNumber:
2532  * @number:     number to format
2533  * @buffer:     output buffer
2534  * @buffersize: size of output buffer
2535  *
2536  * Convert the number into a string representation.
2537  */
2538 static void
xmlXPathFormatNumber(double number,char buffer[],int buffersize)2539 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2540 {
2541     switch (xmlXPathIsInf(number)) {
2542     case 1:
2543 	if (buffersize > (int)sizeof("Infinity"))
2544 	    snprintf(buffer, buffersize, "Infinity");
2545 	break;
2546     case -1:
2547 	if (buffersize > (int)sizeof("-Infinity"))
2548 	    snprintf(buffer, buffersize, "-Infinity");
2549 	break;
2550     default:
2551 	if (xmlXPathIsNaN(number)) {
2552 	    if (buffersize > (int)sizeof("NaN"))
2553 		snprintf(buffer, buffersize, "NaN");
2554 	} else if (number == 0) {
2555             /* Omit sign for negative zero. */
2556 	    snprintf(buffer, buffersize, "0");
2557 	} else if ((number > INT_MIN) && (number < INT_MAX) &&
2558                    (number == (int) number)) {
2559 	    char work[30];
2560 	    char *ptr, *cur;
2561 	    int value = (int) number;
2562 
2563             ptr = &buffer[0];
2564 	    if (value == 0) {
2565 		*ptr++ = '0';
2566 	    } else {
2567 		snprintf(work, 29, "%d", value);
2568 		cur = &work[0];
2569 		while ((*cur) && (ptr - buffer < buffersize)) {
2570 		    *ptr++ = *cur++;
2571 		}
2572 	    }
2573 	    if (ptr - buffer < buffersize) {
2574 		*ptr = 0;
2575 	    } else if (buffersize > 0) {
2576 		ptr--;
2577 		*ptr = 0;
2578 	    }
2579 	} else {
2580 	    /*
2581 	      For the dimension of work,
2582 	          DBL_DIG is number of significant digits
2583 		  EXPONENT is only needed for "scientific notation"
2584 	          3 is sign, decimal point, and terminating zero
2585 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2586 	      Note that this dimension is slightly (a few characters)
2587 	      larger than actually necessary.
2588 	    */
2589 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2590 	    int integer_place, fraction_place;
2591 	    char *ptr;
2592 	    char *after_fraction;
2593 	    double absolute_value;
2594 	    int size;
2595 
2596 	    absolute_value = fabs(number);
2597 
2598 	    /*
2599 	     * First choose format - scientific or regular floating point.
2600 	     * In either case, result is in work, and after_fraction points
2601 	     * just past the fractional part.
2602 	    */
2603 	    if ( ((absolute_value > UPPER_DOUBLE) ||
2604 		  (absolute_value < LOWER_DOUBLE)) &&
2605 		 (absolute_value != 0.0) ) {
2606 		/* Use scientific notation */
2607 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2608 		fraction_place = DBL_DIG - 1;
2609 		size = snprintf(work, sizeof(work),"%*.*e",
2610 			 integer_place, fraction_place, number);
2611 		while ((size > 0) && (work[size] != 'e')) size--;
2612 
2613 	    }
2614 	    else {
2615 		/* Use regular notation */
2616 		if (absolute_value > 0.0) {
2617 		    integer_place = (int)log10(absolute_value);
2618 		    if (integer_place > 0)
2619 		        fraction_place = DBL_DIG - integer_place - 1;
2620 		    else
2621 		        fraction_place = DBL_DIG - integer_place;
2622 		} else {
2623 		    fraction_place = 1;
2624 		}
2625 		size = snprintf(work, sizeof(work), "%0.*f",
2626 				fraction_place, number);
2627 	    }
2628 
2629 	    /* Remove leading spaces sometimes inserted by snprintf */
2630 	    while (work[0] == ' ') {
2631 	        for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2632 		size--;
2633 	    }
2634 
2635 	    /* Remove fractional trailing zeroes */
2636 	    after_fraction = work + size;
2637 	    ptr = after_fraction;
2638 	    while (*(--ptr) == '0')
2639 		;
2640 	    if (*ptr != '.')
2641 	        ptr++;
2642 	    while ((*ptr++ = *after_fraction++) != 0);
2643 
2644 	    /* Finally copy result back to caller */
2645 	    size = strlen(work) + 1;
2646 	    if (size > buffersize) {
2647 		work[buffersize - 1] = 0;
2648 		size = buffersize;
2649 	    }
2650 	    memmove(buffer, work, size);
2651 	}
2652 	break;
2653     }
2654 }
2655 
2656 
2657 /************************************************************************
2658  *									*
2659  *			Routines to handle NodeSets			*
2660  *									*
2661  ************************************************************************/
2662 
2663 /**
2664  * xmlXPathOrderDocElems:
2665  * @doc:  an input document
2666  *
2667  * Call this routine to speed up XPath computation on static documents.
2668  * This stamps all the element nodes with the document order
2669  * Like for line information, the order is kept in the element->content
2670  * field, the value stored is actually - the node number (starting at -1)
2671  * to be able to differentiate from line numbers.
2672  *
2673  * Returns the number of elements found in the document or -1 in case
2674  *    of error.
2675  */
2676 long
xmlXPathOrderDocElems(xmlDocPtr doc)2677 xmlXPathOrderDocElems(xmlDocPtr doc) {
2678     ptrdiff_t count = 0;
2679     xmlNodePtr cur;
2680 
2681     if (doc == NULL)
2682 	return(-1);
2683     cur = doc->children;
2684     while (cur != NULL) {
2685 	if (cur->type == XML_ELEMENT_NODE) {
2686 	    cur->content = (void *) (-(++count));
2687 	    if (cur->children != NULL) {
2688 		cur = cur->children;
2689 		continue;
2690 	    }
2691 	}
2692 	if (cur->next != NULL) {
2693 	    cur = cur->next;
2694 	    continue;
2695 	}
2696 	do {
2697 	    cur = cur->parent;
2698 	    if (cur == NULL)
2699 		break;
2700 	    if (cur == (xmlNodePtr) doc) {
2701 		cur = NULL;
2702 		break;
2703 	    }
2704 	    if (cur->next != NULL) {
2705 		cur = cur->next;
2706 		break;
2707 	    }
2708 	} while (cur != NULL);
2709     }
2710     return(count);
2711 }
2712 
2713 /**
2714  * xmlXPathCmpNodes:
2715  * @node1:  the first node
2716  * @node2:  the second node
2717  *
2718  * Compare two nodes w.r.t document order
2719  *
2720  * Returns -2 in case of error 1 if first point < second point, 0 if
2721  *         it's the same node, -1 otherwise
2722  */
2723 int
xmlXPathCmpNodes(xmlNodePtr node1,xmlNodePtr node2)2724 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2725     int depth1, depth2;
2726     int attr1 = 0, attr2 = 0;
2727     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2728     xmlNodePtr cur, root;
2729 
2730     if ((node1 == NULL) || (node2 == NULL))
2731 	return(-2);
2732     /*
2733      * a couple of optimizations which will avoid computations in most cases
2734      */
2735     if (node1 == node2)		/* trivial case */
2736 	return(0);
2737     if (node1->type == XML_ATTRIBUTE_NODE) {
2738 	attr1 = 1;
2739 	attrNode1 = node1;
2740 	node1 = node1->parent;
2741     }
2742     if (node2->type == XML_ATTRIBUTE_NODE) {
2743 	attr2 = 1;
2744 	attrNode2 = node2;
2745 	node2 = node2->parent;
2746     }
2747     if (node1 == node2) {
2748 	if (attr1 == attr2) {
2749 	    /* not required, but we keep attributes in order */
2750 	    if (attr1 != 0) {
2751 	        cur = attrNode2->prev;
2752 		while (cur != NULL) {
2753 		    if (cur == attrNode1)
2754 		        return (1);
2755 		    cur = cur->prev;
2756 		}
2757 		return (-1);
2758 	    }
2759 	    return(0);
2760 	}
2761 	if (attr2 == 1)
2762 	    return(1);
2763 	return(-1);
2764     }
2765     if ((node1->type == XML_NAMESPACE_DECL) ||
2766         (node2->type == XML_NAMESPACE_DECL))
2767 	return(1);
2768     if (node1 == node2->prev)
2769 	return(1);
2770     if (node1 == node2->next)
2771 	return(-1);
2772 
2773     /*
2774      * Speedup using document order if available.
2775      */
2776     if ((node1->type == XML_ELEMENT_NODE) &&
2777 	(node2->type == XML_ELEMENT_NODE) &&
2778 	(0 > (ptrdiff_t) node1->content) &&
2779 	(0 > (ptrdiff_t) node2->content) &&
2780 	(node1->doc == node2->doc)) {
2781 	ptrdiff_t l1, l2;
2782 
2783 	l1 = -((ptrdiff_t) node1->content);
2784 	l2 = -((ptrdiff_t) node2->content);
2785 	if (l1 < l2)
2786 	    return(1);
2787 	if (l1 > l2)
2788 	    return(-1);
2789     }
2790 
2791     /*
2792      * compute depth to root
2793      */
2794     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2795 	if (cur->parent == node1)
2796 	    return(1);
2797 	depth2++;
2798     }
2799     root = cur;
2800     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2801 	if (cur->parent == node2)
2802 	    return(-1);
2803 	depth1++;
2804     }
2805     /*
2806      * Distinct document (or distinct entities :-( ) case.
2807      */
2808     if (root != cur) {
2809 	return(-2);
2810     }
2811     /*
2812      * get the nearest common ancestor.
2813      */
2814     while (depth1 > depth2) {
2815 	depth1--;
2816 	node1 = node1->parent;
2817     }
2818     while (depth2 > depth1) {
2819 	depth2--;
2820 	node2 = node2->parent;
2821     }
2822     while (node1->parent != node2->parent) {
2823 	node1 = node1->parent;
2824 	node2 = node2->parent;
2825 	/* should not happen but just in case ... */
2826 	if ((node1 == NULL) || (node2 == NULL))
2827 	    return(-2);
2828     }
2829     /*
2830      * Find who's first.
2831      */
2832     if (node1 == node2->prev)
2833 	return(1);
2834     if (node1 == node2->next)
2835 	return(-1);
2836     /*
2837      * Speedup using document order if available.
2838      */
2839     if ((node1->type == XML_ELEMENT_NODE) &&
2840 	(node2->type == XML_ELEMENT_NODE) &&
2841 	(0 > (ptrdiff_t) node1->content) &&
2842 	(0 > (ptrdiff_t) node2->content) &&
2843 	(node1->doc == node2->doc)) {
2844 	ptrdiff_t l1, l2;
2845 
2846 	l1 = -((ptrdiff_t) node1->content);
2847 	l2 = -((ptrdiff_t) node2->content);
2848 	if (l1 < l2)
2849 	    return(1);
2850 	if (l1 > l2)
2851 	    return(-1);
2852     }
2853 
2854     for (cur = node1->next;cur != NULL;cur = cur->next)
2855 	if (cur == node2)
2856 	    return(1);
2857     return(-1); /* assume there is no sibling list corruption */
2858 }
2859 
2860 /**
2861  * xmlXPathNodeSetSort:
2862  * @set:  the node set
2863  *
2864  * Sort the node set in document order
2865  */
2866 void
xmlXPathNodeSetSort(xmlNodeSetPtr set)2867 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
2868 #ifndef WITH_TIM_SORT
2869     int i, j, incr, len;
2870     xmlNodePtr tmp;
2871 #endif
2872 
2873     if (set == NULL)
2874 	return;
2875 
2876 #ifndef WITH_TIM_SORT
2877     /*
2878      * Use the old Shell's sort implementation to sort the node-set
2879      * Timsort ought to be quite faster
2880      */
2881     len = set->nodeNr;
2882     for (incr = len / 2; incr > 0; incr /= 2) {
2883 	for (i = incr; i < len; i++) {
2884 	    j = i - incr;
2885 	    while (j >= 0) {
2886 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2887 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
2888 			set->nodeTab[j + incr]) == -1)
2889 #else
2890 		if (xmlXPathCmpNodes(set->nodeTab[j],
2891 			set->nodeTab[j + incr]) == -1)
2892 #endif
2893 		{
2894 		    tmp = set->nodeTab[j];
2895 		    set->nodeTab[j] = set->nodeTab[j + incr];
2896 		    set->nodeTab[j + incr] = tmp;
2897 		    j -= incr;
2898 		} else
2899 		    break;
2900 	    }
2901 	}
2902     }
2903 #else /* WITH_TIM_SORT */
2904     libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2905 #endif /* WITH_TIM_SORT */
2906 }
2907 
2908 #define XML_NODESET_DEFAULT	10
2909 /**
2910  * xmlXPathNodeSetDupNs:
2911  * @node:  the parent node of the namespace XPath node
2912  * @ns:  the libxml namespace declaration node.
2913  *
2914  * Namespace node in libxml don't match the XPath semantic. In a node set
2915  * the namespace nodes are duplicated and the next pointer is set to the
2916  * parent node in the XPath semantic.
2917  *
2918  * Returns the newly created object.
2919  */
2920 static xmlNodePtr
xmlXPathNodeSetDupNs(xmlNodePtr node,xmlNsPtr ns)2921 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2922     xmlNsPtr cur;
2923 
2924     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2925 	return(NULL);
2926     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
2927 	return((xmlNodePtr) ns);
2928 
2929     /*
2930      * Allocate a new Namespace and fill the fields.
2931      */
2932     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2933     if (cur == NULL) {
2934         xmlXPathErrMemory(NULL, "duplicating namespace\n");
2935 	return(NULL);
2936     }
2937     memset(cur, 0, sizeof(xmlNs));
2938     cur->type = XML_NAMESPACE_DECL;
2939     if (ns->href != NULL)
2940 	cur->href = xmlStrdup(ns->href);
2941     if (ns->prefix != NULL)
2942 	cur->prefix = xmlStrdup(ns->prefix);
2943     cur->next = (xmlNsPtr) node;
2944     return((xmlNodePtr) cur);
2945 }
2946 
2947 /**
2948  * xmlXPathNodeSetFreeNs:
2949  * @ns:  the XPath namespace node found in a nodeset.
2950  *
2951  * Namespace nodes in libxml don't match the XPath semantic. In a node set
2952  * the namespace nodes are duplicated and the next pointer is set to the
2953  * parent node in the XPath semantic. Check if such a node needs to be freed
2954  */
2955 void
xmlXPathNodeSetFreeNs(xmlNsPtr ns)2956 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
2957     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2958 	return;
2959 
2960     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2961 	if (ns->href != NULL)
2962 	    xmlFree((xmlChar *)ns->href);
2963 	if (ns->prefix != NULL)
2964 	    xmlFree((xmlChar *)ns->prefix);
2965 	xmlFree(ns);
2966     }
2967 }
2968 
2969 /**
2970  * xmlXPathNodeSetCreate:
2971  * @val:  an initial xmlNodePtr, or NULL
2972  *
2973  * Create a new xmlNodeSetPtr of type double and of value @val
2974  *
2975  * Returns the newly created object.
2976  */
2977 xmlNodeSetPtr
xmlXPathNodeSetCreate(xmlNodePtr val)2978 xmlXPathNodeSetCreate(xmlNodePtr val) {
2979     xmlNodeSetPtr ret;
2980 
2981     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2982     if (ret == NULL) {
2983         xmlXPathErrMemory(NULL, "creating nodeset\n");
2984 	return(NULL);
2985     }
2986     memset(ret, 0 , sizeof(xmlNodeSet));
2987     if (val != NULL) {
2988         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2989 					     sizeof(xmlNodePtr));
2990 	if (ret->nodeTab == NULL) {
2991 	    xmlXPathErrMemory(NULL, "creating nodeset\n");
2992 	    xmlFree(ret);
2993 	    return(NULL);
2994 	}
2995 	memset(ret->nodeTab, 0 ,
2996 	       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2997         ret->nodeMax = XML_NODESET_DEFAULT;
2998 	if (val->type == XML_NAMESPACE_DECL) {
2999 	    xmlNsPtr ns = (xmlNsPtr) val;
3000             xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3001 
3002             if (nsNode == NULL) {
3003                 xmlXPathFreeNodeSet(ret);
3004                 return(NULL);
3005             }
3006 	    ret->nodeTab[ret->nodeNr++] = nsNode;
3007 	} else
3008 	    ret->nodeTab[ret->nodeNr++] = val;
3009     }
3010     return(ret);
3011 }
3012 
3013 /**
3014  * xmlXPathNodeSetContains:
3015  * @cur:  the node-set
3016  * @val:  the node
3017  *
3018  * checks whether @cur contains @val
3019  *
3020  * Returns true (1) if @cur contains @val, false (0) otherwise
3021  */
3022 int
xmlXPathNodeSetContains(xmlNodeSetPtr cur,xmlNodePtr val)3023 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3024     int i;
3025 
3026     if ((cur == NULL) || (val == NULL)) return(0);
3027     if (val->type == XML_NAMESPACE_DECL) {
3028 	for (i = 0; i < cur->nodeNr; i++) {
3029 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3030 		xmlNsPtr ns1, ns2;
3031 
3032 		ns1 = (xmlNsPtr) val;
3033 		ns2 = (xmlNsPtr) cur->nodeTab[i];
3034 		if (ns1 == ns2)
3035 		    return(1);
3036 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3037 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
3038 		    return(1);
3039 	    }
3040 	}
3041     } else {
3042 	for (i = 0; i < cur->nodeNr; i++) {
3043 	    if (cur->nodeTab[i] == val)
3044 		return(1);
3045 	}
3046     }
3047     return(0);
3048 }
3049 
3050 /**
3051  * xmlXPathNodeSetAddNs:
3052  * @cur:  the initial node set
3053  * @node:  the hosting node
3054  * @ns:  a the namespace node
3055  *
3056  * add a new namespace node to an existing NodeSet
3057  *
3058  * Returns 0 in case of success and -1 in case of error
3059  */
3060 int
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur,xmlNodePtr node,xmlNsPtr ns)3061 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3062     int i;
3063     xmlNodePtr nsNode;
3064 
3065     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3066         (ns->type != XML_NAMESPACE_DECL) ||
3067 	(node->type != XML_ELEMENT_NODE))
3068 	return(-1);
3069 
3070     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3071     /*
3072      * prevent duplicates
3073      */
3074     for (i = 0;i < cur->nodeNr;i++) {
3075         if ((cur->nodeTab[i] != NULL) &&
3076 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3077 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3078 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3079 	    return(0);
3080     }
3081 
3082     /*
3083      * grow the nodeTab if needed
3084      */
3085     if (cur->nodeMax == 0) {
3086         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3087 					     sizeof(xmlNodePtr));
3088 	if (cur->nodeTab == NULL) {
3089 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3090 	    return(-1);
3091 	}
3092 	memset(cur->nodeTab, 0 ,
3093 	       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3094         cur->nodeMax = XML_NODESET_DEFAULT;
3095     } else if (cur->nodeNr == cur->nodeMax) {
3096         xmlNodePtr *temp;
3097 
3098         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3099             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3100             return(-1);
3101         }
3102 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3103 				      sizeof(xmlNodePtr));
3104 	if (temp == NULL) {
3105 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3106 	    return(-1);
3107 	}
3108         cur->nodeMax *= 2;
3109 	cur->nodeTab = temp;
3110     }
3111     nsNode = xmlXPathNodeSetDupNs(node, ns);
3112     if(nsNode == NULL)
3113         return(-1);
3114     cur->nodeTab[cur->nodeNr++] = nsNode;
3115     return(0);
3116 }
3117 
3118 /**
3119  * xmlXPathNodeSetAdd:
3120  * @cur:  the initial node set
3121  * @val:  a new xmlNodePtr
3122  *
3123  * add a new xmlNodePtr to an existing NodeSet
3124  *
3125  * Returns 0 in case of success, and -1 in case of error
3126  */
3127 int
xmlXPathNodeSetAdd(xmlNodeSetPtr cur,xmlNodePtr val)3128 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3129     int i;
3130 
3131     if ((cur == NULL) || (val == NULL)) return(-1);
3132 
3133     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3134     /*
3135      * prevent duplicates
3136      */
3137     for (i = 0;i < cur->nodeNr;i++)
3138         if (cur->nodeTab[i] == val) return(0);
3139 
3140     /*
3141      * grow the nodeTab if needed
3142      */
3143     if (cur->nodeMax == 0) {
3144         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3145 					     sizeof(xmlNodePtr));
3146 	if (cur->nodeTab == NULL) {
3147 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3148 	    return(-1);
3149 	}
3150 	memset(cur->nodeTab, 0 ,
3151 	       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3152         cur->nodeMax = XML_NODESET_DEFAULT;
3153     } else if (cur->nodeNr == cur->nodeMax) {
3154         xmlNodePtr *temp;
3155 
3156         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3157             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3158             return(-1);
3159         }
3160 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3161 				      sizeof(xmlNodePtr));
3162 	if (temp == NULL) {
3163 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3164 	    return(-1);
3165 	}
3166         cur->nodeMax *= 2;
3167 	cur->nodeTab = temp;
3168     }
3169     if (val->type == XML_NAMESPACE_DECL) {
3170 	xmlNsPtr ns = (xmlNsPtr) val;
3171         xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3172 
3173         if (nsNode == NULL)
3174             return(-1);
3175 	cur->nodeTab[cur->nodeNr++] = nsNode;
3176     } else
3177 	cur->nodeTab[cur->nodeNr++] = val;
3178     return(0);
3179 }
3180 
3181 /**
3182  * xmlXPathNodeSetAddUnique:
3183  * @cur:  the initial node set
3184  * @val:  a new xmlNodePtr
3185  *
3186  * add a new xmlNodePtr to an existing NodeSet, optimized version
3187  * when we are sure the node is not already in the set.
3188  *
3189  * Returns 0 in case of success and -1 in case of failure
3190  */
3191 int
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur,xmlNodePtr val)3192 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3193     if ((cur == NULL) || (val == NULL)) return(-1);
3194 
3195     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3196     /*
3197      * grow the nodeTab if needed
3198      */
3199     if (cur->nodeMax == 0) {
3200         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3201 					     sizeof(xmlNodePtr));
3202 	if (cur->nodeTab == NULL) {
3203 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3204 	    return(-1);
3205 	}
3206 	memset(cur->nodeTab, 0 ,
3207 	       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3208         cur->nodeMax = XML_NODESET_DEFAULT;
3209     } else if (cur->nodeNr == cur->nodeMax) {
3210         xmlNodePtr *temp;
3211 
3212         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3213             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3214             return(-1);
3215         }
3216 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3217 				      sizeof(xmlNodePtr));
3218 	if (temp == NULL) {
3219 	    xmlXPathErrMemory(NULL, "growing nodeset\n");
3220 	    return(-1);
3221 	}
3222 	cur->nodeTab = temp;
3223         cur->nodeMax *= 2;
3224     }
3225     if (val->type == XML_NAMESPACE_DECL) {
3226 	xmlNsPtr ns = (xmlNsPtr) val;
3227         xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3228 
3229         if (nsNode == NULL)
3230             return(-1);
3231 	cur->nodeTab[cur->nodeNr++] = nsNode;
3232     } else
3233 	cur->nodeTab[cur->nodeNr++] = val;
3234     return(0);
3235 }
3236 
3237 /**
3238  * xmlXPathNodeSetMerge:
3239  * @val1:  the first NodeSet or NULL
3240  * @val2:  the second NodeSet
3241  *
3242  * Merges two nodesets, all nodes from @val2 are added to @val1
3243  * if @val1 is NULL, a new set is created and copied from @val2
3244  *
3245  * Returns @val1 once extended or NULL in case of error.
3246  *
3247  * Frees @val1 in case of error.
3248  */
3249 xmlNodeSetPtr
xmlXPathNodeSetMerge(xmlNodeSetPtr val1,xmlNodeSetPtr val2)3250 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3251     int i, j, initNr, skip;
3252     xmlNodePtr n1, n2;
3253 
3254     if (val2 == NULL) return(val1);
3255     if (val1 == NULL) {
3256 	val1 = xmlXPathNodeSetCreate(NULL);
3257         if (val1 == NULL)
3258             return (NULL);
3259     }
3260 
3261     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3262     initNr = val1->nodeNr;
3263 
3264     for (i = 0;i < val2->nodeNr;i++) {
3265 	n2 = val2->nodeTab[i];
3266 	/*
3267 	 * check against duplicates
3268 	 */
3269 	skip = 0;
3270 	for (j = 0; j < initNr; j++) {
3271 	    n1 = val1->nodeTab[j];
3272 	    if (n1 == n2) {
3273 		skip = 1;
3274 		break;
3275 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3276 		       (n2->type == XML_NAMESPACE_DECL)) {
3277 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3278 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3279 			((xmlNsPtr) n2)->prefix)))
3280 		{
3281 		    skip = 1;
3282 		    break;
3283 		}
3284 	    }
3285 	}
3286 	if (skip)
3287 	    continue;
3288 
3289 	/*
3290 	 * grow the nodeTab if needed
3291 	 */
3292 	if (val1->nodeMax == 0) {
3293 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3294 						    sizeof(xmlNodePtr));
3295 	    if (val1->nodeTab == NULL) {
3296 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3297 		goto error;
3298 	    }
3299 	    memset(val1->nodeTab, 0 ,
3300 		   XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3301 	    val1->nodeMax = XML_NODESET_DEFAULT;
3302 	} else if (val1->nodeNr == val1->nodeMax) {
3303 	    xmlNodePtr *temp;
3304 
3305             if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3306                 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3307                 goto error;
3308             }
3309 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3310 					     sizeof(xmlNodePtr));
3311 	    if (temp == NULL) {
3312 	        xmlXPathErrMemory(NULL, "merging nodeset\n");
3313 		goto error;
3314 	    }
3315 	    val1->nodeTab = temp;
3316 	    val1->nodeMax *= 2;
3317 	}
3318 	if (n2->type == XML_NAMESPACE_DECL) {
3319 	    xmlNsPtr ns = (xmlNsPtr) n2;
3320             xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3321 
3322             if (nsNode == NULL)
3323                 goto error;
3324 	    val1->nodeTab[val1->nodeNr++] = nsNode;
3325 	} else
3326 	    val1->nodeTab[val1->nodeNr++] = n2;
3327     }
3328 
3329     return(val1);
3330 
3331 error:
3332     xmlXPathFreeNodeSet(val1);
3333     return(NULL);
3334 }
3335 
3336 
3337 /**
3338  * xmlXPathNodeSetMergeAndClear:
3339  * @set1:  the first NodeSet or NULL
3340  * @set2:  the second NodeSet
3341  *
3342  * Merges two nodesets, all nodes from @set2 are added to @set1.
3343  * Checks for duplicate nodes. Clears set2.
3344  *
3345  * Returns @set1 once extended or NULL in case of error.
3346  *
3347  * Frees @set1 in case of error.
3348  */
3349 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1,xmlNodeSetPtr set2)3350 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3351 {
3352     {
3353 	int i, j, initNbSet1;
3354 	xmlNodePtr n1, n2;
3355 
3356 	initNbSet1 = set1->nodeNr;
3357 	for (i = 0;i < set2->nodeNr;i++) {
3358 	    n2 = set2->nodeTab[i];
3359 	    /*
3360 	    * Skip duplicates.
3361 	    */
3362 	    for (j = 0; j < initNbSet1; j++) {
3363 		n1 = set1->nodeTab[j];
3364 		if (n1 == n2) {
3365 		    goto skip_node;
3366 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
3367 		    (n2->type == XML_NAMESPACE_DECL))
3368 		{
3369 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3370 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
3371 			((xmlNsPtr) n2)->prefix)))
3372 		    {
3373 			/*
3374 			* Free the namespace node.
3375 			*/
3376 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3377 			goto skip_node;
3378 		    }
3379 		}
3380 	    }
3381 	    /*
3382 	    * grow the nodeTab if needed
3383 	    */
3384 	    if (set1->nodeMax == 0) {
3385 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3386 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3387 		if (set1->nodeTab == NULL) {
3388 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3389 		    goto error;
3390 		}
3391 		memset(set1->nodeTab, 0,
3392 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3393 		set1->nodeMax = XML_NODESET_DEFAULT;
3394 	    } else if (set1->nodeNr >= set1->nodeMax) {
3395 		xmlNodePtr *temp;
3396 
3397                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3398                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3399                     goto error;
3400                 }
3401 		temp = (xmlNodePtr *) xmlRealloc(
3402 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3403 		if (temp == NULL) {
3404 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3405 		    goto error;
3406 		}
3407 		set1->nodeTab = temp;
3408 		set1->nodeMax *= 2;
3409 	    }
3410 	    set1->nodeTab[set1->nodeNr++] = n2;
3411 skip_node:
3412             set2->nodeTab[i] = NULL;
3413 	}
3414     }
3415     set2->nodeNr = 0;
3416     return(set1);
3417 
3418 error:
3419     xmlXPathFreeNodeSet(set1);
3420     xmlXPathNodeSetClear(set2, 1);
3421     return(NULL);
3422 }
3423 
3424 /**
3425  * xmlXPathNodeSetMergeAndClearNoDupls:
3426  * @set1:  the first NodeSet or NULL
3427  * @set2:  the second NodeSet
3428  *
3429  * Merges two nodesets, all nodes from @set2 are added to @set1.
3430  * Doesn't check for duplicate nodes. Clears set2.
3431  *
3432  * Returns @set1 once extended or NULL in case of error.
3433  *
3434  * Frees @set1 in case of error.
3435  */
3436 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1,xmlNodeSetPtr set2)3437 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3438 {
3439     {
3440 	int i;
3441 	xmlNodePtr n2;
3442 
3443 	for (i = 0;i < set2->nodeNr;i++) {
3444 	    n2 = set2->nodeTab[i];
3445 	    if (set1->nodeMax == 0) {
3446 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3447 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3448 		if (set1->nodeTab == NULL) {
3449 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3450 		    goto error;
3451 		}
3452 		memset(set1->nodeTab, 0,
3453 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3454 		set1->nodeMax = XML_NODESET_DEFAULT;
3455 	    } else if (set1->nodeNr >= set1->nodeMax) {
3456 		xmlNodePtr *temp;
3457 
3458                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3459                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3460                     goto error;
3461                 }
3462 		temp = (xmlNodePtr *) xmlRealloc(
3463 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3464 		if (temp == NULL) {
3465 		    xmlXPathErrMemory(NULL, "merging nodeset\n");
3466 		    goto error;
3467 		}
3468 		set1->nodeTab = temp;
3469 		set1->nodeMax *= 2;
3470 	    }
3471 	    set1->nodeTab[set1->nodeNr++] = n2;
3472             set2->nodeTab[i] = NULL;
3473 	}
3474     }
3475     set2->nodeNr = 0;
3476     return(set1);
3477 
3478 error:
3479     xmlXPathFreeNodeSet(set1);
3480     xmlXPathNodeSetClear(set2, 1);
3481     return(NULL);
3482 }
3483 
3484 /**
3485  * xmlXPathNodeSetDel:
3486  * @cur:  the initial node set
3487  * @val:  an xmlNodePtr
3488  *
3489  * Removes an xmlNodePtr from an existing NodeSet
3490  */
3491 void
xmlXPathNodeSetDel(xmlNodeSetPtr cur,xmlNodePtr val)3492 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3493     int i;
3494 
3495     if (cur == NULL) return;
3496     if (val == NULL) return;
3497 
3498     /*
3499      * find node in nodeTab
3500      */
3501     for (i = 0;i < cur->nodeNr;i++)
3502         if (cur->nodeTab[i] == val) break;
3503 
3504     if (i >= cur->nodeNr) {	/* not found */
3505         return;
3506     }
3507     if ((cur->nodeTab[i] != NULL) &&
3508 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
3509 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
3510     cur->nodeNr--;
3511     for (;i < cur->nodeNr;i++)
3512         cur->nodeTab[i] = cur->nodeTab[i + 1];
3513     cur->nodeTab[cur->nodeNr] = NULL;
3514 }
3515 
3516 /**
3517  * xmlXPathNodeSetRemove:
3518  * @cur:  the initial node set
3519  * @val:  the index to remove
3520  *
3521  * Removes an entry from an existing NodeSet list.
3522  */
3523 void
xmlXPathNodeSetRemove(xmlNodeSetPtr cur,int val)3524 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
3525     if (cur == NULL) return;
3526     if (val >= cur->nodeNr) return;
3527     if ((cur->nodeTab[val] != NULL) &&
3528 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
3529 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
3530     cur->nodeNr--;
3531     for (;val < cur->nodeNr;val++)
3532         cur->nodeTab[val] = cur->nodeTab[val + 1];
3533     cur->nodeTab[cur->nodeNr] = NULL;
3534 }
3535 
3536 /**
3537  * xmlXPathFreeNodeSet:
3538  * @obj:  the xmlNodeSetPtr to free
3539  *
3540  * Free the NodeSet compound (not the actual nodes !).
3541  */
3542 void
xmlXPathFreeNodeSet(xmlNodeSetPtr obj)3543 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
3544     if (obj == NULL) return;
3545     if (obj->nodeTab != NULL) {
3546 	int i;
3547 
3548 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
3549 	for (i = 0;i < obj->nodeNr;i++)
3550 	    if ((obj->nodeTab[i] != NULL) &&
3551 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3552 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3553 	xmlFree(obj->nodeTab);
3554     }
3555     xmlFree(obj);
3556 }
3557 
3558 /**
3559  * xmlXPathNodeSetClearFromPos:
3560  * @set: the node set to be cleared
3561  * @pos: the start position to clear from
3562  *
3563  * Clears the list from temporary XPath objects (e.g. namespace nodes
3564  * are feed) starting with the entry at @pos, but does *not* free the list
3565  * itself. Sets the length of the list to @pos.
3566  */
3567 static void
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set,int pos,int hasNsNodes)3568 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
3569 {
3570     if ((set == NULL) || (pos >= set->nodeNr))
3571 	return;
3572     else if ((hasNsNodes)) {
3573 	int i;
3574 	xmlNodePtr node;
3575 
3576 	for (i = pos; i < set->nodeNr; i++) {
3577 	    node = set->nodeTab[i];
3578 	    if ((node != NULL) &&
3579 		(node->type == XML_NAMESPACE_DECL))
3580 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3581 	}
3582     }
3583     set->nodeNr = pos;
3584 }
3585 
3586 /**
3587  * xmlXPathNodeSetClear:
3588  * @set:  the node set to clear
3589  *
3590  * Clears the list from all temporary XPath objects (e.g. namespace nodes
3591  * are feed), but does *not* free the list itself. Sets the length of the
3592  * list to 0.
3593  */
3594 static void
xmlXPathNodeSetClear(xmlNodeSetPtr set,int hasNsNodes)3595 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
3596 {
3597     xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3598 }
3599 
3600 /**
3601  * xmlXPathNodeSetKeepLast:
3602  * @set: the node set to be cleared
3603  *
3604  * Move the last node to the first position and clear temporary XPath objects
3605  * (e.g. namespace nodes) from all other nodes. Sets the length of the list
3606  * to 1.
3607  */
3608 static void
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)3609 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
3610 {
3611     int i;
3612     xmlNodePtr node;
3613 
3614     if ((set == NULL) || (set->nodeNr <= 1))
3615 	return;
3616     for (i = 0; i < set->nodeNr - 1; i++) {
3617         node = set->nodeTab[i];
3618         if ((node != NULL) &&
3619             (node->type == XML_NAMESPACE_DECL))
3620             xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3621     }
3622     set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
3623     set->nodeNr = 1;
3624 }
3625 
3626 /**
3627  * xmlXPathFreeValueTree:
3628  * @obj:  the xmlNodeSetPtr to free
3629  *
3630  * Free the NodeSet compound and the actual tree, this is different
3631  * from xmlXPathFreeNodeSet()
3632  */
3633 static void
xmlXPathFreeValueTree(xmlNodeSetPtr obj)3634 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
3635     int i;
3636 
3637     if (obj == NULL) return;
3638 
3639     if (obj->nodeTab != NULL) {
3640 	for (i = 0;i < obj->nodeNr;i++) {
3641 	    if (obj->nodeTab[i] != NULL) {
3642 		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3643 		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3644 		} else {
3645 		    xmlFreeNodeList(obj->nodeTab[i]);
3646 		}
3647 	    }
3648 	}
3649 	xmlFree(obj->nodeTab);
3650     }
3651     xmlFree(obj);
3652 }
3653 
3654 /**
3655  * xmlXPathNewNodeSet:
3656  * @val:  the NodePtr value
3657  *
3658  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3659  * it with the single Node @val
3660  *
3661  * Returns the newly created object.
3662  */
3663 xmlXPathObjectPtr
xmlXPathNewNodeSet(xmlNodePtr val)3664 xmlXPathNewNodeSet(xmlNodePtr val) {
3665     xmlXPathObjectPtr ret;
3666 
3667     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3668     if (ret == NULL) {
3669         xmlXPathErrMemory(NULL, "creating nodeset\n");
3670 	return(NULL);
3671     }
3672     memset(ret, 0 , sizeof(xmlXPathObject));
3673     ret->type = XPATH_NODESET;
3674     ret->boolval = 0;
3675     /* TODO: Check memory error. */
3676     ret->nodesetval = xmlXPathNodeSetCreate(val);
3677     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3678     return(ret);
3679 }
3680 
3681 /**
3682  * xmlXPathNewValueTree:
3683  * @val:  the NodePtr value
3684  *
3685  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
3686  * it with the tree root @val
3687  *
3688  * Returns the newly created object.
3689  */
3690 xmlXPathObjectPtr
xmlXPathNewValueTree(xmlNodePtr val)3691 xmlXPathNewValueTree(xmlNodePtr val) {
3692     xmlXPathObjectPtr ret;
3693 
3694     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3695     if (ret == NULL) {
3696         xmlXPathErrMemory(NULL, "creating result value tree\n");
3697 	return(NULL);
3698     }
3699     memset(ret, 0 , sizeof(xmlXPathObject));
3700     ret->type = XPATH_XSLT_TREE;
3701     ret->boolval = 0;
3702     ret->user = (void *) val;
3703     ret->nodesetval = xmlXPathNodeSetCreate(val);
3704     return(ret);
3705 }
3706 
3707 /**
3708  * xmlXPathNewNodeSetList:
3709  * @val:  an existing NodeSet
3710  *
3711  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3712  * it with the Nodeset @val
3713  *
3714  * Returns the newly created object.
3715  */
3716 xmlXPathObjectPtr
xmlXPathNewNodeSetList(xmlNodeSetPtr val)3717 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
3718 {
3719     xmlXPathObjectPtr ret;
3720     int i;
3721 
3722     if (val == NULL)
3723         ret = NULL;
3724     else if (val->nodeTab == NULL)
3725         ret = xmlXPathNewNodeSet(NULL);
3726     else {
3727         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
3728         if (ret) {
3729             for (i = 1; i < val->nodeNr; ++i) {
3730                 /* TODO: Propagate memory error. */
3731                 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
3732 		    < 0) break;
3733 	    }
3734 	}
3735     }
3736 
3737     return (ret);
3738 }
3739 
3740 /**
3741  * xmlXPathWrapNodeSet:
3742  * @val:  the NodePtr value
3743  *
3744  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
3745  *
3746  * Returns the newly created object.
3747  *
3748  * In case of error the node set is destroyed and NULL is returned.
3749  */
3750 xmlXPathObjectPtr
xmlXPathWrapNodeSet(xmlNodeSetPtr val)3751 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
3752     xmlXPathObjectPtr ret;
3753 
3754     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3755     if (ret == NULL) {
3756         xmlXPathErrMemory(NULL, "creating node set object\n");
3757         xmlXPathFreeNodeSet(val);
3758 	return(NULL);
3759     }
3760     memset(ret, 0 , sizeof(xmlXPathObject));
3761     ret->type = XPATH_NODESET;
3762     ret->nodesetval = val;
3763     return(ret);
3764 }
3765 
3766 /**
3767  * xmlXPathFreeNodeSetList:
3768  * @obj:  an existing NodeSetList object
3769  *
3770  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
3771  * the list contrary to xmlXPathFreeObject().
3772  */
3773 void
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj)3774 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
3775     if (obj == NULL) return;
3776     xmlFree(obj);
3777 }
3778 
3779 /**
3780  * xmlXPathDifference:
3781  * @nodes1:  a node-set
3782  * @nodes2:  a node-set
3783  *
3784  * Implements the EXSLT - Sets difference() function:
3785  *    node-set set:difference (node-set, node-set)
3786  *
3787  * Returns the difference between the two node sets, or nodes1 if
3788  *         nodes2 is empty
3789  */
3790 xmlNodeSetPtr
xmlXPathDifference(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3791 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3792     xmlNodeSetPtr ret;
3793     int i, l1;
3794     xmlNodePtr cur;
3795 
3796     if (xmlXPathNodeSetIsEmpty(nodes2))
3797 	return(nodes1);
3798 
3799     /* TODO: Check memory error. */
3800     ret = xmlXPathNodeSetCreate(NULL);
3801     if (xmlXPathNodeSetIsEmpty(nodes1))
3802 	return(ret);
3803 
3804     l1 = xmlXPathNodeSetGetLength(nodes1);
3805 
3806     for (i = 0; i < l1; i++) {
3807 	cur = xmlXPathNodeSetItem(nodes1, i);
3808 	if (!xmlXPathNodeSetContains(nodes2, cur)) {
3809             /* TODO: Propagate memory error. */
3810 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3811 	        break;
3812 	}
3813     }
3814     return(ret);
3815 }
3816 
3817 /**
3818  * xmlXPathIntersection:
3819  * @nodes1:  a node-set
3820  * @nodes2:  a node-set
3821  *
3822  * Implements the EXSLT - Sets intersection() function:
3823  *    node-set set:intersection (node-set, node-set)
3824  *
3825  * Returns a node set comprising the nodes that are within both the
3826  *         node sets passed as arguments
3827  */
3828 xmlNodeSetPtr
xmlXPathIntersection(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3829 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3830     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
3831     int i, l1;
3832     xmlNodePtr cur;
3833 
3834     if (ret == NULL)
3835         return(ret);
3836     if (xmlXPathNodeSetIsEmpty(nodes1))
3837 	return(ret);
3838     if (xmlXPathNodeSetIsEmpty(nodes2))
3839 	return(ret);
3840 
3841     l1 = xmlXPathNodeSetGetLength(nodes1);
3842 
3843     for (i = 0; i < l1; i++) {
3844 	cur = xmlXPathNodeSetItem(nodes1, i);
3845 	if (xmlXPathNodeSetContains(nodes2, cur)) {
3846             /* TODO: Propagate memory error. */
3847 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3848 	        break;
3849 	}
3850     }
3851     return(ret);
3852 }
3853 
3854 /**
3855  * xmlXPathDistinctSorted:
3856  * @nodes:  a node-set, sorted by document order
3857  *
3858  * Implements the EXSLT - Sets distinct() function:
3859  *    node-set set:distinct (node-set)
3860  *
3861  * Returns a subset of the nodes contained in @nodes, or @nodes if
3862  *         it is empty
3863  */
3864 xmlNodeSetPtr
xmlXPathDistinctSorted(xmlNodeSetPtr nodes)3865 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
3866     xmlNodeSetPtr ret;
3867     xmlHashTablePtr hash;
3868     int i, l;
3869     xmlChar * strval;
3870     xmlNodePtr cur;
3871 
3872     if (xmlXPathNodeSetIsEmpty(nodes))
3873 	return(nodes);
3874 
3875     ret = xmlXPathNodeSetCreate(NULL);
3876     if (ret == NULL)
3877         return(ret);
3878     l = xmlXPathNodeSetGetLength(nodes);
3879     hash = xmlHashCreate (l);
3880     for (i = 0; i < l; i++) {
3881 	cur = xmlXPathNodeSetItem(nodes, i);
3882 	strval = xmlXPathCastNodeToString(cur);
3883 	if (xmlHashLookup(hash, strval) == NULL) {
3884 	    if (xmlHashAddEntry(hash, strval, strval) < 0) {
3885                 xmlFree(strval);
3886                 goto error;
3887             }
3888 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3889 	        goto error;
3890 	} else {
3891 	    xmlFree(strval);
3892 	}
3893     }
3894     xmlHashFree(hash, xmlHashDefaultDeallocator);
3895     return(ret);
3896 
3897 error:
3898     xmlHashFree(hash, xmlHashDefaultDeallocator);
3899     xmlXPathFreeNodeSet(ret);
3900     return(NULL);
3901 }
3902 
3903 /**
3904  * xmlXPathDistinct:
3905  * @nodes:  a node-set
3906  *
3907  * Implements the EXSLT - Sets distinct() function:
3908  *    node-set set:distinct (node-set)
3909  * @nodes is sorted by document order, then #exslSetsDistinctSorted
3910  * is called with the sorted node-set
3911  *
3912  * Returns a subset of the nodes contained in @nodes, or @nodes if
3913  *         it is empty
3914  */
3915 xmlNodeSetPtr
xmlXPathDistinct(xmlNodeSetPtr nodes)3916 xmlXPathDistinct (xmlNodeSetPtr nodes) {
3917     if (xmlXPathNodeSetIsEmpty(nodes))
3918 	return(nodes);
3919 
3920     xmlXPathNodeSetSort(nodes);
3921     return(xmlXPathDistinctSorted(nodes));
3922 }
3923 
3924 /**
3925  * xmlXPathHasSameNodes:
3926  * @nodes1:  a node-set
3927  * @nodes2:  a node-set
3928  *
3929  * Implements the EXSLT - Sets has-same-nodes function:
3930  *    boolean set:has-same-node(node-set, node-set)
3931  *
3932  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
3933  *         otherwise
3934  */
3935 int
xmlXPathHasSameNodes(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3936 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3937     int i, l;
3938     xmlNodePtr cur;
3939 
3940     if (xmlXPathNodeSetIsEmpty(nodes1) ||
3941 	xmlXPathNodeSetIsEmpty(nodes2))
3942 	return(0);
3943 
3944     l = xmlXPathNodeSetGetLength(nodes1);
3945     for (i = 0; i < l; i++) {
3946 	cur = xmlXPathNodeSetItem(nodes1, i);
3947 	if (xmlXPathNodeSetContains(nodes2, cur))
3948 	    return(1);
3949     }
3950     return(0);
3951 }
3952 
3953 /**
3954  * xmlXPathNodeLeadingSorted:
3955  * @nodes: a node-set, sorted by document order
3956  * @node: a node
3957  *
3958  * Implements the EXSLT - Sets leading() function:
3959  *    node-set set:leading (node-set, node-set)
3960  *
3961  * Returns the nodes in @nodes that precede @node in document order,
3962  *         @nodes if @node is NULL or an empty node-set if @nodes
3963  *         doesn't contain @node
3964  */
3965 xmlNodeSetPtr
xmlXPathNodeLeadingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)3966 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3967     int i, l;
3968     xmlNodePtr cur;
3969     xmlNodeSetPtr ret;
3970 
3971     if (node == NULL)
3972 	return(nodes);
3973 
3974     ret = xmlXPathNodeSetCreate(NULL);
3975     if (ret == NULL)
3976         return(ret);
3977     if (xmlXPathNodeSetIsEmpty(nodes) ||
3978 	(!xmlXPathNodeSetContains(nodes, node)))
3979 	return(ret);
3980 
3981     l = xmlXPathNodeSetGetLength(nodes);
3982     for (i = 0; i < l; i++) {
3983 	cur = xmlXPathNodeSetItem(nodes, i);
3984 	if (cur == node)
3985 	    break;
3986         /* TODO: Propagate memory error. */
3987 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3988 	    break;
3989     }
3990     return(ret);
3991 }
3992 
3993 /**
3994  * xmlXPathNodeLeading:
3995  * @nodes:  a node-set
3996  * @node:  a node
3997  *
3998  * Implements the EXSLT - Sets leading() function:
3999  *    node-set set:leading (node-set, node-set)
4000  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4001  * is called.
4002  *
4003  * Returns the nodes in @nodes that precede @node in document order,
4004  *         @nodes if @node is NULL or an empty node-set if @nodes
4005  *         doesn't contain @node
4006  */
4007 xmlNodeSetPtr
xmlXPathNodeLeading(xmlNodeSetPtr nodes,xmlNodePtr node)4008 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4009     xmlXPathNodeSetSort(nodes);
4010     return(xmlXPathNodeLeadingSorted(nodes, node));
4011 }
4012 
4013 /**
4014  * xmlXPathLeadingSorted:
4015  * @nodes1:  a node-set, sorted by document order
4016  * @nodes2:  a node-set, sorted by document order
4017  *
4018  * Implements the EXSLT - Sets leading() function:
4019  *    node-set set:leading (node-set, node-set)
4020  *
4021  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4022  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4023  *         an empty node-set if @nodes1 doesn't contain @nodes2
4024  */
4025 xmlNodeSetPtr
xmlXPathLeadingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4026 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4027     if (xmlXPathNodeSetIsEmpty(nodes2))
4028 	return(nodes1);
4029     return(xmlXPathNodeLeadingSorted(nodes1,
4030 				     xmlXPathNodeSetItem(nodes2, 1)));
4031 }
4032 
4033 /**
4034  * xmlXPathLeading:
4035  * @nodes1:  a node-set
4036  * @nodes2:  a node-set
4037  *
4038  * Implements the EXSLT - Sets leading() function:
4039  *    node-set set:leading (node-set, node-set)
4040  * @nodes1 and @nodes2 are sorted by document order, then
4041  * #exslSetsLeadingSorted is called.
4042  *
4043  * Returns the nodes in @nodes1 that precede the first node in @nodes2
4044  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4045  *         an empty node-set if @nodes1 doesn't contain @nodes2
4046  */
4047 xmlNodeSetPtr
xmlXPathLeading(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4048 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4049     if (xmlXPathNodeSetIsEmpty(nodes2))
4050 	return(nodes1);
4051     if (xmlXPathNodeSetIsEmpty(nodes1))
4052 	return(xmlXPathNodeSetCreate(NULL));
4053     xmlXPathNodeSetSort(nodes1);
4054     xmlXPathNodeSetSort(nodes2);
4055     return(xmlXPathNodeLeadingSorted(nodes1,
4056 				     xmlXPathNodeSetItem(nodes2, 1)));
4057 }
4058 
4059 /**
4060  * xmlXPathNodeTrailingSorted:
4061  * @nodes: a node-set, sorted by document order
4062  * @node: a node
4063  *
4064  * Implements the EXSLT - Sets trailing() function:
4065  *    node-set set:trailing (node-set, node-set)
4066  *
4067  * Returns the nodes in @nodes that follow @node in document order,
4068  *         @nodes if @node is NULL or an empty node-set if @nodes
4069  *         doesn't contain @node
4070  */
4071 xmlNodeSetPtr
xmlXPathNodeTrailingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4072 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4073     int i, l;
4074     xmlNodePtr cur;
4075     xmlNodeSetPtr ret;
4076 
4077     if (node == NULL)
4078 	return(nodes);
4079 
4080     ret = xmlXPathNodeSetCreate(NULL);
4081     if (ret == NULL)
4082         return(ret);
4083     if (xmlXPathNodeSetIsEmpty(nodes) ||
4084 	(!xmlXPathNodeSetContains(nodes, node)))
4085 	return(ret);
4086 
4087     l = xmlXPathNodeSetGetLength(nodes);
4088     for (i = l - 1; i >= 0; i--) {
4089 	cur = xmlXPathNodeSetItem(nodes, i);
4090 	if (cur == node)
4091 	    break;
4092         /* TODO: Propagate memory error. */
4093 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4094 	    break;
4095     }
4096     xmlXPathNodeSetSort(ret);	/* bug 413451 */
4097     return(ret);
4098 }
4099 
4100 /**
4101  * xmlXPathNodeTrailing:
4102  * @nodes:  a node-set
4103  * @node:  a node
4104  *
4105  * Implements the EXSLT - Sets trailing() function:
4106  *    node-set set:trailing (node-set, node-set)
4107  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4108  * is called.
4109  *
4110  * Returns the nodes in @nodes that follow @node in document order,
4111  *         @nodes if @node is NULL or an empty node-set if @nodes
4112  *         doesn't contain @node
4113  */
4114 xmlNodeSetPtr
xmlXPathNodeTrailing(xmlNodeSetPtr nodes,xmlNodePtr node)4115 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4116     xmlXPathNodeSetSort(nodes);
4117     return(xmlXPathNodeTrailingSorted(nodes, node));
4118 }
4119 
4120 /**
4121  * xmlXPathTrailingSorted:
4122  * @nodes1:  a node-set, sorted by document order
4123  * @nodes2:  a node-set, sorted by document order
4124  *
4125  * Implements the EXSLT - Sets trailing() function:
4126  *    node-set set:trailing (node-set, node-set)
4127  *
4128  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4129  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4130  *         an empty node-set if @nodes1 doesn't contain @nodes2
4131  */
4132 xmlNodeSetPtr
xmlXPathTrailingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4133 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4134     if (xmlXPathNodeSetIsEmpty(nodes2))
4135 	return(nodes1);
4136     return(xmlXPathNodeTrailingSorted(nodes1,
4137 				      xmlXPathNodeSetItem(nodes2, 0)));
4138 }
4139 
4140 /**
4141  * xmlXPathTrailing:
4142  * @nodes1:  a node-set
4143  * @nodes2:  a node-set
4144  *
4145  * Implements the EXSLT - Sets trailing() function:
4146  *    node-set set:trailing (node-set, node-set)
4147  * @nodes1 and @nodes2 are sorted by document order, then
4148  * #xmlXPathTrailingSorted is called.
4149  *
4150  * Returns the nodes in @nodes1 that follow the first node in @nodes2
4151  *         in document order, @nodes1 if @nodes2 is NULL or empty or
4152  *         an empty node-set if @nodes1 doesn't contain @nodes2
4153  */
4154 xmlNodeSetPtr
xmlXPathTrailing(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4155 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4156     if (xmlXPathNodeSetIsEmpty(nodes2))
4157 	return(nodes1);
4158     if (xmlXPathNodeSetIsEmpty(nodes1))
4159 	return(xmlXPathNodeSetCreate(NULL));
4160     xmlXPathNodeSetSort(nodes1);
4161     xmlXPathNodeSetSort(nodes2);
4162     return(xmlXPathNodeTrailingSorted(nodes1,
4163 				      xmlXPathNodeSetItem(nodes2, 0)));
4164 }
4165 
4166 /************************************************************************
4167  *									*
4168  *		Routines to handle extra functions			*
4169  *									*
4170  ************************************************************************/
4171 
4172 /**
4173  * xmlXPathRegisterFunc:
4174  * @ctxt:  the XPath context
4175  * @name:  the function name
4176  * @f:  the function implementation or NULL
4177  *
4178  * Register a new function. If @f is NULL it unregisters the function
4179  *
4180  * Returns 0 in case of success, -1 in case of error
4181  */
4182 int
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathFunction f)4183 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4184 		     xmlXPathFunction f) {
4185     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4186 }
4187 
4188 /**
4189  * xmlXPathRegisterFuncNS:
4190  * @ctxt:  the XPath context
4191  * @name:  the function name
4192  * @ns_uri:  the function namespace URI
4193  * @f:  the function implementation or NULL
4194  *
4195  * Register a new function. If @f is NULL it unregisters the function
4196  *
4197  * Returns 0 in case of success, -1 in case of error
4198  */
4199 int
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathFunction f)4200 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4201 		       const xmlChar *ns_uri, xmlXPathFunction f) {
4202     if (ctxt == NULL)
4203 	return(-1);
4204     if (name == NULL)
4205 	return(-1);
4206 
4207     if (ctxt->funcHash == NULL)
4208 	ctxt->funcHash = xmlHashCreate(0);
4209     if (ctxt->funcHash == NULL)
4210 	return(-1);
4211     if (f == NULL)
4212         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4213 XML_IGNORE_FPTR_CAST_WARNINGS
4214     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4215 XML_POP_WARNINGS
4216 }
4217 
4218 /**
4219  * xmlXPathRegisterFuncLookup:
4220  * @ctxt:  the XPath context
4221  * @f:  the lookup function
4222  * @funcCtxt:  the lookup data
4223  *
4224  * Registers an external mechanism to do function lookup.
4225  */
4226 void
xmlXPathRegisterFuncLookup(xmlXPathContextPtr ctxt,xmlXPathFuncLookupFunc f,void * funcCtxt)4227 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4228 			    xmlXPathFuncLookupFunc f,
4229 			    void *funcCtxt) {
4230     if (ctxt == NULL)
4231 	return;
4232     ctxt->funcLookupFunc = f;
4233     ctxt->funcLookupData = funcCtxt;
4234 }
4235 
4236 /**
4237  * xmlXPathFunctionLookup:
4238  * @ctxt:  the XPath context
4239  * @name:  the function name
4240  *
4241  * Search in the Function array of the context for the given
4242  * function.
4243  *
4244  * Returns the xmlXPathFunction or NULL if not found
4245  */
4246 xmlXPathFunction
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt,const xmlChar * name)4247 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4248     if (ctxt == NULL)
4249 	return (NULL);
4250 
4251     if (ctxt->funcLookupFunc != NULL) {
4252 	xmlXPathFunction ret;
4253 	xmlXPathFuncLookupFunc f;
4254 
4255 	f = ctxt->funcLookupFunc;
4256 	ret = f(ctxt->funcLookupData, name, NULL);
4257 	if (ret != NULL)
4258 	    return(ret);
4259     }
4260     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4261 }
4262 
4263 /**
4264  * xmlXPathFunctionLookupNS:
4265  * @ctxt:  the XPath context
4266  * @name:  the function name
4267  * @ns_uri:  the function namespace URI
4268  *
4269  * Search in the Function array of the context for the given
4270  * function.
4271  *
4272  * Returns the xmlXPathFunction or NULL if not found
4273  */
4274 xmlXPathFunction
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4275 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4276 			 const xmlChar *ns_uri) {
4277     xmlXPathFunction ret;
4278 
4279     if (ctxt == NULL)
4280 	return(NULL);
4281     if (name == NULL)
4282 	return(NULL);
4283 
4284     if (ctxt->funcLookupFunc != NULL) {
4285 	xmlXPathFuncLookupFunc f;
4286 
4287 	f = ctxt->funcLookupFunc;
4288 	ret = f(ctxt->funcLookupData, name, ns_uri);
4289 	if (ret != NULL)
4290 	    return(ret);
4291     }
4292 
4293     if (ctxt->funcHash == NULL)
4294 	return(NULL);
4295 
4296 XML_IGNORE_FPTR_CAST_WARNINGS
4297     ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4298 XML_POP_WARNINGS
4299     return(ret);
4300 }
4301 
4302 /**
4303  * xmlXPathRegisteredFuncsCleanup:
4304  * @ctxt:  the XPath context
4305  *
4306  * Cleanup the XPath context data associated to registered functions
4307  */
4308 void
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt)4309 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4310     if (ctxt == NULL)
4311 	return;
4312 
4313     xmlHashFree(ctxt->funcHash, NULL);
4314     ctxt->funcHash = NULL;
4315 }
4316 
4317 /************************************************************************
4318  *									*
4319  *			Routines to handle Variables			*
4320  *									*
4321  ************************************************************************/
4322 
4323 /**
4324  * xmlXPathRegisterVariable:
4325  * @ctxt:  the XPath context
4326  * @name:  the variable name
4327  * @value:  the variable value or NULL
4328  *
4329  * Register a new variable value. If @value is NULL it unregisters
4330  * the variable
4331  *
4332  * Returns 0 in case of success, -1 in case of error
4333  */
4334 int
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathObjectPtr value)4335 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4336 			 xmlXPathObjectPtr value) {
4337     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4338 }
4339 
4340 /**
4341  * xmlXPathRegisterVariableNS:
4342  * @ctxt:  the XPath context
4343  * @name:  the variable name
4344  * @ns_uri:  the variable namespace URI
4345  * @value:  the variable value or NULL
4346  *
4347  * Register a new variable value. If @value is NULL it unregisters
4348  * the variable
4349  *
4350  * Returns 0 in case of success, -1 in case of error
4351  */
4352 int
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathObjectPtr value)4353 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4354 			   const xmlChar *ns_uri,
4355 			   xmlXPathObjectPtr value) {
4356     if (ctxt == NULL)
4357 	return(-1);
4358     if (name == NULL)
4359 	return(-1);
4360 
4361     if (ctxt->varHash == NULL)
4362 	ctxt->varHash = xmlHashCreate(0);
4363     if (ctxt->varHash == NULL)
4364 	return(-1);
4365     if (value == NULL)
4366         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4367 	                           xmlXPathFreeObjectEntry));
4368     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4369 			       (void *) value, xmlXPathFreeObjectEntry));
4370 }
4371 
4372 /**
4373  * xmlXPathRegisterVariableLookup:
4374  * @ctxt:  the XPath context
4375  * @f:  the lookup function
4376  * @data:  the lookup data
4377  *
4378  * register an external mechanism to do variable lookup
4379  */
4380 void
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,xmlXPathVariableLookupFunc f,void * data)4381 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4382 	 xmlXPathVariableLookupFunc f, void *data) {
4383     if (ctxt == NULL)
4384 	return;
4385     ctxt->varLookupFunc = f;
4386     ctxt->varLookupData = data;
4387 }
4388 
4389 /**
4390  * xmlXPathVariableLookup:
4391  * @ctxt:  the XPath context
4392  * @name:  the variable name
4393  *
4394  * Search in the Variable array of the context for the given
4395  * variable value.
4396  *
4397  * Returns a copy of the value or NULL if not found
4398  */
4399 xmlXPathObjectPtr
xmlXPathVariableLookup(xmlXPathContextPtr ctxt,const xmlChar * name)4400 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4401     if (ctxt == NULL)
4402 	return(NULL);
4403 
4404     if (ctxt->varLookupFunc != NULL) {
4405 	xmlXPathObjectPtr ret;
4406 
4407 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4408 	        (ctxt->varLookupData, name, NULL);
4409 	return(ret);
4410     }
4411     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4412 }
4413 
4414 /**
4415  * xmlXPathVariableLookupNS:
4416  * @ctxt:  the XPath context
4417  * @name:  the variable name
4418  * @ns_uri:  the variable namespace URI
4419  *
4420  * Search in the Variable array of the context for the given
4421  * variable value.
4422  *
4423  * Returns the a copy of the value or NULL if not found
4424  */
4425 xmlXPathObjectPtr
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4426 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4427 			 const xmlChar *ns_uri) {
4428     if (ctxt == NULL)
4429 	return(NULL);
4430 
4431     if (ctxt->varLookupFunc != NULL) {
4432 	xmlXPathObjectPtr ret;
4433 
4434 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4435 	        (ctxt->varLookupData, name, ns_uri);
4436 	if (ret != NULL) return(ret);
4437     }
4438 
4439     if (ctxt->varHash == NULL)
4440 	return(NULL);
4441     if (name == NULL)
4442 	return(NULL);
4443 
4444     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
4445 		xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4446 }
4447 
4448 /**
4449  * xmlXPathRegisteredVariablesCleanup:
4450  * @ctxt:  the XPath context
4451  *
4452  * Cleanup the XPath context data associated to registered variables
4453  */
4454 void
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt)4455 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4456     if (ctxt == NULL)
4457 	return;
4458 
4459     xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
4460     ctxt->varHash = NULL;
4461 }
4462 
4463 /**
4464  * xmlXPathRegisterNs:
4465  * @ctxt:  the XPath context
4466  * @prefix:  the namespace prefix cannot be NULL or empty string
4467  * @ns_uri:  the namespace name
4468  *
4469  * Register a new namespace. If @ns_uri is NULL it unregisters
4470  * the namespace
4471  *
4472  * Returns 0 in case of success, -1 in case of error
4473  */
4474 int
xmlXPathRegisterNs(xmlXPathContextPtr ctxt,const xmlChar * prefix,const xmlChar * ns_uri)4475 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4476 			   const xmlChar *ns_uri) {
4477     xmlChar *copy;
4478 
4479     if (ctxt == NULL)
4480 	return(-1);
4481     if (prefix == NULL)
4482 	return(-1);
4483     if (prefix[0] == 0)
4484 	return(-1);
4485 
4486     if (ctxt->nsHash == NULL)
4487 	ctxt->nsHash = xmlHashCreate(10);
4488     if (ctxt->nsHash == NULL)
4489 	return(-1);
4490     if (ns_uri == NULL)
4491         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
4492 	                          xmlHashDefaultDeallocator));
4493 
4494     copy = xmlStrdup(ns_uri);
4495     if (copy == NULL)
4496         return(-1);
4497     if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
4498                            xmlHashDefaultDeallocator) < 0) {
4499         xmlFree(copy);
4500         return(-1);
4501     }
4502 
4503     return(0);
4504 }
4505 
4506 /**
4507  * xmlXPathNsLookup:
4508  * @ctxt:  the XPath context
4509  * @prefix:  the namespace prefix value
4510  *
4511  * Search in the namespace declaration array of the context for the given
4512  * namespace name associated to the given prefix
4513  *
4514  * Returns the value or NULL if not found
4515  */
4516 const xmlChar *
xmlXPathNsLookup(xmlXPathContextPtr ctxt,const xmlChar * prefix)4517 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
4518     if (ctxt == NULL)
4519 	return(NULL);
4520     if (prefix == NULL)
4521 	return(NULL);
4522 
4523 #ifdef XML_XML_NAMESPACE
4524     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4525 	return(XML_XML_NAMESPACE);
4526 #endif
4527 
4528     if (ctxt->namespaces != NULL) {
4529 	int i;
4530 
4531 	for (i = 0;i < ctxt->nsNr;i++) {
4532 	    if ((ctxt->namespaces[i] != NULL) &&
4533 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4534 		return(ctxt->namespaces[i]->href);
4535 	}
4536     }
4537 
4538     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4539 }
4540 
4541 /**
4542  * xmlXPathRegisteredNsCleanup:
4543  * @ctxt:  the XPath context
4544  *
4545  * Cleanup the XPath context data associated to registered variables
4546  */
4547 void
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt)4548 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
4549     if (ctxt == NULL)
4550 	return;
4551 
4552     xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4553     ctxt->nsHash = NULL;
4554 }
4555 
4556 /************************************************************************
4557  *									*
4558  *			Routines to handle Values			*
4559  *									*
4560  ************************************************************************/
4561 
4562 /* Allocations are terrible, one needs to optimize all this !!! */
4563 
4564 /**
4565  * xmlXPathNewFloat:
4566  * @val:  the double value
4567  *
4568  * Create a new xmlXPathObjectPtr of type double and of value @val
4569  *
4570  * Returns the newly created object.
4571  */
4572 xmlXPathObjectPtr
xmlXPathNewFloat(double val)4573 xmlXPathNewFloat(double val) {
4574     xmlXPathObjectPtr ret;
4575 
4576     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4577     if (ret == NULL) {
4578         xmlXPathErrMemory(NULL, "creating float object\n");
4579 	return(NULL);
4580     }
4581     memset(ret, 0 , sizeof(xmlXPathObject));
4582     ret->type = XPATH_NUMBER;
4583     ret->floatval = val;
4584     return(ret);
4585 }
4586 
4587 /**
4588  * xmlXPathNewBoolean:
4589  * @val:  the boolean value
4590  *
4591  * Create a new xmlXPathObjectPtr of type boolean and of value @val
4592  *
4593  * Returns the newly created object.
4594  */
4595 xmlXPathObjectPtr
xmlXPathNewBoolean(int val)4596 xmlXPathNewBoolean(int val) {
4597     xmlXPathObjectPtr ret;
4598 
4599     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4600     if (ret == NULL) {
4601         xmlXPathErrMemory(NULL, "creating boolean object\n");
4602 	return(NULL);
4603     }
4604     memset(ret, 0 , sizeof(xmlXPathObject));
4605     ret->type = XPATH_BOOLEAN;
4606     ret->boolval = (val != 0);
4607     return(ret);
4608 }
4609 
4610 /**
4611  * xmlXPathNewString:
4612  * @val:  the xmlChar * value
4613  *
4614  * Create a new xmlXPathObjectPtr of type string and of value @val
4615  *
4616  * Returns the newly created object.
4617  */
4618 xmlXPathObjectPtr
xmlXPathNewString(const xmlChar * val)4619 xmlXPathNewString(const xmlChar *val) {
4620     xmlXPathObjectPtr ret;
4621 
4622     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4623     if (ret == NULL) {
4624         xmlXPathErrMemory(NULL, "creating string object\n");
4625 	return(NULL);
4626     }
4627     memset(ret, 0 , sizeof(xmlXPathObject));
4628     ret->type = XPATH_STRING;
4629     if (val == NULL)
4630         val = BAD_CAST "";
4631     ret->stringval = xmlStrdup(val);
4632     if (ret->stringval == NULL) {
4633         xmlFree(ret);
4634         return(NULL);
4635     }
4636     return(ret);
4637 }
4638 
4639 /**
4640  * xmlXPathWrapString:
4641  * @val:  the xmlChar * value
4642  *
4643  * Wraps the @val string into an XPath object.
4644  *
4645  * Returns the newly created object.
4646  *
4647  * Frees @val in case of error.
4648  */
4649 xmlXPathObjectPtr
xmlXPathWrapString(xmlChar * val)4650 xmlXPathWrapString (xmlChar *val) {
4651     xmlXPathObjectPtr ret;
4652 
4653     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4654     if (ret == NULL) {
4655         xmlXPathErrMemory(NULL, "creating string object\n");
4656         xmlFree(val);
4657 	return(NULL);
4658     }
4659     memset(ret, 0 , sizeof(xmlXPathObject));
4660     ret->type = XPATH_STRING;
4661     ret->stringval = val;
4662     return(ret);
4663 }
4664 
4665 /**
4666  * xmlXPathNewCString:
4667  * @val:  the char * value
4668  *
4669  * Create a new xmlXPathObjectPtr of type string and of value @val
4670  *
4671  * Returns the newly created object.
4672  */
4673 xmlXPathObjectPtr
xmlXPathNewCString(const char * val)4674 xmlXPathNewCString(const char *val) {
4675     return(xmlXPathNewString(BAD_CAST val));
4676 }
4677 
4678 /**
4679  * xmlXPathWrapCString:
4680  * @val:  the char * value
4681  *
4682  * Wraps a string into an XPath object.
4683  *
4684  * Returns the newly created object.
4685  */
4686 xmlXPathObjectPtr
xmlXPathWrapCString(char * val)4687 xmlXPathWrapCString (char * val) {
4688     return(xmlXPathWrapString((xmlChar *)(val)));
4689 }
4690 
4691 /**
4692  * xmlXPathWrapExternal:
4693  * @val:  the user data
4694  *
4695  * Wraps the @val data into an XPath object.
4696  *
4697  * Returns the newly created object.
4698  */
4699 xmlXPathObjectPtr
xmlXPathWrapExternal(void * val)4700 xmlXPathWrapExternal (void *val) {
4701     xmlXPathObjectPtr ret;
4702 
4703     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4704     if (ret == NULL) {
4705         xmlXPathErrMemory(NULL, "creating user object\n");
4706 	return(NULL);
4707     }
4708     memset(ret, 0 , sizeof(xmlXPathObject));
4709     ret->type = XPATH_USERS;
4710     ret->user = val;
4711     return(ret);
4712 }
4713 
4714 /**
4715  * xmlXPathObjectCopy:
4716  * @val:  the original object
4717  *
4718  * allocate a new copy of a given object
4719  *
4720  * Returns the newly created object.
4721  */
4722 xmlXPathObjectPtr
xmlXPathObjectCopy(xmlXPathObjectPtr val)4723 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
4724     xmlXPathObjectPtr ret;
4725 
4726     if (val == NULL)
4727 	return(NULL);
4728 
4729     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4730     if (ret == NULL) {
4731         xmlXPathErrMemory(NULL, "copying object\n");
4732 	return(NULL);
4733     }
4734     memcpy(ret, val , sizeof(xmlXPathObject));
4735     switch (val->type) {
4736 	case XPATH_BOOLEAN:
4737 	case XPATH_NUMBER:
4738 #ifdef LIBXML_XPTR_LOCS_ENABLED
4739 	case XPATH_POINT:
4740 	case XPATH_RANGE:
4741 #endif /* LIBXML_XPTR_LOCS_ENABLED */
4742 	    break;
4743 	case XPATH_STRING:
4744 	    ret->stringval = xmlStrdup(val->stringval);
4745             if (ret->stringval == NULL) {
4746                 xmlFree(ret);
4747                 return(NULL);
4748             }
4749 	    break;
4750 	case XPATH_XSLT_TREE:
4751 #if 0
4752 /*
4753   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
4754   this previous handling is no longer correct, and can cause some serious
4755   problems (ref. bug 145547)
4756 */
4757 	    if ((val->nodesetval != NULL) &&
4758 		(val->nodesetval->nodeTab != NULL)) {
4759 		xmlNodePtr cur, tmp;
4760 		xmlDocPtr top;
4761 
4762 		ret->boolval = 1;
4763 		top =  xmlNewDoc(NULL);
4764 		top->name = (char *)
4765 		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
4766 		ret->user = top;
4767 		if (top != NULL) {
4768 		    top->doc = top;
4769 		    cur = val->nodesetval->nodeTab[0]->children;
4770 		    while (cur != NULL) {
4771 			tmp = xmlDocCopyNode(cur, top, 1);
4772 			xmlAddChild((xmlNodePtr) top, tmp);
4773 			cur = cur->next;
4774 		    }
4775 		}
4776 
4777 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
4778 	    } else
4779 		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
4780 	    /* Deallocate the copied tree value */
4781 	    break;
4782 #endif
4783 	case XPATH_NODESET:
4784             /* TODO: Check memory error. */
4785 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
4786 	    /* Do not deallocate the copied tree value */
4787 	    ret->boolval = 0;
4788 	    break;
4789 #ifdef LIBXML_XPTR_LOCS_ENABLED
4790 	case XPATH_LOCATIONSET:
4791 	{
4792 	    xmlLocationSetPtr loc = val->user;
4793 	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
4794 	    break;
4795 	}
4796 #endif
4797         case XPATH_USERS:
4798 	    ret->user = val->user;
4799 	    break;
4800         case XPATH_UNDEFINED:
4801 	    xmlGenericError(xmlGenericErrorContext,
4802 		    "xmlXPathObjectCopy: unsupported type %d\n",
4803 		    val->type);
4804 	    break;
4805     }
4806     return(ret);
4807 }
4808 
4809 /**
4810  * xmlXPathFreeObject:
4811  * @obj:  the object to free
4812  *
4813  * Free up an xmlXPathObjectPtr object.
4814  */
4815 void
xmlXPathFreeObject(xmlXPathObjectPtr obj)4816 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
4817     if (obj == NULL) return;
4818     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4819 	if (obj->boolval) {
4820 #if 0
4821 	    if (obj->user != NULL) {
4822                 xmlXPathFreeNodeSet(obj->nodesetval);
4823 		xmlFreeNodeList((xmlNodePtr) obj->user);
4824 	    } else
4825 #endif
4826 	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
4827 	    if (obj->nodesetval != NULL)
4828 		xmlXPathFreeValueTree(obj->nodesetval);
4829 	} else {
4830 	    if (obj->nodesetval != NULL)
4831 		xmlXPathFreeNodeSet(obj->nodesetval);
4832 	}
4833 #ifdef LIBXML_XPTR_LOCS_ENABLED
4834     } else if (obj->type == XPATH_LOCATIONSET) {
4835 	if (obj->user != NULL)
4836 	    xmlXPtrFreeLocationSet(obj->user);
4837 #endif
4838     } else if (obj->type == XPATH_STRING) {
4839 	if (obj->stringval != NULL)
4840 	    xmlFree(obj->stringval);
4841     }
4842     xmlFree(obj);
4843 }
4844 
4845 static void
xmlXPathFreeObjectEntry(void * obj,const xmlChar * name ATTRIBUTE_UNUSED)4846 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
4847     xmlXPathFreeObject((xmlXPathObjectPtr) obj);
4848 }
4849 
4850 /**
4851  * xmlXPathReleaseObject:
4852  * @obj:  the xmlXPathObjectPtr to free or to cache
4853  *
4854  * Depending on the state of the cache this frees the given
4855  * XPath object or stores it in the cache.
4856  */
4857 static void
xmlXPathReleaseObject(xmlXPathContextPtr ctxt,xmlXPathObjectPtr obj)4858 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
4859 {
4860 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
4861 	sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
4862     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
4863 
4864 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
4865 
4866     if (obj == NULL)
4867 	return;
4868     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4869 	 xmlXPathFreeObject(obj);
4870     } else {
4871 	xmlXPathContextCachePtr cache =
4872 	    (xmlXPathContextCachePtr) ctxt->cache;
4873 
4874 	switch (obj->type) {
4875 	    case XPATH_NODESET:
4876 	    case XPATH_XSLT_TREE:
4877 		if (obj->nodesetval != NULL) {
4878 		    if (obj->boolval) {
4879 			/*
4880 			* It looks like the @boolval is used for
4881 			* evaluation if this an XSLT Result Tree Fragment.
4882 			* TODO: Check if this assumption is correct.
4883 			*/
4884 			obj->type = XPATH_XSLT_TREE; /* just for debugging */
4885 			xmlXPathFreeValueTree(obj->nodesetval);
4886 			obj->nodesetval = NULL;
4887 		    } else if ((obj->nodesetval->nodeMax <= 40) &&
4888 			(XP_CACHE_WANTS(cache->nodesetObjs,
4889 					cache->maxNodeset)))
4890 		    {
4891 			XP_CACHE_ADD(cache->nodesetObjs, obj);
4892 			goto obj_cached;
4893 		    } else {
4894 			xmlXPathFreeNodeSet(obj->nodesetval);
4895 			obj->nodesetval = NULL;
4896 		    }
4897 		}
4898 		break;
4899 	    case XPATH_STRING:
4900 		if (obj->stringval != NULL)
4901 		    xmlFree(obj->stringval);
4902 
4903 		if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
4904 		    XP_CACHE_ADD(cache->stringObjs, obj);
4905 		    goto obj_cached;
4906 		}
4907 		break;
4908 	    case XPATH_BOOLEAN:
4909 		if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
4910 		    XP_CACHE_ADD(cache->booleanObjs, obj);
4911 		    goto obj_cached;
4912 		}
4913 		break;
4914 	    case XPATH_NUMBER:
4915 		if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
4916 		    XP_CACHE_ADD(cache->numberObjs, obj);
4917 		    goto obj_cached;
4918 		}
4919 		break;
4920 #ifdef LIBXML_XPTR_LOCS_ENABLED
4921 	    case XPATH_LOCATIONSET:
4922 		if (obj->user != NULL) {
4923 		    xmlXPtrFreeLocationSet(obj->user);
4924 		}
4925 		goto free_obj;
4926 #endif
4927 	    default:
4928 		goto free_obj;
4929 	}
4930 
4931 	/*
4932 	* Fallback to adding to the misc-objects slot.
4933 	*/
4934 	if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
4935 	    XP_CACHE_ADD(cache->miscObjs, obj);
4936 	} else
4937 	    goto free_obj;
4938 
4939 obj_cached:
4940 	if (obj->nodesetval != NULL) {
4941 	    xmlNodeSetPtr tmpset = obj->nodesetval;
4942 
4943 	    /*
4944 	    * TODO: Due to those nasty ns-nodes, we need to traverse
4945 	    *  the list and free the ns-nodes.
4946 	    * URGENT TODO: Check if it's actually slowing things down.
4947 	    *  Maybe we shouldn't try to preserve the list.
4948 	    */
4949 	    if (tmpset->nodeNr > 1) {
4950 		int i;
4951 		xmlNodePtr node;
4952 
4953 		for (i = 0; i < tmpset->nodeNr; i++) {
4954 		    node = tmpset->nodeTab[i];
4955 		    if ((node != NULL) &&
4956 			(node->type == XML_NAMESPACE_DECL))
4957 		    {
4958 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4959 		    }
4960 		}
4961 	    } else if (tmpset->nodeNr == 1) {
4962 		if ((tmpset->nodeTab[0] != NULL) &&
4963 		    (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
4964 		    xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
4965 	    }
4966 	    tmpset->nodeNr = 0;
4967 	    memset(obj, 0, sizeof(xmlXPathObject));
4968 	    obj->nodesetval = tmpset;
4969 	} else
4970 	    memset(obj, 0, sizeof(xmlXPathObject));
4971 
4972 	return;
4973 
4974 free_obj:
4975 	/*
4976 	* Cache is full; free the object.
4977 	*/
4978 	if (obj->nodesetval != NULL)
4979 	    xmlXPathFreeNodeSet(obj->nodesetval);
4980 	xmlFree(obj);
4981     }
4982     return;
4983 }
4984 
4985 
4986 /************************************************************************
4987  *									*
4988  *			Type Casting Routines				*
4989  *									*
4990  ************************************************************************/
4991 
4992 /**
4993  * xmlXPathCastBooleanToString:
4994  * @val:  a boolean
4995  *
4996  * Converts a boolean to its string value.
4997  *
4998  * Returns a newly allocated string.
4999  */
5000 xmlChar *
xmlXPathCastBooleanToString(int val)5001 xmlXPathCastBooleanToString (int val) {
5002     xmlChar *ret;
5003     if (val)
5004 	ret = xmlStrdup((const xmlChar *) "true");
5005     else
5006 	ret = xmlStrdup((const xmlChar *) "false");
5007     return(ret);
5008 }
5009 
5010 /**
5011  * xmlXPathCastNumberToString:
5012  * @val:  a number
5013  *
5014  * Converts a number to its string value.
5015  *
5016  * Returns a newly allocated string.
5017  */
5018 xmlChar *
xmlXPathCastNumberToString(double val)5019 xmlXPathCastNumberToString (double val) {
5020     xmlChar *ret;
5021     switch (xmlXPathIsInf(val)) {
5022     case 1:
5023 	ret = xmlStrdup((const xmlChar *) "Infinity");
5024 	break;
5025     case -1:
5026 	ret = xmlStrdup((const xmlChar *) "-Infinity");
5027 	break;
5028     default:
5029 	if (xmlXPathIsNaN(val)) {
5030 	    ret = xmlStrdup((const xmlChar *) "NaN");
5031 	} else if (val == 0) {
5032             /* Omit sign for negative zero. */
5033 	    ret = xmlStrdup((const xmlChar *) "0");
5034 	} else {
5035 	    /* could be improved */
5036 	    char buf[100];
5037 	    xmlXPathFormatNumber(val, buf, 99);
5038 	    buf[99] = 0;
5039 	    ret = xmlStrdup((const xmlChar *) buf);
5040 	}
5041     }
5042     return(ret);
5043 }
5044 
5045 /**
5046  * xmlXPathCastNodeToString:
5047  * @node:  a node
5048  *
5049  * Converts a node to its string value.
5050  *
5051  * Returns a newly allocated string.
5052  */
5053 xmlChar *
xmlXPathCastNodeToString(xmlNodePtr node)5054 xmlXPathCastNodeToString (xmlNodePtr node) {
5055 xmlChar *ret;
5056     if ((ret = xmlNodeGetContent(node)) == NULL)
5057 	ret = xmlStrdup((const xmlChar *) "");
5058     return(ret);
5059 }
5060 
5061 /**
5062  * xmlXPathCastNodeSetToString:
5063  * @ns:  a node-set
5064  *
5065  * Converts a node-set to its string value.
5066  *
5067  * Returns a newly allocated string.
5068  */
5069 xmlChar *
xmlXPathCastNodeSetToString(xmlNodeSetPtr ns)5070 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5071     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5072 	return(xmlStrdup((const xmlChar *) ""));
5073 
5074     if (ns->nodeNr > 1)
5075 	xmlXPathNodeSetSort(ns);
5076     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5077 }
5078 
5079 /**
5080  * xmlXPathCastToString:
5081  * @val:  an XPath object
5082  *
5083  * Converts an existing object to its string() equivalent
5084  *
5085  * Returns the allocated string value of the object, NULL in case of error.
5086  *         It's up to the caller to free the string memory with xmlFree().
5087  */
5088 xmlChar *
xmlXPathCastToString(xmlXPathObjectPtr val)5089 xmlXPathCastToString(xmlXPathObjectPtr val) {
5090     xmlChar *ret = NULL;
5091 
5092     if (val == NULL)
5093 	return(xmlStrdup((const xmlChar *) ""));
5094     switch (val->type) {
5095 	case XPATH_UNDEFINED:
5096 	    ret = xmlStrdup((const xmlChar *) "");
5097 	    break;
5098         case XPATH_NODESET:
5099         case XPATH_XSLT_TREE:
5100 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
5101 	    break;
5102 	case XPATH_STRING:
5103 	    return(xmlStrdup(val->stringval));
5104         case XPATH_BOOLEAN:
5105 	    ret = xmlXPathCastBooleanToString(val->boolval);
5106 	    break;
5107 	case XPATH_NUMBER: {
5108 	    ret = xmlXPathCastNumberToString(val->floatval);
5109 	    break;
5110 	}
5111 	case XPATH_USERS:
5112 #ifdef LIBXML_XPTR_LOCS_ENABLED
5113 	case XPATH_POINT:
5114 	case XPATH_RANGE:
5115 	case XPATH_LOCATIONSET:
5116 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5117 	    TODO
5118 	    ret = xmlStrdup((const xmlChar *) "");
5119 	    break;
5120     }
5121     return(ret);
5122 }
5123 
5124 /**
5125  * xmlXPathConvertString:
5126  * @val:  an XPath object
5127  *
5128  * Converts an existing object to its string() equivalent
5129  *
5130  * Returns the new object, the old one is freed (or the operation
5131  *         is done directly on @val)
5132  */
5133 xmlXPathObjectPtr
xmlXPathConvertString(xmlXPathObjectPtr val)5134 xmlXPathConvertString(xmlXPathObjectPtr val) {
5135     xmlChar *res = NULL;
5136 
5137     if (val == NULL)
5138 	return(xmlXPathNewCString(""));
5139 
5140     switch (val->type) {
5141     case XPATH_UNDEFINED:
5142 	break;
5143     case XPATH_NODESET:
5144     case XPATH_XSLT_TREE:
5145 	res = xmlXPathCastNodeSetToString(val->nodesetval);
5146 	break;
5147     case XPATH_STRING:
5148 	return(val);
5149     case XPATH_BOOLEAN:
5150 	res = xmlXPathCastBooleanToString(val->boolval);
5151 	break;
5152     case XPATH_NUMBER:
5153 	res = xmlXPathCastNumberToString(val->floatval);
5154 	break;
5155     case XPATH_USERS:
5156 #ifdef LIBXML_XPTR_LOCS_ENABLED
5157     case XPATH_POINT:
5158     case XPATH_RANGE:
5159     case XPATH_LOCATIONSET:
5160 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5161 	TODO;
5162 	break;
5163     }
5164     xmlXPathFreeObject(val);
5165     if (res == NULL)
5166 	return(xmlXPathNewCString(""));
5167     return(xmlXPathWrapString(res));
5168 }
5169 
5170 /**
5171  * xmlXPathCastBooleanToNumber:
5172  * @val:  a boolean
5173  *
5174  * Converts a boolean to its number value
5175  *
5176  * Returns the number value
5177  */
5178 double
xmlXPathCastBooleanToNumber(int val)5179 xmlXPathCastBooleanToNumber(int val) {
5180     if (val)
5181 	return(1.0);
5182     return(0.0);
5183 }
5184 
5185 /**
5186  * xmlXPathCastStringToNumber:
5187  * @val:  a string
5188  *
5189  * Converts a string to its number value
5190  *
5191  * Returns the number value
5192  */
5193 double
xmlXPathCastStringToNumber(const xmlChar * val)5194 xmlXPathCastStringToNumber(const xmlChar * val) {
5195     return(xmlXPathStringEvalNumber(val));
5196 }
5197 
5198 /**
5199  * xmlXPathCastNodeToNumber:
5200  * @node:  a node
5201  *
5202  * Converts a node to its number value
5203  *
5204  * Returns the number value
5205  */
5206 double
xmlXPathCastNodeToNumber(xmlNodePtr node)5207 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5208     xmlChar *strval;
5209     double ret;
5210 
5211     if (node == NULL)
5212 	return(xmlXPathNAN);
5213     strval = xmlXPathCastNodeToString(node);
5214     if (strval == NULL)
5215 	return(xmlXPathNAN);
5216     ret = xmlXPathCastStringToNumber(strval);
5217     xmlFree(strval);
5218 
5219     return(ret);
5220 }
5221 
5222 /**
5223  * xmlXPathCastNodeSetToNumber:
5224  * @ns:  a node-set
5225  *
5226  * Converts a node-set to its number value
5227  *
5228  * Returns the number value
5229  */
5230 double
xmlXPathCastNodeSetToNumber(xmlNodeSetPtr ns)5231 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5232     xmlChar *str;
5233     double ret;
5234 
5235     if (ns == NULL)
5236 	return(xmlXPathNAN);
5237     str = xmlXPathCastNodeSetToString(ns);
5238     ret = xmlXPathCastStringToNumber(str);
5239     xmlFree(str);
5240     return(ret);
5241 }
5242 
5243 /**
5244  * xmlXPathCastToNumber:
5245  * @val:  an XPath object
5246  *
5247  * Converts an XPath object to its number value
5248  *
5249  * Returns the number value
5250  */
5251 double
xmlXPathCastToNumber(xmlXPathObjectPtr val)5252 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5253     double ret = 0.0;
5254 
5255     if (val == NULL)
5256 	return(xmlXPathNAN);
5257     switch (val->type) {
5258     case XPATH_UNDEFINED:
5259 	ret = xmlXPathNAN;
5260 	break;
5261     case XPATH_NODESET:
5262     case XPATH_XSLT_TREE:
5263 	ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5264 	break;
5265     case XPATH_STRING:
5266 	ret = xmlXPathCastStringToNumber(val->stringval);
5267 	break;
5268     case XPATH_NUMBER:
5269 	ret = val->floatval;
5270 	break;
5271     case XPATH_BOOLEAN:
5272 	ret = xmlXPathCastBooleanToNumber(val->boolval);
5273 	break;
5274     case XPATH_USERS:
5275 #ifdef LIBXML_XPTR_LOCS_ENABLED
5276     case XPATH_POINT:
5277     case XPATH_RANGE:
5278     case XPATH_LOCATIONSET:
5279 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5280 	TODO;
5281 	ret = xmlXPathNAN;
5282 	break;
5283     }
5284     return(ret);
5285 }
5286 
5287 /**
5288  * xmlXPathConvertNumber:
5289  * @val:  an XPath object
5290  *
5291  * Converts an existing object to its number() equivalent
5292  *
5293  * Returns the new object, the old one is freed (or the operation
5294  *         is done directly on @val)
5295  */
5296 xmlXPathObjectPtr
xmlXPathConvertNumber(xmlXPathObjectPtr val)5297 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5298     xmlXPathObjectPtr ret;
5299 
5300     if (val == NULL)
5301 	return(xmlXPathNewFloat(0.0));
5302     if (val->type == XPATH_NUMBER)
5303 	return(val);
5304     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5305     xmlXPathFreeObject(val);
5306     return(ret);
5307 }
5308 
5309 /**
5310  * xmlXPathCastNumberToBoolean:
5311  * @val:  a number
5312  *
5313  * Converts a number to its boolean value
5314  *
5315  * Returns the boolean value
5316  */
5317 int
xmlXPathCastNumberToBoolean(double val)5318 xmlXPathCastNumberToBoolean (double val) {
5319      if (xmlXPathIsNaN(val) || (val == 0.0))
5320 	 return(0);
5321      return(1);
5322 }
5323 
5324 /**
5325  * xmlXPathCastStringToBoolean:
5326  * @val:  a string
5327  *
5328  * Converts a string to its boolean value
5329  *
5330  * Returns the boolean value
5331  */
5332 int
xmlXPathCastStringToBoolean(const xmlChar * val)5333 xmlXPathCastStringToBoolean (const xmlChar *val) {
5334     if ((val == NULL) || (xmlStrlen(val) == 0))
5335 	return(0);
5336     return(1);
5337 }
5338 
5339 /**
5340  * xmlXPathCastNodeSetToBoolean:
5341  * @ns:  a node-set
5342  *
5343  * Converts a node-set to its boolean value
5344  *
5345  * Returns the boolean value
5346  */
5347 int
xmlXPathCastNodeSetToBoolean(xmlNodeSetPtr ns)5348 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5349     if ((ns == NULL) || (ns->nodeNr == 0))
5350 	return(0);
5351     return(1);
5352 }
5353 
5354 /**
5355  * xmlXPathCastToBoolean:
5356  * @val:  an XPath object
5357  *
5358  * Converts an XPath object to its boolean value
5359  *
5360  * Returns the boolean value
5361  */
5362 int
xmlXPathCastToBoolean(xmlXPathObjectPtr val)5363 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5364     int ret = 0;
5365 
5366     if (val == NULL)
5367 	return(0);
5368     switch (val->type) {
5369     case XPATH_UNDEFINED:
5370 	ret = 0;
5371 	break;
5372     case XPATH_NODESET:
5373     case XPATH_XSLT_TREE:
5374 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5375 	break;
5376     case XPATH_STRING:
5377 	ret = xmlXPathCastStringToBoolean(val->stringval);
5378 	break;
5379     case XPATH_NUMBER:
5380 	ret = xmlXPathCastNumberToBoolean(val->floatval);
5381 	break;
5382     case XPATH_BOOLEAN:
5383 	ret = val->boolval;
5384 	break;
5385     case XPATH_USERS:
5386 #ifdef LIBXML_XPTR_LOCS_ENABLED
5387     case XPATH_POINT:
5388     case XPATH_RANGE:
5389     case XPATH_LOCATIONSET:
5390 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5391 	TODO;
5392 	ret = 0;
5393 	break;
5394     }
5395     return(ret);
5396 }
5397 
5398 
5399 /**
5400  * xmlXPathConvertBoolean:
5401  * @val:  an XPath object
5402  *
5403  * Converts an existing object to its boolean() equivalent
5404  *
5405  * Returns the new object, the old one is freed (or the operation
5406  *         is done directly on @val)
5407  */
5408 xmlXPathObjectPtr
xmlXPathConvertBoolean(xmlXPathObjectPtr val)5409 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5410     xmlXPathObjectPtr ret;
5411 
5412     if (val == NULL)
5413 	return(xmlXPathNewBoolean(0));
5414     if (val->type == XPATH_BOOLEAN)
5415 	return(val);
5416     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5417     xmlXPathFreeObject(val);
5418     return(ret);
5419 }
5420 
5421 /************************************************************************
5422  *									*
5423  *		Routines to handle XPath contexts			*
5424  *									*
5425  ************************************************************************/
5426 
5427 /**
5428  * xmlXPathNewContext:
5429  * @doc:  the XML document
5430  *
5431  * Create a new xmlXPathContext
5432  *
5433  * Returns the xmlXPathContext just allocated. The caller will need to free it.
5434  */
5435 xmlXPathContextPtr
xmlXPathNewContext(xmlDocPtr doc)5436 xmlXPathNewContext(xmlDocPtr doc) {
5437     xmlXPathContextPtr ret;
5438 
5439     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5440     if (ret == NULL) {
5441         xmlXPathErrMemory(NULL, "creating context\n");
5442 	return(NULL);
5443     }
5444     memset(ret, 0 , sizeof(xmlXPathContext));
5445     ret->doc = doc;
5446     ret->node = NULL;
5447 
5448     ret->varHash = NULL;
5449 
5450     ret->nb_types = 0;
5451     ret->max_types = 0;
5452     ret->types = NULL;
5453 
5454     ret->funcHash = xmlHashCreate(0);
5455 
5456     ret->nb_axis = 0;
5457     ret->max_axis = 0;
5458     ret->axis = NULL;
5459 
5460     ret->nsHash = NULL;
5461     ret->user = NULL;
5462 
5463     ret->contextSize = -1;
5464     ret->proximityPosition = -1;
5465 
5466 #ifdef XP_DEFAULT_CACHE_ON
5467     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
5468 	xmlXPathFreeContext(ret);
5469 	return(NULL);
5470     }
5471 #endif
5472 
5473     xmlXPathRegisterAllFunctions(ret);
5474 
5475     return(ret);
5476 }
5477 
5478 /**
5479  * xmlXPathFreeContext:
5480  * @ctxt:  the context to free
5481  *
5482  * Free up an xmlXPathContext
5483  */
5484 void
xmlXPathFreeContext(xmlXPathContextPtr ctxt)5485 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
5486     if (ctxt == NULL) return;
5487 
5488     if (ctxt->cache != NULL)
5489 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
5490     xmlXPathRegisteredNsCleanup(ctxt);
5491     xmlXPathRegisteredFuncsCleanup(ctxt);
5492     xmlXPathRegisteredVariablesCleanup(ctxt);
5493     xmlResetError(&ctxt->lastError);
5494     xmlFree(ctxt);
5495 }
5496 
5497 /************************************************************************
5498  *									*
5499  *		Routines to handle XPath parser contexts		*
5500  *									*
5501  ************************************************************************/
5502 
5503 #define CHECK_CTXT(ctxt)						\
5504     if (ctxt == NULL) {						\
5505 	__xmlRaiseError(NULL, NULL, NULL,				\
5506 		NULL, NULL, XML_FROM_XPATH,				\
5507 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
5508 		__FILE__, __LINE__,					\
5509 		NULL, NULL, NULL, 0, 0,					\
5510 		"NULL context pointer\n");				\
5511 	return(NULL);							\
5512     }									\
5513 
5514 #define CHECK_CTXT_NEG(ctxt)						\
5515     if (ctxt == NULL) {						\
5516 	__xmlRaiseError(NULL, NULL, NULL,				\
5517 		NULL, NULL, XML_FROM_XPATH,				\
5518 		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
5519 		__FILE__, __LINE__,					\
5520 		NULL, NULL, NULL, 0, 0,					\
5521 		"NULL context pointer\n");				\
5522 	return(-1);							\
5523     }									\
5524 
5525 
5526 #define CHECK_CONTEXT(ctxt)						\
5527     if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
5528         (ctxt->doc->children == NULL)) {				\
5529 	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
5530 	return(NULL);							\
5531     }
5532 
5533 
5534 /**
5535  * xmlXPathNewParserContext:
5536  * @str:  the XPath expression
5537  * @ctxt:  the XPath context
5538  *
5539  * Create a new xmlXPathParserContext
5540  *
5541  * Returns the xmlXPathParserContext just allocated.
5542  */
5543 xmlXPathParserContextPtr
xmlXPathNewParserContext(const xmlChar * str,xmlXPathContextPtr ctxt)5544 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
5545     xmlXPathParserContextPtr ret;
5546 
5547     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5548     if (ret == NULL) {
5549         xmlXPathErrMemory(ctxt, "creating parser context\n");
5550 	return(NULL);
5551     }
5552     memset(ret, 0 , sizeof(xmlXPathParserContext));
5553     ret->cur = ret->base = str;
5554     ret->context = ctxt;
5555 
5556     ret->comp = xmlXPathNewCompExpr();
5557     if (ret->comp == NULL) {
5558 	xmlFree(ret->valueTab);
5559 	xmlFree(ret);
5560 	return(NULL);
5561     }
5562     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
5563         ret->comp->dict = ctxt->dict;
5564 	xmlDictReference(ret->comp->dict);
5565     }
5566 
5567     return(ret);
5568 }
5569 
5570 /**
5571  * xmlXPathCompParserContext:
5572  * @comp:  the XPath compiled expression
5573  * @ctxt:  the XPath context
5574  *
5575  * Create a new xmlXPathParserContext when processing a compiled expression
5576  *
5577  * Returns the xmlXPathParserContext just allocated.
5578  */
5579 static xmlXPathParserContextPtr
xmlXPathCompParserContext(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)5580 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
5581     xmlXPathParserContextPtr ret;
5582 
5583     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5584     if (ret == NULL) {
5585         xmlXPathErrMemory(ctxt, "creating evaluation context\n");
5586 	return(NULL);
5587     }
5588     memset(ret, 0 , sizeof(xmlXPathParserContext));
5589 
5590     /* Allocate the value stack */
5591     ret->valueTab = (xmlXPathObjectPtr *)
5592                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
5593     if (ret->valueTab == NULL) {
5594 	xmlFree(ret);
5595 	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
5596 	return(NULL);
5597     }
5598     ret->valueNr = 0;
5599     ret->valueMax = 10;
5600     ret->value = NULL;
5601 
5602     ret->context = ctxt;
5603     ret->comp = comp;
5604 
5605     return(ret);
5606 }
5607 
5608 /**
5609  * xmlXPathFreeParserContext:
5610  * @ctxt:  the context to free
5611  *
5612  * Free up an xmlXPathParserContext
5613  */
5614 void
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt)5615 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
5616     int i;
5617 
5618     if (ctxt->valueTab != NULL) {
5619         for (i = 0; i < ctxt->valueNr; i++) {
5620             if (ctxt->context)
5621                 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
5622             else
5623                 xmlXPathFreeObject(ctxt->valueTab[i]);
5624         }
5625         xmlFree(ctxt->valueTab);
5626     }
5627     if (ctxt->comp != NULL) {
5628 #ifdef XPATH_STREAMING
5629 	if (ctxt->comp->stream != NULL) {
5630 	    xmlFreePatternList(ctxt->comp->stream);
5631 	    ctxt->comp->stream = NULL;
5632 	}
5633 #endif
5634 	xmlXPathFreeCompExpr(ctxt->comp);
5635     }
5636     xmlFree(ctxt);
5637 }
5638 
5639 /************************************************************************
5640  *									*
5641  *		The implicit core function library			*
5642  *									*
5643  ************************************************************************/
5644 
5645 /**
5646  * xmlXPathNodeValHash:
5647  * @node:  a node pointer
5648  *
5649  * Function computing the beginning of the string value of the node,
5650  * used to speed up comparisons
5651  *
5652  * Returns an int usable as a hash
5653  */
5654 static unsigned int
xmlXPathNodeValHash(xmlNodePtr node)5655 xmlXPathNodeValHash(xmlNodePtr node) {
5656     int len = 2;
5657     const xmlChar * string = NULL;
5658     xmlNodePtr tmp = NULL;
5659     unsigned int ret = 0;
5660 
5661     if (node == NULL)
5662 	return(0);
5663 
5664     if (node->type == XML_DOCUMENT_NODE) {
5665 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
5666 	if (tmp == NULL)
5667 	    node = node->children;
5668 	else
5669 	    node = tmp;
5670 
5671 	if (node == NULL)
5672 	    return(0);
5673     }
5674 
5675     switch (node->type) {
5676 	case XML_COMMENT_NODE:
5677 	case XML_PI_NODE:
5678 	case XML_CDATA_SECTION_NODE:
5679 	case XML_TEXT_NODE:
5680 	    string = node->content;
5681 	    if (string == NULL)
5682 		return(0);
5683 	    if (string[0] == 0)
5684 		return(0);
5685 	    return(string[0] + (string[1] << 8));
5686 	case XML_NAMESPACE_DECL:
5687 	    string = ((xmlNsPtr)node)->href;
5688 	    if (string == NULL)
5689 		return(0);
5690 	    if (string[0] == 0)
5691 		return(0);
5692 	    return(string[0] + (string[1] << 8));
5693 	case XML_ATTRIBUTE_NODE:
5694 	    tmp = ((xmlAttrPtr) node)->children;
5695 	    break;
5696 	case XML_ELEMENT_NODE:
5697 	    tmp = node->children;
5698 	    break;
5699 	default:
5700 	    return(0);
5701     }
5702     while (tmp != NULL) {
5703 	switch (tmp->type) {
5704 	    case XML_CDATA_SECTION_NODE:
5705 	    case XML_TEXT_NODE:
5706 		string = tmp->content;
5707 		break;
5708 	    default:
5709                 string = NULL;
5710 		break;
5711 	}
5712 	if ((string != NULL) && (string[0] != 0)) {
5713 	    if (len == 1) {
5714 		return(ret + (string[0] << 8));
5715 	    }
5716 	    if (string[1] == 0) {
5717 		len = 1;
5718 		ret = string[0];
5719 	    } else {
5720 		return(string[0] + (string[1] << 8));
5721 	    }
5722 	}
5723 	/*
5724 	 * Skip to next node
5725 	 */
5726         if ((tmp->children != NULL) &&
5727             (tmp->type != XML_DTD_NODE) &&
5728             (tmp->type != XML_ENTITY_REF_NODE) &&
5729             (tmp->children->type != XML_ENTITY_DECL)) {
5730             tmp = tmp->children;
5731             continue;
5732 	}
5733 	if (tmp == node)
5734 	    break;
5735 
5736 	if (tmp->next != NULL) {
5737 	    tmp = tmp->next;
5738 	    continue;
5739 	}
5740 
5741 	do {
5742 	    tmp = tmp->parent;
5743 	    if (tmp == NULL)
5744 		break;
5745 	    if (tmp == node) {
5746 		tmp = NULL;
5747 		break;
5748 	    }
5749 	    if (tmp->next != NULL) {
5750 		tmp = tmp->next;
5751 		break;
5752 	    }
5753 	} while (tmp != NULL);
5754     }
5755     return(ret);
5756 }
5757 
5758 /**
5759  * xmlXPathStringHash:
5760  * @string:  a string
5761  *
5762  * Function computing the beginning of the string value of the node,
5763  * used to speed up comparisons
5764  *
5765  * Returns an int usable as a hash
5766  */
5767 static unsigned int
xmlXPathStringHash(const xmlChar * string)5768 xmlXPathStringHash(const xmlChar * string) {
5769     if (string == NULL)
5770 	return(0);
5771     if (string[0] == 0)
5772 	return(0);
5773     return(string[0] + (string[1] << 8));
5774 }
5775 
5776 /**
5777  * xmlXPathCompareNodeSetFloat:
5778  * @ctxt:  the XPath Parser context
5779  * @inf:  less than (1) or greater than (0)
5780  * @strict:  is the comparison strict
5781  * @arg:  the node set
5782  * @f:  the value
5783  *
5784  * Implement the compare operation between a nodeset and a number
5785  *     @ns < @val    (1, 1, ...
5786  *     @ns <= @val   (1, 0, ...
5787  *     @ns > @val    (0, 1, ...
5788  *     @ns >= @val   (0, 0, ...
5789  *
5790  * If one object to be compared is a node-set and the other is a number,
5791  * then the comparison will be true if and only if there is a node in the
5792  * node-set such that the result of performing the comparison on the number
5793  * to be compared and on the result of converting the string-value of that
5794  * node to a number using the number function is true.
5795  *
5796  * Returns 0 or 1 depending on the results of the test.
5797  */
5798 static int
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr f)5799 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
5800 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5801     int i, ret = 0;
5802     xmlNodeSetPtr ns;
5803     xmlChar *str2;
5804 
5805     if ((f == NULL) || (arg == NULL) ||
5806 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5807 	xmlXPathReleaseObject(ctxt->context, arg);
5808 	xmlXPathReleaseObject(ctxt->context, f);
5809         return(0);
5810     }
5811     ns = arg->nodesetval;
5812     if (ns != NULL) {
5813 	for (i = 0;i < ns->nodeNr;i++) {
5814 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5815 	     if (str2 != NULL) {
5816 		 valuePush(ctxt,
5817 			   xmlXPathCacheNewString(ctxt->context, str2));
5818 		 xmlFree(str2);
5819 		 xmlXPathNumberFunction(ctxt, 1);
5820 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
5821 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
5822 		 if (ret)
5823 		     break;
5824 	     }
5825 	}
5826     }
5827     xmlXPathReleaseObject(ctxt->context, arg);
5828     xmlXPathReleaseObject(ctxt->context, f);
5829     return(ret);
5830 }
5831 
5832 /**
5833  * xmlXPathCompareNodeSetString:
5834  * @ctxt:  the XPath Parser context
5835  * @inf:  less than (1) or greater than (0)
5836  * @strict:  is the comparison strict
5837  * @arg:  the node set
5838  * @s:  the value
5839  *
5840  * Implement the compare operation between a nodeset and a string
5841  *     @ns < @val    (1, 1, ...
5842  *     @ns <= @val   (1, 0, ...
5843  *     @ns > @val    (0, 1, ...
5844  *     @ns >= @val   (0, 0, ...
5845  *
5846  * If one object to be compared is a node-set and the other is a string,
5847  * then the comparison will be true if and only if there is a node in
5848  * the node-set such that the result of performing the comparison on the
5849  * string-value of the node and the other string is true.
5850  *
5851  * Returns 0 or 1 depending on the results of the test.
5852  */
5853 static int
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr s)5854 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
5855 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5856     int i, ret = 0;
5857     xmlNodeSetPtr ns;
5858     xmlChar *str2;
5859 
5860     if ((s == NULL) || (arg == NULL) ||
5861 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5862 	xmlXPathReleaseObject(ctxt->context, arg);
5863 	xmlXPathReleaseObject(ctxt->context, s);
5864         return(0);
5865     }
5866     ns = arg->nodesetval;
5867     if (ns != NULL) {
5868 	for (i = 0;i < ns->nodeNr;i++) {
5869 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5870 	     if (str2 != NULL) {
5871 		 valuePush(ctxt,
5872 			   xmlXPathCacheNewString(ctxt->context, str2));
5873 		 xmlFree(str2);
5874 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
5875 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
5876 		 if (ret)
5877 		     break;
5878 	     }
5879 	}
5880     }
5881     xmlXPathReleaseObject(ctxt->context, arg);
5882     xmlXPathReleaseObject(ctxt->context, s);
5883     return(ret);
5884 }
5885 
5886 /**
5887  * xmlXPathCompareNodeSets:
5888  * @inf:  less than (1) or greater than (0)
5889  * @strict:  is the comparison strict
5890  * @arg1:  the first node set object
5891  * @arg2:  the second node set object
5892  *
5893  * Implement the compare operation on nodesets:
5894  *
5895  * If both objects to be compared are node-sets, then the comparison
5896  * will be true if and only if there is a node in the first node-set
5897  * and a node in the second node-set such that the result of performing
5898  * the comparison on the string-values of the two nodes is true.
5899  * ....
5900  * When neither object to be compared is a node-set and the operator
5901  * is <=, <, >= or >, then the objects are compared by converting both
5902  * objects to numbers and comparing the numbers according to IEEE 754.
5903  * ....
5904  * The number function converts its argument to a number as follows:
5905  *  - a string that consists of optional whitespace followed by an
5906  *    optional minus sign followed by a Number followed by whitespace
5907  *    is converted to the IEEE 754 number that is nearest (according
5908  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
5909  *    represented by the string; any other string is converted to NaN
5910  *
5911  * Conclusion all nodes need to be converted first to their string value
5912  * and then the comparison must be done when possible
5913  */
5914 static int
xmlXPathCompareNodeSets(int inf,int strict,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)5915 xmlXPathCompareNodeSets(int inf, int strict,
5916 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5917     int i, j, init = 0;
5918     double val1;
5919     double *values2;
5920     int ret = 0;
5921     xmlNodeSetPtr ns1;
5922     xmlNodeSetPtr ns2;
5923 
5924     if ((arg1 == NULL) ||
5925 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5926 	xmlXPathFreeObject(arg2);
5927         return(0);
5928     }
5929     if ((arg2 == NULL) ||
5930 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
5931 	xmlXPathFreeObject(arg1);
5932 	xmlXPathFreeObject(arg2);
5933         return(0);
5934     }
5935 
5936     ns1 = arg1->nodesetval;
5937     ns2 = arg2->nodesetval;
5938 
5939     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5940 	xmlXPathFreeObject(arg1);
5941 	xmlXPathFreeObject(arg2);
5942 	return(0);
5943     }
5944     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5945 	xmlXPathFreeObject(arg1);
5946 	xmlXPathFreeObject(arg2);
5947 	return(0);
5948     }
5949 
5950     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5951     if (values2 == NULL) {
5952         /* TODO: Propagate memory error. */
5953         xmlXPathErrMemory(NULL, "comparing nodesets\n");
5954 	xmlXPathFreeObject(arg1);
5955 	xmlXPathFreeObject(arg2);
5956 	return(0);
5957     }
5958     for (i = 0;i < ns1->nodeNr;i++) {
5959 	val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
5960 	if (xmlXPathIsNaN(val1))
5961 	    continue;
5962 	for (j = 0;j < ns2->nodeNr;j++) {
5963 	    if (init == 0) {
5964 		values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
5965 	    }
5966 	    if (xmlXPathIsNaN(values2[j]))
5967 		continue;
5968 	    if (inf && strict)
5969 		ret = (val1 < values2[j]);
5970 	    else if (inf && !strict)
5971 		ret = (val1 <= values2[j]);
5972 	    else if (!inf && strict)
5973 		ret = (val1 > values2[j]);
5974 	    else if (!inf && !strict)
5975 		ret = (val1 >= values2[j]);
5976 	    if (ret)
5977 		break;
5978 	}
5979 	if (ret)
5980 	    break;
5981 	init = 1;
5982     }
5983     xmlFree(values2);
5984     xmlXPathFreeObject(arg1);
5985     xmlXPathFreeObject(arg2);
5986     return(ret);
5987 }
5988 
5989 /**
5990  * xmlXPathCompareNodeSetValue:
5991  * @ctxt:  the XPath Parser context
5992  * @inf:  less than (1) or greater than (0)
5993  * @strict:  is the comparison strict
5994  * @arg:  the node set
5995  * @val:  the value
5996  *
5997  * Implement the compare operation between a nodeset and a value
5998  *     @ns < @val    (1, 1, ...
5999  *     @ns <= @val   (1, 0, ...
6000  *     @ns > @val    (0, 1, ...
6001  *     @ns >= @val   (0, 0, ...
6002  *
6003  * If one object to be compared is a node-set and the other is a boolean,
6004  * then the comparison will be true if and only if the result of performing
6005  * the comparison on the boolean and on the result of converting
6006  * the node-set to a boolean using the boolean function is true.
6007  *
6008  * Returns 0 or 1 depending on the results of the test.
6009  */
6010 static int
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr val)6011 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6012 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6013     if ((val == NULL) || (arg == NULL) ||
6014 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6015         return(0);
6016 
6017     switch(val->type) {
6018         case XPATH_NUMBER:
6019 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6020         case XPATH_NODESET:
6021         case XPATH_XSLT_TREE:
6022 	    return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6023         case XPATH_STRING:
6024 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6025         case XPATH_BOOLEAN:
6026 	    valuePush(ctxt, arg);
6027 	    xmlXPathBooleanFunction(ctxt, 1);
6028 	    valuePush(ctxt, val);
6029 	    return(xmlXPathCompareValues(ctxt, inf, strict));
6030 	default:
6031             xmlGenericError(xmlGenericErrorContext,
6032                     "xmlXPathCompareNodeSetValue: Can't compare node set "
6033                     "and object of type %d\n",
6034                     val->type);
6035             xmlXPathReleaseObject(ctxt->context, arg);
6036             xmlXPathReleaseObject(ctxt->context, val);
6037             XP_ERROR0(XPATH_INVALID_TYPE);
6038     }
6039     return(0);
6040 }
6041 
6042 /**
6043  * xmlXPathEqualNodeSetString:
6044  * @arg:  the nodeset object argument
6045  * @str:  the string to compare to.
6046  * @neq:  flag to show whether for '=' (0) or '!=' (1)
6047  *
6048  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6049  * If one object to be compared is a node-set and the other is a string,
6050  * then the comparison will be true if and only if there is a node in
6051  * the node-set such that the result of performing the comparison on the
6052  * string-value of the node and the other string is true.
6053  *
6054  * Returns 0 or 1 depending on the results of the test.
6055  */
6056 static int
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg,const xmlChar * str,int neq)6057 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6058 {
6059     int i;
6060     xmlNodeSetPtr ns;
6061     xmlChar *str2;
6062     unsigned int hash;
6063 
6064     if ((str == NULL) || (arg == NULL) ||
6065         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6066         return (0);
6067     ns = arg->nodesetval;
6068     /*
6069      * A NULL nodeset compared with a string is always false
6070      * (since there is no node equal, and no node not equal)
6071      */
6072     if ((ns == NULL) || (ns->nodeNr <= 0) )
6073         return (0);
6074     hash = xmlXPathStringHash(str);
6075     for (i = 0; i < ns->nodeNr; i++) {
6076         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6077             str2 = xmlNodeGetContent(ns->nodeTab[i]);
6078             if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6079                 xmlFree(str2);
6080 		if (neq)
6081 		    continue;
6082                 return (1);
6083 	    } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6084 		if (neq)
6085 		    continue;
6086                 return (1);
6087             } else if (neq) {
6088 		if (str2 != NULL)
6089 		    xmlFree(str2);
6090 		return (1);
6091 	    }
6092             if (str2 != NULL)
6093                 xmlFree(str2);
6094         } else if (neq)
6095 	    return (1);
6096     }
6097     return (0);
6098 }
6099 
6100 /**
6101  * xmlXPathEqualNodeSetFloat:
6102  * @arg:  the nodeset object argument
6103  * @f:  the float to compare to
6104  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6105  *
6106  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6107  * If one object to be compared is a node-set and the other is a number,
6108  * then the comparison will be true if and only if there is a node in
6109  * the node-set such that the result of performing the comparison on the
6110  * number to be compared and on the result of converting the string-value
6111  * of that node to a number using the number function is true.
6112  *
6113  * Returns 0 or 1 depending on the results of the test.
6114  */
6115 static int
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,double f,int neq)6116 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6117     xmlXPathObjectPtr arg, double f, int neq) {
6118   int i, ret=0;
6119   xmlNodeSetPtr ns;
6120   xmlChar *str2;
6121   xmlXPathObjectPtr val;
6122   double v;
6123 
6124     if ((arg == NULL) ||
6125 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6126         return(0);
6127 
6128     ns = arg->nodesetval;
6129     if (ns != NULL) {
6130 	for (i=0;i<ns->nodeNr;i++) {
6131 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6132 	    if (str2 != NULL) {
6133 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6134 		xmlFree(str2);
6135 		xmlXPathNumberFunction(ctxt, 1);
6136                 CHECK_ERROR0;
6137 		val = valuePop(ctxt);
6138 		v = val->floatval;
6139 		xmlXPathReleaseObject(ctxt->context, val);
6140 		if (!xmlXPathIsNaN(v)) {
6141 		    if ((!neq) && (v==f)) {
6142 			ret = 1;
6143 			break;
6144 		    } else if ((neq) && (v!=f)) {
6145 			ret = 1;
6146 			break;
6147 		    }
6148 		} else {	/* NaN is unequal to any value */
6149 		    if (neq)
6150 			ret = 1;
6151 		}
6152 	    }
6153 	}
6154     }
6155 
6156     return(ret);
6157 }
6158 
6159 
6160 /**
6161  * xmlXPathEqualNodeSets:
6162  * @arg1:  first nodeset object argument
6163  * @arg2:  second nodeset object argument
6164  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6165  *
6166  * Implement the equal / not equal operation on XPath nodesets:
6167  * @arg1 == @arg2  or  @arg1 != @arg2
6168  * If both objects to be compared are node-sets, then the comparison
6169  * will be true if and only if there is a node in the first node-set and
6170  * a node in the second node-set such that the result of performing the
6171  * comparison on the string-values of the two nodes is true.
6172  *
6173  * (needless to say, this is a costly operation)
6174  *
6175  * Returns 0 or 1 depending on the results of the test.
6176  */
6177 static int
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2,int neq)6178 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6179     int i, j;
6180     unsigned int *hashs1;
6181     unsigned int *hashs2;
6182     xmlChar **values1;
6183     xmlChar **values2;
6184     int ret = 0;
6185     xmlNodeSetPtr ns1;
6186     xmlNodeSetPtr ns2;
6187 
6188     if ((arg1 == NULL) ||
6189 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6190         return(0);
6191     if ((arg2 == NULL) ||
6192 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6193         return(0);
6194 
6195     ns1 = arg1->nodesetval;
6196     ns2 = arg2->nodesetval;
6197 
6198     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6199 	return(0);
6200     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6201 	return(0);
6202 
6203     /*
6204      * for equal, check if there is a node pertaining to both sets
6205      */
6206     if (neq == 0)
6207 	for (i = 0;i < ns1->nodeNr;i++)
6208 	    for (j = 0;j < ns2->nodeNr;j++)
6209 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
6210 		    return(1);
6211 
6212     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6213     if (values1 == NULL) {
6214         /* TODO: Propagate memory error. */
6215         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6216 	return(0);
6217     }
6218     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6219     if (hashs1 == NULL) {
6220         /* TODO: Propagate memory error. */
6221         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6222 	xmlFree(values1);
6223 	return(0);
6224     }
6225     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6226     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6227     if (values2 == NULL) {
6228         /* TODO: Propagate memory error. */
6229         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6230 	xmlFree(hashs1);
6231 	xmlFree(values1);
6232 	return(0);
6233     }
6234     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6235     if (hashs2 == NULL) {
6236         /* TODO: Propagate memory error. */
6237         xmlXPathErrMemory(NULL, "comparing nodesets\n");
6238 	xmlFree(hashs1);
6239 	xmlFree(values1);
6240 	xmlFree(values2);
6241 	return(0);
6242     }
6243     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6244     for (i = 0;i < ns1->nodeNr;i++) {
6245 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6246 	for (j = 0;j < ns2->nodeNr;j++) {
6247 	    if (i == 0)
6248 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6249 	    if (hashs1[i] != hashs2[j]) {
6250 		if (neq) {
6251 		    ret = 1;
6252 		    break;
6253 		}
6254 	    }
6255 	    else {
6256 		if (values1[i] == NULL)
6257 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6258 		if (values2[j] == NULL)
6259 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6260 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6261 		if (ret)
6262 		    break;
6263 	    }
6264 	}
6265 	if (ret)
6266 	    break;
6267     }
6268     for (i = 0;i < ns1->nodeNr;i++)
6269 	if (values1[i] != NULL)
6270 	    xmlFree(values1[i]);
6271     for (j = 0;j < ns2->nodeNr;j++)
6272 	if (values2[j] != NULL)
6273 	    xmlFree(values2[j]);
6274     xmlFree(values1);
6275     xmlFree(values2);
6276     xmlFree(hashs1);
6277     xmlFree(hashs2);
6278     return(ret);
6279 }
6280 
6281 static int
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6282 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6283   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6284     int ret = 0;
6285     /*
6286      *At this point we are assured neither arg1 nor arg2
6287      *is a nodeset, so we can just pick the appropriate routine.
6288      */
6289     switch (arg1->type) {
6290         case XPATH_UNDEFINED:
6291 	    break;
6292         case XPATH_BOOLEAN:
6293 	    switch (arg2->type) {
6294 	        case XPATH_UNDEFINED:
6295 		    break;
6296 		case XPATH_BOOLEAN:
6297 		    ret = (arg1->boolval == arg2->boolval);
6298 		    break;
6299 		case XPATH_NUMBER:
6300 		    ret = (arg1->boolval ==
6301 			   xmlXPathCastNumberToBoolean(arg2->floatval));
6302 		    break;
6303 		case XPATH_STRING:
6304 		    if ((arg2->stringval == NULL) ||
6305 			(arg2->stringval[0] == 0)) ret = 0;
6306 		    else
6307 			ret = 1;
6308 		    ret = (arg1->boolval == ret);
6309 		    break;
6310 		case XPATH_USERS:
6311 #ifdef LIBXML_XPTR_LOCS_ENABLED
6312 		case XPATH_POINT:
6313 		case XPATH_RANGE:
6314 		case XPATH_LOCATIONSET:
6315 #endif /* LIBXML_XPTR_LOCS_ENABLED */
6316 		    TODO
6317 		    break;
6318 		case XPATH_NODESET:
6319 		case XPATH_XSLT_TREE:
6320 		    break;
6321 	    }
6322 	    break;
6323         case XPATH_NUMBER:
6324 	    switch (arg2->type) {
6325 	        case XPATH_UNDEFINED:
6326 		    break;
6327 		case XPATH_BOOLEAN:
6328 		    ret = (arg2->boolval==
6329 			   xmlXPathCastNumberToBoolean(arg1->floatval));
6330 		    break;
6331 		case XPATH_STRING:
6332 		    valuePush(ctxt, arg2);
6333 		    xmlXPathNumberFunction(ctxt, 1);
6334 		    arg2 = valuePop(ctxt);
6335                     if (ctxt->error)
6336                         break;
6337                     /* Falls through. */
6338 		case XPATH_NUMBER:
6339 		    /* Hand check NaN and Infinity equalities */
6340 		    if (xmlXPathIsNaN(arg1->floatval) ||
6341 			    xmlXPathIsNaN(arg2->floatval)) {
6342 		        ret = 0;
6343 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6344 		        if (xmlXPathIsInf(arg2->floatval) == 1)
6345 			    ret = 1;
6346 			else
6347 			    ret = 0;
6348 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6349 			if (xmlXPathIsInf(arg2->floatval) == -1)
6350 			    ret = 1;
6351 			else
6352 			    ret = 0;
6353 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6354 			if (xmlXPathIsInf(arg1->floatval) == 1)
6355 			    ret = 1;
6356 			else
6357 			    ret = 0;
6358 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6359 			if (xmlXPathIsInf(arg1->floatval) == -1)
6360 			    ret = 1;
6361 			else
6362 			    ret = 0;
6363 		    } else {
6364 		        ret = (arg1->floatval == arg2->floatval);
6365 		    }
6366 		    break;
6367 		case XPATH_USERS:
6368 #ifdef LIBXML_XPTR_LOCS_ENABLED
6369 		case XPATH_POINT:
6370 		case XPATH_RANGE:
6371 		case XPATH_LOCATIONSET:
6372 #endif /* LIBXML_XPTR_LOCS_ENABLED */
6373 		    TODO
6374 		    break;
6375 		case XPATH_NODESET:
6376 		case XPATH_XSLT_TREE:
6377 		    break;
6378 	    }
6379 	    break;
6380         case XPATH_STRING:
6381 	    switch (arg2->type) {
6382 	        case XPATH_UNDEFINED:
6383 		    break;
6384 		case XPATH_BOOLEAN:
6385 		    if ((arg1->stringval == NULL) ||
6386 			(arg1->stringval[0] == 0)) ret = 0;
6387 		    else
6388 			ret = 1;
6389 		    ret = (arg2->boolval == ret);
6390 		    break;
6391 		case XPATH_STRING:
6392 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6393 		    break;
6394 		case XPATH_NUMBER:
6395 		    valuePush(ctxt, arg1);
6396 		    xmlXPathNumberFunction(ctxt, 1);
6397 		    arg1 = valuePop(ctxt);
6398                     if (ctxt->error)
6399                         break;
6400 		    /* Hand check NaN and Infinity equalities */
6401 		    if (xmlXPathIsNaN(arg1->floatval) ||
6402 			    xmlXPathIsNaN(arg2->floatval)) {
6403 		        ret = 0;
6404 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6405 			if (xmlXPathIsInf(arg2->floatval) == 1)
6406 			    ret = 1;
6407 			else
6408 			    ret = 0;
6409 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6410 			if (xmlXPathIsInf(arg2->floatval) == -1)
6411 			    ret = 1;
6412 			else
6413 			    ret = 0;
6414 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6415 			if (xmlXPathIsInf(arg1->floatval) == 1)
6416 			    ret = 1;
6417 			else
6418 			    ret = 0;
6419 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6420 			if (xmlXPathIsInf(arg1->floatval) == -1)
6421 			    ret = 1;
6422 			else
6423 			    ret = 0;
6424 		    } else {
6425 		        ret = (arg1->floatval == arg2->floatval);
6426 		    }
6427 		    break;
6428 		case XPATH_USERS:
6429 #ifdef LIBXML_XPTR_LOCS_ENABLED
6430 		case XPATH_POINT:
6431 		case XPATH_RANGE:
6432 		case XPATH_LOCATIONSET:
6433 #endif /* LIBXML_XPTR_LOCS_ENABLED */
6434 		    TODO
6435 		    break;
6436 		case XPATH_NODESET:
6437 		case XPATH_XSLT_TREE:
6438 		    break;
6439 	    }
6440 	    break;
6441         case XPATH_USERS:
6442 #ifdef LIBXML_XPTR_LOCS_ENABLED
6443 	case XPATH_POINT:
6444 	case XPATH_RANGE:
6445 	case XPATH_LOCATIONSET:
6446 #endif /* LIBXML_XPTR_LOCS_ENABLED */
6447 	    TODO
6448 	    break;
6449 	case XPATH_NODESET:
6450 	case XPATH_XSLT_TREE:
6451 	    break;
6452     }
6453     xmlXPathReleaseObject(ctxt->context, arg1);
6454     xmlXPathReleaseObject(ctxt->context, arg2);
6455     return(ret);
6456 }
6457 
6458 /**
6459  * xmlXPathEqualValues:
6460  * @ctxt:  the XPath Parser context
6461  *
6462  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6463  *
6464  * Returns 0 or 1 depending on the results of the test.
6465  */
6466 int
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt)6467 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
6468     xmlXPathObjectPtr arg1, arg2, argtmp;
6469     int ret = 0;
6470 
6471     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6472     arg2 = valuePop(ctxt);
6473     arg1 = valuePop(ctxt);
6474     if ((arg1 == NULL) || (arg2 == NULL)) {
6475 	if (arg1 != NULL)
6476 	    xmlXPathReleaseObject(ctxt->context, arg1);
6477 	else
6478 	    xmlXPathReleaseObject(ctxt->context, arg2);
6479 	XP_ERROR0(XPATH_INVALID_OPERAND);
6480     }
6481 
6482     if (arg1 == arg2) {
6483 	xmlXPathFreeObject(arg1);
6484         return(1);
6485     }
6486 
6487     /*
6488      *If either argument is a nodeset, it's a 'special case'
6489      */
6490     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6491       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6492 	/*
6493 	 *Hack it to assure arg1 is the nodeset
6494 	 */
6495 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6496 		argtmp = arg2;
6497 		arg2 = arg1;
6498 		arg1 = argtmp;
6499 	}
6500 	switch (arg2->type) {
6501 	    case XPATH_UNDEFINED:
6502 		break;
6503 	    case XPATH_NODESET:
6504 	    case XPATH_XSLT_TREE:
6505 		ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
6506 		break;
6507 	    case XPATH_BOOLEAN:
6508 		if ((arg1->nodesetval == NULL) ||
6509 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
6510 		else
6511 		    ret = 1;
6512 		ret = (ret == arg2->boolval);
6513 		break;
6514 	    case XPATH_NUMBER:
6515 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
6516 		break;
6517 	    case XPATH_STRING:
6518 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
6519 		break;
6520 	    case XPATH_USERS:
6521 #ifdef LIBXML_XPTR_LOCS_ENABLED
6522 	    case XPATH_POINT:
6523 	    case XPATH_RANGE:
6524 	    case XPATH_LOCATIONSET:
6525 #endif /* LIBXML_XPTR_LOCS_ENABLED */
6526 		TODO
6527 		break;
6528 	}
6529 	xmlXPathReleaseObject(ctxt->context, arg1);
6530 	xmlXPathReleaseObject(ctxt->context, arg2);
6531 	return(ret);
6532     }
6533 
6534     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6535 }
6536 
6537 /**
6538  * xmlXPathNotEqualValues:
6539  * @ctxt:  the XPath Parser context
6540  *
6541  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6542  *
6543  * Returns 0 or 1 depending on the results of the test.
6544  */
6545 int
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt)6546 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
6547     xmlXPathObjectPtr arg1, arg2, argtmp;
6548     int ret = 0;
6549 
6550     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6551     arg2 = valuePop(ctxt);
6552     arg1 = valuePop(ctxt);
6553     if ((arg1 == NULL) || (arg2 == NULL)) {
6554 	if (arg1 != NULL)
6555 	    xmlXPathReleaseObject(ctxt->context, arg1);
6556 	else
6557 	    xmlXPathReleaseObject(ctxt->context, arg2);
6558 	XP_ERROR0(XPATH_INVALID_OPERAND);
6559     }
6560 
6561     if (arg1 == arg2) {
6562 	xmlXPathReleaseObject(ctxt->context, arg1);
6563         return(0);
6564     }
6565 
6566     /*
6567      *If either argument is a nodeset, it's a 'special case'
6568      */
6569     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6570       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6571 	/*
6572 	 *Hack it to assure arg1 is the nodeset
6573 	 */
6574 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6575 		argtmp = arg2;
6576 		arg2 = arg1;
6577 		arg1 = argtmp;
6578 	}
6579 	switch (arg2->type) {
6580 	    case XPATH_UNDEFINED:
6581 		break;
6582 	    case XPATH_NODESET:
6583 	    case XPATH_XSLT_TREE:
6584 		ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
6585 		break;
6586 	    case XPATH_BOOLEAN:
6587 		if ((arg1->nodesetval == NULL) ||
6588 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
6589 		else
6590 		    ret = 1;
6591 		ret = (ret != arg2->boolval);
6592 		break;
6593 	    case XPATH_NUMBER:
6594 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
6595 		break;
6596 	    case XPATH_STRING:
6597 		ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
6598 		break;
6599 	    case XPATH_USERS:
6600 #ifdef LIBXML_XPTR_LOCS_ENABLED
6601 	    case XPATH_POINT:
6602 	    case XPATH_RANGE:
6603 	    case XPATH_LOCATIONSET:
6604 #endif /* LIBXML_XPTR_LOCS_ENABLED */
6605 		TODO
6606 		break;
6607 	}
6608 	xmlXPathReleaseObject(ctxt->context, arg1);
6609 	xmlXPathReleaseObject(ctxt->context, arg2);
6610 	return(ret);
6611     }
6612 
6613     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6614 }
6615 
6616 /**
6617  * xmlXPathCompareValues:
6618  * @ctxt:  the XPath Parser context
6619  * @inf:  less than (1) or greater than (0)
6620  * @strict:  is the comparison strict
6621  *
6622  * Implement the compare operation on XPath objects:
6623  *     @arg1 < @arg2    (1, 1, ...
6624  *     @arg1 <= @arg2   (1, 0, ...
6625  *     @arg1 > @arg2    (0, 1, ...
6626  *     @arg1 >= @arg2   (0, 0, ...
6627  *
6628  * When neither object to be compared is a node-set and the operator is
6629  * <=, <, >=, >, then the objects are compared by converted both objects
6630  * to numbers and comparing the numbers according to IEEE 754. The <
6631  * comparison will be true if and only if the first number is less than the
6632  * second number. The <= comparison will be true if and only if the first
6633  * number is less than or equal to the second number. The > comparison
6634  * will be true if and only if the first number is greater than the second
6635  * number. The >= comparison will be true if and only if the first number
6636  * is greater than or equal to the second number.
6637  *
6638  * Returns 1 if the comparison succeeded, 0 if it failed
6639  */
6640 int
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt,int inf,int strict)6641 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
6642     int ret = 0, arg1i = 0, arg2i = 0;
6643     xmlXPathObjectPtr arg1, arg2;
6644 
6645     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6646     arg2 = valuePop(ctxt);
6647     arg1 = valuePop(ctxt);
6648     if ((arg1 == NULL) || (arg2 == NULL)) {
6649 	if (arg1 != NULL)
6650 	    xmlXPathReleaseObject(ctxt->context, arg1);
6651 	else
6652 	    xmlXPathReleaseObject(ctxt->context, arg2);
6653 	XP_ERROR0(XPATH_INVALID_OPERAND);
6654     }
6655 
6656     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6657       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6658 	/*
6659 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
6660 	 * are not freed from within this routine; they will be freed from the
6661 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
6662 	 */
6663 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
6664 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
6665 	    ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
6666 	} else {
6667 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6668 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
6669 			                          arg1, arg2);
6670 	    } else {
6671 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
6672 			                          arg2, arg1);
6673 	    }
6674 	}
6675 	return(ret);
6676     }
6677 
6678     if (arg1->type != XPATH_NUMBER) {
6679 	valuePush(ctxt, arg1);
6680 	xmlXPathNumberFunction(ctxt, 1);
6681 	arg1 = valuePop(ctxt);
6682     }
6683     if (arg2->type != XPATH_NUMBER) {
6684 	valuePush(ctxt, arg2);
6685 	xmlXPathNumberFunction(ctxt, 1);
6686 	arg2 = valuePop(ctxt);
6687     }
6688     if (ctxt->error)
6689         goto error;
6690     /*
6691      * Add tests for infinity and nan
6692      * => feedback on 3.4 for Inf and NaN
6693      */
6694     /* Hand check NaN and Infinity comparisons */
6695     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
6696 	ret=0;
6697     } else {
6698 	arg1i=xmlXPathIsInf(arg1->floatval);
6699 	arg2i=xmlXPathIsInf(arg2->floatval);
6700 	if (inf && strict) {
6701 	    if ((arg1i == -1 && arg2i != -1) ||
6702 		(arg2i == 1 && arg1i != 1)) {
6703 		ret = 1;
6704 	    } else if (arg1i == 0 && arg2i == 0) {
6705 		ret = (arg1->floatval < arg2->floatval);
6706 	    } else {
6707 		ret = 0;
6708 	    }
6709 	}
6710 	else if (inf && !strict) {
6711 	    if (arg1i == -1 || arg2i == 1) {
6712 		ret = 1;
6713 	    } else if (arg1i == 0 && arg2i == 0) {
6714 		ret = (arg1->floatval <= arg2->floatval);
6715 	    } else {
6716 		ret = 0;
6717 	    }
6718 	}
6719 	else if (!inf && strict) {
6720 	    if ((arg1i == 1 && arg2i != 1) ||
6721 		(arg2i == -1 && arg1i != -1)) {
6722 		ret = 1;
6723 	    } else if (arg1i == 0 && arg2i == 0) {
6724 		ret = (arg1->floatval > arg2->floatval);
6725 	    } else {
6726 		ret = 0;
6727 	    }
6728 	}
6729 	else if (!inf && !strict) {
6730 	    if (arg1i == 1 || arg2i == -1) {
6731 		ret = 1;
6732 	    } else if (arg1i == 0 && arg2i == 0) {
6733 		ret = (arg1->floatval >= arg2->floatval);
6734 	    } else {
6735 		ret = 0;
6736 	    }
6737 	}
6738     }
6739 error:
6740     xmlXPathReleaseObject(ctxt->context, arg1);
6741     xmlXPathReleaseObject(ctxt->context, arg2);
6742     return(ret);
6743 }
6744 
6745 /**
6746  * xmlXPathValueFlipSign:
6747  * @ctxt:  the XPath Parser context
6748  *
6749  * Implement the unary - operation on an XPath object
6750  * The numeric operators convert their operands to numbers as if
6751  * by calling the number function.
6752  */
6753 void
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt)6754 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
6755     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
6756     CAST_TO_NUMBER;
6757     CHECK_TYPE(XPATH_NUMBER);
6758     ctxt->value->floatval = -ctxt->value->floatval;
6759 }
6760 
6761 /**
6762  * xmlXPathAddValues:
6763  * @ctxt:  the XPath Parser context
6764  *
6765  * Implement the add operation on XPath objects:
6766  * The numeric operators convert their operands to numbers as if
6767  * by calling the number function.
6768  */
6769 void
xmlXPathAddValues(xmlXPathParserContextPtr ctxt)6770 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
6771     xmlXPathObjectPtr arg;
6772     double val;
6773 
6774     arg = valuePop(ctxt);
6775     if (arg == NULL)
6776 	XP_ERROR(XPATH_INVALID_OPERAND);
6777     val = xmlXPathCastToNumber(arg);
6778     xmlXPathReleaseObject(ctxt->context, arg);
6779     CAST_TO_NUMBER;
6780     CHECK_TYPE(XPATH_NUMBER);
6781     ctxt->value->floatval += val;
6782 }
6783 
6784 /**
6785  * xmlXPathSubValues:
6786  * @ctxt:  the XPath Parser context
6787  *
6788  * Implement the subtraction operation on XPath objects:
6789  * The numeric operators convert their operands to numbers as if
6790  * by calling the number function.
6791  */
6792 void
xmlXPathSubValues(xmlXPathParserContextPtr ctxt)6793 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
6794     xmlXPathObjectPtr arg;
6795     double val;
6796 
6797     arg = valuePop(ctxt);
6798     if (arg == NULL)
6799 	XP_ERROR(XPATH_INVALID_OPERAND);
6800     val = xmlXPathCastToNumber(arg);
6801     xmlXPathReleaseObject(ctxt->context, arg);
6802     CAST_TO_NUMBER;
6803     CHECK_TYPE(XPATH_NUMBER);
6804     ctxt->value->floatval -= val;
6805 }
6806 
6807 /**
6808  * xmlXPathMultValues:
6809  * @ctxt:  the XPath Parser context
6810  *
6811  * Implement the multiply operation on XPath objects:
6812  * The numeric operators convert their operands to numbers as if
6813  * by calling the number function.
6814  */
6815 void
xmlXPathMultValues(xmlXPathParserContextPtr ctxt)6816 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
6817     xmlXPathObjectPtr arg;
6818     double val;
6819 
6820     arg = valuePop(ctxt);
6821     if (arg == NULL)
6822 	XP_ERROR(XPATH_INVALID_OPERAND);
6823     val = xmlXPathCastToNumber(arg);
6824     xmlXPathReleaseObject(ctxt->context, arg);
6825     CAST_TO_NUMBER;
6826     CHECK_TYPE(XPATH_NUMBER);
6827     ctxt->value->floatval *= val;
6828 }
6829 
6830 /**
6831  * xmlXPathDivValues:
6832  * @ctxt:  the XPath Parser context
6833  *
6834  * Implement the div operation on XPath objects @arg1 / @arg2:
6835  * The numeric operators convert their operands to numbers as if
6836  * by calling the number function.
6837  */
6838 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
6839 void
xmlXPathDivValues(xmlXPathParserContextPtr ctxt)6840 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
6841     xmlXPathObjectPtr arg;
6842     double val;
6843 
6844     arg = valuePop(ctxt);
6845     if (arg == NULL)
6846 	XP_ERROR(XPATH_INVALID_OPERAND);
6847     val = xmlXPathCastToNumber(arg);
6848     xmlXPathReleaseObject(ctxt->context, arg);
6849     CAST_TO_NUMBER;
6850     CHECK_TYPE(XPATH_NUMBER);
6851     ctxt->value->floatval /= val;
6852 }
6853 
6854 /**
6855  * xmlXPathModValues:
6856  * @ctxt:  the XPath Parser context
6857  *
6858  * Implement the mod operation on XPath objects: @arg1 / @arg2
6859  * The numeric operators convert their operands to numbers as if
6860  * by calling the number function.
6861  */
6862 void
xmlXPathModValues(xmlXPathParserContextPtr ctxt)6863 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
6864     xmlXPathObjectPtr arg;
6865     double arg1, arg2;
6866 
6867     arg = valuePop(ctxt);
6868     if (arg == NULL)
6869 	XP_ERROR(XPATH_INVALID_OPERAND);
6870     arg2 = xmlXPathCastToNumber(arg);
6871     xmlXPathReleaseObject(ctxt->context, arg);
6872     CAST_TO_NUMBER;
6873     CHECK_TYPE(XPATH_NUMBER);
6874     arg1 = ctxt->value->floatval;
6875     if (arg2 == 0)
6876 	ctxt->value->floatval = xmlXPathNAN;
6877     else {
6878 	ctxt->value->floatval = fmod(arg1, arg2);
6879     }
6880 }
6881 
6882 /************************************************************************
6883  *									*
6884  *		The traversal functions					*
6885  *									*
6886  ************************************************************************/
6887 
6888 /*
6889  * A traversal function enumerates nodes along an axis.
6890  * Initially it must be called with NULL, and it indicates
6891  * termination on the axis by returning NULL.
6892  */
6893 typedef xmlNodePtr (*xmlXPathTraversalFunction)
6894                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
6895 
6896 /*
6897  * xmlXPathTraversalFunctionExt:
6898  * A traversal function enumerates nodes along an axis.
6899  * Initially it must be called with NULL, and it indicates
6900  * termination on the axis by returning NULL.
6901  * The context node of the traversal is specified via @contextNode.
6902  */
6903 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
6904                     (xmlNodePtr cur, xmlNodePtr contextNode);
6905 
6906 /*
6907  * xmlXPathNodeSetMergeFunction:
6908  * Used for merging node sets in xmlXPathCollectAndTest().
6909  */
6910 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
6911 		    (xmlNodeSetPtr, xmlNodeSetPtr);
6912 
6913 
6914 /**
6915  * xmlXPathNextSelf:
6916  * @ctxt:  the XPath Parser context
6917  * @cur:  the current node in the traversal
6918  *
6919  * Traversal function for the "self" direction
6920  * The self axis contains just the context node itself
6921  *
6922  * Returns the next element following that axis
6923  */
6924 xmlNodePtr
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6925 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6926     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6927     if (cur == NULL)
6928         return(ctxt->context->node);
6929     return(NULL);
6930 }
6931 
6932 /**
6933  * xmlXPathNextChild:
6934  * @ctxt:  the XPath Parser context
6935  * @cur:  the current node in the traversal
6936  *
6937  * Traversal function for the "child" direction
6938  * The child axis contains the children of the context node in document order.
6939  *
6940  * Returns the next element following that axis
6941  */
6942 xmlNodePtr
xmlXPathNextChild(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6943 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6944     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6945     if (cur == NULL) {
6946 	if (ctxt->context->node == NULL) return(NULL);
6947 	switch (ctxt->context->node->type) {
6948             case XML_ELEMENT_NODE:
6949             case XML_TEXT_NODE:
6950             case XML_CDATA_SECTION_NODE:
6951             case XML_ENTITY_REF_NODE:
6952             case XML_ENTITY_NODE:
6953             case XML_PI_NODE:
6954             case XML_COMMENT_NODE:
6955             case XML_NOTATION_NODE:
6956             case XML_DTD_NODE:
6957 		return(ctxt->context->node->children);
6958             case XML_DOCUMENT_NODE:
6959             case XML_DOCUMENT_TYPE_NODE:
6960             case XML_DOCUMENT_FRAG_NODE:
6961             case XML_HTML_DOCUMENT_NODE:
6962 		return(((xmlDocPtr) ctxt->context->node)->children);
6963 	    case XML_ELEMENT_DECL:
6964 	    case XML_ATTRIBUTE_DECL:
6965 	    case XML_ENTITY_DECL:
6966             case XML_ATTRIBUTE_NODE:
6967 	    case XML_NAMESPACE_DECL:
6968 	    case XML_XINCLUDE_START:
6969 	    case XML_XINCLUDE_END:
6970 		return(NULL);
6971 	}
6972 	return(NULL);
6973     }
6974     if ((cur->type == XML_DOCUMENT_NODE) ||
6975         (cur->type == XML_HTML_DOCUMENT_NODE))
6976 	return(NULL);
6977     return(cur->next);
6978 }
6979 
6980 /**
6981  * xmlXPathNextChildElement:
6982  * @ctxt:  the XPath Parser context
6983  * @cur:  the current node in the traversal
6984  *
6985  * Traversal function for the "child" direction and nodes of type element.
6986  * The child axis contains the children of the context node in document order.
6987  *
6988  * Returns the next element following that axis
6989  */
6990 static xmlNodePtr
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6991 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6992     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6993     if (cur == NULL) {
6994 	cur = ctxt->context->node;
6995 	if (cur == NULL) return(NULL);
6996 	/*
6997 	* Get the first element child.
6998 	*/
6999 	switch (cur->type) {
7000             case XML_ELEMENT_NODE:
7001 	    case XML_DOCUMENT_FRAG_NODE:
7002 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7003             case XML_ENTITY_NODE:
7004 		cur = cur->children;
7005 		if (cur != NULL) {
7006 		    if (cur->type == XML_ELEMENT_NODE)
7007 			return(cur);
7008 		    do {
7009 			cur = cur->next;
7010 		    } while ((cur != NULL) &&
7011 			(cur->type != XML_ELEMENT_NODE));
7012 		    return(cur);
7013 		}
7014 		return(NULL);
7015             case XML_DOCUMENT_NODE:
7016             case XML_HTML_DOCUMENT_NODE:
7017 		return(xmlDocGetRootElement((xmlDocPtr) cur));
7018 	    default:
7019 		return(NULL);
7020 	}
7021 	return(NULL);
7022     }
7023     /*
7024     * Get the next sibling element node.
7025     */
7026     switch (cur->type) {
7027 	case XML_ELEMENT_NODE:
7028 	case XML_TEXT_NODE:
7029 	case XML_ENTITY_REF_NODE:
7030 	case XML_ENTITY_NODE:
7031 	case XML_CDATA_SECTION_NODE:
7032 	case XML_PI_NODE:
7033 	case XML_COMMENT_NODE:
7034 	case XML_XINCLUDE_END:
7035 	    break;
7036 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7037 	default:
7038 	    return(NULL);
7039     }
7040     if (cur->next != NULL) {
7041 	if (cur->next->type == XML_ELEMENT_NODE)
7042 	    return(cur->next);
7043 	cur = cur->next;
7044 	do {
7045 	    cur = cur->next;
7046 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7047 	return(cur);
7048     }
7049     return(NULL);
7050 }
7051 
7052 #if 0
7053 /**
7054  * xmlXPathNextDescendantOrSelfElemParent:
7055  * @ctxt:  the XPath Parser context
7056  * @cur:  the current node in the traversal
7057  *
7058  * Traversal function for the "descendant-or-self" axis.
7059  * Additionally it returns only nodes which can be parents of
7060  * element nodes.
7061  *
7062  *
7063  * Returns the next element following that axis
7064  */
7065 static xmlNodePtr
7066 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7067 				       xmlNodePtr contextNode)
7068 {
7069     if (cur == NULL) {
7070 	if (contextNode == NULL)
7071 	    return(NULL);
7072 	switch (contextNode->type) {
7073 	    case XML_ELEMENT_NODE:
7074 	    case XML_XINCLUDE_START:
7075 	    case XML_DOCUMENT_FRAG_NODE:
7076 	    case XML_DOCUMENT_NODE:
7077 	    case XML_HTML_DOCUMENT_NODE:
7078 		return(contextNode);
7079 	    default:
7080 		return(NULL);
7081 	}
7082 	return(NULL);
7083     } else {
7084 	xmlNodePtr start = cur;
7085 
7086 	while (cur != NULL) {
7087 	    switch (cur->type) {
7088 		case XML_ELEMENT_NODE:
7089 		/* TODO: OK to have XInclude here? */
7090 		case XML_XINCLUDE_START:
7091 		case XML_DOCUMENT_FRAG_NODE:
7092 		    if (cur != start)
7093 			return(cur);
7094 		    if (cur->children != NULL) {
7095 			cur = cur->children;
7096 			continue;
7097 		    }
7098 		    break;
7099 		/* Not sure if we need those here. */
7100 		case XML_DOCUMENT_NODE:
7101 		case XML_HTML_DOCUMENT_NODE:
7102 		    if (cur != start)
7103 			return(cur);
7104 		    return(xmlDocGetRootElement((xmlDocPtr) cur));
7105 		default:
7106 		    break;
7107 	    }
7108 
7109 next_sibling:
7110 	    if ((cur == NULL) || (cur == contextNode))
7111 		return(NULL);
7112 	    if (cur->next != NULL) {
7113 		cur = cur->next;
7114 	    } else {
7115 		cur = cur->parent;
7116 		goto next_sibling;
7117 	    }
7118 	}
7119     }
7120     return(NULL);
7121 }
7122 #endif
7123 
7124 /**
7125  * xmlXPathNextDescendant:
7126  * @ctxt:  the XPath Parser context
7127  * @cur:  the current node in the traversal
7128  *
7129  * Traversal function for the "descendant" direction
7130  * the descendant axis contains the descendants of the context node in document
7131  * order; a descendant is a child or a child of a child and so on.
7132  *
7133  * Returns the next element following that axis
7134  */
7135 xmlNodePtr
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7136 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7137     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7138     if (cur == NULL) {
7139 	if (ctxt->context->node == NULL)
7140 	    return(NULL);
7141 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7142 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
7143 	    return(NULL);
7144 
7145         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7146 	    return(ctxt->context->doc->children);
7147         return(ctxt->context->node->children);
7148     }
7149 
7150     if (cur->type == XML_NAMESPACE_DECL)
7151         return(NULL);
7152     if (cur->children != NULL) {
7153 	/*
7154 	 * Do not descend on entities declarations
7155 	 */
7156 	if (cur->children->type != XML_ENTITY_DECL) {
7157 	    cur = cur->children;
7158 	    /*
7159 	     * Skip DTDs
7160 	     */
7161 	    if (cur->type != XML_DTD_NODE)
7162 		return(cur);
7163 	}
7164     }
7165 
7166     if (cur == ctxt->context->node) return(NULL);
7167 
7168     while (cur->next != NULL) {
7169 	cur = cur->next;
7170 	if ((cur->type != XML_ENTITY_DECL) &&
7171 	    (cur->type != XML_DTD_NODE))
7172 	    return(cur);
7173     }
7174 
7175     do {
7176         cur = cur->parent;
7177 	if (cur == NULL) break;
7178 	if (cur == ctxt->context->node) return(NULL);
7179 	if (cur->next != NULL) {
7180 	    cur = cur->next;
7181 	    return(cur);
7182 	}
7183     } while (cur != NULL);
7184     return(cur);
7185 }
7186 
7187 /**
7188  * xmlXPathNextDescendantOrSelf:
7189  * @ctxt:  the XPath Parser context
7190  * @cur:  the current node in the traversal
7191  *
7192  * Traversal function for the "descendant-or-self" direction
7193  * the descendant-or-self axis contains the context node and the descendants
7194  * of the context node in document order; thus the context node is the first
7195  * node on the axis, and the first child of the context node is the second node
7196  * on the axis
7197  *
7198  * Returns the next element following that axis
7199  */
7200 xmlNodePtr
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7201 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7202     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7203     if (cur == NULL)
7204         return(ctxt->context->node);
7205 
7206     if (ctxt->context->node == NULL)
7207         return(NULL);
7208     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7209         (ctxt->context->node->type == XML_NAMESPACE_DECL))
7210         return(NULL);
7211 
7212     return(xmlXPathNextDescendant(ctxt, cur));
7213 }
7214 
7215 /**
7216  * xmlXPathNextParent:
7217  * @ctxt:  the XPath Parser context
7218  * @cur:  the current node in the traversal
7219  *
7220  * Traversal function for the "parent" direction
7221  * The parent axis contains the parent of the context node, if there is one.
7222  *
7223  * Returns the next element following that axis
7224  */
7225 xmlNodePtr
xmlXPathNextParent(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7226 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7227     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7228     /*
7229      * the parent of an attribute or namespace node is the element
7230      * to which the attribute or namespace node is attached
7231      * Namespace handling !!!
7232      */
7233     if (cur == NULL) {
7234 	if (ctxt->context->node == NULL) return(NULL);
7235 	switch (ctxt->context->node->type) {
7236             case XML_ELEMENT_NODE:
7237             case XML_TEXT_NODE:
7238             case XML_CDATA_SECTION_NODE:
7239             case XML_ENTITY_REF_NODE:
7240             case XML_ENTITY_NODE:
7241             case XML_PI_NODE:
7242             case XML_COMMENT_NODE:
7243             case XML_NOTATION_NODE:
7244             case XML_DTD_NODE:
7245 	    case XML_ELEMENT_DECL:
7246 	    case XML_ATTRIBUTE_DECL:
7247 	    case XML_XINCLUDE_START:
7248 	    case XML_XINCLUDE_END:
7249 	    case XML_ENTITY_DECL:
7250 		if (ctxt->context->node->parent == NULL)
7251 		    return((xmlNodePtr) ctxt->context->doc);
7252 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7253 		    ((ctxt->context->node->parent->name[0] == ' ') ||
7254 		     (xmlStrEqual(ctxt->context->node->parent->name,
7255 				 BAD_CAST "fake node libxslt"))))
7256 		    return(NULL);
7257 		return(ctxt->context->node->parent);
7258             case XML_ATTRIBUTE_NODE: {
7259 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7260 
7261 		return(att->parent);
7262 	    }
7263             case XML_DOCUMENT_NODE:
7264             case XML_DOCUMENT_TYPE_NODE:
7265             case XML_DOCUMENT_FRAG_NODE:
7266             case XML_HTML_DOCUMENT_NODE:
7267                 return(NULL);
7268 	    case XML_NAMESPACE_DECL: {
7269 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7270 
7271 		if ((ns->next != NULL) &&
7272 		    (ns->next->type != XML_NAMESPACE_DECL))
7273 		    return((xmlNodePtr) ns->next);
7274                 return(NULL);
7275 	    }
7276 	}
7277     }
7278     return(NULL);
7279 }
7280 
7281 /**
7282  * xmlXPathNextAncestor:
7283  * @ctxt:  the XPath Parser context
7284  * @cur:  the current node in the traversal
7285  *
7286  * Traversal function for the "ancestor" direction
7287  * the ancestor axis contains the ancestors of the context node; the ancestors
7288  * of the context node consist of the parent of context node and the parent's
7289  * parent and so on; the nodes are ordered in reverse document order; thus the
7290  * parent is the first node on the axis, and the parent's parent is the second
7291  * node on the axis
7292  *
7293  * Returns the next element following that axis
7294  */
7295 xmlNodePtr
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7296 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7297     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7298     /*
7299      * the parent of an attribute or namespace node is the element
7300      * to which the attribute or namespace node is attached
7301      * !!!!!!!!!!!!!
7302      */
7303     if (cur == NULL) {
7304 	if (ctxt->context->node == NULL) return(NULL);
7305 	switch (ctxt->context->node->type) {
7306             case XML_ELEMENT_NODE:
7307             case XML_TEXT_NODE:
7308             case XML_CDATA_SECTION_NODE:
7309             case XML_ENTITY_REF_NODE:
7310             case XML_ENTITY_NODE:
7311             case XML_PI_NODE:
7312             case XML_COMMENT_NODE:
7313 	    case XML_DTD_NODE:
7314 	    case XML_ELEMENT_DECL:
7315 	    case XML_ATTRIBUTE_DECL:
7316 	    case XML_ENTITY_DECL:
7317             case XML_NOTATION_NODE:
7318 	    case XML_XINCLUDE_START:
7319 	    case XML_XINCLUDE_END:
7320 		if (ctxt->context->node->parent == NULL)
7321 		    return((xmlNodePtr) ctxt->context->doc);
7322 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7323 		    ((ctxt->context->node->parent->name[0] == ' ') ||
7324 		     (xmlStrEqual(ctxt->context->node->parent->name,
7325 				 BAD_CAST "fake node libxslt"))))
7326 		    return(NULL);
7327 		return(ctxt->context->node->parent);
7328             case XML_ATTRIBUTE_NODE: {
7329 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
7330 
7331 		return(tmp->parent);
7332 	    }
7333             case XML_DOCUMENT_NODE:
7334             case XML_DOCUMENT_TYPE_NODE:
7335             case XML_DOCUMENT_FRAG_NODE:
7336             case XML_HTML_DOCUMENT_NODE:
7337                 return(NULL);
7338 	    case XML_NAMESPACE_DECL: {
7339 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7340 
7341 		if ((ns->next != NULL) &&
7342 		    (ns->next->type != XML_NAMESPACE_DECL))
7343 		    return((xmlNodePtr) ns->next);
7344 		/* Bad, how did that namespace end up here ? */
7345                 return(NULL);
7346 	    }
7347 	}
7348 	return(NULL);
7349     }
7350     if (cur == ctxt->context->doc->children)
7351 	return((xmlNodePtr) ctxt->context->doc);
7352     if (cur == (xmlNodePtr) ctxt->context->doc)
7353 	return(NULL);
7354     switch (cur->type) {
7355 	case XML_ELEMENT_NODE:
7356 	case XML_TEXT_NODE:
7357 	case XML_CDATA_SECTION_NODE:
7358 	case XML_ENTITY_REF_NODE:
7359 	case XML_ENTITY_NODE:
7360 	case XML_PI_NODE:
7361 	case XML_COMMENT_NODE:
7362 	case XML_NOTATION_NODE:
7363 	case XML_DTD_NODE:
7364         case XML_ELEMENT_DECL:
7365         case XML_ATTRIBUTE_DECL:
7366         case XML_ENTITY_DECL:
7367 	case XML_XINCLUDE_START:
7368 	case XML_XINCLUDE_END:
7369 	    if (cur->parent == NULL)
7370 		return(NULL);
7371 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
7372 		((cur->parent->name[0] == ' ') ||
7373 		 (xmlStrEqual(cur->parent->name,
7374 			      BAD_CAST "fake node libxslt"))))
7375 		return(NULL);
7376 	    return(cur->parent);
7377 	case XML_ATTRIBUTE_NODE: {
7378 	    xmlAttrPtr att = (xmlAttrPtr) cur;
7379 
7380 	    return(att->parent);
7381 	}
7382 	case XML_NAMESPACE_DECL: {
7383 	    xmlNsPtr ns = (xmlNsPtr) cur;
7384 
7385 	    if ((ns->next != NULL) &&
7386 	        (ns->next->type != XML_NAMESPACE_DECL))
7387 	        return((xmlNodePtr) ns->next);
7388 	    /* Bad, how did that namespace end up here ? */
7389             return(NULL);
7390 	}
7391 	case XML_DOCUMENT_NODE:
7392 	case XML_DOCUMENT_TYPE_NODE:
7393 	case XML_DOCUMENT_FRAG_NODE:
7394 	case XML_HTML_DOCUMENT_NODE:
7395 	    return(NULL);
7396     }
7397     return(NULL);
7398 }
7399 
7400 /**
7401  * xmlXPathNextAncestorOrSelf:
7402  * @ctxt:  the XPath Parser context
7403  * @cur:  the current node in the traversal
7404  *
7405  * Traversal function for the "ancestor-or-self" direction
7406  * he ancestor-or-self axis contains the context node and ancestors of
7407  * the context node in reverse document order; thus the context node is
7408  * the first node on the axis, and the context node's parent the second;
7409  * parent here is defined the same as with the parent axis.
7410  *
7411  * Returns the next element following that axis
7412  */
7413 xmlNodePtr
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7414 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7415     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7416     if (cur == NULL)
7417         return(ctxt->context->node);
7418     return(xmlXPathNextAncestor(ctxt, cur));
7419 }
7420 
7421 /**
7422  * xmlXPathNextFollowingSibling:
7423  * @ctxt:  the XPath Parser context
7424  * @cur:  the current node in the traversal
7425  *
7426  * Traversal function for the "following-sibling" direction
7427  * The following-sibling axis contains the following siblings of the context
7428  * node in document order.
7429  *
7430  * Returns the next element following that axis
7431  */
7432 xmlNodePtr
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7433 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7434     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7435     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7436 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
7437 	return(NULL);
7438     if (cur == (xmlNodePtr) ctxt->context->doc)
7439         return(NULL);
7440     if (cur == NULL)
7441         return(ctxt->context->node->next);
7442     return(cur->next);
7443 }
7444 
7445 /**
7446  * xmlXPathNextPrecedingSibling:
7447  * @ctxt:  the XPath Parser context
7448  * @cur:  the current node in the traversal
7449  *
7450  * Traversal function for the "preceding-sibling" direction
7451  * The preceding-sibling axis contains the preceding siblings of the context
7452  * node in reverse document order; the first preceding sibling is first on the
7453  * axis; the sibling preceding that node is the second on the axis and so on.
7454  *
7455  * Returns the next element following that axis
7456  */
7457 xmlNodePtr
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7458 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7459     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7460     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7461 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
7462 	return(NULL);
7463     if (cur == (xmlNodePtr) ctxt->context->doc)
7464         return(NULL);
7465     if (cur == NULL)
7466         return(ctxt->context->node->prev);
7467     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
7468 	cur = cur->prev;
7469 	if (cur == NULL)
7470 	    return(ctxt->context->node->prev);
7471     }
7472     return(cur->prev);
7473 }
7474 
7475 /**
7476  * xmlXPathNextFollowing:
7477  * @ctxt:  the XPath Parser context
7478  * @cur:  the current node in the traversal
7479  *
7480  * Traversal function for the "following" direction
7481  * The following axis contains all nodes in the same document as the context
7482  * node that are after the context node in document order, excluding any
7483  * descendants and excluding attribute nodes and namespace nodes; the nodes
7484  * are ordered in document order
7485  *
7486  * Returns the next element following that axis
7487  */
7488 xmlNodePtr
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7489 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7490     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7491     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
7492         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
7493         return(cur->children);
7494 
7495     if (cur == NULL) {
7496         cur = ctxt->context->node;
7497         if (cur->type == XML_ATTRIBUTE_NODE) {
7498             cur = cur->parent;
7499         } else if (cur->type == XML_NAMESPACE_DECL) {
7500             xmlNsPtr ns = (xmlNsPtr) cur;
7501 
7502             if ((ns->next == NULL) ||
7503                 (ns->next->type == XML_NAMESPACE_DECL))
7504                 return (NULL);
7505             cur = (xmlNodePtr) ns->next;
7506         }
7507     }
7508     if (cur == NULL) return(NULL) ; /* ERROR */
7509     if (cur->next != NULL) return(cur->next) ;
7510     do {
7511         cur = cur->parent;
7512         if (cur == NULL) break;
7513         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
7514         if (cur->next != NULL) return(cur->next);
7515     } while (cur != NULL);
7516     return(cur);
7517 }
7518 
7519 /*
7520  * xmlXPathIsAncestor:
7521  * @ancestor:  the ancestor node
7522  * @node:  the current node
7523  *
7524  * Check that @ancestor is a @node's ancestor
7525  *
7526  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
7527  */
7528 static int
xmlXPathIsAncestor(xmlNodePtr ancestor,xmlNodePtr node)7529 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
7530     if ((ancestor == NULL) || (node == NULL)) return(0);
7531     if (node->type == XML_NAMESPACE_DECL)
7532         return(0);
7533     if (ancestor->type == XML_NAMESPACE_DECL)
7534         return(0);
7535     /* nodes need to be in the same document */
7536     if (ancestor->doc != node->doc) return(0);
7537     /* avoid searching if ancestor or node is the root node */
7538     if (ancestor == (xmlNodePtr) node->doc) return(1);
7539     if (node == (xmlNodePtr) ancestor->doc) return(0);
7540     while (node->parent != NULL) {
7541         if (node->parent == ancestor)
7542             return(1);
7543 	node = node->parent;
7544     }
7545     return(0);
7546 }
7547 
7548 /**
7549  * xmlXPathNextPreceding:
7550  * @ctxt:  the XPath Parser context
7551  * @cur:  the current node in the traversal
7552  *
7553  * Traversal function for the "preceding" direction
7554  * the preceding axis contains all nodes in the same document as the context
7555  * node that are before the context node in document order, excluding any
7556  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7557  * ordered in reverse document order
7558  *
7559  * Returns the next element following that axis
7560  */
7561 xmlNodePtr
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7562 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
7563 {
7564     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7565     if (cur == NULL) {
7566         cur = ctxt->context->node;
7567         if (cur->type == XML_ATTRIBUTE_NODE) {
7568             cur = cur->parent;
7569         } else if (cur->type == XML_NAMESPACE_DECL) {
7570             xmlNsPtr ns = (xmlNsPtr) cur;
7571 
7572             if ((ns->next == NULL) ||
7573                 (ns->next->type == XML_NAMESPACE_DECL))
7574                 return (NULL);
7575             cur = (xmlNodePtr) ns->next;
7576         }
7577     }
7578     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
7579 	return (NULL);
7580     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7581 	cur = cur->prev;
7582     do {
7583         if (cur->prev != NULL) {
7584             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
7585             return (cur);
7586         }
7587 
7588         cur = cur->parent;
7589         if (cur == NULL)
7590             return (NULL);
7591         if (cur == ctxt->context->doc->children)
7592             return (NULL);
7593     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
7594     return (cur);
7595 }
7596 
7597 /**
7598  * xmlXPathNextPrecedingInternal:
7599  * @ctxt:  the XPath Parser context
7600  * @cur:  the current node in the traversal
7601  *
7602  * Traversal function for the "preceding" direction
7603  * the preceding axis contains all nodes in the same document as the context
7604  * node that are before the context node in document order, excluding any
7605  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7606  * ordered in reverse document order
7607  * This is a faster implementation but internal only since it requires a
7608  * state kept in the parser context: ctxt->ancestor.
7609  *
7610  * Returns the next element following that axis
7611  */
7612 static xmlNodePtr
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7613 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
7614                               xmlNodePtr cur)
7615 {
7616     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7617     if (cur == NULL) {
7618         cur = ctxt->context->node;
7619         if (cur == NULL)
7620             return (NULL);
7621         if (cur->type == XML_ATTRIBUTE_NODE) {
7622             cur = cur->parent;
7623         } else if (cur->type == XML_NAMESPACE_DECL) {
7624             xmlNsPtr ns = (xmlNsPtr) cur;
7625 
7626             if ((ns->next == NULL) ||
7627                 (ns->next->type == XML_NAMESPACE_DECL))
7628                 return (NULL);
7629             cur = (xmlNodePtr) ns->next;
7630         }
7631         ctxt->ancestor = cur->parent;
7632     }
7633     if (cur->type == XML_NAMESPACE_DECL)
7634         return(NULL);
7635     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7636 	cur = cur->prev;
7637     while (cur->prev == NULL) {
7638         cur = cur->parent;
7639         if (cur == NULL)
7640             return (NULL);
7641         if (cur == ctxt->context->doc->children)
7642             return (NULL);
7643         if (cur != ctxt->ancestor)
7644             return (cur);
7645         ctxt->ancestor = cur->parent;
7646     }
7647     cur = cur->prev;
7648     while (cur->last != NULL)
7649         cur = cur->last;
7650     return (cur);
7651 }
7652 
7653 /**
7654  * xmlXPathNextNamespace:
7655  * @ctxt:  the XPath Parser context
7656  * @cur:  the current attribute in the traversal
7657  *
7658  * Traversal function for the "namespace" direction
7659  * the namespace axis contains the namespace nodes of the context node;
7660  * the order of nodes on this axis is implementation-defined; the axis will
7661  * be empty unless the context node is an element
7662  *
7663  * We keep the XML namespace node at the end of the list.
7664  *
7665  * Returns the next element following that axis
7666  */
7667 xmlNodePtr
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7668 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7669     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7670     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
7671     if (cur == NULL) {
7672         if (ctxt->context->tmpNsList != NULL)
7673 	    xmlFree(ctxt->context->tmpNsList);
7674 	ctxt->context->tmpNsList =
7675 	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
7676 	ctxt->context->tmpNsNr = 0;
7677 	if (ctxt->context->tmpNsList != NULL) {
7678 	    while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
7679 		ctxt->context->tmpNsNr++;
7680 	    }
7681 	}
7682 	return((xmlNodePtr) xmlXPathXMLNamespace);
7683     }
7684     if (ctxt->context->tmpNsNr > 0) {
7685 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
7686     } else {
7687 	if (ctxt->context->tmpNsList != NULL)
7688 	    xmlFree(ctxt->context->tmpNsList);
7689 	ctxt->context->tmpNsList = NULL;
7690 	return(NULL);
7691     }
7692 }
7693 
7694 /**
7695  * xmlXPathNextAttribute:
7696  * @ctxt:  the XPath Parser context
7697  * @cur:  the current attribute in the traversal
7698  *
7699  * Traversal function for the "attribute" direction
7700  * TODO: support DTD inherited default attributes
7701  *
7702  * Returns the next element following that axis
7703  */
7704 xmlNodePtr
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7705 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7706     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7707     if (ctxt->context->node == NULL)
7708 	return(NULL);
7709     if (ctxt->context->node->type != XML_ELEMENT_NODE)
7710 	return(NULL);
7711     if (cur == NULL) {
7712         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7713 	    return(NULL);
7714         return((xmlNodePtr)ctxt->context->node->properties);
7715     }
7716     return((xmlNodePtr)cur->next);
7717 }
7718 
7719 /************************************************************************
7720  *									*
7721  *		NodeTest Functions					*
7722  *									*
7723  ************************************************************************/
7724 
7725 #define IS_FUNCTION			200
7726 
7727 
7728 /************************************************************************
7729  *									*
7730  *		Implicit tree core function library			*
7731  *									*
7732  ************************************************************************/
7733 
7734 /**
7735  * xmlXPathRoot:
7736  * @ctxt:  the XPath Parser context
7737  *
7738  * Initialize the context to the root of the document
7739  */
7740 void
xmlXPathRoot(xmlXPathParserContextPtr ctxt)7741 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
7742     if ((ctxt == NULL) || (ctxt->context == NULL))
7743 	return;
7744     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
7745 	(xmlNodePtr) ctxt->context->doc));
7746 }
7747 
7748 /************************************************************************
7749  *									*
7750  *		The explicit core function library			*
7751  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
7752  *									*
7753  ************************************************************************/
7754 
7755 
7756 /**
7757  * xmlXPathLastFunction:
7758  * @ctxt:  the XPath Parser context
7759  * @nargs:  the number of arguments
7760  *
7761  * Implement the last() XPath function
7762  *    number last()
7763  * The last function returns the number of nodes in the context node list.
7764  */
7765 void
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt,int nargs)7766 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7767     CHECK_ARITY(0);
7768     if (ctxt->context->contextSize >= 0) {
7769 	valuePush(ctxt,
7770 	    xmlXPathCacheNewFloat(ctxt->context,
7771 		(double) ctxt->context->contextSize));
7772     } else {
7773 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
7774     }
7775 }
7776 
7777 /**
7778  * xmlXPathPositionFunction:
7779  * @ctxt:  the XPath Parser context
7780  * @nargs:  the number of arguments
7781  *
7782  * Implement the position() XPath function
7783  *    number position()
7784  * The position function returns the position of the context node in the
7785  * context node list. The first position is 1, and so the last position
7786  * will be equal to last().
7787  */
7788 void
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt,int nargs)7789 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7790     CHECK_ARITY(0);
7791     if (ctxt->context->proximityPosition >= 0) {
7792 	valuePush(ctxt,
7793 	      xmlXPathCacheNewFloat(ctxt->context,
7794 		(double) ctxt->context->proximityPosition));
7795     } else {
7796 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
7797     }
7798 }
7799 
7800 /**
7801  * xmlXPathCountFunction:
7802  * @ctxt:  the XPath Parser context
7803  * @nargs:  the number of arguments
7804  *
7805  * Implement the count() XPath function
7806  *    number count(node-set)
7807  */
7808 void
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt,int nargs)7809 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7810     xmlXPathObjectPtr cur;
7811 
7812     CHECK_ARITY(1);
7813     if ((ctxt->value == NULL) ||
7814 	((ctxt->value->type != XPATH_NODESET) &&
7815 	 (ctxt->value->type != XPATH_XSLT_TREE)))
7816 	XP_ERROR(XPATH_INVALID_TYPE);
7817     cur = valuePop(ctxt);
7818 
7819     if ((cur == NULL) || (cur->nodesetval == NULL))
7820 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
7821     else
7822 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
7823 	    (double) cur->nodesetval->nodeNr));
7824     xmlXPathReleaseObject(ctxt->context, cur);
7825 }
7826 
7827 /**
7828  * xmlXPathGetElementsByIds:
7829  * @doc:  the document
7830  * @ids:  a whitespace separated list of IDs
7831  *
7832  * Selects elements by their unique ID.
7833  *
7834  * Returns a node-set of selected elements.
7835  */
7836 static xmlNodeSetPtr
xmlXPathGetElementsByIds(xmlDocPtr doc,const xmlChar * ids)7837 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
7838     xmlNodeSetPtr ret;
7839     const xmlChar *cur = ids;
7840     xmlChar *ID;
7841     xmlAttrPtr attr;
7842     xmlNodePtr elem = NULL;
7843 
7844     if (ids == NULL) return(NULL);
7845 
7846     ret = xmlXPathNodeSetCreate(NULL);
7847     if (ret == NULL)
7848         return(ret);
7849 
7850     while (IS_BLANK_CH(*cur)) cur++;
7851     while (*cur != 0) {
7852 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
7853 	    cur++;
7854 
7855         ID = xmlStrndup(ids, cur - ids);
7856 	if (ID != NULL) {
7857 	    /*
7858 	     * We used to check the fact that the value passed
7859 	     * was an NCName, but this generated much troubles for
7860 	     * me and Aleksey Sanin, people blatantly violated that
7861 	     * constraint, like Visa3D spec.
7862 	     * if (xmlValidateNCName(ID, 1) == 0)
7863 	     */
7864 	    attr = xmlGetID(doc, ID);
7865 	    if (attr != NULL) {
7866 		if (attr->type == XML_ATTRIBUTE_NODE)
7867 		    elem = attr->parent;
7868 		else if (attr->type == XML_ELEMENT_NODE)
7869 		    elem = (xmlNodePtr) attr;
7870 		else
7871 		    elem = NULL;
7872                 /* TODO: Check memory error. */
7873 		if (elem != NULL)
7874 		    xmlXPathNodeSetAdd(ret, elem);
7875 	    }
7876 	    xmlFree(ID);
7877 	}
7878 
7879 	while (IS_BLANK_CH(*cur)) cur++;
7880 	ids = cur;
7881     }
7882     return(ret);
7883 }
7884 
7885 /**
7886  * xmlXPathIdFunction:
7887  * @ctxt:  the XPath Parser context
7888  * @nargs:  the number of arguments
7889  *
7890  * Implement the id() XPath function
7891  *    node-set id(object)
7892  * The id function selects elements by their unique ID
7893  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
7894  * then the result is the union of the result of applying id to the
7895  * string value of each of the nodes in the argument node-set. When the
7896  * argument to id is of any other type, the argument is converted to a
7897  * string as if by a call to the string function; the string is split
7898  * into a whitespace-separated list of tokens (whitespace is any sequence
7899  * of characters matching the production S); the result is a node-set
7900  * containing the elements in the same document as the context node that
7901  * have a unique ID equal to any of the tokens in the list.
7902  */
7903 void
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt,int nargs)7904 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7905     xmlChar *tokens;
7906     xmlNodeSetPtr ret;
7907     xmlXPathObjectPtr obj;
7908 
7909     CHECK_ARITY(1);
7910     obj = valuePop(ctxt);
7911     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7912     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7913 	xmlNodeSetPtr ns;
7914 	int i;
7915 
7916         /* TODO: Check memory error. */
7917 	ret = xmlXPathNodeSetCreate(NULL);
7918 
7919 	if (obj->nodesetval != NULL) {
7920 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7921 		tokens =
7922 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7923 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7924                 /* TODO: Check memory error. */
7925 		ret = xmlXPathNodeSetMerge(ret, ns);
7926 		xmlXPathFreeNodeSet(ns);
7927 		if (tokens != NULL)
7928 		    xmlFree(tokens);
7929 	    }
7930 	}
7931 	xmlXPathReleaseObject(ctxt->context, obj);
7932 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
7933 	return;
7934     }
7935     obj = xmlXPathCacheConvertString(ctxt->context, obj);
7936     if (obj == NULL) return;
7937     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
7938     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
7939     xmlXPathReleaseObject(ctxt->context, obj);
7940     return;
7941 }
7942 
7943 /**
7944  * xmlXPathLocalNameFunction:
7945  * @ctxt:  the XPath Parser context
7946  * @nargs:  the number of arguments
7947  *
7948  * Implement the local-name() XPath function
7949  *    string local-name(node-set?)
7950  * The local-name function returns a string containing the local part
7951  * of the name of the node in the argument node-set that is first in
7952  * document order. If the node-set is empty or the first node has no
7953  * name, an empty string is returned. If the argument is omitted it
7954  * defaults to the context node.
7955  */
7956 void
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt,int nargs)7957 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7958     xmlXPathObjectPtr cur;
7959 
7960     if (ctxt == NULL) return;
7961 
7962     if (nargs == 0) {
7963 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
7964 	    ctxt->context->node));
7965 	nargs = 1;
7966     }
7967 
7968     CHECK_ARITY(1);
7969     if ((ctxt->value == NULL) ||
7970 	((ctxt->value->type != XPATH_NODESET) &&
7971 	 (ctxt->value->type != XPATH_XSLT_TREE)))
7972 	XP_ERROR(XPATH_INVALID_TYPE);
7973     cur = valuePop(ctxt);
7974 
7975     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7976 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
7977     } else {
7978 	int i = 0; /* Should be first in document order !!!!! */
7979 	switch (cur->nodesetval->nodeTab[i]->type) {
7980 	case XML_ELEMENT_NODE:
7981 	case XML_ATTRIBUTE_NODE:
7982 	case XML_PI_NODE:
7983 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7984 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
7985 	    else
7986 		valuePush(ctxt,
7987 		      xmlXPathCacheNewString(ctxt->context,
7988 			cur->nodesetval->nodeTab[i]->name));
7989 	    break;
7990 	case XML_NAMESPACE_DECL:
7991 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
7992 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
7993 	    break;
7994 	default:
7995 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
7996 	}
7997     }
7998     xmlXPathReleaseObject(ctxt->context, cur);
7999 }
8000 
8001 /**
8002  * xmlXPathNamespaceURIFunction:
8003  * @ctxt:  the XPath Parser context
8004  * @nargs:  the number of arguments
8005  *
8006  * Implement the namespace-uri() XPath function
8007  *    string namespace-uri(node-set?)
8008  * The namespace-uri function returns a string containing the
8009  * namespace URI of the expanded name of the node in the argument
8010  * node-set that is first in document order. If the node-set is empty,
8011  * the first node has no name, or the expanded name has no namespace
8012  * URI, an empty string is returned. If the argument is omitted it
8013  * defaults to the context node.
8014  */
8015 void
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt,int nargs)8016 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8017     xmlXPathObjectPtr cur;
8018 
8019     if (ctxt == NULL) return;
8020 
8021     if (nargs == 0) {
8022 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8023 	    ctxt->context->node));
8024 	nargs = 1;
8025     }
8026     CHECK_ARITY(1);
8027     if ((ctxt->value == NULL) ||
8028 	((ctxt->value->type != XPATH_NODESET) &&
8029 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8030 	XP_ERROR(XPATH_INVALID_TYPE);
8031     cur = valuePop(ctxt);
8032 
8033     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8034 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8035     } else {
8036 	int i = 0; /* Should be first in document order !!!!! */
8037 	switch (cur->nodesetval->nodeTab[i]->type) {
8038 	case XML_ELEMENT_NODE:
8039 	case XML_ATTRIBUTE_NODE:
8040 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
8041 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8042 	    else
8043 		valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8044 			  cur->nodesetval->nodeTab[i]->ns->href));
8045 	    break;
8046 	default:
8047 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8048 	}
8049     }
8050     xmlXPathReleaseObject(ctxt->context, cur);
8051 }
8052 
8053 /**
8054  * xmlXPathNameFunction:
8055  * @ctxt:  the XPath Parser context
8056  * @nargs:  the number of arguments
8057  *
8058  * Implement the name() XPath function
8059  *    string name(node-set?)
8060  * The name function returns a string containing a QName representing
8061  * the name of the node in the argument node-set that is first in document
8062  * order. The QName must represent the name with respect to the namespace
8063  * declarations in effect on the node whose name is being represented.
8064  * Typically, this will be the form in which the name occurred in the XML
8065  * source. This need not be the case if there are namespace declarations
8066  * in effect on the node that associate multiple prefixes with the same
8067  * namespace. However, an implementation may include information about
8068  * the original prefix in its representation of nodes; in this case, an
8069  * implementation can ensure that the returned string is always the same
8070  * as the QName used in the XML source. If the argument it omitted it
8071  * defaults to the context node.
8072  * Libxml keep the original prefix so the "real qualified name" used is
8073  * returned.
8074  */
8075 static void
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8076 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8077 {
8078     xmlXPathObjectPtr cur;
8079 
8080     if (nargs == 0) {
8081 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8082 	    ctxt->context->node));
8083         nargs = 1;
8084     }
8085 
8086     CHECK_ARITY(1);
8087     if ((ctxt->value == NULL) ||
8088         ((ctxt->value->type != XPATH_NODESET) &&
8089          (ctxt->value->type != XPATH_XSLT_TREE)))
8090         XP_ERROR(XPATH_INVALID_TYPE);
8091     cur = valuePop(ctxt);
8092 
8093     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8094         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8095     } else {
8096         int i = 0;              /* Should be first in document order !!!!! */
8097 
8098         switch (cur->nodesetval->nodeTab[i]->type) {
8099             case XML_ELEMENT_NODE:
8100             case XML_ATTRIBUTE_NODE:
8101 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8102 		    valuePush(ctxt,
8103 			xmlXPathCacheNewCString(ctxt->context, ""));
8104 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8105                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8106 		    valuePush(ctxt,
8107 		        xmlXPathCacheNewString(ctxt->context,
8108 			    cur->nodesetval->nodeTab[i]->name));
8109 		} else {
8110 		    xmlChar *fullname;
8111 
8112 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8113 				     cur->nodesetval->nodeTab[i]->ns->prefix,
8114 				     NULL, 0);
8115 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
8116 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8117 		    if (fullname == NULL)
8118                         xmlXPathPErrMemory(ctxt, NULL);
8119 		    valuePush(ctxt, xmlXPathCacheWrapString(
8120 			ctxt->context, fullname));
8121                 }
8122                 break;
8123             default:
8124 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8125 		    cur->nodesetval->nodeTab[i]));
8126                 xmlXPathLocalNameFunction(ctxt, 1);
8127         }
8128     }
8129     xmlXPathReleaseObject(ctxt->context, cur);
8130 }
8131 
8132 
8133 /**
8134  * xmlXPathStringFunction:
8135  * @ctxt:  the XPath Parser context
8136  * @nargs:  the number of arguments
8137  *
8138  * Implement the string() XPath function
8139  *    string string(object?)
8140  * The string function converts an object to a string as follows:
8141  *    - A node-set is converted to a string by returning the value of
8142  *      the node in the node-set that is first in document order.
8143  *      If the node-set is empty, an empty string is returned.
8144  *    - A number is converted to a string as follows
8145  *      + NaN is converted to the string NaN
8146  *      + positive zero is converted to the string 0
8147  *      + negative zero is converted to the string 0
8148  *      + positive infinity is converted to the string Infinity
8149  *      + negative infinity is converted to the string -Infinity
8150  *      + if the number is an integer, the number is represented in
8151  *        decimal form as a Number with no decimal point and no leading
8152  *        zeros, preceded by a minus sign (-) if the number is negative
8153  *      + otherwise, the number is represented in decimal form as a
8154  *        Number including a decimal point with at least one digit
8155  *        before the decimal point and at least one digit after the
8156  *        decimal point, preceded by a minus sign (-) if the number
8157  *        is negative; there must be no leading zeros before the decimal
8158  *        point apart possibly from the one required digit immediately
8159  *        before the decimal point; beyond the one required digit
8160  *        after the decimal point there must be as many, but only as
8161  *        many, more digits as are needed to uniquely distinguish the
8162  *        number from all other IEEE 754 numeric values.
8163  *    - The boolean false value is converted to the string false.
8164  *      The boolean true value is converted to the string true.
8165  *
8166  * If the argument is omitted, it defaults to a node-set with the
8167  * context node as its only member.
8168  */
8169 void
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt,int nargs)8170 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8171     xmlXPathObjectPtr cur;
8172 
8173     if (ctxt == NULL) return;
8174     if (nargs == 0) {
8175     valuePush(ctxt,
8176 	xmlXPathCacheWrapString(ctxt->context,
8177 	    xmlXPathCastNodeToString(ctxt->context->node)));
8178 	return;
8179     }
8180 
8181     CHECK_ARITY(1);
8182     cur = valuePop(ctxt);
8183     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8184     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8185 }
8186 
8187 /**
8188  * xmlXPathStringLengthFunction:
8189  * @ctxt:  the XPath Parser context
8190  * @nargs:  the number of arguments
8191  *
8192  * Implement the string-length() XPath function
8193  *    number string-length(string?)
8194  * The string-length returns the number of characters in the string
8195  * (see [3.6 Strings]). If the argument is omitted, it defaults to
8196  * the context node converted to a string, in other words the value
8197  * of the context node.
8198  */
8199 void
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt,int nargs)8200 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8201     xmlXPathObjectPtr cur;
8202 
8203     if (nargs == 0) {
8204         if ((ctxt == NULL) || (ctxt->context == NULL))
8205 	    return;
8206 	if (ctxt->context->node == NULL) {
8207 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8208 	} else {
8209 	    xmlChar *content;
8210 
8211 	    content = xmlXPathCastNodeToString(ctxt->context->node);
8212 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8213 		xmlUTF8Strlen(content)));
8214 	    xmlFree(content);
8215 	}
8216 	return;
8217     }
8218     CHECK_ARITY(1);
8219     CAST_TO_STRING;
8220     CHECK_TYPE(XPATH_STRING);
8221     cur = valuePop(ctxt);
8222     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8223 	xmlUTF8Strlen(cur->stringval)));
8224     xmlXPathReleaseObject(ctxt->context, cur);
8225 }
8226 
8227 /**
8228  * xmlXPathConcatFunction:
8229  * @ctxt:  the XPath Parser context
8230  * @nargs:  the number of arguments
8231  *
8232  * Implement the concat() XPath function
8233  *    string concat(string, string, string*)
8234  * The concat function returns the concatenation of its arguments.
8235  */
8236 void
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt,int nargs)8237 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8238     xmlXPathObjectPtr cur, newobj;
8239     xmlChar *tmp;
8240 
8241     if (ctxt == NULL) return;
8242     if (nargs < 2) {
8243 	CHECK_ARITY(2);
8244     }
8245 
8246     CAST_TO_STRING;
8247     cur = valuePop(ctxt);
8248     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8249 	xmlXPathReleaseObject(ctxt->context, cur);
8250 	return;
8251     }
8252     nargs--;
8253 
8254     while (nargs > 0) {
8255 	CAST_TO_STRING;
8256 	newobj = valuePop(ctxt);
8257 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8258 	    xmlXPathReleaseObject(ctxt->context, newobj);
8259 	    xmlXPathReleaseObject(ctxt->context, cur);
8260 	    XP_ERROR(XPATH_INVALID_TYPE);
8261 	}
8262 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
8263 	newobj->stringval = cur->stringval;
8264 	cur->stringval = tmp;
8265 	xmlXPathReleaseObject(ctxt->context, newobj);
8266 	nargs--;
8267     }
8268     valuePush(ctxt, cur);
8269 }
8270 
8271 /**
8272  * xmlXPathContainsFunction:
8273  * @ctxt:  the XPath Parser context
8274  * @nargs:  the number of arguments
8275  *
8276  * Implement the contains() XPath function
8277  *    boolean contains(string, string)
8278  * The contains function returns true if the first argument string
8279  * contains the second argument string, and otherwise returns false.
8280  */
8281 void
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt,int nargs)8282 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8283     xmlXPathObjectPtr hay, needle;
8284 
8285     CHECK_ARITY(2);
8286     CAST_TO_STRING;
8287     CHECK_TYPE(XPATH_STRING);
8288     needle = valuePop(ctxt);
8289     CAST_TO_STRING;
8290     hay = valuePop(ctxt);
8291 
8292     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8293 	xmlXPathReleaseObject(ctxt->context, hay);
8294 	xmlXPathReleaseObject(ctxt->context, needle);
8295 	XP_ERROR(XPATH_INVALID_TYPE);
8296     }
8297     if (xmlStrstr(hay->stringval, needle->stringval))
8298 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8299     else
8300 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8301     xmlXPathReleaseObject(ctxt->context, hay);
8302     xmlXPathReleaseObject(ctxt->context, needle);
8303 }
8304 
8305 /**
8306  * xmlXPathStartsWithFunction:
8307  * @ctxt:  the XPath Parser context
8308  * @nargs:  the number of arguments
8309  *
8310  * Implement the starts-with() XPath function
8311  *    boolean starts-with(string, string)
8312  * The starts-with function returns true if the first argument string
8313  * starts with the second argument string, and otherwise returns false.
8314  */
8315 void
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt,int nargs)8316 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8317     xmlXPathObjectPtr hay, needle;
8318     int n;
8319 
8320     CHECK_ARITY(2);
8321     CAST_TO_STRING;
8322     CHECK_TYPE(XPATH_STRING);
8323     needle = valuePop(ctxt);
8324     CAST_TO_STRING;
8325     hay = valuePop(ctxt);
8326 
8327     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8328 	xmlXPathReleaseObject(ctxt->context, hay);
8329 	xmlXPathReleaseObject(ctxt->context, needle);
8330 	XP_ERROR(XPATH_INVALID_TYPE);
8331     }
8332     n = xmlStrlen(needle->stringval);
8333     if (xmlStrncmp(hay->stringval, needle->stringval, n))
8334         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8335     else
8336         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8337     xmlXPathReleaseObject(ctxt->context, hay);
8338     xmlXPathReleaseObject(ctxt->context, needle);
8339 }
8340 
8341 /**
8342  * xmlXPathSubstringFunction:
8343  * @ctxt:  the XPath Parser context
8344  * @nargs:  the number of arguments
8345  *
8346  * Implement the substring() XPath function
8347  *    string substring(string, number, number?)
8348  * The substring function returns the substring of the first argument
8349  * starting at the position specified in the second argument with
8350  * length specified in the third argument. For example,
8351  * substring("12345",2,3) returns "234". If the third argument is not
8352  * specified, it returns the substring starting at the position specified
8353  * in the second argument and continuing to the end of the string. For
8354  * example, substring("12345",2) returns "2345".  More precisely, each
8355  * character in the string (see [3.6 Strings]) is considered to have a
8356  * numeric position: the position of the first character is 1, the position
8357  * of the second character is 2 and so on. The returned substring contains
8358  * those characters for which the position of the character is greater than
8359  * or equal to the second argument and, if the third argument is specified,
8360  * less than the sum of the second and third arguments; the comparisons
8361  * and addition used for the above follow the standard IEEE 754 rules. Thus:
8362  *  - substring("12345", 1.5, 2.6) returns "234"
8363  *  - substring("12345", 0, 3) returns "12"
8364  *  - substring("12345", 0 div 0, 3) returns ""
8365  *  - substring("12345", 1, 0 div 0) returns ""
8366  *  - substring("12345", -42, 1 div 0) returns "12345"
8367  *  - substring("12345", -1 div 0, 1 div 0) returns ""
8368  */
8369 void
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt,int nargs)8370 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8371     xmlXPathObjectPtr str, start, len;
8372     double le=0, in;
8373     int i = 1, j = INT_MAX;
8374 
8375     if (nargs < 2) {
8376 	CHECK_ARITY(2);
8377     }
8378     if (nargs > 3) {
8379 	CHECK_ARITY(3);
8380     }
8381     /*
8382      * take care of possible last (position) argument
8383     */
8384     if (nargs == 3) {
8385 	CAST_TO_NUMBER;
8386 	CHECK_TYPE(XPATH_NUMBER);
8387 	len = valuePop(ctxt);
8388 	le = len->floatval;
8389 	xmlXPathReleaseObject(ctxt->context, len);
8390     }
8391 
8392     CAST_TO_NUMBER;
8393     CHECK_TYPE(XPATH_NUMBER);
8394     start = valuePop(ctxt);
8395     in = start->floatval;
8396     xmlXPathReleaseObject(ctxt->context, start);
8397     CAST_TO_STRING;
8398     CHECK_TYPE(XPATH_STRING);
8399     str = valuePop(ctxt);
8400 
8401     if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
8402         i = INT_MAX;
8403     } else if (in >= 1.0) {
8404         i = (int)in;
8405         if (in - floor(in) >= 0.5)
8406             i += 1;
8407     }
8408 
8409     if (nargs == 3) {
8410         double rin, rle, end;
8411 
8412         rin = floor(in);
8413         if (in - rin >= 0.5)
8414             rin += 1.0;
8415 
8416         rle = floor(le);
8417         if (le - rle >= 0.5)
8418             rle += 1.0;
8419 
8420         end = rin + rle;
8421         if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
8422             j = 1;
8423         } else if (end < INT_MAX) {
8424             j = (int)end;
8425         }
8426     }
8427 
8428     if (i < j) {
8429         xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
8430 	valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
8431 	xmlFree(ret);
8432     } else {
8433 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8434     }
8435 
8436     xmlXPathReleaseObject(ctxt->context, str);
8437 }
8438 
8439 /**
8440  * xmlXPathSubstringBeforeFunction:
8441  * @ctxt:  the XPath Parser context
8442  * @nargs:  the number of arguments
8443  *
8444  * Implement the substring-before() XPath function
8445  *    string substring-before(string, string)
8446  * The substring-before function returns the substring of the first
8447  * argument string that precedes the first occurrence of the second
8448  * argument string in the first argument string, or the empty string
8449  * if the first argument string does not contain the second argument
8450  * string. For example, substring-before("1999/04/01","/") returns 1999.
8451  */
8452 void
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt,int nargs)8453 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8454   xmlXPathObjectPtr str;
8455   xmlXPathObjectPtr find;
8456   xmlBufPtr target;
8457   const xmlChar *point;
8458   int offset;
8459 
8460   CHECK_ARITY(2);
8461   CAST_TO_STRING;
8462   find = valuePop(ctxt);
8463   CAST_TO_STRING;
8464   str = valuePop(ctxt);
8465 
8466   target = xmlBufCreate();
8467   if (target) {
8468     point = xmlStrstr(str->stringval, find->stringval);
8469     if (point) {
8470       offset = point - str->stringval;
8471       xmlBufAdd(target, str->stringval, offset);
8472     }
8473     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8474 	xmlBufContent(target)));
8475     xmlBufFree(target);
8476   }
8477   xmlXPathReleaseObject(ctxt->context, str);
8478   xmlXPathReleaseObject(ctxt->context, find);
8479 }
8480 
8481 /**
8482  * xmlXPathSubstringAfterFunction:
8483  * @ctxt:  the XPath Parser context
8484  * @nargs:  the number of arguments
8485  *
8486  * Implement the substring-after() XPath function
8487  *    string substring-after(string, string)
8488  * The substring-after function returns the substring of the first
8489  * argument string that follows the first occurrence of the second
8490  * argument string in the first argument string, or the empty stringi
8491  * if the first argument string does not contain the second argument
8492  * string. For example, substring-after("1999/04/01","/") returns 04/01,
8493  * and substring-after("1999/04/01","19") returns 99/04/01.
8494  */
8495 void
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt,int nargs)8496 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8497   xmlXPathObjectPtr str;
8498   xmlXPathObjectPtr find;
8499   xmlBufPtr target;
8500   const xmlChar *point;
8501   int offset;
8502 
8503   CHECK_ARITY(2);
8504   CAST_TO_STRING;
8505   find = valuePop(ctxt);
8506   CAST_TO_STRING;
8507   str = valuePop(ctxt);
8508 
8509   target = xmlBufCreate();
8510   if (target) {
8511     point = xmlStrstr(str->stringval, find->stringval);
8512     if (point) {
8513       offset = point - str->stringval + xmlStrlen(find->stringval);
8514       xmlBufAdd(target, &str->stringval[offset],
8515 		   xmlStrlen(str->stringval) - offset);
8516     }
8517     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8518 	xmlBufContent(target)));
8519     xmlBufFree(target);
8520   }
8521   xmlXPathReleaseObject(ctxt->context, str);
8522   xmlXPathReleaseObject(ctxt->context, find);
8523 }
8524 
8525 /**
8526  * xmlXPathNormalizeFunction:
8527  * @ctxt:  the XPath Parser context
8528  * @nargs:  the number of arguments
8529  *
8530  * Implement the normalize-space() XPath function
8531  *    string normalize-space(string?)
8532  * The normalize-space function returns the argument string with white
8533  * space normalized by stripping leading and trailing whitespace
8534  * and replacing sequences of whitespace characters by a single
8535  * space. Whitespace characters are the same allowed by the S production
8536  * in XML. If the argument is omitted, it defaults to the context
8537  * node converted to a string, in other words the value of the context node.
8538  */
8539 void
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt,int nargs)8540 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8541     xmlChar *source, *target;
8542     int blank;
8543 
8544     if (ctxt == NULL) return;
8545     if (nargs == 0) {
8546         /* Use current context node */
8547         valuePush(ctxt,
8548             xmlXPathCacheWrapString(ctxt->context,
8549                 xmlXPathCastNodeToString(ctxt->context->node)));
8550         nargs = 1;
8551     }
8552 
8553     CHECK_ARITY(1);
8554     CAST_TO_STRING;
8555     CHECK_TYPE(XPATH_STRING);
8556     source = ctxt->value->stringval;
8557     if (source == NULL)
8558         return;
8559     target = source;
8560 
8561     /* Skip leading whitespaces */
8562     while (IS_BLANK_CH(*source))
8563         source++;
8564 
8565     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
8566     blank = 0;
8567     while (*source) {
8568         if (IS_BLANK_CH(*source)) {
8569 	    blank = 1;
8570         } else {
8571             if (blank) {
8572                 *target++ = 0x20;
8573                 blank = 0;
8574             }
8575             *target++ = *source;
8576         }
8577         source++;
8578     }
8579     *target = 0;
8580 }
8581 
8582 /**
8583  * xmlXPathTranslateFunction:
8584  * @ctxt:  the XPath Parser context
8585  * @nargs:  the number of arguments
8586  *
8587  * Implement the translate() XPath function
8588  *    string translate(string, string, string)
8589  * The translate function returns the first argument string with
8590  * occurrences of characters in the second argument string replaced
8591  * by the character at the corresponding position in the third argument
8592  * string. For example, translate("bar","abc","ABC") returns the string
8593  * BAr. If there is a character in the second argument string with no
8594  * character at a corresponding position in the third argument string
8595  * (because the second argument string is longer than the third argument
8596  * string), then occurrences of that character in the first argument
8597  * string are removed. For example, translate("--aaa--","abc-","ABC")
8598  * returns "AAA". If a character occurs more than once in second
8599  * argument string, then the first occurrence determines the replacement
8600  * character. If the third argument string is longer than the second
8601  * argument string, then excess characters are ignored.
8602  */
8603 void
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt,int nargs)8604 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8605     xmlXPathObjectPtr str;
8606     xmlXPathObjectPtr from;
8607     xmlXPathObjectPtr to;
8608     xmlBufPtr target;
8609     int offset, max;
8610     int ch;
8611     const xmlChar *point;
8612     xmlChar *cptr;
8613 
8614     CHECK_ARITY(3);
8615 
8616     CAST_TO_STRING;
8617     to = valuePop(ctxt);
8618     CAST_TO_STRING;
8619     from = valuePop(ctxt);
8620     CAST_TO_STRING;
8621     str = valuePop(ctxt);
8622 
8623     target = xmlBufCreate();
8624     if (target) {
8625 	max = xmlUTF8Strlen(to->stringval);
8626 	for (cptr = str->stringval; (ch=*cptr); ) {
8627 	    offset = xmlUTF8Strloc(from->stringval, cptr);
8628 	    if (offset >= 0) {
8629 		if (offset < max) {
8630 		    point = xmlUTF8Strpos(to->stringval, offset);
8631 		    if (point)
8632 			xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
8633 		}
8634 	    } else
8635 		xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
8636 
8637 	    /* Step to next character in input */
8638 	    cptr++;
8639 	    if ( ch & 0x80 ) {
8640 		/* if not simple ascii, verify proper format */
8641 		if ( (ch & 0xc0) != 0xc0 ) {
8642 		    xmlGenericError(xmlGenericErrorContext,
8643 			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
8644                     /* not asserting an XPath error is probably better */
8645 		    break;
8646 		}
8647 		/* then skip over remaining bytes for this char */
8648 		while ( (ch <<= 1) & 0x80 )
8649 		    if ( (*cptr++ & 0xc0) != 0x80 ) {
8650 			xmlGenericError(xmlGenericErrorContext,
8651 			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
8652                         /* not asserting an XPath error is probably better */
8653 			break;
8654 		    }
8655 		if (ch & 0x80) /* must have had error encountered */
8656 		    break;
8657 	    }
8658 	}
8659     }
8660     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8661 	xmlBufContent(target)));
8662     xmlBufFree(target);
8663     xmlXPathReleaseObject(ctxt->context, str);
8664     xmlXPathReleaseObject(ctxt->context, from);
8665     xmlXPathReleaseObject(ctxt->context, to);
8666 }
8667 
8668 /**
8669  * xmlXPathBooleanFunction:
8670  * @ctxt:  the XPath Parser context
8671  * @nargs:  the number of arguments
8672  *
8673  * Implement the boolean() XPath function
8674  *    boolean boolean(object)
8675  * The boolean function converts its argument to a boolean as follows:
8676  *    - a number is true if and only if it is neither positive or
8677  *      negative zero nor NaN
8678  *    - a node-set is true if and only if it is non-empty
8679  *    - a string is true if and only if its length is non-zero
8680  */
8681 void
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt,int nargs)8682 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8683     xmlXPathObjectPtr cur;
8684 
8685     CHECK_ARITY(1);
8686     cur = valuePop(ctxt);
8687     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8688     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
8689     valuePush(ctxt, cur);
8690 }
8691 
8692 /**
8693  * xmlXPathNotFunction:
8694  * @ctxt:  the XPath Parser context
8695  * @nargs:  the number of arguments
8696  *
8697  * Implement the not() XPath function
8698  *    boolean not(boolean)
8699  * The not function returns true if its argument is false,
8700  * and false otherwise.
8701  */
8702 void
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt,int nargs)8703 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8704     CHECK_ARITY(1);
8705     CAST_TO_BOOLEAN;
8706     CHECK_TYPE(XPATH_BOOLEAN);
8707     ctxt->value->boolval = ! ctxt->value->boolval;
8708 }
8709 
8710 /**
8711  * xmlXPathTrueFunction:
8712  * @ctxt:  the XPath Parser context
8713  * @nargs:  the number of arguments
8714  *
8715  * Implement the true() XPath function
8716  *    boolean true()
8717  */
8718 void
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt,int nargs)8719 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8720     CHECK_ARITY(0);
8721     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8722 }
8723 
8724 /**
8725  * xmlXPathFalseFunction:
8726  * @ctxt:  the XPath Parser context
8727  * @nargs:  the number of arguments
8728  *
8729  * Implement the false() XPath function
8730  *    boolean false()
8731  */
8732 void
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt,int nargs)8733 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8734     CHECK_ARITY(0);
8735     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8736 }
8737 
8738 /**
8739  * xmlXPathLangFunction:
8740  * @ctxt:  the XPath Parser context
8741  * @nargs:  the number of arguments
8742  *
8743  * Implement the lang() XPath function
8744  *    boolean lang(string)
8745  * The lang function returns true or false depending on whether the
8746  * language of the context node as specified by xml:lang attributes
8747  * is the same as or is a sublanguage of the language specified by
8748  * the argument string. The language of the context node is determined
8749  * by the value of the xml:lang attribute on the context node, or, if
8750  * the context node has no xml:lang attribute, by the value of the
8751  * xml:lang attribute on the nearest ancestor of the context node that
8752  * has an xml:lang attribute. If there is no such attribute, then lang
8753  * returns false. If there is such an attribute, then lang returns
8754  * true if the attribute value is equal to the argument ignoring case,
8755  * or if there is some suffix starting with - such that the attribute
8756  * value is equal to the argument ignoring that suffix of the attribute
8757  * value and ignoring case.
8758  */
8759 void
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt,int nargs)8760 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8761     xmlXPathObjectPtr val = NULL;
8762     const xmlChar *theLang = NULL;
8763     const xmlChar *lang;
8764     int ret = 0;
8765     int i;
8766 
8767     CHECK_ARITY(1);
8768     CAST_TO_STRING;
8769     CHECK_TYPE(XPATH_STRING);
8770     val = valuePop(ctxt);
8771     lang = val->stringval;
8772     theLang = xmlNodeGetLang(ctxt->context->node);
8773     if ((theLang != NULL) && (lang != NULL)) {
8774         for (i = 0;lang[i] != 0;i++)
8775 	    if (toupper(lang[i]) != toupper(theLang[i]))
8776 	        goto not_equal;
8777 	if ((theLang[i] == 0) || (theLang[i] == '-'))
8778 	    ret = 1;
8779     }
8780 not_equal:
8781     if (theLang != NULL)
8782 	xmlFree((void *)theLang);
8783 
8784     xmlXPathReleaseObject(ctxt->context, val);
8785     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
8786 }
8787 
8788 /**
8789  * xmlXPathNumberFunction:
8790  * @ctxt:  the XPath Parser context
8791  * @nargs:  the number of arguments
8792  *
8793  * Implement the number() XPath function
8794  *    number number(object?)
8795  */
8796 void
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt,int nargs)8797 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8798     xmlXPathObjectPtr cur;
8799     double res;
8800 
8801     if (ctxt == NULL) return;
8802     if (nargs == 0) {
8803 	if (ctxt->context->node == NULL) {
8804 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
8805 	} else {
8806 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
8807 
8808 	    res = xmlXPathStringEvalNumber(content);
8809 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
8810 	    xmlFree(content);
8811 	}
8812 	return;
8813     }
8814 
8815     CHECK_ARITY(1);
8816     cur = valuePop(ctxt);
8817     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
8818 }
8819 
8820 /**
8821  * xmlXPathSumFunction:
8822  * @ctxt:  the XPath Parser context
8823  * @nargs:  the number of arguments
8824  *
8825  * Implement the sum() XPath function
8826  *    number sum(node-set)
8827  * The sum function returns the sum of the values of the nodes in
8828  * the argument node-set.
8829  */
8830 void
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt,int nargs)8831 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8832     xmlXPathObjectPtr cur;
8833     int i;
8834     double res = 0.0;
8835 
8836     CHECK_ARITY(1);
8837     if ((ctxt->value == NULL) ||
8838 	((ctxt->value->type != XPATH_NODESET) &&
8839 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8840 	XP_ERROR(XPATH_INVALID_TYPE);
8841     cur = valuePop(ctxt);
8842 
8843     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
8844 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
8845 	    res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
8846 	}
8847     }
8848     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
8849     xmlXPathReleaseObject(ctxt->context, cur);
8850 }
8851 
8852 /**
8853  * xmlXPathFloorFunction:
8854  * @ctxt:  the XPath Parser context
8855  * @nargs:  the number of arguments
8856  *
8857  * Implement the floor() XPath function
8858  *    number floor(number)
8859  * The floor function returns the largest (closest to positive infinity)
8860  * number that is not greater than the argument and that is an integer.
8861  */
8862 void
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt,int nargs)8863 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8864     CHECK_ARITY(1);
8865     CAST_TO_NUMBER;
8866     CHECK_TYPE(XPATH_NUMBER);
8867 
8868     ctxt->value->floatval = floor(ctxt->value->floatval);
8869 }
8870 
8871 /**
8872  * xmlXPathCeilingFunction:
8873  * @ctxt:  the XPath Parser context
8874  * @nargs:  the number of arguments
8875  *
8876  * Implement the ceiling() XPath function
8877  *    number ceiling(number)
8878  * The ceiling function returns the smallest (closest to negative infinity)
8879  * number that is not less than the argument and that is an integer.
8880  */
8881 void
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt,int nargs)8882 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8883     CHECK_ARITY(1);
8884     CAST_TO_NUMBER;
8885     CHECK_TYPE(XPATH_NUMBER);
8886 
8887 #ifdef _AIX
8888     /* Work around buggy ceil() function on AIX */
8889     ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
8890 #else
8891     ctxt->value->floatval = ceil(ctxt->value->floatval);
8892 #endif
8893 }
8894 
8895 /**
8896  * xmlXPathRoundFunction:
8897  * @ctxt:  the XPath Parser context
8898  * @nargs:  the number of arguments
8899  *
8900  * Implement the round() XPath function
8901  *    number round(number)
8902  * The round function returns the number that is closest to the
8903  * argument and that is an integer. If there are two such numbers,
8904  * then the one that is closest to positive infinity is returned.
8905  */
8906 void
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt,int nargs)8907 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8908     double f;
8909 
8910     CHECK_ARITY(1);
8911     CAST_TO_NUMBER;
8912     CHECK_TYPE(XPATH_NUMBER);
8913 
8914     f = ctxt->value->floatval;
8915 
8916     if ((f >= -0.5) && (f < 0.5)) {
8917         /* Handles negative zero. */
8918         ctxt->value->floatval *= 0.0;
8919     }
8920     else {
8921         double rounded = floor(f);
8922         if (f - rounded >= 0.5)
8923             rounded += 1.0;
8924         ctxt->value->floatval = rounded;
8925     }
8926 }
8927 
8928 /************************************************************************
8929  *									*
8930  *			The Parser					*
8931  *									*
8932  ************************************************************************/
8933 
8934 /*
8935  * a few forward declarations since we use a recursive call based
8936  * implementation.
8937  */
8938 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
8939 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
8940 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
8941 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
8942 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
8943 	                                  int qualified);
8944 
8945 /**
8946  * xmlXPathCurrentChar:
8947  * @ctxt:  the XPath parser context
8948  * @cur:  pointer to the beginning of the char
8949  * @len:  pointer to the length of the char read
8950  *
8951  * The current char value, if using UTF-8 this may actually span multiple
8952  * bytes in the input buffer.
8953  *
8954  * Returns the current char value and its length
8955  */
8956 
8957 static int
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt,int * len)8958 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
8959     unsigned char c;
8960     unsigned int val;
8961     const xmlChar *cur;
8962 
8963     if (ctxt == NULL)
8964 	return(0);
8965     cur = ctxt->cur;
8966 
8967     /*
8968      * We are supposed to handle UTF8, check it's valid
8969      * From rfc2044: encoding of the Unicode values on UTF-8:
8970      *
8971      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
8972      * 0000 0000-0000 007F   0xxxxxxx
8973      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
8974      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
8975      *
8976      * Check for the 0x110000 limit too
8977      */
8978     c = *cur;
8979     if (c & 0x80) {
8980 	if ((cur[1] & 0xc0) != 0x80)
8981 	    goto encoding_error;
8982 	if ((c & 0xe0) == 0xe0) {
8983 
8984 	    if ((cur[2] & 0xc0) != 0x80)
8985 		goto encoding_error;
8986 	    if ((c & 0xf0) == 0xf0) {
8987 		if (((c & 0xf8) != 0xf0) ||
8988 		    ((cur[3] & 0xc0) != 0x80))
8989 		    goto encoding_error;
8990 		/* 4-byte code */
8991 		*len = 4;
8992 		val = (cur[0] & 0x7) << 18;
8993 		val |= (cur[1] & 0x3f) << 12;
8994 		val |= (cur[2] & 0x3f) << 6;
8995 		val |= cur[3] & 0x3f;
8996 	    } else {
8997 	      /* 3-byte code */
8998 		*len = 3;
8999 		val = (cur[0] & 0xf) << 12;
9000 		val |= (cur[1] & 0x3f) << 6;
9001 		val |= cur[2] & 0x3f;
9002 	    }
9003 	} else {
9004 	  /* 2-byte code */
9005 	    *len = 2;
9006 	    val = (cur[0] & 0x1f) << 6;
9007 	    val |= cur[1] & 0x3f;
9008 	}
9009 	if (!IS_CHAR(val)) {
9010 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9011 	}
9012 	return(val);
9013     } else {
9014 	/* 1-byte code */
9015 	*len = 1;
9016 	return(*cur);
9017     }
9018 encoding_error:
9019     /*
9020      * If we detect an UTF8 error that probably means that the
9021      * input encoding didn't get properly advertised in the
9022      * declaration header. Report the error and switch the encoding
9023      * to ISO-Latin-1 (if you don't like this policy, just declare the
9024      * encoding !)
9025      */
9026     *len = 0;
9027     XP_ERROR0(XPATH_ENCODING_ERROR);
9028 }
9029 
9030 /**
9031  * xmlXPathParseNCName:
9032  * @ctxt:  the XPath Parser context
9033  *
9034  * parse an XML namespace non qualified name.
9035  *
9036  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9037  *
9038  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9039  *                       CombiningChar | Extender
9040  *
9041  * Returns the namespace name or NULL
9042  */
9043 
9044 xmlChar *
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt)9045 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9046     const xmlChar *in;
9047     xmlChar *ret;
9048     int count = 0;
9049 
9050     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9051     /*
9052      * Accelerator for simple ASCII names
9053      */
9054     in = ctxt->cur;
9055     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9056 	((*in >= 0x41) && (*in <= 0x5A)) ||
9057 	(*in == '_')) {
9058 	in++;
9059 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9060 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9061 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9062 	       (*in == '_') || (*in == '.') ||
9063 	       (*in == '-'))
9064 	    in++;
9065 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9066             (*in == '[') || (*in == ']') || (*in == ':') ||
9067             (*in == '@') || (*in == '*')) {
9068 	    count = in - ctxt->cur;
9069 	    if (count == 0)
9070 		return(NULL);
9071 	    ret = xmlStrndup(ctxt->cur, count);
9072 	    ctxt->cur = in;
9073 	    return(ret);
9074 	}
9075     }
9076     return(xmlXPathParseNameComplex(ctxt, 0));
9077 }
9078 
9079 
9080 /**
9081  * xmlXPathParseQName:
9082  * @ctxt:  the XPath Parser context
9083  * @prefix:  a xmlChar **
9084  *
9085  * parse an XML qualified name
9086  *
9087  * [NS 5] QName ::= (Prefix ':')? LocalPart
9088  *
9089  * [NS 6] Prefix ::= NCName
9090  *
9091  * [NS 7] LocalPart ::= NCName
9092  *
9093  * Returns the function returns the local part, and prefix is updated
9094  *   to get the Prefix if any.
9095  */
9096 
9097 static xmlChar *
xmlXPathParseQName(xmlXPathParserContextPtr ctxt,xmlChar ** prefix)9098 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9099     xmlChar *ret = NULL;
9100 
9101     *prefix = NULL;
9102     ret = xmlXPathParseNCName(ctxt);
9103     if (ret && CUR == ':') {
9104         *prefix = ret;
9105 	NEXT;
9106 	ret = xmlXPathParseNCName(ctxt);
9107     }
9108     return(ret);
9109 }
9110 
9111 /**
9112  * xmlXPathParseName:
9113  * @ctxt:  the XPath Parser context
9114  *
9115  * parse an XML name
9116  *
9117  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9118  *                  CombiningChar | Extender
9119  *
9120  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9121  *
9122  * Returns the namespace name or NULL
9123  */
9124 
9125 xmlChar *
xmlXPathParseName(xmlXPathParserContextPtr ctxt)9126 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9127     const xmlChar *in;
9128     xmlChar *ret;
9129     size_t count = 0;
9130 
9131     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9132     /*
9133      * Accelerator for simple ASCII names
9134      */
9135     in = ctxt->cur;
9136     if (((*in >= 0x61) && (*in <= 0x7A)) ||
9137 	((*in >= 0x41) && (*in <= 0x5A)) ||
9138 	(*in == '_') || (*in == ':')) {
9139 	in++;
9140 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
9141 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
9142 	       ((*in >= 0x30) && (*in <= 0x39)) ||
9143 	       (*in == '_') || (*in == '-') ||
9144 	       (*in == ':') || (*in == '.'))
9145 	    in++;
9146 	if ((*in > 0) && (*in < 0x80)) {
9147 	    count = in - ctxt->cur;
9148             if (count > XML_MAX_NAME_LENGTH) {
9149                 ctxt->cur = in;
9150                 XP_ERRORNULL(XPATH_EXPR_ERROR);
9151             }
9152 	    ret = xmlStrndup(ctxt->cur, count);
9153 	    ctxt->cur = in;
9154 	    return(ret);
9155 	}
9156     }
9157     return(xmlXPathParseNameComplex(ctxt, 1));
9158 }
9159 
9160 static xmlChar *
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,int qualified)9161 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9162     xmlChar buf[XML_MAX_NAMELEN + 5];
9163     int len = 0, l;
9164     int c;
9165 
9166     /*
9167      * Handler for more complex cases
9168      */
9169     c = CUR_CHAR(l);
9170     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9171         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9172         (c == '*') || /* accelerators */
9173 	(!IS_LETTER(c) && (c != '_') &&
9174          ((!qualified) || (c != ':')))) {
9175 	return(NULL);
9176     }
9177 
9178     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9179 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9180             (c == '.') || (c == '-') ||
9181 	    (c == '_') || ((qualified) && (c == ':')) ||
9182 	    (IS_COMBINING(c)) ||
9183 	    (IS_EXTENDER(c)))) {
9184 	COPY_BUF(l,buf,len,c);
9185 	NEXTL(l);
9186 	c = CUR_CHAR(l);
9187 	if (len >= XML_MAX_NAMELEN) {
9188 	    /*
9189 	     * Okay someone managed to make a huge name, so he's ready to pay
9190 	     * for the processing speed.
9191 	     */
9192 	    xmlChar *buffer;
9193 	    int max = len * 2;
9194 
9195             if (len > XML_MAX_NAME_LENGTH) {
9196                 XP_ERRORNULL(XPATH_EXPR_ERROR);
9197             }
9198 	    buffer = (xmlChar *) xmlMallocAtomic(max);
9199 	    if (buffer == NULL) {
9200 		XP_ERRORNULL(XPATH_MEMORY_ERROR);
9201 	    }
9202 	    memcpy(buffer, buf, len);
9203 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9204 		   (c == '.') || (c == '-') ||
9205 		   (c == '_') || ((qualified) && (c == ':')) ||
9206 		   (IS_COMBINING(c)) ||
9207 		   (IS_EXTENDER(c))) {
9208 		if (len + 10 > max) {
9209                     xmlChar *tmp;
9210                     if (max > XML_MAX_NAME_LENGTH) {
9211                         xmlFree(buffer);
9212                         XP_ERRORNULL(XPATH_EXPR_ERROR);
9213                     }
9214 		    max *= 2;
9215 		    tmp = (xmlChar *) xmlRealloc(buffer, max);
9216 		    if (tmp == NULL) {
9217                         xmlFree(buffer);
9218 			XP_ERRORNULL(XPATH_MEMORY_ERROR);
9219 		    }
9220                     buffer = tmp;
9221 		}
9222 		COPY_BUF(l,buffer,len,c);
9223 		NEXTL(l);
9224 		c = CUR_CHAR(l);
9225 	    }
9226 	    buffer[len] = 0;
9227 	    return(buffer);
9228 	}
9229     }
9230     if (len == 0)
9231 	return(NULL);
9232     return(xmlStrndup(buf, len));
9233 }
9234 
9235 #define MAX_FRAC 20
9236 
9237 /**
9238  * xmlXPathStringEvalNumber:
9239  * @str:  A string to scan
9240  *
9241  *  [30a]  Float  ::= Number ('e' Digits?)?
9242  *
9243  *  [30]   Number ::=   Digits ('.' Digits?)?
9244  *                    | '.' Digits
9245  *  [31]   Digits ::=   [0-9]+
9246  *
9247  * Compile a Number in the string
9248  * In complement of the Number expression, this function also handles
9249  * negative values : '-' Number.
9250  *
9251  * Returns the double value.
9252  */
9253 double
xmlXPathStringEvalNumber(const xmlChar * str)9254 xmlXPathStringEvalNumber(const xmlChar *str) {
9255     const xmlChar *cur = str;
9256     double ret;
9257     int ok = 0;
9258     int isneg = 0;
9259     int exponent = 0;
9260     int is_exponent_negative = 0;
9261 #ifdef __GNUC__
9262     unsigned long tmp = 0;
9263     double temp;
9264 #endif
9265     if (cur == NULL) return(0);
9266     while (IS_BLANK_CH(*cur)) cur++;
9267     if (*cur == '-') {
9268 	isneg = 1;
9269 	cur++;
9270     }
9271     if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
9272         return(xmlXPathNAN);
9273     }
9274 
9275 #ifdef __GNUC__
9276     /*
9277      * tmp/temp is a workaround against a gcc compiler bug
9278      * http://veillard.com/gcc.bug
9279      */
9280     ret = 0;
9281     while ((*cur >= '0') && (*cur <= '9')) {
9282 	ret = ret * 10;
9283 	tmp = (*cur - '0');
9284 	ok = 1;
9285 	cur++;
9286 	temp = (double) tmp;
9287 	ret = ret + temp;
9288     }
9289 #else
9290     ret = 0;
9291     while ((*cur >= '0') && (*cur <= '9')) {
9292 	ret = ret * 10 + (*cur - '0');
9293 	ok = 1;
9294 	cur++;
9295     }
9296 #endif
9297 
9298     if (*cur == '.') {
9299 	int v, frac = 0, max;
9300 	double fraction = 0;
9301 
9302         cur++;
9303 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9304 	    return(xmlXPathNAN);
9305 	}
9306         while (*cur == '0') {
9307 	    frac = frac + 1;
9308 	    cur++;
9309         }
9310         max = frac + MAX_FRAC;
9311 	while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
9312 	    v = (*cur - '0');
9313 	    fraction = fraction * 10 + v;
9314 	    frac = frac + 1;
9315 	    cur++;
9316 	}
9317 	fraction /= pow(10.0, frac);
9318 	ret = ret + fraction;
9319 	while ((*cur >= '0') && (*cur <= '9'))
9320 	    cur++;
9321     }
9322     if ((*cur == 'e') || (*cur == 'E')) {
9323       cur++;
9324       if (*cur == '-') {
9325 	is_exponent_negative = 1;
9326 	cur++;
9327       } else if (*cur == '+') {
9328         cur++;
9329       }
9330       while ((*cur >= '0') && (*cur <= '9')) {
9331         if (exponent < 1000000)
9332 	  exponent = exponent * 10 + (*cur - '0');
9333 	cur++;
9334       }
9335     }
9336     while (IS_BLANK_CH(*cur)) cur++;
9337     if (*cur != 0) return(xmlXPathNAN);
9338     if (isneg) ret = -ret;
9339     if (is_exponent_negative) exponent = -exponent;
9340     ret *= pow(10.0, (double)exponent);
9341     return(ret);
9342 }
9343 
9344 /**
9345  * xmlXPathCompNumber:
9346  * @ctxt:  the XPath Parser context
9347  *
9348  *  [30]   Number ::=   Digits ('.' Digits?)?
9349  *                    | '.' Digits
9350  *  [31]   Digits ::=   [0-9]+
9351  *
9352  * Compile a Number, then push it on the stack
9353  *
9354  */
9355 static void
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)9356 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
9357 {
9358     double ret = 0.0;
9359     int ok = 0;
9360     int exponent = 0;
9361     int is_exponent_negative = 0;
9362     xmlXPathObjectPtr num;
9363 #ifdef __GNUC__
9364     unsigned long tmp = 0;
9365     double temp;
9366 #endif
9367 
9368     CHECK_ERROR;
9369     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
9370         XP_ERROR(XPATH_NUMBER_ERROR);
9371     }
9372 #ifdef __GNUC__
9373     /*
9374      * tmp/temp is a workaround against a gcc compiler bug
9375      * http://veillard.com/gcc.bug
9376      */
9377     ret = 0;
9378     while ((CUR >= '0') && (CUR <= '9')) {
9379 	ret = ret * 10;
9380 	tmp = (CUR - '0');
9381         ok = 1;
9382         NEXT;
9383 	temp = (double) tmp;
9384 	ret = ret + temp;
9385     }
9386 #else
9387     ret = 0;
9388     while ((CUR >= '0') && (CUR <= '9')) {
9389 	ret = ret * 10 + (CUR - '0');
9390 	ok = 1;
9391 	NEXT;
9392     }
9393 #endif
9394     if (CUR == '.') {
9395 	int v, frac = 0, max;
9396 	double fraction = 0;
9397 
9398         NEXT;
9399         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
9400             XP_ERROR(XPATH_NUMBER_ERROR);
9401         }
9402         while (CUR == '0') {
9403             frac = frac + 1;
9404             NEXT;
9405         }
9406         max = frac + MAX_FRAC;
9407         while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
9408 	    v = (CUR - '0');
9409 	    fraction = fraction * 10 + v;
9410 	    frac = frac + 1;
9411             NEXT;
9412         }
9413         fraction /= pow(10.0, frac);
9414         ret = ret + fraction;
9415         while ((CUR >= '0') && (CUR <= '9'))
9416             NEXT;
9417     }
9418     if ((CUR == 'e') || (CUR == 'E')) {
9419         NEXT;
9420         if (CUR == '-') {
9421             is_exponent_negative = 1;
9422             NEXT;
9423         } else if (CUR == '+') {
9424 	    NEXT;
9425 	}
9426         while ((CUR >= '0') && (CUR <= '9')) {
9427             if (exponent < 1000000)
9428                 exponent = exponent * 10 + (CUR - '0');
9429             NEXT;
9430         }
9431         if (is_exponent_negative)
9432             exponent = -exponent;
9433         ret *= pow(10.0, (double) exponent);
9434     }
9435     num = xmlXPathCacheNewFloat(ctxt->context, ret);
9436     if (num == NULL) {
9437 	ctxt->error = XPATH_MEMORY_ERROR;
9438     } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
9439                               NULL) == -1) {
9440         xmlXPathReleaseObject(ctxt->context, num);
9441     }
9442 }
9443 
9444 /**
9445  * xmlXPathParseLiteral:
9446  * @ctxt:  the XPath Parser context
9447  *
9448  * Parse a Literal
9449  *
9450  *  [29]   Literal ::=   '"' [^"]* '"'
9451  *                    | "'" [^']* "'"
9452  *
9453  * Returns the value found or NULL in case of error
9454  */
9455 static xmlChar *
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt)9456 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
9457     const xmlChar *q;
9458     xmlChar *ret = NULL;
9459 
9460     if (CUR == '"') {
9461         NEXT;
9462 	q = CUR_PTR;
9463 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
9464 	    NEXT;
9465 	if (!IS_CHAR_CH(CUR)) {
9466 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
9467 	} else {
9468 	    ret = xmlStrndup(q, CUR_PTR - q);
9469 	    NEXT;
9470         }
9471     } else if (CUR == '\'') {
9472         NEXT;
9473 	q = CUR_PTR;
9474 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
9475 	    NEXT;
9476 	if (!IS_CHAR_CH(CUR)) {
9477 	    XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
9478 	} else {
9479 	    ret = xmlStrndup(q, CUR_PTR - q);
9480 	    NEXT;
9481         }
9482     } else {
9483 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
9484     }
9485     return(ret);
9486 }
9487 
9488 /**
9489  * xmlXPathCompLiteral:
9490  * @ctxt:  the XPath Parser context
9491  *
9492  * Parse a Literal and push it on the stack.
9493  *
9494  *  [29]   Literal ::=   '"' [^"]* '"'
9495  *                    | "'" [^']* "'"
9496  *
9497  * TODO: xmlXPathCompLiteral memory allocation could be improved.
9498  */
9499 static void
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt)9500 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
9501     const xmlChar *q;
9502     xmlChar *ret = NULL;
9503     xmlXPathObjectPtr lit;
9504 
9505     if (CUR == '"') {
9506         NEXT;
9507 	q = CUR_PTR;
9508 	while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
9509 	    NEXT;
9510 	if (!IS_CHAR_CH(CUR)) {
9511 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
9512 	} else {
9513 	    ret = xmlStrndup(q, CUR_PTR - q);
9514 	    NEXT;
9515         }
9516     } else if (CUR == '\'') {
9517         NEXT;
9518 	q = CUR_PTR;
9519 	while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
9520 	    NEXT;
9521 	if (!IS_CHAR_CH(CUR)) {
9522 	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
9523 	} else {
9524 	    ret = xmlStrndup(q, CUR_PTR - q);
9525 	    NEXT;
9526         }
9527     } else {
9528 	XP_ERROR(XPATH_START_LITERAL_ERROR);
9529     }
9530     if (ret == NULL) {
9531         xmlXPathPErrMemory(ctxt, NULL);
9532         return;
9533     }
9534     lit = xmlXPathCacheNewString(ctxt->context, ret);
9535     if (lit == NULL) {
9536 	ctxt->error = XPATH_MEMORY_ERROR;
9537     } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
9538                               NULL) == -1) {
9539         xmlXPathReleaseObject(ctxt->context, lit);
9540     }
9541     xmlFree(ret);
9542 }
9543 
9544 /**
9545  * xmlXPathCompVariableReference:
9546  * @ctxt:  the XPath Parser context
9547  *
9548  * Parse a VariableReference, evaluate it and push it on the stack.
9549  *
9550  * The variable bindings consist of a mapping from variable names
9551  * to variable values. The value of a variable is an object, which can be
9552  * of any of the types that are possible for the value of an expression,
9553  * and may also be of additional types not specified here.
9554  *
9555  * Early evaluation is possible since:
9556  * The variable bindings [...] used to evaluate a subexpression are
9557  * always the same as those used to evaluate the containing expression.
9558  *
9559  *  [36]   VariableReference ::=   '$' QName
9560  */
9561 static void
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt)9562 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
9563     xmlChar *name;
9564     xmlChar *prefix;
9565 
9566     SKIP_BLANKS;
9567     if (CUR != '$') {
9568 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9569     }
9570     NEXT;
9571     name = xmlXPathParseQName(ctxt, &prefix);
9572     if (name == NULL) {
9573         xmlFree(prefix);
9574 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9575     }
9576     ctxt->comp->last = -1;
9577     if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
9578         xmlFree(prefix);
9579         xmlFree(name);
9580     }
9581     SKIP_BLANKS;
9582     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
9583 	XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
9584     }
9585 }
9586 
9587 /**
9588  * xmlXPathIsNodeType:
9589  * @name:  a name string
9590  *
9591  * Is the name given a NodeType one.
9592  *
9593  *  [38]   NodeType ::=   'comment'
9594  *                    | 'text'
9595  *                    | 'processing-instruction'
9596  *                    | 'node'
9597  *
9598  * Returns 1 if true 0 otherwise
9599  */
9600 int
xmlXPathIsNodeType(const xmlChar * name)9601 xmlXPathIsNodeType(const xmlChar *name) {
9602     if (name == NULL)
9603 	return(0);
9604 
9605     if (xmlStrEqual(name, BAD_CAST "node"))
9606 	return(1);
9607     if (xmlStrEqual(name, BAD_CAST "text"))
9608 	return(1);
9609     if (xmlStrEqual(name, BAD_CAST "comment"))
9610 	return(1);
9611     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9612 	return(1);
9613     return(0);
9614 }
9615 
9616 /**
9617  * xmlXPathCompFunctionCall:
9618  * @ctxt:  the XPath Parser context
9619  *
9620  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
9621  *  [17]   Argument ::=   Expr
9622  *
9623  * Compile a function call, the evaluation of all arguments are
9624  * pushed on the stack
9625  */
9626 static void
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt)9627 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
9628     xmlChar *name;
9629     xmlChar *prefix;
9630     int nbargs = 0;
9631     int sort = 1;
9632 
9633     name = xmlXPathParseQName(ctxt, &prefix);
9634     if (name == NULL) {
9635 	xmlFree(prefix);
9636 	XP_ERROR(XPATH_EXPR_ERROR);
9637     }
9638     SKIP_BLANKS;
9639 
9640     if (CUR != '(') {
9641 	xmlFree(name);
9642 	xmlFree(prefix);
9643 	XP_ERROR(XPATH_EXPR_ERROR);
9644     }
9645     NEXT;
9646     SKIP_BLANKS;
9647 
9648     /*
9649     * Optimization for count(): we don't need the node-set to be sorted.
9650     */
9651     if ((prefix == NULL) && (name[0] == 'c') &&
9652 	xmlStrEqual(name, BAD_CAST "count"))
9653     {
9654 	sort = 0;
9655     }
9656     ctxt->comp->last = -1;
9657     if (CUR != ')') {
9658 	while (CUR != 0) {
9659 	    int op1 = ctxt->comp->last;
9660 	    ctxt->comp->last = -1;
9661 	    xmlXPathCompileExpr(ctxt, sort);
9662 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
9663 		xmlFree(name);
9664 		xmlFree(prefix);
9665 		return;
9666 	    }
9667 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
9668 	    nbargs++;
9669 	    if (CUR == ')') break;
9670 	    if (CUR != ',') {
9671 		xmlFree(name);
9672 		xmlFree(prefix);
9673 		XP_ERROR(XPATH_EXPR_ERROR);
9674 	    }
9675 	    NEXT;
9676 	    SKIP_BLANKS;
9677 	}
9678     }
9679     if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
9680         xmlFree(prefix);
9681         xmlFree(name);
9682     }
9683     NEXT;
9684     SKIP_BLANKS;
9685 }
9686 
9687 /**
9688  * xmlXPathCompPrimaryExpr:
9689  * @ctxt:  the XPath Parser context
9690  *
9691  *  [15]   PrimaryExpr ::=   VariableReference
9692  *                | '(' Expr ')'
9693  *                | Literal
9694  *                | Number
9695  *                | FunctionCall
9696  *
9697  * Compile a primary expression.
9698  */
9699 static void
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt)9700 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
9701     SKIP_BLANKS;
9702     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
9703     else if (CUR == '(') {
9704 	NEXT;
9705 	SKIP_BLANKS;
9706 	xmlXPathCompileExpr(ctxt, 1);
9707 	CHECK_ERROR;
9708 	if (CUR != ')') {
9709 	    XP_ERROR(XPATH_EXPR_ERROR);
9710 	}
9711 	NEXT;
9712 	SKIP_BLANKS;
9713     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9714 	xmlXPathCompNumber(ctxt);
9715     } else if ((CUR == '\'') || (CUR == '"')) {
9716 	xmlXPathCompLiteral(ctxt);
9717     } else {
9718 	xmlXPathCompFunctionCall(ctxt);
9719     }
9720     SKIP_BLANKS;
9721 }
9722 
9723 /**
9724  * xmlXPathCompFilterExpr:
9725  * @ctxt:  the XPath Parser context
9726  *
9727  *  [20]   FilterExpr ::=   PrimaryExpr
9728  *               | FilterExpr Predicate
9729  *
9730  * Compile a filter expression.
9731  * Square brackets are used to filter expressions in the same way that
9732  * they are used in location paths. It is an error if the expression to
9733  * be filtered does not evaluate to a node-set. The context node list
9734  * used for evaluating the expression in square brackets is the node-set
9735  * to be filtered listed in document order.
9736  */
9737 
9738 static void
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt)9739 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
9740     xmlXPathCompPrimaryExpr(ctxt);
9741     CHECK_ERROR;
9742     SKIP_BLANKS;
9743 
9744     while (CUR == '[') {
9745 	xmlXPathCompPredicate(ctxt, 1);
9746 	SKIP_BLANKS;
9747     }
9748 
9749 
9750 }
9751 
9752 /**
9753  * xmlXPathScanName:
9754  * @ctxt:  the XPath Parser context
9755  *
9756  * Trickery: parse an XML name but without consuming the input flow
9757  * Needed to avoid insanity in the parser state.
9758  *
9759  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9760  *                  CombiningChar | Extender
9761  *
9762  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9763  *
9764  * [6] Names ::= Name (S Name)*
9765  *
9766  * Returns the Name parsed or NULL
9767  */
9768 
9769 static xmlChar *
xmlXPathScanName(xmlXPathParserContextPtr ctxt)9770 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
9771     int l;
9772     int c;
9773     const xmlChar *cur;
9774     xmlChar *ret;
9775 
9776     cur = ctxt->cur;
9777 
9778     c = CUR_CHAR(l);
9779     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9780 	(!IS_LETTER(c) && (c != '_') &&
9781          (c != ':'))) {
9782 	return(NULL);
9783     }
9784 
9785     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9786 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9787             (c == '.') || (c == '-') ||
9788 	    (c == '_') || (c == ':') ||
9789 	    (IS_COMBINING(c)) ||
9790 	    (IS_EXTENDER(c)))) {
9791 	NEXTL(l);
9792 	c = CUR_CHAR(l);
9793     }
9794     ret = xmlStrndup(cur, ctxt->cur - cur);
9795     ctxt->cur = cur;
9796     return(ret);
9797 }
9798 
9799 /**
9800  * xmlXPathCompPathExpr:
9801  * @ctxt:  the XPath Parser context
9802  *
9803  *  [19]   PathExpr ::=   LocationPath
9804  *               | FilterExpr
9805  *               | FilterExpr '/' RelativeLocationPath
9806  *               | FilterExpr '//' RelativeLocationPath
9807  *
9808  * Compile a path expression.
9809  * The / operator and // operators combine an arbitrary expression
9810  * and a relative location path. It is an error if the expression
9811  * does not evaluate to a node-set.
9812  * The / operator does composition in the same way as when / is
9813  * used in a location path. As in location paths, // is short for
9814  * /descendant-or-self::node()/.
9815  */
9816 
9817 static void
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt)9818 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
9819     int lc = 1;           /* Should we branch to LocationPath ?         */
9820     xmlChar *name = NULL; /* we may have to preparse a name to find out */
9821 
9822     SKIP_BLANKS;
9823     if ((CUR == '$') || (CUR == '(') ||
9824 	(IS_ASCII_DIGIT(CUR)) ||
9825         (CUR == '\'') || (CUR == '"') ||
9826 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9827 	lc = 0;
9828     } else if (CUR == '*') {
9829 	/* relative or absolute location path */
9830 	lc = 1;
9831     } else if (CUR == '/') {
9832 	/* relative or absolute location path */
9833 	lc = 1;
9834     } else if (CUR == '@') {
9835 	/* relative abbreviated attribute location path */
9836 	lc = 1;
9837     } else if (CUR == '.') {
9838 	/* relative abbreviated attribute location path */
9839 	lc = 1;
9840     } else {
9841 	/*
9842 	 * Problem is finding if we have a name here whether it's:
9843 	 *   - a nodetype
9844 	 *   - a function call in which case it's followed by '('
9845 	 *   - an axis in which case it's followed by ':'
9846 	 *   - a element name
9847 	 * We do an a priori analysis here rather than having to
9848 	 * maintain parsed token content through the recursive function
9849 	 * calls. This looks uglier but makes the code easier to
9850 	 * read/write/debug.
9851 	 */
9852 	SKIP_BLANKS;
9853 	name = xmlXPathScanName(ctxt);
9854 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
9855 	    lc = 1;
9856 	    xmlFree(name);
9857 	} else if (name != NULL) {
9858 	    int len =xmlStrlen(name);
9859 
9860 
9861 	    while (NXT(len) != 0) {
9862 		if (NXT(len) == '/') {
9863 		    /* element name */
9864 		    lc = 1;
9865 		    break;
9866 		} else if (IS_BLANK_CH(NXT(len))) {
9867 		    /* ignore blanks */
9868 		    ;
9869 		} else if (NXT(len) == ':') {
9870 		    lc = 1;
9871 		    break;
9872 		} else if ((NXT(len) == '(')) {
9873 		    /* Node Type or Function */
9874 		    if (xmlXPathIsNodeType(name)) {
9875 			lc = 1;
9876 #ifdef LIBXML_XPTR_LOCS_ENABLED
9877                     } else if (ctxt->xptr &&
9878                                xmlStrEqual(name, BAD_CAST "range-to")) {
9879                         lc = 1;
9880 #endif
9881 		    } else {
9882 			lc = 0;
9883 		    }
9884                     break;
9885 		} else if ((NXT(len) == '[')) {
9886 		    /* element name */
9887 		    lc = 1;
9888 		    break;
9889 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
9890 			   (NXT(len) == '=')) {
9891 		    lc = 1;
9892 		    break;
9893 		} else {
9894 		    lc = 1;
9895 		    break;
9896 		}
9897 		len++;
9898 	    }
9899 	    if (NXT(len) == 0) {
9900 		/* element name */
9901 		lc = 1;
9902 	    }
9903 	    xmlFree(name);
9904 	} else {
9905 	    /* make sure all cases are covered explicitly */
9906 	    XP_ERROR(XPATH_EXPR_ERROR);
9907 	}
9908     }
9909 
9910     if (lc) {
9911 	if (CUR == '/') {
9912 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
9913 	} else {
9914 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9915 	}
9916 	xmlXPathCompLocationPath(ctxt);
9917     } else {
9918 	xmlXPathCompFilterExpr(ctxt);
9919 	CHECK_ERROR;
9920 	if ((CUR == '/') && (NXT(1) == '/')) {
9921 	    SKIP(2);
9922 	    SKIP_BLANKS;
9923 
9924 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9925 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9926 
9927 	    xmlXPathCompRelativeLocationPath(ctxt);
9928 	} else if (CUR == '/') {
9929 	    xmlXPathCompRelativeLocationPath(ctxt);
9930 	}
9931     }
9932     SKIP_BLANKS;
9933 }
9934 
9935 /**
9936  * xmlXPathCompUnionExpr:
9937  * @ctxt:  the XPath Parser context
9938  *
9939  *  [18]   UnionExpr ::=   PathExpr
9940  *               | UnionExpr '|' PathExpr
9941  *
9942  * Compile an union expression.
9943  */
9944 
9945 static void
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt)9946 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
9947     xmlXPathCompPathExpr(ctxt);
9948     CHECK_ERROR;
9949     SKIP_BLANKS;
9950     while (CUR == '|') {
9951 	int op1 = ctxt->comp->last;
9952 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9953 
9954 	NEXT;
9955 	SKIP_BLANKS;
9956 	xmlXPathCompPathExpr(ctxt);
9957 
9958 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
9959 
9960 	SKIP_BLANKS;
9961     }
9962 }
9963 
9964 /**
9965  * xmlXPathCompUnaryExpr:
9966  * @ctxt:  the XPath Parser context
9967  *
9968  *  [27]   UnaryExpr ::=   UnionExpr
9969  *                   | '-' UnaryExpr
9970  *
9971  * Compile an unary expression.
9972  */
9973 
9974 static void
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt)9975 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
9976     int minus = 0;
9977     int found = 0;
9978 
9979     SKIP_BLANKS;
9980     while (CUR == '-') {
9981         minus = 1 - minus;
9982 	found = 1;
9983 	NEXT;
9984 	SKIP_BLANKS;
9985     }
9986 
9987     xmlXPathCompUnionExpr(ctxt);
9988     CHECK_ERROR;
9989     if (found) {
9990 	if (minus)
9991 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
9992 	else
9993 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
9994     }
9995 }
9996 
9997 /**
9998  * xmlXPathCompMultiplicativeExpr:
9999  * @ctxt:  the XPath Parser context
10000  *
10001  *  [26]   MultiplicativeExpr ::=   UnaryExpr
10002  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10003  *                   | MultiplicativeExpr 'div' UnaryExpr
10004  *                   | MultiplicativeExpr 'mod' UnaryExpr
10005  *  [34]   MultiplyOperator ::=   '*'
10006  *
10007  * Compile an Additive expression.
10008  */
10009 
10010 static void
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt)10011 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10012     xmlXPathCompUnaryExpr(ctxt);
10013     CHECK_ERROR;
10014     SKIP_BLANKS;
10015     while ((CUR == '*') ||
10016            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10017            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10018 	int op = -1;
10019 	int op1 = ctxt->comp->last;
10020 
10021         if (CUR == '*') {
10022 	    op = 0;
10023 	    NEXT;
10024 	} else if (CUR == 'd') {
10025 	    op = 1;
10026 	    SKIP(3);
10027 	} else if (CUR == 'm') {
10028 	    op = 2;
10029 	    SKIP(3);
10030 	}
10031 	SKIP_BLANKS;
10032         xmlXPathCompUnaryExpr(ctxt);
10033 	CHECK_ERROR;
10034 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10035 	SKIP_BLANKS;
10036     }
10037 }
10038 
10039 /**
10040  * xmlXPathCompAdditiveExpr:
10041  * @ctxt:  the XPath Parser context
10042  *
10043  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10044  *                   | AdditiveExpr '+' MultiplicativeExpr
10045  *                   | AdditiveExpr '-' MultiplicativeExpr
10046  *
10047  * Compile an Additive expression.
10048  */
10049 
10050 static void
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt)10051 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10052 
10053     xmlXPathCompMultiplicativeExpr(ctxt);
10054     CHECK_ERROR;
10055     SKIP_BLANKS;
10056     while ((CUR == '+') || (CUR == '-')) {
10057 	int plus;
10058 	int op1 = ctxt->comp->last;
10059 
10060         if (CUR == '+') plus = 1;
10061 	else plus = 0;
10062 	NEXT;
10063 	SKIP_BLANKS;
10064         xmlXPathCompMultiplicativeExpr(ctxt);
10065 	CHECK_ERROR;
10066 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10067 	SKIP_BLANKS;
10068     }
10069 }
10070 
10071 /**
10072  * xmlXPathCompRelationalExpr:
10073  * @ctxt:  the XPath Parser context
10074  *
10075  *  [24]   RelationalExpr ::=   AdditiveExpr
10076  *                 | RelationalExpr '<' AdditiveExpr
10077  *                 | RelationalExpr '>' AdditiveExpr
10078  *                 | RelationalExpr '<=' AdditiveExpr
10079  *                 | RelationalExpr '>=' AdditiveExpr
10080  *
10081  *  A <= B > C is allowed ? Answer from James, yes with
10082  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10083  *  which is basically what got implemented.
10084  *
10085  * Compile a Relational expression, then push the result
10086  * on the stack
10087  */
10088 
10089 static void
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt)10090 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10091     xmlXPathCompAdditiveExpr(ctxt);
10092     CHECK_ERROR;
10093     SKIP_BLANKS;
10094     while ((CUR == '<') || (CUR == '>')) {
10095 	int inf, strict;
10096 	int op1 = ctxt->comp->last;
10097 
10098         if (CUR == '<') inf = 1;
10099 	else inf = 0;
10100 	if (NXT(1) == '=') strict = 0;
10101 	else strict = 1;
10102 	NEXT;
10103 	if (!strict) NEXT;
10104 	SKIP_BLANKS;
10105         xmlXPathCompAdditiveExpr(ctxt);
10106 	CHECK_ERROR;
10107 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10108 	SKIP_BLANKS;
10109     }
10110 }
10111 
10112 /**
10113  * xmlXPathCompEqualityExpr:
10114  * @ctxt:  the XPath Parser context
10115  *
10116  *  [23]   EqualityExpr ::=   RelationalExpr
10117  *                 | EqualityExpr '=' RelationalExpr
10118  *                 | EqualityExpr '!=' RelationalExpr
10119  *
10120  *  A != B != C is allowed ? Answer from James, yes with
10121  *  (RelationalExpr = RelationalExpr) = RelationalExpr
10122  *  (RelationalExpr != RelationalExpr) != RelationalExpr
10123  *  which is basically what got implemented.
10124  *
10125  * Compile an Equality expression.
10126  *
10127  */
10128 static void
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt)10129 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10130     xmlXPathCompRelationalExpr(ctxt);
10131     CHECK_ERROR;
10132     SKIP_BLANKS;
10133     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10134 	int eq;
10135 	int op1 = ctxt->comp->last;
10136 
10137         if (CUR == '=') eq = 1;
10138 	else eq = 0;
10139 	NEXT;
10140 	if (!eq) NEXT;
10141 	SKIP_BLANKS;
10142         xmlXPathCompRelationalExpr(ctxt);
10143 	CHECK_ERROR;
10144 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10145 	SKIP_BLANKS;
10146     }
10147 }
10148 
10149 /**
10150  * xmlXPathCompAndExpr:
10151  * @ctxt:  the XPath Parser context
10152  *
10153  *  [22]   AndExpr ::=   EqualityExpr
10154  *                 | AndExpr 'and' EqualityExpr
10155  *
10156  * Compile an AND expression.
10157  *
10158  */
10159 static void
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt)10160 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10161     xmlXPathCompEqualityExpr(ctxt);
10162     CHECK_ERROR;
10163     SKIP_BLANKS;
10164     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10165 	int op1 = ctxt->comp->last;
10166         SKIP(3);
10167 	SKIP_BLANKS;
10168         xmlXPathCompEqualityExpr(ctxt);
10169 	CHECK_ERROR;
10170 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10171 	SKIP_BLANKS;
10172     }
10173 }
10174 
10175 /**
10176  * xmlXPathCompileExpr:
10177  * @ctxt:  the XPath Parser context
10178  *
10179  *  [14]   Expr ::=   OrExpr
10180  *  [21]   OrExpr ::=   AndExpr
10181  *                 | OrExpr 'or' AndExpr
10182  *
10183  * Parse and compile an expression
10184  */
10185 static void
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt,int sort)10186 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10187     xmlXPathContextPtr xpctxt = ctxt->context;
10188 
10189     if (xpctxt != NULL) {
10190         if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10191             XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10192         /*
10193          * Parsing a single '(' pushes about 10 functions on the call stack
10194          * before recursing!
10195          */
10196         xpctxt->depth += 10;
10197     }
10198 
10199     xmlXPathCompAndExpr(ctxt);
10200     CHECK_ERROR;
10201     SKIP_BLANKS;
10202     while ((CUR == 'o') && (NXT(1) == 'r')) {
10203 	int op1 = ctxt->comp->last;
10204         SKIP(2);
10205 	SKIP_BLANKS;
10206         xmlXPathCompAndExpr(ctxt);
10207 	CHECK_ERROR;
10208 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10209 	SKIP_BLANKS;
10210     }
10211     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10212 	/* more ops could be optimized too */
10213 	/*
10214 	* This is the main place to eliminate sorting for
10215 	* operations which don't require a sorted node-set.
10216 	* E.g. count().
10217 	*/
10218 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10219     }
10220 
10221     if (xpctxt != NULL)
10222         xpctxt->depth -= 10;
10223 }
10224 
10225 /**
10226  * xmlXPathCompPredicate:
10227  * @ctxt:  the XPath Parser context
10228  * @filter:  act as a filter
10229  *
10230  *  [8]   Predicate ::=   '[' PredicateExpr ']'
10231  *  [9]   PredicateExpr ::=   Expr
10232  *
10233  * Compile a predicate expression
10234  */
10235 static void
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt,int filter)10236 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10237     int op1 = ctxt->comp->last;
10238 
10239     SKIP_BLANKS;
10240     if (CUR != '[') {
10241 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10242     }
10243     NEXT;
10244     SKIP_BLANKS;
10245 
10246     ctxt->comp->last = -1;
10247     /*
10248     * This call to xmlXPathCompileExpr() will deactivate sorting
10249     * of the predicate result.
10250     * TODO: Sorting is still activated for filters, since I'm not
10251     *  sure if needed. Normally sorting should not be needed, since
10252     *  a filter can only diminish the number of items in a sequence,
10253     *  but won't change its order; so if the initial sequence is sorted,
10254     *  subsequent sorting is not needed.
10255     */
10256     if (! filter)
10257 	xmlXPathCompileExpr(ctxt, 0);
10258     else
10259 	xmlXPathCompileExpr(ctxt, 1);
10260     CHECK_ERROR;
10261 
10262     if (CUR != ']') {
10263 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10264     }
10265 
10266     if (filter)
10267 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10268     else
10269 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10270 
10271     NEXT;
10272     SKIP_BLANKS;
10273 }
10274 
10275 /**
10276  * xmlXPathCompNodeTest:
10277  * @ctxt:  the XPath Parser context
10278  * @test:  pointer to a xmlXPathTestVal
10279  * @type:  pointer to a xmlXPathTypeVal
10280  * @prefix:  placeholder for a possible name prefix
10281  *
10282  * [7] NodeTest ::=   NameTest
10283  *		    | NodeType '(' ')'
10284  *		    | 'processing-instruction' '(' Literal ')'
10285  *
10286  * [37] NameTest ::=  '*'
10287  *		    | NCName ':' '*'
10288  *		    | QName
10289  * [38] NodeType ::= 'comment'
10290  *		   | 'text'
10291  *		   | 'processing-instruction'
10292  *		   | 'node'
10293  *
10294  * Returns the name found and updates @test, @type and @prefix appropriately
10295  */
10296 static xmlChar *
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt,xmlXPathTestVal * test,xmlXPathTypeVal * type,xmlChar ** prefix,xmlChar * name)10297 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10298 	             xmlXPathTypeVal *type, xmlChar **prefix,
10299 		     xmlChar *name) {
10300     int blanks;
10301 
10302     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10303 	STRANGE;
10304 	return(NULL);
10305     }
10306     *type = (xmlXPathTypeVal) 0;
10307     *test = (xmlXPathTestVal) 0;
10308     *prefix = NULL;
10309     SKIP_BLANKS;
10310 
10311     if ((name == NULL) && (CUR == '*')) {
10312 	/*
10313 	 * All elements
10314 	 */
10315 	NEXT;
10316 	*test = NODE_TEST_ALL;
10317 	return(NULL);
10318     }
10319 
10320     if (name == NULL)
10321 	name = xmlXPathParseNCName(ctxt);
10322     if (name == NULL) {
10323 	XP_ERRORNULL(XPATH_EXPR_ERROR);
10324     }
10325 
10326     blanks = IS_BLANK_CH(CUR);
10327     SKIP_BLANKS;
10328     if (CUR == '(') {
10329 	NEXT;
10330 	/*
10331 	 * NodeType or PI search
10332 	 */
10333 	if (xmlStrEqual(name, BAD_CAST "comment"))
10334 	    *type = NODE_TYPE_COMMENT;
10335 	else if (xmlStrEqual(name, BAD_CAST "node"))
10336 	    *type = NODE_TYPE_NODE;
10337 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10338 	    *type = NODE_TYPE_PI;
10339 	else if (xmlStrEqual(name, BAD_CAST "text"))
10340 	    *type = NODE_TYPE_TEXT;
10341 	else {
10342 	    if (name != NULL)
10343 		xmlFree(name);
10344 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
10345 	}
10346 
10347 	*test = NODE_TEST_TYPE;
10348 
10349 	SKIP_BLANKS;
10350 	if (*type == NODE_TYPE_PI) {
10351 	    /*
10352 	     * Specific case: search a PI by name.
10353 	     */
10354 	    if (name != NULL)
10355 		xmlFree(name);
10356 	    name = NULL;
10357 	    if (CUR != ')') {
10358 		name = xmlXPathParseLiteral(ctxt);
10359                 if (name == NULL) {
10360 	            XP_ERRORNULL(XPATH_EXPR_ERROR);
10361                 }
10362 		*test = NODE_TEST_PI;
10363 		SKIP_BLANKS;
10364 	    }
10365 	}
10366 	if (CUR != ')') {
10367 	    if (name != NULL)
10368 		xmlFree(name);
10369 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
10370 	}
10371 	NEXT;
10372 	return(name);
10373     }
10374     *test = NODE_TEST_NAME;
10375     if ((!blanks) && (CUR == ':')) {
10376 	NEXT;
10377 
10378 	/*
10379 	 * Since currently the parser context don't have a
10380 	 * namespace list associated:
10381 	 * The namespace name for this prefix can be computed
10382 	 * only at evaluation time. The compilation is done
10383 	 * outside of any context.
10384 	 */
10385 #if 0
10386 	*prefix = xmlXPathNsLookup(ctxt->context, name);
10387 	if (name != NULL)
10388 	    xmlFree(name);
10389 	if (*prefix == NULL) {
10390 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10391 	}
10392 #else
10393 	*prefix = name;
10394 #endif
10395 
10396 	if (CUR == '*') {
10397 	    /*
10398 	     * All elements
10399 	     */
10400 	    NEXT;
10401 	    *test = NODE_TEST_ALL;
10402 	    return(NULL);
10403 	}
10404 
10405 	name = xmlXPathParseNCName(ctxt);
10406 	if (name == NULL) {
10407 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
10408 	}
10409     }
10410     return(name);
10411 }
10412 
10413 /**
10414  * xmlXPathIsAxisName:
10415  * @name:  a preparsed name token
10416  *
10417  * [6] AxisName ::=   'ancestor'
10418  *                  | 'ancestor-or-self'
10419  *                  | 'attribute'
10420  *                  | 'child'
10421  *                  | 'descendant'
10422  *                  | 'descendant-or-self'
10423  *                  | 'following'
10424  *                  | 'following-sibling'
10425  *                  | 'namespace'
10426  *                  | 'parent'
10427  *                  | 'preceding'
10428  *                  | 'preceding-sibling'
10429  *                  | 'self'
10430  *
10431  * Returns the axis or 0
10432  */
10433 static xmlXPathAxisVal
xmlXPathIsAxisName(const xmlChar * name)10434 xmlXPathIsAxisName(const xmlChar *name) {
10435     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
10436     switch (name[0]) {
10437 	case 'a':
10438 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
10439 		ret = AXIS_ANCESTOR;
10440 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
10441 		ret = AXIS_ANCESTOR_OR_SELF;
10442 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
10443 		ret = AXIS_ATTRIBUTE;
10444 	    break;
10445 	case 'c':
10446 	    if (xmlStrEqual(name, BAD_CAST "child"))
10447 		ret = AXIS_CHILD;
10448 	    break;
10449 	case 'd':
10450 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
10451 		ret = AXIS_DESCENDANT;
10452 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
10453 		ret = AXIS_DESCENDANT_OR_SELF;
10454 	    break;
10455 	case 'f':
10456 	    if (xmlStrEqual(name, BAD_CAST "following"))
10457 		ret = AXIS_FOLLOWING;
10458 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
10459 		ret = AXIS_FOLLOWING_SIBLING;
10460 	    break;
10461 	case 'n':
10462 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
10463 		ret = AXIS_NAMESPACE;
10464 	    break;
10465 	case 'p':
10466 	    if (xmlStrEqual(name, BAD_CAST "parent"))
10467 		ret = AXIS_PARENT;
10468 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
10469 		ret = AXIS_PRECEDING;
10470 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
10471 		ret = AXIS_PRECEDING_SIBLING;
10472 	    break;
10473 	case 's':
10474 	    if (xmlStrEqual(name, BAD_CAST "self"))
10475 		ret = AXIS_SELF;
10476 	    break;
10477     }
10478     return(ret);
10479 }
10480 
10481 /**
10482  * xmlXPathCompStep:
10483  * @ctxt:  the XPath Parser context
10484  *
10485  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
10486  *                  | AbbreviatedStep
10487  *
10488  * [12] AbbreviatedStep ::=   '.' | '..'
10489  *
10490  * [5] AxisSpecifier ::= AxisName '::'
10491  *                  | AbbreviatedAxisSpecifier
10492  *
10493  * [13] AbbreviatedAxisSpecifier ::= '@'?
10494  *
10495  * Modified for XPtr range support as:
10496  *
10497  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
10498  *                     | AbbreviatedStep
10499  *                     | 'range-to' '(' Expr ')' Predicate*
10500  *
10501  * Compile one step in a Location Path
10502  * A location step of . is short for self::node(). This is
10503  * particularly useful in conjunction with //. For example, the
10504  * location path .//para is short for
10505  * self::node()/descendant-or-self::node()/child::para
10506  * and so will select all para descendant elements of the context
10507  * node.
10508  * Similarly, a location step of .. is short for parent::node().
10509  * For example, ../title is short for parent::node()/child::title
10510  * and so will select the title children of the parent of the context
10511  * node.
10512  */
10513 static void
xmlXPathCompStep(xmlXPathParserContextPtr ctxt)10514 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
10515 #ifdef LIBXML_XPTR_LOCS_ENABLED
10516     int rangeto = 0;
10517     int op2 = -1;
10518 #endif
10519 
10520     SKIP_BLANKS;
10521     if ((CUR == '.') && (NXT(1) == '.')) {
10522 	SKIP(2);
10523 	SKIP_BLANKS;
10524 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
10525 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10526     } else if (CUR == '.') {
10527 	NEXT;
10528 	SKIP_BLANKS;
10529     } else {
10530 	xmlChar *name = NULL;
10531 	xmlChar *prefix = NULL;
10532 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
10533 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
10534 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
10535 	int op1;
10536 
10537 	/*
10538 	 * The modification needed for XPointer change to the production
10539 	 */
10540 #ifdef LIBXML_XPTR_LOCS_ENABLED
10541 	if (ctxt->xptr) {
10542 	    name = xmlXPathParseNCName(ctxt);
10543 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
10544                 op2 = ctxt->comp->last;
10545 		xmlFree(name);
10546 		SKIP_BLANKS;
10547 		if (CUR != '(') {
10548 		    XP_ERROR(XPATH_EXPR_ERROR);
10549 		}
10550 		NEXT;
10551 		SKIP_BLANKS;
10552 
10553 		xmlXPathCompileExpr(ctxt, 1);
10554 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
10555 		CHECK_ERROR;
10556 
10557 		SKIP_BLANKS;
10558 		if (CUR != ')') {
10559 		    XP_ERROR(XPATH_EXPR_ERROR);
10560 		}
10561 		NEXT;
10562 		rangeto = 1;
10563 		goto eval_predicates;
10564 	    }
10565 	}
10566 #endif
10567 	if (CUR == '*') {
10568 	    axis = AXIS_CHILD;
10569 	} else {
10570 	    if (name == NULL)
10571 		name = xmlXPathParseNCName(ctxt);
10572 	    if (name != NULL) {
10573 		axis = xmlXPathIsAxisName(name);
10574 		if (axis != 0) {
10575 		    SKIP_BLANKS;
10576 		    if ((CUR == ':') && (NXT(1) == ':')) {
10577 			SKIP(2);
10578 			xmlFree(name);
10579 			name = NULL;
10580 		    } else {
10581 			/* an element name can conflict with an axis one :-\ */
10582 			axis = AXIS_CHILD;
10583 		    }
10584 		} else {
10585 		    axis = AXIS_CHILD;
10586 		}
10587 	    } else if (CUR == '@') {
10588 		NEXT;
10589 		axis = AXIS_ATTRIBUTE;
10590 	    } else {
10591 		axis = AXIS_CHILD;
10592 	    }
10593 	}
10594 
10595         if (ctxt->error != XPATH_EXPRESSION_OK) {
10596             xmlFree(name);
10597             return;
10598         }
10599 
10600 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
10601 	if (test == 0)
10602 	    return;
10603 
10604         if ((prefix != NULL) && (ctxt->context != NULL) &&
10605 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
10606 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
10607 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
10608 	    }
10609 	}
10610 
10611 #ifdef LIBXML_XPTR_LOCS_ENABLED
10612 eval_predicates:
10613 #endif
10614 	op1 = ctxt->comp->last;
10615 	ctxt->comp->last = -1;
10616 
10617 	SKIP_BLANKS;
10618 	while (CUR == '[') {
10619 	    xmlXPathCompPredicate(ctxt, 0);
10620 	}
10621 
10622 #ifdef LIBXML_XPTR_LOCS_ENABLED
10623 	if (rangeto) {
10624 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
10625 	} else
10626 #endif
10627         if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
10628                            test, type, (void *)prefix, (void *)name) == -1) {
10629             xmlFree(prefix);
10630             xmlFree(name);
10631         }
10632     }
10633 }
10634 
10635 /**
10636  * xmlXPathCompRelativeLocationPath:
10637  * @ctxt:  the XPath Parser context
10638  *
10639  *  [3]   RelativeLocationPath ::=   Step
10640  *                     | RelativeLocationPath '/' Step
10641  *                     | AbbreviatedRelativeLocationPath
10642  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
10643  *
10644  * Compile a relative location path.
10645  */
10646 static void
xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt)10647 xmlXPathCompRelativeLocationPath
10648 (xmlXPathParserContextPtr ctxt) {
10649     SKIP_BLANKS;
10650     if ((CUR == '/') && (NXT(1) == '/')) {
10651 	SKIP(2);
10652 	SKIP_BLANKS;
10653 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10654 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10655     } else if (CUR == '/') {
10656 	    NEXT;
10657 	SKIP_BLANKS;
10658     }
10659     xmlXPathCompStep(ctxt);
10660     CHECK_ERROR;
10661     SKIP_BLANKS;
10662     while (CUR == '/') {
10663 	if ((CUR == '/') && (NXT(1) == '/')) {
10664 	    SKIP(2);
10665 	    SKIP_BLANKS;
10666 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10667 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10668 	    xmlXPathCompStep(ctxt);
10669 	} else if (CUR == '/') {
10670 	    NEXT;
10671 	    SKIP_BLANKS;
10672 	    xmlXPathCompStep(ctxt);
10673 	}
10674 	SKIP_BLANKS;
10675     }
10676 }
10677 
10678 /**
10679  * xmlXPathCompLocationPath:
10680  * @ctxt:  the XPath Parser context
10681  *
10682  *  [1]   LocationPath ::=   RelativeLocationPath
10683  *                     | AbsoluteLocationPath
10684  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
10685  *                     | AbbreviatedAbsoluteLocationPath
10686  *  [10]   AbbreviatedAbsoluteLocationPath ::=
10687  *                           '//' RelativeLocationPath
10688  *
10689  * Compile a location path
10690  *
10691  * // is short for /descendant-or-self::node()/. For example,
10692  * //para is short for /descendant-or-self::node()/child::para and
10693  * so will select any para element in the document (even a para element
10694  * that is a document element will be selected by //para since the
10695  * document element node is a child of the root node); div//para is
10696  * short for div/descendant-or-self::node()/child::para and so will
10697  * select all para descendants of div children.
10698  */
10699 static void
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt)10700 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
10701     SKIP_BLANKS;
10702     if (CUR != '/') {
10703         xmlXPathCompRelativeLocationPath(ctxt);
10704     } else {
10705 	while (CUR == '/') {
10706 	    if ((CUR == '/') && (NXT(1) == '/')) {
10707 		SKIP(2);
10708 		SKIP_BLANKS;
10709 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10710 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10711 		xmlXPathCompRelativeLocationPath(ctxt);
10712 	    } else if (CUR == '/') {
10713 		NEXT;
10714 		SKIP_BLANKS;
10715 		if ((CUR != 0 ) &&
10716 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
10717 		     (CUR == '@') || (CUR == '*')))
10718 		    xmlXPathCompRelativeLocationPath(ctxt);
10719 	    }
10720 	    CHECK_ERROR;
10721 	}
10722     }
10723 }
10724 
10725 /************************************************************************
10726  *									*
10727  *		XPath precompiled expression evaluation			*
10728  *									*
10729  ************************************************************************/
10730 
10731 static int
10732 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
10733 
10734 /**
10735  * xmlXPathNodeSetFilter:
10736  * @ctxt:  the XPath Parser context
10737  * @set: the node set to filter
10738  * @filterOpIndex: the index of the predicate/filter op
10739  * @minPos: minimum position in the filtered set (1-based)
10740  * @maxPos: maximum position in the filtered set (1-based)
10741  * @hasNsNodes: true if the node set may contain namespace nodes
10742  *
10743  * Filter a node set, keeping only nodes for which the predicate expression
10744  * matches. Afterwards, keep only nodes between minPos and maxPos in the
10745  * filtered result.
10746  */
10747 static void
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,xmlNodeSetPtr set,int filterOpIndex,int minPos,int maxPos,int hasNsNodes)10748 xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
10749 		      xmlNodeSetPtr set,
10750 		      int filterOpIndex,
10751                       int minPos, int maxPos,
10752 		      int hasNsNodes)
10753 {
10754     xmlXPathContextPtr xpctxt;
10755     xmlNodePtr oldnode;
10756     xmlDocPtr olddoc;
10757     xmlXPathStepOpPtr filterOp;
10758     int oldcs, oldpp;
10759     int i, j, pos;
10760 
10761     if ((set == NULL) || (set->nodeNr == 0))
10762         return;
10763 
10764     /*
10765     * Check if the node set contains a sufficient number of nodes for
10766     * the requested range.
10767     */
10768     if (set->nodeNr < minPos) {
10769         xmlXPathNodeSetClear(set, hasNsNodes);
10770         return;
10771     }
10772 
10773     xpctxt = ctxt->context;
10774     oldnode = xpctxt->node;
10775     olddoc = xpctxt->doc;
10776     oldcs = xpctxt->contextSize;
10777     oldpp = xpctxt->proximityPosition;
10778     filterOp = &ctxt->comp->steps[filterOpIndex];
10779 
10780     xpctxt->contextSize = set->nodeNr;
10781 
10782     for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
10783         xmlNodePtr node = set->nodeTab[i];
10784         int res;
10785 
10786         xpctxt->node = node;
10787         xpctxt->proximityPosition = i + 1;
10788 
10789         /*
10790         * Also set the xpath document in case things like
10791         * key() are evaluated in the predicate.
10792         *
10793         * TODO: Get real doc for namespace nodes.
10794         */
10795         if ((node->type != XML_NAMESPACE_DECL) &&
10796             (node->doc != NULL))
10797             xpctxt->doc = node->doc;
10798 
10799         res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
10800 
10801         if (ctxt->error != XPATH_EXPRESSION_OK)
10802             break;
10803         if (res < 0) {
10804             /* Shouldn't happen */
10805             xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
10806             break;
10807         }
10808 
10809         if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
10810             if (i != j) {
10811                 set->nodeTab[j] = node;
10812                 set->nodeTab[i] = NULL;
10813             }
10814 
10815             j += 1;
10816         } else {
10817             /* Remove the entry from the initial node set. */
10818             set->nodeTab[i] = NULL;
10819             if (node->type == XML_NAMESPACE_DECL)
10820                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10821         }
10822 
10823         if (res != 0) {
10824             if (pos == maxPos) {
10825                 i += 1;
10826                 break;
10827             }
10828 
10829             pos += 1;
10830         }
10831     }
10832 
10833     /* Free remaining nodes. */
10834     if (hasNsNodes) {
10835         for (; i < set->nodeNr; i++) {
10836             xmlNodePtr node = set->nodeTab[i];
10837             if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
10838                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10839         }
10840     }
10841 
10842     set->nodeNr = j;
10843 
10844     /* If too many elements were removed, shrink table to preserve memory. */
10845     if ((set->nodeMax > XML_NODESET_DEFAULT) &&
10846         (set->nodeNr < set->nodeMax / 2)) {
10847         xmlNodePtr *tmp;
10848         int nodeMax = set->nodeNr;
10849 
10850         if (nodeMax < XML_NODESET_DEFAULT)
10851             nodeMax = XML_NODESET_DEFAULT;
10852         tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
10853                 nodeMax * sizeof(xmlNodePtr));
10854         if (tmp == NULL) {
10855             xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
10856         } else {
10857             set->nodeTab = tmp;
10858             set->nodeMax = nodeMax;
10859         }
10860     }
10861 
10862     xpctxt->node = oldnode;
10863     xpctxt->doc = olddoc;
10864     xpctxt->contextSize = oldcs;
10865     xpctxt->proximityPosition = oldpp;
10866 }
10867 
10868 #ifdef LIBXML_XPTR_LOCS_ENABLED
10869 /**
10870  * xmlXPathLocationSetFilter:
10871  * @ctxt:  the XPath Parser context
10872  * @locset: the location set to filter
10873  * @filterOpIndex: the index of the predicate/filter op
10874  * @minPos: minimum position in the filtered set (1-based)
10875  * @maxPos: maximum position in the filtered set (1-based)
10876  *
10877  * Filter a location set, keeping only nodes for which the predicate
10878  * expression matches. Afterwards, keep only nodes between minPos and maxPos
10879  * in the filtered result.
10880  */
10881 static void
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,xmlLocationSetPtr locset,int filterOpIndex,int minPos,int maxPos)10882 xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
10883 		          xmlLocationSetPtr locset,
10884 		          int filterOpIndex,
10885                           int minPos, int maxPos)
10886 {
10887     xmlXPathContextPtr xpctxt;
10888     xmlNodePtr oldnode;
10889     xmlDocPtr olddoc;
10890     xmlXPathStepOpPtr filterOp;
10891     int oldcs, oldpp;
10892     int i, j, pos;
10893 
10894     if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
10895         return;
10896 
10897     xpctxt = ctxt->context;
10898     oldnode = xpctxt->node;
10899     olddoc = xpctxt->doc;
10900     oldcs = xpctxt->contextSize;
10901     oldpp = xpctxt->proximityPosition;
10902     filterOp = &ctxt->comp->steps[filterOpIndex];
10903 
10904     xpctxt->contextSize = locset->locNr;
10905 
10906     for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
10907         xmlNodePtr contextNode = locset->locTab[i]->user;
10908         int res;
10909 
10910         xpctxt->node = contextNode;
10911         xpctxt->proximityPosition = i + 1;
10912 
10913         /*
10914         * Also set the xpath document in case things like
10915         * key() are evaluated in the predicate.
10916         *
10917         * TODO: Get real doc for namespace nodes.
10918         */
10919         if ((contextNode->type != XML_NAMESPACE_DECL) &&
10920             (contextNode->doc != NULL))
10921             xpctxt->doc = contextNode->doc;
10922 
10923         res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
10924 
10925         if (ctxt->error != XPATH_EXPRESSION_OK)
10926             break;
10927         if (res < 0) {
10928             /* Shouldn't happen */
10929             xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
10930             break;
10931         }
10932 
10933         if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
10934             if (i != j) {
10935                 locset->locTab[j] = locset->locTab[i];
10936                 locset->locTab[i] = NULL;
10937             }
10938 
10939             j += 1;
10940         } else {
10941             /* Remove the entry from the initial location set. */
10942             xmlXPathFreeObject(locset->locTab[i]);
10943             locset->locTab[i] = NULL;
10944         }
10945 
10946         if (res != 0) {
10947             if (pos == maxPos) {
10948                 i += 1;
10949                 break;
10950             }
10951 
10952             pos += 1;
10953         }
10954     }
10955 
10956     /* Free remaining nodes. */
10957     for (; i < locset->locNr; i++)
10958         xmlXPathFreeObject(locset->locTab[i]);
10959 
10960     locset->locNr = j;
10961 
10962     /* If too many elements were removed, shrink table to preserve memory. */
10963     if ((locset->locMax > XML_NODESET_DEFAULT) &&
10964         (locset->locNr < locset->locMax / 2)) {
10965         xmlXPathObjectPtr *tmp;
10966         int locMax = locset->locNr;
10967 
10968         if (locMax < XML_NODESET_DEFAULT)
10969             locMax = XML_NODESET_DEFAULT;
10970         tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
10971                 locMax * sizeof(xmlXPathObjectPtr));
10972         if (tmp == NULL) {
10973             xmlXPathPErrMemory(ctxt, "shrinking locset\n");
10974         } else {
10975             locset->locTab = tmp;
10976             locset->locMax = locMax;
10977         }
10978     }
10979 
10980     xpctxt->node = oldnode;
10981     xpctxt->doc = olddoc;
10982     xpctxt->contextSize = oldcs;
10983     xpctxt->proximityPosition = oldpp;
10984 }
10985 #endif /* LIBXML_XPTR_LOCS_ENABLED */
10986 
10987 /**
10988  * xmlXPathCompOpEvalPredicate:
10989  * @ctxt:  the XPath Parser context
10990  * @op: the predicate op
10991  * @set: the node set to filter
10992  * @minPos: minimum position in the filtered set (1-based)
10993  * @maxPos: maximum position in the filtered set (1-based)
10994  * @hasNsNodes: true if the node set may contain namespace nodes
10995  *
10996  * Filter a node set, keeping only nodes for which the sequence of predicate
10997  * expressions matches. Afterwards, keep only nodes between minPos and maxPos
10998  * in the filtered result.
10999  */
11000 static void
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int minPos,int maxPos,int hasNsNodes)11001 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11002 			    xmlXPathStepOpPtr op,
11003 			    xmlNodeSetPtr set,
11004                             int minPos, int maxPos,
11005 			    int hasNsNodes)
11006 {
11007     if (op->ch1 != -1) {
11008 	xmlXPathCompExprPtr comp = ctxt->comp;
11009 	/*
11010 	* Process inner predicates first.
11011 	*/
11012 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11013             xmlGenericError(xmlGenericErrorContext,
11014                 "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11015             XP_ERROR(XPATH_INVALID_OPERAND);
11016 	}
11017         if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11018             XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11019         ctxt->context->depth += 1;
11020 	xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11021                                     1, set->nodeNr, hasNsNodes);
11022         ctxt->context->depth -= 1;
11023 	CHECK_ERROR;
11024     }
11025 
11026     if (op->ch2 != -1)
11027         xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11028 }
11029 
11030 static int
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int * maxPos)11031 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11032 			    xmlXPathStepOpPtr op,
11033 			    int *maxPos)
11034 {
11035 
11036     xmlXPathStepOpPtr exprOp;
11037 
11038     /*
11039     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11040     */
11041 
11042     /*
11043     * If not -1, then ch1 will point to:
11044     * 1) For predicates (XPATH_OP_PREDICATE):
11045     *    - an inner predicate operator
11046     * 2) For filters (XPATH_OP_FILTER):
11047     *    - an inner filter operator OR
11048     *    - an expression selecting the node set.
11049     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11050     */
11051     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11052 	return(0);
11053 
11054     if (op->ch2 != -1) {
11055 	exprOp = &ctxt->comp->steps[op->ch2];
11056     } else
11057 	return(0);
11058 
11059     if ((exprOp != NULL) &&
11060 	(exprOp->op == XPATH_OP_VALUE) &&
11061 	(exprOp->value4 != NULL) &&
11062 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11063     {
11064         double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11065 
11066 	/*
11067 	* We have a "[n]" predicate here.
11068 	* TODO: Unfortunately this simplistic test here is not
11069 	* able to detect a position() predicate in compound
11070 	* expressions like "[@attr = 'a" and position() = 1],
11071 	* and even not the usage of position() in
11072 	* "[position() = 1]"; thus - obviously - a position-range,
11073 	* like it "[position() < 5]", is also not detected.
11074 	* Maybe we could rewrite the AST to ease the optimization.
11075 	*/
11076 
11077         if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11078 	    *maxPos = (int) floatval;
11079             if (floatval == (double) *maxPos)
11080                 return(1);
11081         }
11082     }
11083     return(0);
11084 }
11085 
11086 static int
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first,xmlNodePtr * last,int toBool)11087 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11088                            xmlXPathStepOpPtr op,
11089 			   xmlNodePtr * first, xmlNodePtr * last,
11090 			   int toBool)
11091 {
11092 
11093 #define XP_TEST_HIT \
11094     if (hasAxisRange != 0) { \
11095 	if (++pos == maxPos) { \
11096 	    if (addNode(seq, cur) < 0) \
11097 	        ctxt->error = XPATH_MEMORY_ERROR; \
11098 	    goto axis_range_end; } \
11099     } else { \
11100 	if (addNode(seq, cur) < 0) \
11101 	    ctxt->error = XPATH_MEMORY_ERROR; \
11102 	if (breakOnFirstHit) goto first_hit; }
11103 
11104 #define XP_TEST_HIT_NS \
11105     if (hasAxisRange != 0) { \
11106 	if (++pos == maxPos) { \
11107 	    hasNsNodes = 1; \
11108 	    if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11109 	        ctxt->error = XPATH_MEMORY_ERROR; \
11110 	goto axis_range_end; } \
11111     } else { \
11112 	hasNsNodes = 1; \
11113 	if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11114 	    ctxt->error = XPATH_MEMORY_ERROR; \
11115 	if (breakOnFirstHit) goto first_hit; }
11116 
11117     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11118     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11119     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11120     const xmlChar *prefix = op->value4;
11121     const xmlChar *name = op->value5;
11122     const xmlChar *URI = NULL;
11123 
11124     int total = 0, hasNsNodes = 0;
11125     /* The popped object holding the context nodes */
11126     xmlXPathObjectPtr obj;
11127     /* The set of context nodes for the node tests */
11128     xmlNodeSetPtr contextSeq;
11129     int contextIdx;
11130     xmlNodePtr contextNode;
11131     /* The final resulting node set wrt to all context nodes */
11132     xmlNodeSetPtr outSeq;
11133     /*
11134     * The temporary resulting node set wrt 1 context node.
11135     * Used to feed predicate evaluation.
11136     */
11137     xmlNodeSetPtr seq;
11138     xmlNodePtr cur;
11139     /* First predicate operator */
11140     xmlXPathStepOpPtr predOp;
11141     int maxPos; /* The requested position() (when a "[n]" predicate) */
11142     int hasPredicateRange, hasAxisRange, pos;
11143     int breakOnFirstHit;
11144 
11145     xmlXPathTraversalFunction next = NULL;
11146     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11147     xmlXPathNodeSetMergeFunction mergeAndClear;
11148     xmlNodePtr oldContextNode;
11149     xmlXPathContextPtr xpctxt = ctxt->context;
11150 
11151 
11152     CHECK_TYPE0(XPATH_NODESET);
11153     obj = valuePop(ctxt);
11154     /*
11155     * Setup namespaces.
11156     */
11157     if (prefix != NULL) {
11158         URI = xmlXPathNsLookup(xpctxt, prefix);
11159         if (URI == NULL) {
11160 	    xmlXPathReleaseObject(xpctxt, obj);
11161             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11162 	}
11163     }
11164     /*
11165     * Setup axis.
11166     *
11167     * MAYBE FUTURE TODO: merging optimizations:
11168     * - If the nodes to be traversed wrt to the initial nodes and
11169     *   the current axis cannot overlap, then we could avoid searching
11170     *   for duplicates during the merge.
11171     *   But the question is how/when to evaluate if they cannot overlap.
11172     *   Example: if we know that for two initial nodes, the one is
11173     *   not in the ancestor-or-self axis of the other, then we could safely
11174     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
11175     *   the descendant-or-self axis.
11176     */
11177     mergeAndClear = xmlXPathNodeSetMergeAndClear;
11178     switch (axis) {
11179         case AXIS_ANCESTOR:
11180             first = NULL;
11181             next = xmlXPathNextAncestor;
11182             break;
11183         case AXIS_ANCESTOR_OR_SELF:
11184             first = NULL;
11185             next = xmlXPathNextAncestorOrSelf;
11186             break;
11187         case AXIS_ATTRIBUTE:
11188             first = NULL;
11189 	    last = NULL;
11190             next = xmlXPathNextAttribute;
11191 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11192             break;
11193         case AXIS_CHILD:
11194 	    last = NULL;
11195 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
11196 		(type == NODE_TYPE_NODE))
11197 	    {
11198 		/*
11199 		* Optimization if an element node type is 'element'.
11200 		*/
11201 		next = xmlXPathNextChildElement;
11202 	    } else
11203 		next = xmlXPathNextChild;
11204 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11205             break;
11206         case AXIS_DESCENDANT:
11207 	    last = NULL;
11208             next = xmlXPathNextDescendant;
11209             break;
11210         case AXIS_DESCENDANT_OR_SELF:
11211 	    last = NULL;
11212             next = xmlXPathNextDescendantOrSelf;
11213             break;
11214         case AXIS_FOLLOWING:
11215 	    last = NULL;
11216             next = xmlXPathNextFollowing;
11217             break;
11218         case AXIS_FOLLOWING_SIBLING:
11219 	    last = NULL;
11220             next = xmlXPathNextFollowingSibling;
11221             break;
11222         case AXIS_NAMESPACE:
11223             first = NULL;
11224 	    last = NULL;
11225             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
11226 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11227             break;
11228         case AXIS_PARENT:
11229             first = NULL;
11230             next = xmlXPathNextParent;
11231             break;
11232         case AXIS_PRECEDING:
11233             first = NULL;
11234             next = xmlXPathNextPrecedingInternal;
11235             break;
11236         case AXIS_PRECEDING_SIBLING:
11237             first = NULL;
11238             next = xmlXPathNextPrecedingSibling;
11239             break;
11240         case AXIS_SELF:
11241             first = NULL;
11242 	    last = NULL;
11243             next = xmlXPathNextSelf;
11244 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11245             break;
11246     }
11247 
11248     if (next == NULL) {
11249 	xmlXPathReleaseObject(xpctxt, obj);
11250         return(0);
11251     }
11252     contextSeq = obj->nodesetval;
11253     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
11254 	xmlXPathReleaseObject(xpctxt, obj);
11255         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
11256         return(0);
11257     }
11258     /*
11259     * Predicate optimization ---------------------------------------------
11260     * If this step has a last predicate, which contains a position(),
11261     * then we'll optimize (although not exactly "position()", but only
11262     * the  short-hand form, i.e., "[n]".
11263     *
11264     * Example - expression "/foo[parent::bar][1]":
11265     *
11266     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
11267     *   ROOT                               -- op->ch1
11268     *   PREDICATE                          -- op->ch2 (predOp)
11269     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
11270     *       SORT
11271     *         COLLECT  'parent' 'name' 'node' bar
11272     *           NODE
11273     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
11274     *
11275     */
11276     maxPos = 0;
11277     predOp = NULL;
11278     hasPredicateRange = 0;
11279     hasAxisRange = 0;
11280     if (op->ch2 != -1) {
11281 	/*
11282 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
11283 	*/
11284 	predOp = &ctxt->comp->steps[op->ch2];
11285 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
11286 	    if (predOp->ch1 != -1) {
11287 		/*
11288 		* Use the next inner predicate operator.
11289 		*/
11290 		predOp = &ctxt->comp->steps[predOp->ch1];
11291 		hasPredicateRange = 1;
11292 	    } else {
11293 		/*
11294 		* There's no other predicate than the [n] predicate.
11295 		*/
11296 		predOp = NULL;
11297 		hasAxisRange = 1;
11298 	    }
11299 	}
11300     }
11301     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
11302     /*
11303     * Axis traversal -----------------------------------------------------
11304     */
11305     /*
11306      * 2.3 Node Tests
11307      *  - For the attribute axis, the principal node type is attribute.
11308      *  - For the namespace axis, the principal node type is namespace.
11309      *  - For other axes, the principal node type is element.
11310      *
11311      * A node test * is true for any node of the
11312      * principal node type. For example, child::* will
11313      * select all element children of the context node
11314      */
11315     oldContextNode = xpctxt->node;
11316     addNode = xmlXPathNodeSetAddUnique;
11317     outSeq = NULL;
11318     seq = NULL;
11319     contextNode = NULL;
11320     contextIdx = 0;
11321 
11322 
11323     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
11324            (ctxt->error == XPATH_EXPRESSION_OK)) {
11325 	xpctxt->node = contextSeq->nodeTab[contextIdx++];
11326 
11327 	if (seq == NULL) {
11328 	    seq = xmlXPathNodeSetCreate(NULL);
11329 	    if (seq == NULL) {
11330                 /* TODO: Propagate memory error. */
11331 		total = 0;
11332 		goto error;
11333 	    }
11334 	}
11335 	/*
11336 	* Traverse the axis and test the nodes.
11337 	*/
11338 	pos = 0;
11339 	cur = NULL;
11340 	hasNsNodes = 0;
11341         do {
11342             if (OP_LIMIT_EXCEEDED(ctxt, 1))
11343                 goto error;
11344 
11345             cur = next(ctxt, cur);
11346             if (cur == NULL)
11347                 break;
11348 
11349 	    /*
11350 	    * QUESTION TODO: What does the "first" and "last" stuff do?
11351 	    */
11352             if ((first != NULL) && (*first != NULL)) {
11353 		if (*first == cur)
11354 		    break;
11355 		if (((total % 256) == 0) &&
11356 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11357 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
11358 #else
11359 		    (xmlXPathCmpNodes(*first, cur) >= 0))
11360 #endif
11361 		{
11362 		    break;
11363 		}
11364 	    }
11365 	    if ((last != NULL) && (*last != NULL)) {
11366 		if (*last == cur)
11367 		    break;
11368 		if (((total % 256) == 0) &&
11369 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11370 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
11371 #else
11372 		    (xmlXPathCmpNodes(cur, *last) >= 0))
11373 #endif
11374 		{
11375 		    break;
11376 		}
11377 	    }
11378 
11379             total++;
11380 
11381 	    switch (test) {
11382                 case NODE_TEST_NONE:
11383 		    total = 0;
11384                     STRANGE
11385 		    goto error;
11386                 case NODE_TEST_TYPE:
11387 		    if (type == NODE_TYPE_NODE) {
11388 			switch (cur->type) {
11389 			    case XML_DOCUMENT_NODE:
11390 			    case XML_HTML_DOCUMENT_NODE:
11391 			    case XML_ELEMENT_NODE:
11392 			    case XML_ATTRIBUTE_NODE:
11393 			    case XML_PI_NODE:
11394 			    case XML_COMMENT_NODE:
11395 			    case XML_CDATA_SECTION_NODE:
11396 			    case XML_TEXT_NODE:
11397 				XP_TEST_HIT
11398 				break;
11399 			    case XML_NAMESPACE_DECL: {
11400 				if (axis == AXIS_NAMESPACE) {
11401 				    XP_TEST_HIT_NS
11402 				} else {
11403 	                            hasNsNodes = 1;
11404 				    XP_TEST_HIT
11405 				}
11406 				break;
11407                             }
11408 			    default:
11409 				break;
11410 			}
11411 		    } else if (cur->type == (xmlElementType) type) {
11412 			if (cur->type == XML_NAMESPACE_DECL)
11413 			    XP_TEST_HIT_NS
11414 			else
11415 			    XP_TEST_HIT
11416 		    } else if ((type == NODE_TYPE_TEXT) &&
11417 			 (cur->type == XML_CDATA_SECTION_NODE))
11418 		    {
11419 			XP_TEST_HIT
11420 		    }
11421 		    break;
11422                 case NODE_TEST_PI:
11423                     if ((cur->type == XML_PI_NODE) &&
11424                         ((name == NULL) || xmlStrEqual(name, cur->name)))
11425 		    {
11426 			XP_TEST_HIT
11427                     }
11428                     break;
11429                 case NODE_TEST_ALL:
11430                     if (axis == AXIS_ATTRIBUTE) {
11431                         if (cur->type == XML_ATTRIBUTE_NODE)
11432 			{
11433                             if (prefix == NULL)
11434 			    {
11435 				XP_TEST_HIT
11436                             } else if ((cur->ns != NULL) &&
11437 				(xmlStrEqual(URI, cur->ns->href)))
11438 			    {
11439 				XP_TEST_HIT
11440                             }
11441                         }
11442                     } else if (axis == AXIS_NAMESPACE) {
11443                         if (cur->type == XML_NAMESPACE_DECL)
11444 			{
11445 			    XP_TEST_HIT_NS
11446                         }
11447                     } else {
11448                         if (cur->type == XML_ELEMENT_NODE) {
11449                             if (prefix == NULL)
11450 			    {
11451 				XP_TEST_HIT
11452 
11453                             } else if ((cur->ns != NULL) &&
11454 				(xmlStrEqual(URI, cur->ns->href)))
11455 			    {
11456 				XP_TEST_HIT
11457                             }
11458                         }
11459                     }
11460                     break;
11461                 case NODE_TEST_NS:{
11462                         TODO;
11463                         break;
11464                     }
11465                 case NODE_TEST_NAME:
11466                     if (axis == AXIS_ATTRIBUTE) {
11467                         if (cur->type != XML_ATTRIBUTE_NODE)
11468 			    break;
11469 		    } else if (axis == AXIS_NAMESPACE) {
11470                         if (cur->type != XML_NAMESPACE_DECL)
11471 			    break;
11472 		    } else {
11473 		        if (cur->type != XML_ELEMENT_NODE)
11474 			    break;
11475 		    }
11476                     switch (cur->type) {
11477                         case XML_ELEMENT_NODE:
11478                             if (xmlStrEqual(name, cur->name)) {
11479                                 if (prefix == NULL) {
11480                                     if (cur->ns == NULL)
11481 				    {
11482 					XP_TEST_HIT
11483                                     }
11484                                 } else {
11485                                     if ((cur->ns != NULL) &&
11486                                         (xmlStrEqual(URI, cur->ns->href)))
11487 				    {
11488 					XP_TEST_HIT
11489                                     }
11490                                 }
11491                             }
11492                             break;
11493                         case XML_ATTRIBUTE_NODE:{
11494                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
11495 
11496                                 if (xmlStrEqual(name, attr->name)) {
11497                                     if (prefix == NULL) {
11498                                         if ((attr->ns == NULL) ||
11499                                             (attr->ns->prefix == NULL))
11500 					{
11501 					    XP_TEST_HIT
11502                                         }
11503                                     } else {
11504                                         if ((attr->ns != NULL) &&
11505                                             (xmlStrEqual(URI,
11506 					      attr->ns->href)))
11507 					{
11508 					    XP_TEST_HIT
11509                                         }
11510                                     }
11511                                 }
11512                                 break;
11513                             }
11514                         case XML_NAMESPACE_DECL:
11515                             if (cur->type == XML_NAMESPACE_DECL) {
11516                                 xmlNsPtr ns = (xmlNsPtr) cur;
11517 
11518                                 if ((ns->prefix != NULL) && (name != NULL)
11519                                     && (xmlStrEqual(ns->prefix, name)))
11520 				{
11521 				    XP_TEST_HIT_NS
11522                                 }
11523                             }
11524                             break;
11525                         default:
11526                             break;
11527                     }
11528                     break;
11529 	    } /* switch(test) */
11530         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
11531 
11532 	goto apply_predicates;
11533 
11534 axis_range_end: /* ----------------------------------------------------- */
11535 	/*
11536 	* We have a "/foo[n]", and position() = n was reached.
11537 	* Note that we can have as well "/foo/::parent::foo[1]", so
11538 	* a duplicate-aware merge is still needed.
11539 	* Merge with the result.
11540 	*/
11541 	if (outSeq == NULL) {
11542 	    outSeq = seq;
11543 	    seq = NULL;
11544 	} else
11545             /* TODO: Check memory error. */
11546 	    outSeq = mergeAndClear(outSeq, seq);
11547 	/*
11548 	* Break if only a true/false result was requested.
11549 	*/
11550 	if (toBool)
11551 	    break;
11552 	continue;
11553 
11554 first_hit: /* ---------------------------------------------------------- */
11555 	/*
11556 	* Break if only a true/false result was requested and
11557 	* no predicates existed and a node test succeeded.
11558 	*/
11559 	if (outSeq == NULL) {
11560 	    outSeq = seq;
11561 	    seq = NULL;
11562 	} else
11563             /* TODO: Check memory error. */
11564 	    outSeq = mergeAndClear(outSeq, seq);
11565 	break;
11566 
11567 apply_predicates: /* --------------------------------------------------- */
11568         if (ctxt->error != XPATH_EXPRESSION_OK)
11569 	    goto error;
11570 
11571         /*
11572 	* Apply predicates.
11573 	*/
11574         if ((predOp != NULL) && (seq->nodeNr > 0)) {
11575 	    /*
11576 	    * E.g. when we have a "/foo[some expression][n]".
11577 	    */
11578 	    /*
11579 	    * QUESTION TODO: The old predicate evaluation took into
11580 	    *  account location-sets.
11581 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
11582 	    *  Do we expect such a set here?
11583 	    *  All what I learned now from the evaluation semantics
11584 	    *  does not indicate that a location-set will be processed
11585 	    *  here, so this looks OK.
11586 	    */
11587 	    /*
11588 	    * Iterate over all predicates, starting with the outermost
11589 	    * predicate.
11590 	    * TODO: Problem: we cannot execute the inner predicates first
11591 	    *  since we cannot go back *up* the operator tree!
11592 	    *  Options we have:
11593 	    *  1) Use of recursive functions (like is it currently done
11594 	    *     via xmlXPathCompOpEval())
11595 	    *  2) Add a predicate evaluation information stack to the
11596 	    *     context struct
11597 	    *  3) Change the way the operators are linked; we need a
11598 	    *     "parent" field on xmlXPathStepOp
11599 	    *
11600 	    * For the moment, I'll try to solve this with a recursive
11601 	    * function: xmlXPathCompOpEvalPredicate().
11602 	    */
11603 	    if (hasPredicateRange != 0)
11604 		xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
11605 					    hasNsNodes);
11606 	    else
11607 		xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
11608 					    hasNsNodes);
11609 
11610 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
11611 		total = 0;
11612 		goto error;
11613 	    }
11614         }
11615 
11616         if (seq->nodeNr > 0) {
11617 	    /*
11618 	    * Add to result set.
11619 	    */
11620 	    if (outSeq == NULL) {
11621 		outSeq = seq;
11622 		seq = NULL;
11623 	    } else {
11624                 /* TODO: Check memory error. */
11625 		outSeq = mergeAndClear(outSeq, seq);
11626 	    }
11627 
11628             if (toBool)
11629                 break;
11630 	}
11631     }
11632 
11633 error:
11634     if ((obj->boolval) && (obj->user != NULL)) {
11635 	/*
11636 	* QUESTION TODO: What does this do and why?
11637 	* TODO: Do we have to do this also for the "error"
11638 	* cleanup further down?
11639 	*/
11640 	ctxt->value->boolval = 1;
11641 	ctxt->value->user = obj->user;
11642 	obj->user = NULL;
11643 	obj->boolval = 0;
11644     }
11645     xmlXPathReleaseObject(xpctxt, obj);
11646 
11647     /*
11648     * Ensure we return at least an empty set.
11649     */
11650     if (outSeq == NULL) {
11651 	if ((seq != NULL) && (seq->nodeNr == 0))
11652 	    outSeq = seq;
11653 	else
11654             /* TODO: Check memory error. */
11655 	    outSeq = xmlXPathNodeSetCreate(NULL);
11656     }
11657     if ((seq != NULL) && (seq != outSeq)) {
11658 	 xmlXPathFreeNodeSet(seq);
11659     }
11660     /*
11661     * Hand over the result. Better to push the set also in
11662     * case of errors.
11663     */
11664     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
11665     /*
11666     * Reset the context node.
11667     */
11668     xpctxt->node = oldContextNode;
11669     /*
11670     * When traversing the namespace axis in "toBool" mode, it's
11671     * possible that tmpNsList wasn't freed.
11672     */
11673     if (xpctxt->tmpNsList != NULL) {
11674         xmlFree(xpctxt->tmpNsList);
11675         xpctxt->tmpNsList = NULL;
11676     }
11677 
11678     return(total);
11679 }
11680 
11681 static int
11682 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11683 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
11684 
11685 /**
11686  * xmlXPathCompOpEvalFirst:
11687  * @ctxt:  the XPath parser context with the compiled expression
11688  * @op:  an XPath compiled operation
11689  * @first:  the first elem found so far
11690  *
11691  * Evaluate the Precompiled XPath operation searching only the first
11692  * element in document order
11693  *
11694  * Returns the number of examined objects.
11695  */
11696 static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)11697 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
11698                         xmlXPathStepOpPtr op, xmlNodePtr * first)
11699 {
11700     int total = 0, cur;
11701     xmlXPathCompExprPtr comp;
11702     xmlXPathObjectPtr arg1, arg2;
11703 
11704     CHECK_ERROR0;
11705     if (OP_LIMIT_EXCEEDED(ctxt, 1))
11706         return(0);
11707     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11708         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11709     ctxt->context->depth += 1;
11710     comp = ctxt->comp;
11711     switch (op->op) {
11712         case XPATH_OP_END:
11713             break;
11714         case XPATH_OP_UNION:
11715             total =
11716                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11717                                         first);
11718 	    CHECK_ERROR0;
11719             if ((ctxt->value != NULL)
11720                 && (ctxt->value->type == XPATH_NODESET)
11721                 && (ctxt->value->nodesetval != NULL)
11722                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
11723                 /*
11724                  * limit tree traversing to first node in the result
11725                  */
11726 		/*
11727 		* OPTIMIZE TODO: This implicitly sorts
11728 		*  the result, even if not needed. E.g. if the argument
11729 		*  of the count() function, no sorting is needed.
11730 		* OPTIMIZE TODO: How do we know if the node-list wasn't
11731 		*  already sorted?
11732 		*/
11733 		if (ctxt->value->nodesetval->nodeNr > 1)
11734 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
11735                 *first = ctxt->value->nodesetval->nodeTab[0];
11736             }
11737             cur =
11738                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
11739                                         first);
11740 	    CHECK_ERROR0;
11741 
11742             arg2 = valuePop(ctxt);
11743             arg1 = valuePop(ctxt);
11744             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11745                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11746 	        xmlXPathReleaseObject(ctxt->context, arg1);
11747 	        xmlXPathReleaseObject(ctxt->context, arg2);
11748                 XP_ERROR0(XPATH_INVALID_TYPE);
11749             }
11750             if ((ctxt->context->opLimit != 0) &&
11751                 (((arg1->nodesetval != NULL) &&
11752                   (xmlXPathCheckOpLimit(ctxt,
11753                                         arg1->nodesetval->nodeNr) < 0)) ||
11754                  ((arg2->nodesetval != NULL) &&
11755                   (xmlXPathCheckOpLimit(ctxt,
11756                                         arg2->nodesetval->nodeNr) < 0)))) {
11757 	        xmlXPathReleaseObject(ctxt->context, arg1);
11758 	        xmlXPathReleaseObject(ctxt->context, arg2);
11759                 break;
11760             }
11761 
11762             /* TODO: Check memory error. */
11763             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11764                                                     arg2->nodesetval);
11765             valuePush(ctxt, arg1);
11766 	    xmlXPathReleaseObject(ctxt->context, arg2);
11767             /* optimizer */
11768 	    if (total > cur)
11769 		xmlXPathCompSwap(op);
11770             total += cur;
11771             break;
11772         case XPATH_OP_ROOT:
11773             xmlXPathRoot(ctxt);
11774             break;
11775         case XPATH_OP_NODE:
11776             if (op->ch1 != -1)
11777                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11778 	    CHECK_ERROR0;
11779             if (op->ch2 != -1)
11780                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11781 	    CHECK_ERROR0;
11782 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
11783 		ctxt->context->node));
11784             break;
11785         case XPATH_OP_COLLECT:{
11786                 if (op->ch1 == -1)
11787                     break;
11788 
11789                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11790 		CHECK_ERROR0;
11791 
11792                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
11793                 break;
11794             }
11795         case XPATH_OP_VALUE:
11796             valuePush(ctxt,
11797                       xmlXPathCacheObjectCopy(ctxt->context,
11798 			(xmlXPathObjectPtr) op->value4));
11799             break;
11800         case XPATH_OP_SORT:
11801             if (op->ch1 != -1)
11802                 total +=
11803                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11804                                             first);
11805 	    CHECK_ERROR0;
11806             if ((ctxt->value != NULL)
11807                 && (ctxt->value->type == XPATH_NODESET)
11808                 && (ctxt->value->nodesetval != NULL)
11809 		&& (ctxt->value->nodesetval->nodeNr > 1))
11810                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11811             break;
11812 #ifdef XP_OPTIMIZED_FILTER_FIRST
11813 	case XPATH_OP_FILTER:
11814                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
11815             break;
11816 #endif
11817         default:
11818             total += xmlXPathCompOpEval(ctxt, op);
11819             break;
11820     }
11821 
11822     ctxt->context->depth -= 1;
11823     return(total);
11824 }
11825 
11826 /**
11827  * xmlXPathCompOpEvalLast:
11828  * @ctxt:  the XPath parser context with the compiled expression
11829  * @op:  an XPath compiled operation
11830  * @last:  the last elem found so far
11831  *
11832  * Evaluate the Precompiled XPath operation searching only the last
11833  * element in document order
11834  *
11835  * Returns the number of nodes traversed
11836  */
11837 static int
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * last)11838 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
11839                        xmlNodePtr * last)
11840 {
11841     int total = 0, cur;
11842     xmlXPathCompExprPtr comp;
11843     xmlXPathObjectPtr arg1, arg2;
11844 
11845     CHECK_ERROR0;
11846     if (OP_LIMIT_EXCEEDED(ctxt, 1))
11847         return(0);
11848     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11849         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11850     ctxt->context->depth += 1;
11851     comp = ctxt->comp;
11852     switch (op->op) {
11853         case XPATH_OP_END:
11854             break;
11855         case XPATH_OP_UNION:
11856             total =
11857                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
11858 	    CHECK_ERROR0;
11859             if ((ctxt->value != NULL)
11860                 && (ctxt->value->type == XPATH_NODESET)
11861                 && (ctxt->value->nodesetval != NULL)
11862                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
11863                 /*
11864                  * limit tree traversing to first node in the result
11865                  */
11866 		if (ctxt->value->nodesetval->nodeNr > 1)
11867 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
11868                 *last =
11869                     ctxt->value->nodesetval->nodeTab[ctxt->value->
11870                                                      nodesetval->nodeNr -
11871                                                      1];
11872             }
11873             cur =
11874                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
11875 	    CHECK_ERROR0;
11876             if ((ctxt->value != NULL)
11877                 && (ctxt->value->type == XPATH_NODESET)
11878                 && (ctxt->value->nodesetval != NULL)
11879                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
11880             }
11881 
11882             arg2 = valuePop(ctxt);
11883             arg1 = valuePop(ctxt);
11884             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11885                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11886 	        xmlXPathReleaseObject(ctxt->context, arg1);
11887 	        xmlXPathReleaseObject(ctxt->context, arg2);
11888                 XP_ERROR0(XPATH_INVALID_TYPE);
11889             }
11890             if ((ctxt->context->opLimit != 0) &&
11891                 (((arg1->nodesetval != NULL) &&
11892                   (xmlXPathCheckOpLimit(ctxt,
11893                                         arg1->nodesetval->nodeNr) < 0)) ||
11894                  ((arg2->nodesetval != NULL) &&
11895                   (xmlXPathCheckOpLimit(ctxt,
11896                                         arg2->nodesetval->nodeNr) < 0)))) {
11897 	        xmlXPathReleaseObject(ctxt->context, arg1);
11898 	        xmlXPathReleaseObject(ctxt->context, arg2);
11899                 break;
11900             }
11901 
11902             /* TODO: Check memory error. */
11903             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11904                                                     arg2->nodesetval);
11905             valuePush(ctxt, arg1);
11906 	    xmlXPathReleaseObject(ctxt->context, arg2);
11907             /* optimizer */
11908 	    if (total > cur)
11909 		xmlXPathCompSwap(op);
11910             total += cur;
11911             break;
11912         case XPATH_OP_ROOT:
11913             xmlXPathRoot(ctxt);
11914             break;
11915         case XPATH_OP_NODE:
11916             if (op->ch1 != -1)
11917                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11918 	    CHECK_ERROR0;
11919             if (op->ch2 != -1)
11920                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11921 	    CHECK_ERROR0;
11922 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
11923 		ctxt->context->node));
11924             break;
11925         case XPATH_OP_COLLECT:{
11926                 if (op->ch1 == -1)
11927                     break;
11928 
11929                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11930 		CHECK_ERROR0;
11931 
11932                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
11933                 break;
11934             }
11935         case XPATH_OP_VALUE:
11936             valuePush(ctxt,
11937                       xmlXPathCacheObjectCopy(ctxt->context,
11938 			(xmlXPathObjectPtr) op->value4));
11939             break;
11940         case XPATH_OP_SORT:
11941             if (op->ch1 != -1)
11942                 total +=
11943                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
11944                                            last);
11945 	    CHECK_ERROR0;
11946             if ((ctxt->value != NULL)
11947                 && (ctxt->value->type == XPATH_NODESET)
11948                 && (ctxt->value->nodesetval != NULL)
11949 		&& (ctxt->value->nodesetval->nodeNr > 1))
11950                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11951             break;
11952         default:
11953             total += xmlXPathCompOpEval(ctxt, op);
11954             break;
11955     }
11956 
11957     ctxt->context->depth -= 1;
11958     return (total);
11959 }
11960 
11961 #ifdef XP_OPTIMIZED_FILTER_FIRST
11962 static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)11963 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11964 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
11965 {
11966     int total = 0;
11967     xmlXPathCompExprPtr comp;
11968     xmlXPathObjectPtr obj;
11969     xmlNodeSetPtr set;
11970 
11971     CHECK_ERROR0;
11972     comp = ctxt->comp;
11973     /*
11974     * Optimization for ()[last()] selection i.e. the last elem
11975     */
11976     if ((op->ch1 != -1) && (op->ch2 != -1) &&
11977 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11978 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11979 	int f = comp->steps[op->ch2].ch1;
11980 
11981 	if ((f != -1) &&
11982 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11983 	    (comp->steps[f].value5 == NULL) &&
11984 	    (comp->steps[f].value == 0) &&
11985 	    (comp->steps[f].value4 != NULL) &&
11986 	    (xmlStrEqual
11987 	    (comp->steps[f].value4, BAD_CAST "last"))) {
11988 	    xmlNodePtr last = NULL;
11989 
11990 	    total +=
11991 		xmlXPathCompOpEvalLast(ctxt,
11992 		    &comp->steps[op->ch1],
11993 		    &last);
11994 	    CHECK_ERROR0;
11995 	    /*
11996 	    * The nodeset should be in document order,
11997 	    * Keep only the last value
11998 	    */
11999 	    if ((ctxt->value != NULL) &&
12000 		(ctxt->value->type == XPATH_NODESET) &&
12001 		(ctxt->value->nodesetval != NULL) &&
12002 		(ctxt->value->nodesetval->nodeTab != NULL) &&
12003 		(ctxt->value->nodesetval->nodeNr > 1)) {
12004                 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12005 		*first = *(ctxt->value->nodesetval->nodeTab);
12006 	    }
12007 	    return (total);
12008 	}
12009     }
12010 
12011     if (op->ch1 != -1)
12012 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12013     CHECK_ERROR0;
12014     if (op->ch2 == -1)
12015 	return (total);
12016     if (ctxt->value == NULL)
12017 	return (total);
12018 
12019 #ifdef LIBXML_XPTR_LOCS_ENABLED
12020     /*
12021     * Hum are we filtering the result of an XPointer expression
12022     */
12023     if (ctxt->value->type == XPATH_LOCATIONSET) {
12024         xmlLocationSetPtr locset = ctxt->value->user;
12025 
12026         if (locset != NULL) {
12027             xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12028             if (locset->locNr > 0)
12029                 *first = (xmlNodePtr) locset->locTab[0]->user;
12030         }
12031 
12032 	return (total);
12033     }
12034 #endif /* LIBXML_XPTR_LOCS_ENABLED */
12035 
12036     /*
12037      * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
12038      * the stack. We have to temporarily remove the nodeset object from the
12039      * stack to avoid freeing it prematurely.
12040      */
12041     CHECK_TYPE0(XPATH_NODESET);
12042     obj = valuePop(ctxt);
12043     set = obj->nodesetval;
12044     if (set != NULL) {
12045         xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12046         if (set->nodeNr > 0)
12047             *first = set->nodeTab[0];
12048     }
12049     valuePush(ctxt, obj);
12050 
12051     return (total);
12052 }
12053 #endif /* XP_OPTIMIZED_FILTER_FIRST */
12054 
12055 /**
12056  * xmlXPathCompOpEval:
12057  * @ctxt:  the XPath parser context with the compiled expression
12058  * @op:  an XPath compiled operation
12059  *
12060  * Evaluate the Precompiled XPath operation
12061  * Returns the number of nodes traversed
12062  */
12063 static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op)12064 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12065 {
12066     int total = 0;
12067     int equal, ret;
12068     xmlXPathCompExprPtr comp;
12069     xmlXPathObjectPtr arg1, arg2;
12070 
12071     CHECK_ERROR0;
12072     if (OP_LIMIT_EXCEEDED(ctxt, 1))
12073         return(0);
12074     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12075         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12076     ctxt->context->depth += 1;
12077     comp = ctxt->comp;
12078     switch (op->op) {
12079         case XPATH_OP_END:
12080             break;
12081         case XPATH_OP_AND:
12082             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12083 	    CHECK_ERROR0;
12084             xmlXPathBooleanFunction(ctxt, 1);
12085             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12086                 break;
12087             arg2 = valuePop(ctxt);
12088             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12089 	    if (ctxt->error) {
12090 		xmlXPathFreeObject(arg2);
12091 		break;
12092 	    }
12093             xmlXPathBooleanFunction(ctxt, 1);
12094             if (ctxt->value != NULL)
12095                 ctxt->value->boolval &= arg2->boolval;
12096 	    xmlXPathReleaseObject(ctxt->context, arg2);
12097             break;
12098         case XPATH_OP_OR:
12099             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12100 	    CHECK_ERROR0;
12101             xmlXPathBooleanFunction(ctxt, 1);
12102             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12103                 break;
12104             arg2 = valuePop(ctxt);
12105             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12106 	    if (ctxt->error) {
12107 		xmlXPathFreeObject(arg2);
12108 		break;
12109 	    }
12110             xmlXPathBooleanFunction(ctxt, 1);
12111             if (ctxt->value != NULL)
12112                 ctxt->value->boolval |= arg2->boolval;
12113 	    xmlXPathReleaseObject(ctxt->context, arg2);
12114             break;
12115         case XPATH_OP_EQUAL:
12116             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12117 	    CHECK_ERROR0;
12118             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12119 	    CHECK_ERROR0;
12120 	    if (op->value)
12121 		equal = xmlXPathEqualValues(ctxt);
12122 	    else
12123 		equal = xmlXPathNotEqualValues(ctxt);
12124 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
12125             break;
12126         case XPATH_OP_CMP:
12127             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12128 	    CHECK_ERROR0;
12129             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12130 	    CHECK_ERROR0;
12131             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
12132 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
12133             break;
12134         case XPATH_OP_PLUS:
12135             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12136 	    CHECK_ERROR0;
12137             if (op->ch2 != -1) {
12138                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12139 	    }
12140 	    CHECK_ERROR0;
12141             if (op->value == 0)
12142                 xmlXPathSubValues(ctxt);
12143             else if (op->value == 1)
12144                 xmlXPathAddValues(ctxt);
12145             else if (op->value == 2)
12146                 xmlXPathValueFlipSign(ctxt);
12147             else if (op->value == 3) {
12148                 CAST_TO_NUMBER;
12149                 CHECK_TYPE0(XPATH_NUMBER);
12150             }
12151             break;
12152         case XPATH_OP_MULT:
12153             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12154 	    CHECK_ERROR0;
12155             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12156 	    CHECK_ERROR0;
12157             if (op->value == 0)
12158                 xmlXPathMultValues(ctxt);
12159             else if (op->value == 1)
12160                 xmlXPathDivValues(ctxt);
12161             else if (op->value == 2)
12162                 xmlXPathModValues(ctxt);
12163             break;
12164         case XPATH_OP_UNION:
12165             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12166 	    CHECK_ERROR0;
12167             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12168 	    CHECK_ERROR0;
12169 
12170             arg2 = valuePop(ctxt);
12171             arg1 = valuePop(ctxt);
12172             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12173                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12174 	        xmlXPathReleaseObject(ctxt->context, arg1);
12175 	        xmlXPathReleaseObject(ctxt->context, arg2);
12176                 XP_ERROR0(XPATH_INVALID_TYPE);
12177             }
12178             if ((ctxt->context->opLimit != 0) &&
12179                 (((arg1->nodesetval != NULL) &&
12180                   (xmlXPathCheckOpLimit(ctxt,
12181                                         arg1->nodesetval->nodeNr) < 0)) ||
12182                  ((arg2->nodesetval != NULL) &&
12183                   (xmlXPathCheckOpLimit(ctxt,
12184                                         arg2->nodesetval->nodeNr) < 0)))) {
12185 	        xmlXPathReleaseObject(ctxt->context, arg1);
12186 	        xmlXPathReleaseObject(ctxt->context, arg2);
12187                 break;
12188             }
12189 
12190 	    if ((arg1->nodesetval == NULL) ||
12191 		((arg2->nodesetval != NULL) &&
12192 		 (arg2->nodesetval->nodeNr != 0)))
12193 	    {
12194                 /* TODO: Check memory error. */
12195 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12196 							arg2->nodesetval);
12197 	    }
12198 
12199             valuePush(ctxt, arg1);
12200 	    xmlXPathReleaseObject(ctxt->context, arg2);
12201             break;
12202         case XPATH_OP_ROOT:
12203             xmlXPathRoot(ctxt);
12204             break;
12205         case XPATH_OP_NODE:
12206             if (op->ch1 != -1)
12207                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12208 	    CHECK_ERROR0;
12209             if (op->ch2 != -1)
12210                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12211 	    CHECK_ERROR0;
12212 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12213 		ctxt->context->node));
12214             break;
12215         case XPATH_OP_COLLECT:{
12216                 if (op->ch1 == -1)
12217                     break;
12218 
12219                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12220 		CHECK_ERROR0;
12221 
12222                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
12223                 break;
12224             }
12225         case XPATH_OP_VALUE:
12226             valuePush(ctxt,
12227                       xmlXPathCacheObjectCopy(ctxt->context,
12228 			(xmlXPathObjectPtr) op->value4));
12229             break;
12230         case XPATH_OP_VARIABLE:{
12231 		xmlXPathObjectPtr val;
12232 
12233                 if (op->ch1 != -1)
12234                     total +=
12235                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12236                 if (op->value5 == NULL) {
12237 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
12238 		    if (val == NULL)
12239 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
12240                     valuePush(ctxt, val);
12241 		} else {
12242                     const xmlChar *URI;
12243 
12244                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
12245                     if (URI == NULL) {
12246                         xmlGenericError(xmlGenericErrorContext,
12247             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
12248                                     (char *) op->value4, (char *)op->value5);
12249                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
12250                         break;
12251                     }
12252 		    val = xmlXPathVariableLookupNS(ctxt->context,
12253                                                        op->value4, URI);
12254 		    if (val == NULL)
12255 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
12256                     valuePush(ctxt, val);
12257                 }
12258                 break;
12259             }
12260         case XPATH_OP_FUNCTION:{
12261                 xmlXPathFunction func;
12262                 const xmlChar *oldFunc, *oldFuncURI;
12263 		int i;
12264                 int frame;
12265 
12266                 frame = ctxt->valueNr;
12267                 if (op->ch1 != -1) {
12268                     total +=
12269                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12270                     if (ctxt->error != XPATH_EXPRESSION_OK)
12271                         break;
12272                 }
12273 		if (ctxt->valueNr < frame + op->value) {
12274 		    xmlGenericError(xmlGenericErrorContext,
12275 			    "xmlXPathCompOpEval: parameter error\n");
12276 		    ctxt->error = XPATH_INVALID_OPERAND;
12277 		    break;
12278 		}
12279 		for (i = 0; i < op->value; i++) {
12280 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
12281 			xmlGenericError(xmlGenericErrorContext,
12282 				"xmlXPathCompOpEval: parameter error\n");
12283 			ctxt->error = XPATH_INVALID_OPERAND;
12284 			break;
12285 		    }
12286                 }
12287                 if (op->cache != NULL)
12288                     func = op->cache;
12289                 else {
12290                     const xmlChar *URI = NULL;
12291 
12292                     if (op->value5 == NULL)
12293                         func =
12294                             xmlXPathFunctionLookup(ctxt->context,
12295                                                    op->value4);
12296                     else {
12297                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
12298                         if (URI == NULL) {
12299                             xmlGenericError(xmlGenericErrorContext,
12300             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
12301                                     (char *)op->value4, (char *)op->value5);
12302                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
12303                             break;
12304                         }
12305                         func = xmlXPathFunctionLookupNS(ctxt->context,
12306                                                         op->value4, URI);
12307                     }
12308                     if (func == NULL) {
12309                         xmlGenericError(xmlGenericErrorContext,
12310                                 "xmlXPathCompOpEval: function %s not found\n",
12311                                         (char *)op->value4);
12312                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
12313                     }
12314                     op->cache = func;
12315                     op->cacheURI = (void *) URI;
12316                 }
12317                 oldFunc = ctxt->context->function;
12318                 oldFuncURI = ctxt->context->functionURI;
12319                 ctxt->context->function = op->value4;
12320                 ctxt->context->functionURI = op->cacheURI;
12321                 func(ctxt, op->value);
12322                 ctxt->context->function = oldFunc;
12323                 ctxt->context->functionURI = oldFuncURI;
12324                 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
12325                     (ctxt->valueNr != frame + 1))
12326                     XP_ERROR0(XPATH_STACK_ERROR);
12327                 break;
12328             }
12329         case XPATH_OP_ARG:
12330             if (op->ch1 != -1) {
12331                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12332 	        CHECK_ERROR0;
12333             }
12334             if (op->ch2 != -1) {
12335                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12336 	        CHECK_ERROR0;
12337 	    }
12338             break;
12339         case XPATH_OP_PREDICATE:
12340         case XPATH_OP_FILTER:{
12341                 xmlXPathObjectPtr obj;
12342                 xmlNodeSetPtr set;
12343 
12344                 /*
12345                  * Optimization for ()[1] selection i.e. the first elem
12346                  */
12347                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12348 #ifdef XP_OPTIMIZED_FILTER_FIRST
12349 		    /*
12350 		    * FILTER TODO: Can we assume that the inner processing
12351 		    *  will result in an ordered list if we have an
12352 		    *  XPATH_OP_FILTER?
12353 		    *  What about an additional field or flag on
12354 		    *  xmlXPathObject like @sorted ? This way we wouldn't need
12355 		    *  to assume anything, so it would be more robust and
12356 		    *  easier to optimize.
12357 		    */
12358                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
12359 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
12360 #else
12361 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12362 #endif
12363                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
12364                     xmlXPathObjectPtr val;
12365 
12366                     val = comp->steps[op->ch2].value4;
12367                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
12368                         (val->floatval == 1.0)) {
12369                         xmlNodePtr first = NULL;
12370 
12371                         total +=
12372                             xmlXPathCompOpEvalFirst(ctxt,
12373                                                     &comp->steps[op->ch1],
12374                                                     &first);
12375 			CHECK_ERROR0;
12376                         /*
12377                          * The nodeset should be in document order,
12378                          * Keep only the first value
12379                          */
12380                         if ((ctxt->value != NULL) &&
12381                             (ctxt->value->type == XPATH_NODESET) &&
12382                             (ctxt->value->nodesetval != NULL) &&
12383                             (ctxt->value->nodesetval->nodeNr > 1))
12384                             xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
12385                                                         1, 1);
12386                         break;
12387                     }
12388                 }
12389                 /*
12390                  * Optimization for ()[last()] selection i.e. the last elem
12391                  */
12392                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12393                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12394                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12395                     int f = comp->steps[op->ch2].ch1;
12396 
12397                     if ((f != -1) &&
12398                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12399                         (comp->steps[f].value5 == NULL) &&
12400                         (comp->steps[f].value == 0) &&
12401                         (comp->steps[f].value4 != NULL) &&
12402                         (xmlStrEqual
12403                          (comp->steps[f].value4, BAD_CAST "last"))) {
12404                         xmlNodePtr last = NULL;
12405 
12406                         total +=
12407                             xmlXPathCompOpEvalLast(ctxt,
12408                                                    &comp->steps[op->ch1],
12409                                                    &last);
12410 			CHECK_ERROR0;
12411                         /*
12412                          * The nodeset should be in document order,
12413                          * Keep only the last value
12414                          */
12415                         if ((ctxt->value != NULL) &&
12416                             (ctxt->value->type == XPATH_NODESET) &&
12417                             (ctxt->value->nodesetval != NULL) &&
12418                             (ctxt->value->nodesetval->nodeTab != NULL) &&
12419                             (ctxt->value->nodesetval->nodeNr > 1))
12420                             xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12421                         break;
12422                     }
12423                 }
12424 		/*
12425 		* Process inner predicates first.
12426 		* Example "index[parent::book][1]":
12427 		* ...
12428 		*   PREDICATE   <-- we are here "[1]"
12429 		*     PREDICATE <-- process "[parent::book]" first
12430 		*       SORT
12431 		*         COLLECT  'parent' 'name' 'node' book
12432 		*           NODE
12433 		*     ELEM Object is a number : 1
12434 		*/
12435                 if (op->ch1 != -1)
12436                     total +=
12437                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12438 		CHECK_ERROR0;
12439                 if (op->ch2 == -1)
12440                     break;
12441                 if (ctxt->value == NULL)
12442                     break;
12443 
12444 #ifdef LIBXML_XPTR_LOCS_ENABLED
12445                 /*
12446                  * Hum are we filtering the result of an XPointer expression
12447                  */
12448                 if (ctxt->value->type == XPATH_LOCATIONSET) {
12449                     xmlLocationSetPtr locset = ctxt->value->user;
12450                     xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
12451                                               1, locset->locNr);
12452                     break;
12453                 }
12454 #endif /* LIBXML_XPTR_LOCS_ENABLED */
12455 
12456                 /*
12457                  * In case of errors, xmlXPathNodeSetFilter can pop additional
12458                  * nodes from the stack. We have to temporarily remove the
12459                  * nodeset object from the stack to avoid freeing it
12460                  * prematurely.
12461                  */
12462                 CHECK_TYPE0(XPATH_NODESET);
12463                 obj = valuePop(ctxt);
12464                 set = obj->nodesetval;
12465                 if (set != NULL)
12466                     xmlXPathNodeSetFilter(ctxt, set, op->ch2,
12467                                           1, set->nodeNr, 1);
12468                 valuePush(ctxt, obj);
12469                 break;
12470             }
12471         case XPATH_OP_SORT:
12472             if (op->ch1 != -1)
12473                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12474 	    CHECK_ERROR0;
12475             if ((ctxt->value != NULL) &&
12476                 (ctxt->value->type == XPATH_NODESET) &&
12477                 (ctxt->value->nodesetval != NULL) &&
12478 		(ctxt->value->nodesetval->nodeNr > 1))
12479 	    {
12480                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12481 	    }
12482             break;
12483 #ifdef LIBXML_XPTR_LOCS_ENABLED
12484         case XPATH_OP_RANGETO:{
12485                 xmlXPathObjectPtr range;
12486                 xmlXPathObjectPtr res, obj;
12487                 xmlXPathObjectPtr tmp;
12488                 xmlLocationSetPtr newlocset = NULL;
12489 		    xmlLocationSetPtr oldlocset;
12490                 xmlNodeSetPtr oldset;
12491                 xmlNodePtr oldnode = ctxt->context->node;
12492                 int oldcs = ctxt->context->contextSize;
12493                 int oldpp = ctxt->context->proximityPosition;
12494                 int i, j;
12495 
12496                 if (op->ch1 != -1) {
12497                     total +=
12498                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12499                     CHECK_ERROR0;
12500                 }
12501                 if (ctxt->value == NULL) {
12502                     XP_ERROR0(XPATH_INVALID_OPERAND);
12503                 }
12504                 if (op->ch2 == -1)
12505                     break;
12506 
12507                 if (ctxt->value->type == XPATH_LOCATIONSET) {
12508                     /*
12509                      * Extract the old locset, and then evaluate the result of the
12510                      * expression for all the element in the locset. use it to grow
12511                      * up a new locset.
12512                      */
12513                     CHECK_TYPE0(XPATH_LOCATIONSET);
12514 
12515                     if ((ctxt->value->user == NULL) ||
12516                         (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
12517                         break;
12518 
12519                     obj = valuePop(ctxt);
12520                     oldlocset = obj->user;
12521 
12522                     newlocset = xmlXPtrLocationSetCreate(NULL);
12523 
12524                     for (i = 0; i < oldlocset->locNr; i++) {
12525                         /*
12526                          * Run the evaluation with a node list made of a
12527                          * single item in the nodelocset.
12528                          */
12529                         ctxt->context->node = oldlocset->locTab[i]->user;
12530                         ctxt->context->contextSize = oldlocset->locNr;
12531                         ctxt->context->proximityPosition = i + 1;
12532 			tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12533 			    ctxt->context->node);
12534                         valuePush(ctxt, tmp);
12535 
12536                         if (op->ch2 != -1)
12537                             total +=
12538                                 xmlXPathCompOpEval(ctxt,
12539                                                    &comp->steps[op->ch2]);
12540 			if (ctxt->error != XPATH_EXPRESSION_OK) {
12541                             xmlXPtrFreeLocationSet(newlocset);
12542                             goto rangeto_error;
12543 			}
12544 
12545                         res = valuePop(ctxt);
12546 			if (res->type == XPATH_LOCATIONSET) {
12547 			    xmlLocationSetPtr rloc =
12548 			        (xmlLocationSetPtr)res->user;
12549 			    for (j=0; j<rloc->locNr; j++) {
12550 			        range = xmlXPtrNewRange(
12551 				  oldlocset->locTab[i]->user,
12552 				  oldlocset->locTab[i]->index,
12553 				  rloc->locTab[j]->user2,
12554 				  rloc->locTab[j]->index2);
12555 				if (range != NULL) {
12556 				    xmlXPtrLocationSetAdd(newlocset, range);
12557 				}
12558 			    }
12559 			} else {
12560 			    range = xmlXPtrNewRangeNodeObject(
12561 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
12562                             if (range != NULL) {
12563                                 xmlXPtrLocationSetAdd(newlocset,range);
12564 			    }
12565                         }
12566 
12567                         /*
12568                          * Cleanup
12569                          */
12570                         if (res != NULL) {
12571 			    xmlXPathReleaseObject(ctxt->context, res);
12572 			}
12573                         if (ctxt->value == tmp) {
12574                             res = valuePop(ctxt);
12575 			    xmlXPathReleaseObject(ctxt->context, res);
12576                         }
12577                     }
12578 		} else {	/* Not a location set */
12579                     CHECK_TYPE0(XPATH_NODESET);
12580                     obj = valuePop(ctxt);
12581                     oldset = obj->nodesetval;
12582 
12583                     newlocset = xmlXPtrLocationSetCreate(NULL);
12584 
12585                     if (oldset != NULL) {
12586                         for (i = 0; i < oldset->nodeNr; i++) {
12587                             /*
12588                              * Run the evaluation with a node list made of a single item
12589                              * in the nodeset.
12590                              */
12591                             ctxt->context->node = oldset->nodeTab[i];
12592 			    /*
12593 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
12594 			    */
12595 			    tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12596 				ctxt->context->node);
12597                             valuePush(ctxt, tmp);
12598 
12599                             if (op->ch2 != -1)
12600                                 total +=
12601                                     xmlXPathCompOpEval(ctxt,
12602                                                    &comp->steps[op->ch2]);
12603 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
12604                                 xmlXPtrFreeLocationSet(newlocset);
12605                                 goto rangeto_error;
12606 			    }
12607 
12608                             res = valuePop(ctxt);
12609                             range =
12610                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
12611                                                       res);
12612                             if (range != NULL) {
12613                                 xmlXPtrLocationSetAdd(newlocset, range);
12614                             }
12615 
12616                             /*
12617                              * Cleanup
12618                              */
12619                             if (res != NULL) {
12620 				xmlXPathReleaseObject(ctxt->context, res);
12621 			    }
12622                             if (ctxt->value == tmp) {
12623                                 res = valuePop(ctxt);
12624 				xmlXPathReleaseObject(ctxt->context, res);
12625                             }
12626                         }
12627                     }
12628                 }
12629 
12630                 /*
12631                  * The result is used as the new evaluation set.
12632                  */
12633                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12634 rangeto_error:
12635 		xmlXPathReleaseObject(ctxt->context, obj);
12636                 ctxt->context->node = oldnode;
12637                 ctxt->context->contextSize = oldcs;
12638                 ctxt->context->proximityPosition = oldpp;
12639                 break;
12640             }
12641 #endif /* LIBXML_XPTR_LOCS_ENABLED */
12642         default:
12643             xmlGenericError(xmlGenericErrorContext,
12644                             "XPath: unknown precompiled operation %d\n", op->op);
12645             ctxt->error = XPATH_INVALID_OPERAND;
12646             break;
12647     }
12648 
12649     ctxt->context->depth -= 1;
12650     return (total);
12651 }
12652 
12653 /**
12654  * xmlXPathCompOpEvalToBoolean:
12655  * @ctxt:  the XPath parser context
12656  *
12657  * Evaluates if the expression evaluates to true.
12658  *
12659  * Returns 1 if true, 0 if false and -1 on API or internal errors.
12660  */
12661 static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int isPredicate)12662 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
12663 			    xmlXPathStepOpPtr op,
12664 			    int isPredicate)
12665 {
12666     xmlXPathObjectPtr resObj = NULL;
12667 
12668 start:
12669     if (OP_LIMIT_EXCEEDED(ctxt, 1))
12670         return(0);
12671     /* comp = ctxt->comp; */
12672     switch (op->op) {
12673         case XPATH_OP_END:
12674             return (0);
12675 	case XPATH_OP_VALUE:
12676 	    resObj = (xmlXPathObjectPtr) op->value4;
12677 	    if (isPredicate)
12678 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
12679 	    return(xmlXPathCastToBoolean(resObj));
12680 	case XPATH_OP_SORT:
12681 	    /*
12682 	    * We don't need sorting for boolean results. Skip this one.
12683 	    */
12684             if (op->ch1 != -1) {
12685 		op = &ctxt->comp->steps[op->ch1];
12686 		goto start;
12687 	    }
12688 	    return(0);
12689 	case XPATH_OP_COLLECT:
12690 	    if (op->ch1 == -1)
12691 		return(0);
12692 
12693             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
12694 	    if (ctxt->error != XPATH_EXPRESSION_OK)
12695 		return(-1);
12696 
12697             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
12698 	    if (ctxt->error != XPATH_EXPRESSION_OK)
12699 		return(-1);
12700 
12701 	    resObj = valuePop(ctxt);
12702 	    if (resObj == NULL)
12703 		return(-1);
12704 	    break;
12705 	default:
12706 	    /*
12707 	    * Fallback to call xmlXPathCompOpEval().
12708 	    */
12709 	    xmlXPathCompOpEval(ctxt, op);
12710 	    if (ctxt->error != XPATH_EXPRESSION_OK)
12711 		return(-1);
12712 
12713 	    resObj = valuePop(ctxt);
12714 	    if (resObj == NULL)
12715 		return(-1);
12716 	    break;
12717     }
12718 
12719     if (resObj) {
12720 	int res;
12721 
12722 	if (resObj->type == XPATH_BOOLEAN) {
12723 	    res = resObj->boolval;
12724 	} else if (isPredicate) {
12725 	    /*
12726 	    * For predicates a result of type "number" is handled
12727 	    * differently:
12728 	    * SPEC XPath 1.0:
12729 	    * "If the result is a number, the result will be converted
12730 	    *  to true if the number is equal to the context position
12731 	    *  and will be converted to false otherwise;"
12732 	    */
12733 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
12734 	} else {
12735 	    res = xmlXPathCastToBoolean(resObj);
12736 	}
12737 	xmlXPathReleaseObject(ctxt->context, resObj);
12738 	return(res);
12739     }
12740 
12741     return(0);
12742 }
12743 
12744 #ifdef XPATH_STREAMING
12745 /**
12746  * xmlXPathRunStreamEval:
12747  * @ctxt:  the XPath parser context with the compiled expression
12748  *
12749  * Evaluate the Precompiled Streamable XPath expression in the given context.
12750  */
12751 static int
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt,xmlPatternPtr comp,xmlXPathObjectPtr * resultSeq,int toBool)12752 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
12753 		      xmlXPathObjectPtr *resultSeq, int toBool)
12754 {
12755     int max_depth, min_depth;
12756     int from_root;
12757     int ret, depth;
12758     int eval_all_nodes;
12759     xmlNodePtr cur = NULL, limit = NULL;
12760     xmlStreamCtxtPtr patstream = NULL;
12761 
12762     if ((ctxt == NULL) || (comp == NULL))
12763         return(-1);
12764     max_depth = xmlPatternMaxDepth(comp);
12765     if (max_depth == -1)
12766         return(-1);
12767     if (max_depth == -2)
12768         max_depth = 10000;
12769     min_depth = xmlPatternMinDepth(comp);
12770     if (min_depth == -1)
12771         return(-1);
12772     from_root = xmlPatternFromRoot(comp);
12773     if (from_root < 0)
12774         return(-1);
12775 #if 0
12776     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
12777 #endif
12778 
12779     if (! toBool) {
12780 	if (resultSeq == NULL)
12781 	    return(-1);
12782 	*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
12783 	if (*resultSeq == NULL)
12784 	    return(-1);
12785     }
12786 
12787     /*
12788      * handle the special cases of "/" amd "." being matched
12789      */
12790     if (min_depth == 0) {
12791 	if (from_root) {
12792 	    /* Select "/" */
12793 	    if (toBool)
12794 		return(1);
12795             /* TODO: Check memory error. */
12796 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
12797 		                     (xmlNodePtr) ctxt->doc);
12798 	} else {
12799 	    /* Select "self::node()" */
12800 	    if (toBool)
12801 		return(1);
12802             /* TODO: Check memory error. */
12803 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
12804 	}
12805     }
12806     if (max_depth == 0) {
12807 	return(0);
12808     }
12809 
12810     if (from_root) {
12811         cur = (xmlNodePtr)ctxt->doc;
12812     } else if (ctxt->node != NULL) {
12813         switch (ctxt->node->type) {
12814             case XML_ELEMENT_NODE:
12815             case XML_DOCUMENT_NODE:
12816             case XML_DOCUMENT_FRAG_NODE:
12817             case XML_HTML_DOCUMENT_NODE:
12818 	        cur = ctxt->node;
12819 		break;
12820             case XML_ATTRIBUTE_NODE:
12821             case XML_TEXT_NODE:
12822             case XML_CDATA_SECTION_NODE:
12823             case XML_ENTITY_REF_NODE:
12824             case XML_ENTITY_NODE:
12825             case XML_PI_NODE:
12826             case XML_COMMENT_NODE:
12827             case XML_NOTATION_NODE:
12828             case XML_DTD_NODE:
12829             case XML_DOCUMENT_TYPE_NODE:
12830             case XML_ELEMENT_DECL:
12831             case XML_ATTRIBUTE_DECL:
12832             case XML_ENTITY_DECL:
12833             case XML_NAMESPACE_DECL:
12834             case XML_XINCLUDE_START:
12835             case XML_XINCLUDE_END:
12836 		break;
12837 	}
12838 	limit = cur;
12839     }
12840     if (cur == NULL) {
12841         return(0);
12842     }
12843 
12844     patstream = xmlPatternGetStreamCtxt(comp);
12845     if (patstream == NULL) {
12846 	/*
12847 	* QUESTION TODO: Is this an error?
12848 	*/
12849 	return(0);
12850     }
12851 
12852     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
12853 
12854     if (from_root) {
12855 	ret = xmlStreamPush(patstream, NULL, NULL);
12856 	if (ret < 0) {
12857 	} else if (ret == 1) {
12858 	    if (toBool)
12859 		goto return_1;
12860             /* TODO: Check memory error. */
12861 	    xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
12862 	}
12863     }
12864     depth = 0;
12865     goto scan_children;
12866 next_node:
12867     do {
12868         if (ctxt->opLimit != 0) {
12869             if (ctxt->opCount >= ctxt->opLimit) {
12870                 xmlGenericError(xmlGenericErrorContext,
12871                         "XPath operation limit exceeded\n");
12872                 xmlFreeStreamCtxt(patstream);
12873                 return(-1);
12874             }
12875             ctxt->opCount++;
12876         }
12877 
12878 	switch (cur->type) {
12879 	    case XML_ELEMENT_NODE:
12880 	    case XML_TEXT_NODE:
12881 	    case XML_CDATA_SECTION_NODE:
12882 	    case XML_COMMENT_NODE:
12883 	    case XML_PI_NODE:
12884 		if (cur->type == XML_ELEMENT_NODE) {
12885 		    ret = xmlStreamPush(patstream, cur->name,
12886 				(cur->ns ? cur->ns->href : NULL));
12887 		} else if (eval_all_nodes)
12888 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
12889 		else
12890 		    break;
12891 
12892 		if (ret < 0) {
12893 		    /* NOP. */
12894 		} else if (ret == 1) {
12895 		    if (toBool)
12896 			goto return_1;
12897 		    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
12898 		        < 0) {
12899 			ctxt->lastError.domain = XML_FROM_XPATH;
12900 			ctxt->lastError.code = XML_ERR_NO_MEMORY;
12901 		    }
12902 		}
12903 		if ((cur->children == NULL) || (depth >= max_depth)) {
12904 		    ret = xmlStreamPop(patstream);
12905 		    while (cur->next != NULL) {
12906 			cur = cur->next;
12907 			if ((cur->type != XML_ENTITY_DECL) &&
12908 			    (cur->type != XML_DTD_NODE))
12909 			    goto next_node;
12910 		    }
12911 		}
12912 	    default:
12913 		break;
12914 	}
12915 
12916 scan_children:
12917 	if (cur->type == XML_NAMESPACE_DECL) break;
12918 	if ((cur->children != NULL) && (depth < max_depth)) {
12919 	    /*
12920 	     * Do not descend on entities declarations
12921 	     */
12922 	    if (cur->children->type != XML_ENTITY_DECL) {
12923 		cur = cur->children;
12924 		depth++;
12925 		/*
12926 		 * Skip DTDs
12927 		 */
12928 		if (cur->type != XML_DTD_NODE)
12929 		    continue;
12930 	    }
12931 	}
12932 
12933 	if (cur == limit)
12934 	    break;
12935 
12936 	while (cur->next != NULL) {
12937 	    cur = cur->next;
12938 	    if ((cur->type != XML_ENTITY_DECL) &&
12939 		(cur->type != XML_DTD_NODE))
12940 		goto next_node;
12941 	}
12942 
12943 	do {
12944 	    cur = cur->parent;
12945 	    depth--;
12946 	    if ((cur == NULL) || (cur == limit) ||
12947                 (cur->type == XML_DOCUMENT_NODE))
12948 	        goto done;
12949 	    if (cur->type == XML_ELEMENT_NODE) {
12950 		ret = xmlStreamPop(patstream);
12951 	    } else if ((eval_all_nodes) &&
12952 		((cur->type == XML_TEXT_NODE) ||
12953 		 (cur->type == XML_CDATA_SECTION_NODE) ||
12954 		 (cur->type == XML_COMMENT_NODE) ||
12955 		 (cur->type == XML_PI_NODE)))
12956 	    {
12957 		ret = xmlStreamPop(patstream);
12958 	    }
12959 	    if (cur->next != NULL) {
12960 		cur = cur->next;
12961 		break;
12962 	    }
12963 	} while (cur != NULL);
12964 
12965     } while ((cur != NULL) && (depth >= 0));
12966 
12967 done:
12968 
12969     if (patstream)
12970 	xmlFreeStreamCtxt(patstream);
12971     return(0);
12972 
12973 return_1:
12974     if (patstream)
12975 	xmlFreeStreamCtxt(patstream);
12976     return(1);
12977 }
12978 #endif /* XPATH_STREAMING */
12979 
12980 /**
12981  * xmlXPathRunEval:
12982  * @ctxt:  the XPath parser context with the compiled expression
12983  * @toBool:  evaluate to a boolean result
12984  *
12985  * Evaluate the Precompiled XPath expression in the given context.
12986  */
12987 static int
xmlXPathRunEval(xmlXPathParserContextPtr ctxt,int toBool)12988 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
12989 {
12990     xmlXPathCompExprPtr comp;
12991     int oldDepth;
12992 
12993     if ((ctxt == NULL) || (ctxt->comp == NULL))
12994 	return(-1);
12995 
12996     if (ctxt->valueTab == NULL) {
12997 	/* Allocate the value stack */
12998 	ctxt->valueTab = (xmlXPathObjectPtr *)
12999 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13000 	if (ctxt->valueTab == NULL) {
13001 	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13002 	    return(-1);
13003 	}
13004 	ctxt->valueNr = 0;
13005 	ctxt->valueMax = 10;
13006 	ctxt->value = NULL;
13007     }
13008 #ifdef XPATH_STREAMING
13009     if (ctxt->comp->stream) {
13010 	int res;
13011 
13012 	if (toBool) {
13013 	    /*
13014 	    * Evaluation to boolean result.
13015 	    */
13016 	    res = xmlXPathRunStreamEval(ctxt->context,
13017 		ctxt->comp->stream, NULL, 1);
13018 	    if (res != -1)
13019 		return(res);
13020 	} else {
13021 	    xmlXPathObjectPtr resObj = NULL;
13022 
13023 	    /*
13024 	    * Evaluation to a sequence.
13025 	    */
13026 	    res = xmlXPathRunStreamEval(ctxt->context,
13027 		ctxt->comp->stream, &resObj, 0);
13028 
13029 	    if ((res != -1) && (resObj != NULL)) {
13030 		valuePush(ctxt, resObj);
13031 		return(0);
13032 	    }
13033 	    if (resObj != NULL)
13034 		xmlXPathReleaseObject(ctxt->context, resObj);
13035 	}
13036 	/*
13037 	* QUESTION TODO: This falls back to normal XPath evaluation
13038 	* if res == -1. Is this intended?
13039 	*/
13040     }
13041 #endif
13042     comp = ctxt->comp;
13043     if (comp->last < 0) {
13044 	xmlGenericError(xmlGenericErrorContext,
13045 	    "xmlXPathRunEval: last is less than zero\n");
13046 	return(-1);
13047     }
13048     oldDepth = ctxt->context->depth;
13049     if (toBool)
13050 	return(xmlXPathCompOpEvalToBoolean(ctxt,
13051 	    &comp->steps[comp->last], 0));
13052     else
13053 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13054     ctxt->context->depth = oldDepth;
13055 
13056     return(0);
13057 }
13058 
13059 /************************************************************************
13060  *									*
13061  *			Public interfaces				*
13062  *									*
13063  ************************************************************************/
13064 
13065 /**
13066  * xmlXPathEvalPredicate:
13067  * @ctxt:  the XPath context
13068  * @res:  the Predicate Expression evaluation result
13069  *
13070  * Evaluate a predicate result for the current node.
13071  * A PredicateExpr is evaluated by evaluating the Expr and converting
13072  * the result to a boolean. If the result is a number, the result will
13073  * be converted to true if the number is equal to the position of the
13074  * context node in the context node list (as returned by the position
13075  * function) and will be converted to false otherwise; if the result
13076  * is not a number, then the result will be converted as if by a call
13077  * to the boolean function.
13078  *
13079  * Returns 1 if predicate is true, 0 otherwise
13080  */
13081 int
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt,xmlXPathObjectPtr res)13082 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13083     if ((ctxt == NULL) || (res == NULL)) return(0);
13084     switch (res->type) {
13085         case XPATH_BOOLEAN:
13086 	    return(res->boolval);
13087         case XPATH_NUMBER:
13088 	    return(res->floatval == ctxt->proximityPosition);
13089         case XPATH_NODESET:
13090         case XPATH_XSLT_TREE:
13091 	    if (res->nodesetval == NULL)
13092 		return(0);
13093 	    return(res->nodesetval->nodeNr != 0);
13094         case XPATH_STRING:
13095 	    return((res->stringval != NULL) &&
13096 	           (xmlStrlen(res->stringval) != 0));
13097         default:
13098 	    STRANGE
13099     }
13100     return(0);
13101 }
13102 
13103 /**
13104  * xmlXPathEvaluatePredicateResult:
13105  * @ctxt:  the XPath Parser context
13106  * @res:  the Predicate Expression evaluation result
13107  *
13108  * Evaluate a predicate result for the current node.
13109  * A PredicateExpr is evaluated by evaluating the Expr and converting
13110  * the result to a boolean. If the result is a number, the result will
13111  * be converted to true if the number is equal to the position of the
13112  * context node in the context node list (as returned by the position
13113  * function) and will be converted to false otherwise; if the result
13114  * is not a number, then the result will be converted as if by a call
13115  * to the boolean function.
13116  *
13117  * Returns 1 if predicate is true, 0 otherwise
13118  */
13119 int
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr res)13120 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
13121                                 xmlXPathObjectPtr res) {
13122     if ((ctxt == NULL) || (res == NULL)) return(0);
13123     switch (res->type) {
13124         case XPATH_BOOLEAN:
13125 	    return(res->boolval);
13126         case XPATH_NUMBER:
13127 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
13128 	    return((res->floatval == ctxt->context->proximityPosition) &&
13129 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
13130 #else
13131 	    return(res->floatval == ctxt->context->proximityPosition);
13132 #endif
13133         case XPATH_NODESET:
13134         case XPATH_XSLT_TREE:
13135 	    if (res->nodesetval == NULL)
13136 		return(0);
13137 	    return(res->nodesetval->nodeNr != 0);
13138         case XPATH_STRING:
13139 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
13140 #ifdef LIBXML_XPTR_LOCS_ENABLED
13141 	case XPATH_LOCATIONSET:{
13142 	    xmlLocationSetPtr ptr = res->user;
13143 	    if (ptr == NULL)
13144 	        return(0);
13145 	    return (ptr->locNr != 0);
13146 	    }
13147 #endif
13148         default:
13149 	    STRANGE
13150     }
13151     return(0);
13152 }
13153 
13154 #ifdef XPATH_STREAMING
13155 /**
13156  * xmlXPathTryStreamCompile:
13157  * @ctxt: an XPath context
13158  * @str:  the XPath expression
13159  *
13160  * Try to compile the XPath expression as a streamable subset.
13161  *
13162  * Returns the compiled expression or NULL if failed to compile.
13163  */
13164 static xmlXPathCompExprPtr
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt,const xmlChar * str)13165 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
13166     /*
13167      * Optimization: use streaming patterns when the XPath expression can
13168      * be compiled to a stream lookup
13169      */
13170     xmlPatternPtr stream;
13171     xmlXPathCompExprPtr comp;
13172     xmlDictPtr dict = NULL;
13173     const xmlChar **namespaces = NULL;
13174     xmlNsPtr ns;
13175     int i, j;
13176 
13177     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
13178         (!xmlStrchr(str, '@'))) {
13179 	const xmlChar *tmp;
13180 
13181 	/*
13182 	 * We don't try to handle expressions using the verbose axis
13183 	 * specifiers ("::"), just the simplified form at this point.
13184 	 * Additionally, if there is no list of namespaces available and
13185 	 *  there's a ":" in the expression, indicating a prefixed QName,
13186 	 *  then we won't try to compile either. xmlPatterncompile() needs
13187 	 *  to have a list of namespaces at compilation time in order to
13188 	 *  compile prefixed name tests.
13189 	 */
13190 	tmp = xmlStrchr(str, ':');
13191 	if ((tmp != NULL) &&
13192 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
13193 	    return(NULL);
13194 
13195 	if (ctxt != NULL) {
13196 	    dict = ctxt->dict;
13197 	    if (ctxt->nsNr > 0) {
13198 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
13199 		if (namespaces == NULL) {
13200 		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
13201 		    return(NULL);
13202 		}
13203 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
13204 		    ns = ctxt->namespaces[j];
13205 		    namespaces[i++] = ns->href;
13206 		    namespaces[i++] = ns->prefix;
13207 		}
13208 		namespaces[i++] = NULL;
13209 		namespaces[i] = NULL;
13210 	    }
13211 	}
13212 
13213 	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
13214 	if (namespaces != NULL) {
13215 	    xmlFree((xmlChar **)namespaces);
13216 	}
13217 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
13218 	    comp = xmlXPathNewCompExpr();
13219 	    if (comp == NULL) {
13220 		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
13221 	        xmlFreePattern(stream);
13222 		return(NULL);
13223 	    }
13224 	    comp->stream = stream;
13225 	    comp->dict = dict;
13226 	    if (comp->dict)
13227 		xmlDictReference(comp->dict);
13228 	    return(comp);
13229 	}
13230 	xmlFreePattern(stream);
13231     }
13232     return(NULL);
13233 }
13234 #endif /* XPATH_STREAMING */
13235 
13236 static void
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,xmlXPathStepOpPtr op)13237 xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
13238                            xmlXPathStepOpPtr op)
13239 {
13240     xmlXPathCompExprPtr comp = pctxt->comp;
13241     xmlXPathContextPtr ctxt;
13242 
13243     /*
13244     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
13245     * internal representation.
13246     */
13247 
13248     if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
13249         (op->ch1 != -1) &&
13250         (op->ch2 == -1 /* no predicate */))
13251     {
13252         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
13253 
13254         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
13255             ((xmlXPathAxisVal) prevop->value ==
13256                 AXIS_DESCENDANT_OR_SELF) &&
13257             (prevop->ch2 == -1) &&
13258             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
13259             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
13260         {
13261             /*
13262             * This is a "descendant-or-self::node()" without predicates.
13263             * Try to eliminate it.
13264             */
13265 
13266             switch ((xmlXPathAxisVal) op->value) {
13267                 case AXIS_CHILD:
13268                 case AXIS_DESCENDANT:
13269                     /*
13270                     * Convert "descendant-or-self::node()/child::" or
13271                     * "descendant-or-self::node()/descendant::" to
13272                     * "descendant::"
13273                     */
13274                     op->ch1   = prevop->ch1;
13275                     op->value = AXIS_DESCENDANT;
13276                     break;
13277                 case AXIS_SELF:
13278                 case AXIS_DESCENDANT_OR_SELF:
13279                     /*
13280                     * Convert "descendant-or-self::node()/self::" or
13281                     * "descendant-or-self::node()/descendant-or-self::" to
13282                     * to "descendant-or-self::"
13283                     */
13284                     op->ch1   = prevop->ch1;
13285                     op->value = AXIS_DESCENDANT_OR_SELF;
13286                     break;
13287                 default:
13288                     break;
13289             }
13290 	}
13291     }
13292 
13293     /* OP_VALUE has invalid ch1. */
13294     if (op->op == XPATH_OP_VALUE)
13295         return;
13296 
13297     /* Recurse */
13298     ctxt = pctxt->context;
13299     if (ctxt != NULL) {
13300         if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
13301             return;
13302         ctxt->depth += 1;
13303     }
13304     if (op->ch1 != -1)
13305         xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
13306     if (op->ch2 != -1)
13307 	xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
13308     if (ctxt != NULL)
13309         ctxt->depth -= 1;
13310 }
13311 
13312 /**
13313  * xmlXPathCtxtCompile:
13314  * @ctxt: an XPath context
13315  * @str:  the XPath expression
13316  *
13317  * Compile an XPath expression
13318  *
13319  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
13320  *         the caller has to free the object.
13321  */
13322 xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt,const xmlChar * str)13323 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
13324     xmlXPathParserContextPtr pctxt;
13325     xmlXPathCompExprPtr comp;
13326     int oldDepth = 0;
13327 
13328 #ifdef XPATH_STREAMING
13329     comp = xmlXPathTryStreamCompile(ctxt, str);
13330     if (comp != NULL)
13331         return(comp);
13332 #endif
13333 
13334     xmlInitParser();
13335 
13336     pctxt = xmlXPathNewParserContext(str, ctxt);
13337     if (pctxt == NULL)
13338         return NULL;
13339     if (ctxt != NULL)
13340         oldDepth = ctxt->depth;
13341     xmlXPathCompileExpr(pctxt, 1);
13342     if (ctxt != NULL)
13343         ctxt->depth = oldDepth;
13344 
13345     if( pctxt->error != XPATH_EXPRESSION_OK )
13346     {
13347         xmlXPathFreeParserContext(pctxt);
13348         return(NULL);
13349     }
13350 
13351     if (*pctxt->cur != 0) {
13352 	/*
13353 	 * aleksey: in some cases this line prints *second* error message
13354 	 * (see bug #78858) and probably this should be fixed.
13355 	 * However, we are not sure that all error messages are printed
13356 	 * out in other places. It's not critical so we leave it as-is for now
13357 	 */
13358 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
13359 	comp = NULL;
13360     } else {
13361 	comp = pctxt->comp;
13362 	if ((comp->nbStep > 1) && (comp->last >= 0)) {
13363             if (ctxt != NULL)
13364                 oldDepth = ctxt->depth;
13365 	    xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
13366             if (ctxt != NULL)
13367                 ctxt->depth = oldDepth;
13368 	}
13369 	pctxt->comp = NULL;
13370     }
13371     xmlXPathFreeParserContext(pctxt);
13372 
13373     if (comp != NULL) {
13374 	comp->expr = xmlStrdup(str);
13375     }
13376     return(comp);
13377 }
13378 
13379 /**
13380  * xmlXPathCompile:
13381  * @str:  the XPath expression
13382  *
13383  * Compile an XPath expression
13384  *
13385  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
13386  *         the caller has to free the object.
13387  */
13388 xmlXPathCompExprPtr
xmlXPathCompile(const xmlChar * str)13389 xmlXPathCompile(const xmlChar *str) {
13390     return(xmlXPathCtxtCompile(NULL, str));
13391 }
13392 
13393 /**
13394  * xmlXPathCompiledEvalInternal:
13395  * @comp:  the compiled XPath expression
13396  * @ctxt:  the XPath context
13397  * @resObj: the resulting XPath object or NULL
13398  * @toBool: 1 if only a boolean result is requested
13399  *
13400  * Evaluate the Precompiled XPath expression in the given context.
13401  * The caller has to free @resObj.
13402  *
13403  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13404  *         the caller has to free the object.
13405  */
13406 static int
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt,xmlXPathObjectPtr * resObjPtr,int toBool)13407 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
13408 			     xmlXPathContextPtr ctxt,
13409 			     xmlXPathObjectPtr *resObjPtr,
13410 			     int toBool)
13411 {
13412     xmlXPathParserContextPtr pctxt;
13413     xmlXPathObjectPtr resObj;
13414 #ifndef LIBXML_THREAD_ENABLED
13415     static int reentance = 0;
13416 #endif
13417     int res;
13418 
13419     CHECK_CTXT_NEG(ctxt)
13420 
13421     if (comp == NULL)
13422 	return(-1);
13423     xmlInitParser();
13424 
13425 #ifndef LIBXML_THREAD_ENABLED
13426     reentance++;
13427     if (reentance > 1)
13428 	xmlXPathDisableOptimizer = 1;
13429 #endif
13430 
13431     pctxt = xmlXPathCompParserContext(comp, ctxt);
13432     if (pctxt == NULL)
13433         return(-1);
13434     res = xmlXPathRunEval(pctxt, toBool);
13435 
13436     if (pctxt->error != XPATH_EXPRESSION_OK) {
13437         resObj = NULL;
13438     } else {
13439         resObj = valuePop(pctxt);
13440         if (resObj == NULL) {
13441             if (!toBool)
13442                 xmlGenericError(xmlGenericErrorContext,
13443                     "xmlXPathCompiledEval: No result on the stack.\n");
13444         } else if (pctxt->valueNr > 0) {
13445             xmlGenericError(xmlGenericErrorContext,
13446                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
13447                 pctxt->valueNr);
13448         }
13449     }
13450 
13451     if (resObjPtr)
13452         *resObjPtr = resObj;
13453     else
13454         xmlXPathReleaseObject(ctxt, resObj);
13455 
13456     pctxt->comp = NULL;
13457     xmlXPathFreeParserContext(pctxt);
13458 #ifndef LIBXML_THREAD_ENABLED
13459     reentance--;
13460 #endif
13461 
13462     return(res);
13463 }
13464 
13465 /**
13466  * xmlXPathCompiledEval:
13467  * @comp:  the compiled XPath expression
13468  * @ctx:  the XPath context
13469  *
13470  * Evaluate the Precompiled XPath expression in the given context.
13471  *
13472  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13473  *         the caller has to free the object.
13474  */
13475 xmlXPathObjectPtr
xmlXPathCompiledEval(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctx)13476 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
13477 {
13478     xmlXPathObjectPtr res = NULL;
13479 
13480     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
13481     return(res);
13482 }
13483 
13484 /**
13485  * xmlXPathCompiledEvalToBoolean:
13486  * @comp:  the compiled XPath expression
13487  * @ctxt:  the XPath context
13488  *
13489  * Applies the XPath boolean() function on the result of the given
13490  * compiled expression.
13491  *
13492  * Returns 1 if the expression evaluated to true, 0 if to false and
13493  *         -1 in API and internal errors.
13494  */
13495 int
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)13496 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
13497 			      xmlXPathContextPtr ctxt)
13498 {
13499     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
13500 }
13501 
13502 /**
13503  * xmlXPathEvalExpr:
13504  * @ctxt:  the XPath Parser context
13505  *
13506  * Parse and evaluate an XPath expression in the given context,
13507  * then push the result on the context stack
13508  */
13509 void
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt)13510 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
13511 #ifdef XPATH_STREAMING
13512     xmlXPathCompExprPtr comp;
13513 #endif
13514     int oldDepth = 0;
13515 
13516     if (ctxt == NULL) return;
13517 
13518 #ifdef XPATH_STREAMING
13519     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
13520     if (comp != NULL) {
13521         if (ctxt->comp != NULL)
13522 	    xmlXPathFreeCompExpr(ctxt->comp);
13523         ctxt->comp = comp;
13524     } else
13525 #endif
13526     {
13527         if (ctxt->context != NULL)
13528             oldDepth = ctxt->context->depth;
13529 	xmlXPathCompileExpr(ctxt, 1);
13530         if (ctxt->context != NULL)
13531             ctxt->context->depth = oldDepth;
13532         CHECK_ERROR;
13533 
13534         /* Check for trailing characters. */
13535         if (*ctxt->cur != 0)
13536             XP_ERROR(XPATH_EXPR_ERROR);
13537 
13538 	if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
13539             if (ctxt->context != NULL)
13540                 oldDepth = ctxt->context->depth;
13541 	    xmlXPathOptimizeExpression(ctxt,
13542 		&ctxt->comp->steps[ctxt->comp->last]);
13543             if (ctxt->context != NULL)
13544                 ctxt->context->depth = oldDepth;
13545         }
13546     }
13547 
13548     xmlXPathRunEval(ctxt, 0);
13549 }
13550 
13551 /**
13552  * xmlXPathEval:
13553  * @str:  the XPath expression
13554  * @ctx:  the XPath context
13555  *
13556  * Evaluate the XPath Location Path in the given context.
13557  *
13558  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13559  *         the caller has to free the object.
13560  */
13561 xmlXPathObjectPtr
xmlXPathEval(const xmlChar * str,xmlXPathContextPtr ctx)13562 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
13563     xmlXPathParserContextPtr ctxt;
13564     xmlXPathObjectPtr res;
13565 
13566     CHECK_CTXT(ctx)
13567 
13568     xmlInitParser();
13569 
13570     ctxt = xmlXPathNewParserContext(str, ctx);
13571     if (ctxt == NULL)
13572         return NULL;
13573     xmlXPathEvalExpr(ctxt);
13574 
13575     if (ctxt->error != XPATH_EXPRESSION_OK) {
13576 	res = NULL;
13577     } else {
13578 	res = valuePop(ctxt);
13579         if (res == NULL) {
13580             xmlGenericError(xmlGenericErrorContext,
13581                 "xmlXPathCompiledEval: No result on the stack.\n");
13582         } else if (ctxt->valueNr > 0) {
13583             xmlGenericError(xmlGenericErrorContext,
13584                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
13585                 ctxt->valueNr);
13586         }
13587     }
13588 
13589     xmlXPathFreeParserContext(ctxt);
13590     return(res);
13591 }
13592 
13593 /**
13594  * xmlXPathSetContextNode:
13595  * @node: the node to to use as the context node
13596  * @ctx:  the XPath context
13597  *
13598  * Sets 'node' as the context node. The node must be in the same
13599  * document as that associated with the context.
13600  *
13601  * Returns -1 in case of error or 0 if successful
13602  */
13603 int
xmlXPathSetContextNode(xmlNodePtr node,xmlXPathContextPtr ctx)13604 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
13605     if ((node == NULL) || (ctx == NULL))
13606         return(-1);
13607 
13608     if (node->doc == ctx->doc) {
13609         ctx->node = node;
13610 	return(0);
13611     }
13612     return(-1);
13613 }
13614 
13615 /**
13616  * xmlXPathNodeEval:
13617  * @node: the node to to use as the context node
13618  * @str:  the XPath expression
13619  * @ctx:  the XPath context
13620  *
13621  * Evaluate the XPath Location Path in the given context. The node 'node'
13622  * is set as the context node. The context node is not restored.
13623  *
13624  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13625  *         the caller has to free the object.
13626  */
13627 xmlXPathObjectPtr
xmlXPathNodeEval(xmlNodePtr node,const xmlChar * str,xmlXPathContextPtr ctx)13628 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
13629     if (str == NULL)
13630         return(NULL);
13631     if (xmlXPathSetContextNode(node, ctx) < 0)
13632         return(NULL);
13633     return(xmlXPathEval(str, ctx));
13634 }
13635 
13636 /**
13637  * xmlXPathEvalExpression:
13638  * @str:  the XPath expression
13639  * @ctxt:  the XPath context
13640  *
13641  * Alias for xmlXPathEval().
13642  *
13643  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13644  *         the caller has to free the object.
13645  */
13646 xmlXPathObjectPtr
xmlXPathEvalExpression(const xmlChar * str,xmlXPathContextPtr ctxt)13647 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
13648     return(xmlXPathEval(str, ctxt));
13649 }
13650 
13651 /************************************************************************
13652  *									*
13653  *	Extra functions not pertaining to the XPath spec		*
13654  *									*
13655  ************************************************************************/
13656 /**
13657  * xmlXPathEscapeUriFunction:
13658  * @ctxt:  the XPath Parser context
13659  * @nargs:  the number of arguments
13660  *
13661  * Implement the escape-uri() XPath function
13662  *    string escape-uri(string $str, bool $escape-reserved)
13663  *
13664  * This function applies the URI escaping rules defined in section 2 of [RFC
13665  * 2396] to the string supplied as $uri-part, which typically represents all
13666  * or part of a URI. The effect of the function is to replace any special
13667  * character in the string by an escape sequence of the form %xx%yy...,
13668  * where xxyy... is the hexadecimal representation of the octets used to
13669  * represent the character in UTF-8.
13670  *
13671  * The set of characters that are escaped depends on the setting of the
13672  * boolean argument $escape-reserved.
13673  *
13674  * If $escape-reserved is true, all characters are escaped other than lower
13675  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
13676  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
13677  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
13678  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
13679  * A-F).
13680  *
13681  * If $escape-reserved is false, the behavior differs in that characters
13682  * referred to in [RFC 2396] as reserved characters are not escaped. These
13683  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
13684  *
13685  * [RFC 2396] does not define whether escaped URIs should use lower case or
13686  * upper case for hexadecimal digits. To ensure that escaped URIs can be
13687  * compared using string comparison functions, this function must always use
13688  * the upper-case letters A-F.
13689  *
13690  * Generally, $escape-reserved should be set to true when escaping a string
13691  * that is to form a single part of a URI, and to false when escaping an
13692  * entire URI or URI reference.
13693  *
13694  * In the case of non-ascii characters, the string is encoded according to
13695  * utf-8 and then converted according to RFC 2396.
13696  *
13697  * Examples
13698  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
13699  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
13700  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
13701  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
13702  *
13703  */
13704 static void
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt,int nargs)13705 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
13706     xmlXPathObjectPtr str;
13707     int escape_reserved;
13708     xmlBufPtr target;
13709     xmlChar *cptr;
13710     xmlChar escape[4];
13711 
13712     CHECK_ARITY(2);
13713 
13714     escape_reserved = xmlXPathPopBoolean(ctxt);
13715 
13716     CAST_TO_STRING;
13717     str = valuePop(ctxt);
13718 
13719     target = xmlBufCreate();
13720 
13721     escape[0] = '%';
13722     escape[3] = 0;
13723 
13724     if (target) {
13725 	for (cptr = str->stringval; *cptr; cptr++) {
13726 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
13727 		(*cptr >= 'a' && *cptr <= 'z') ||
13728 		(*cptr >= '0' && *cptr <= '9') ||
13729 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
13730 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
13731 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
13732 		(*cptr == '%' &&
13733 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
13734 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
13735 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
13736 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
13737 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
13738 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
13739 		(!escape_reserved &&
13740 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
13741 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
13742 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
13743 		  *cptr == ','))) {
13744 		xmlBufAdd(target, cptr, 1);
13745 	    } else {
13746 		if ((*cptr >> 4) < 10)
13747 		    escape[1] = '0' + (*cptr >> 4);
13748 		else
13749 		    escape[1] = 'A' - 10 + (*cptr >> 4);
13750 		if ((*cptr & 0xF) < 10)
13751 		    escape[2] = '0' + (*cptr & 0xF);
13752 		else
13753 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
13754 
13755 		xmlBufAdd(target, &escape[0], 3);
13756 	    }
13757 	}
13758     }
13759     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
13760 	xmlBufContent(target)));
13761     xmlBufFree(target);
13762     xmlXPathReleaseObject(ctxt->context, str);
13763 }
13764 
13765 /**
13766  * xmlXPathRegisterAllFunctions:
13767  * @ctxt:  the XPath context
13768  *
13769  * Registers all default XPath functions in this context
13770  */
13771 void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)13772 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
13773 {
13774     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
13775                          xmlXPathBooleanFunction);
13776     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
13777                          xmlXPathCeilingFunction);
13778     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
13779                          xmlXPathCountFunction);
13780     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
13781                          xmlXPathConcatFunction);
13782     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
13783                          xmlXPathContainsFunction);
13784     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
13785                          xmlXPathIdFunction);
13786     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
13787                          xmlXPathFalseFunction);
13788     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
13789                          xmlXPathFloorFunction);
13790     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
13791                          xmlXPathLastFunction);
13792     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
13793                          xmlXPathLangFunction);
13794     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
13795                          xmlXPathLocalNameFunction);
13796     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
13797                          xmlXPathNotFunction);
13798     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
13799                          xmlXPathNameFunction);
13800     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
13801                          xmlXPathNamespaceURIFunction);
13802     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
13803                          xmlXPathNormalizeFunction);
13804     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
13805                          xmlXPathNumberFunction);
13806     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
13807                          xmlXPathPositionFunction);
13808     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
13809                          xmlXPathRoundFunction);
13810     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
13811                          xmlXPathStringFunction);
13812     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
13813                          xmlXPathStringLengthFunction);
13814     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
13815                          xmlXPathStartsWithFunction);
13816     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
13817                          xmlXPathSubstringFunction);
13818     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
13819                          xmlXPathSubstringBeforeFunction);
13820     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
13821                          xmlXPathSubstringAfterFunction);
13822     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
13823                          xmlXPathSumFunction);
13824     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
13825                          xmlXPathTrueFunction);
13826     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
13827                          xmlXPathTranslateFunction);
13828 
13829     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
13830 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
13831                          xmlXPathEscapeUriFunction);
13832 }
13833 
13834 #endif /* LIBXML_XPATH_ENABLED */
13835