xref: /aosp_15_r20/external/cronet/third_party/libxml/src/xpath.c (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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: [email protected]
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 /* Disabled for now */
55 #if 0
56 #ifdef LIBXML_PATTERN_ENABLED
57 #define XPATH_STREAMING
58 #endif
59 #endif
60 
61 /**
62  * WITH_TIM_SORT:
63  *
64  * Use the Timsort algorithm provided in timsort.h to sort
65  * nodeset as this is a great improvement over the old Shell sort
66  * used in xmlXPathNodeSetSort()
67  */
68 #define WITH_TIM_SORT
69 
70 /*
71 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
72 * If defined, this will use xmlXPathCmpNodesExt() instead of
73 * xmlXPathCmpNodes(). The new function is optimized comparison of
74 * non-element nodes; actually it will speed up comparison only if
75 * xmlXPathOrderDocElems() was called in order to index the elements of
76 * a tree in document order; Libxslt does such an indexing, thus it will
77 * benefit from this optimization.
78 */
79 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
80 
81 /*
82 * XP_OPTIMIZED_FILTER_FIRST:
83 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
84 * in a way, that it stop evaluation at the first node.
85 */
86 #define XP_OPTIMIZED_FILTER_FIRST
87 
88 /*
89  * XPATH_MAX_STEPS:
90  * when compiling an XPath expression we arbitrary limit the maximum
91  * number of step operation in the compiled expression. 1000000 is
92  * an insanely large value which should never be reached under normal
93  * circumstances
94  */
95 #define XPATH_MAX_STEPS 1000000
96 
97 /*
98  * XPATH_MAX_STACK_DEPTH:
99  * when evaluating an XPath expression we arbitrary limit the maximum
100  * number of object allowed to be pushed on the stack. 1000000 is
101  * an insanely large value which should never be reached under normal
102  * circumstances
103  */
104 #define XPATH_MAX_STACK_DEPTH 1000000
105 
106 /*
107  * XPATH_MAX_NODESET_LENGTH:
108  * when evaluating an XPath expression nodesets are created and we
109  * arbitrary limit the maximum length of those node set. 10000000 is
110  * an insanely large value which should never be reached under normal
111  * circumstances, one would first need to construct an in memory tree
112  * with more than 10 millions nodes.
113  */
114 #define XPATH_MAX_NODESET_LENGTH 10000000
115 
116 /*
117  * XPATH_MAX_RECRUSION_DEPTH:
118  * Maximum amount of nested functions calls when parsing or evaluating
119  * expressions
120  */
121 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
122 #define XPATH_MAX_RECURSION_DEPTH 500
123 #elif defined(_WIN32)
124 /* Windows typically limits stack size to 1MB. */
125 #define XPATH_MAX_RECURSION_DEPTH 1000
126 #else
127 #define XPATH_MAX_RECURSION_DEPTH 5000
128 #endif
129 
130 /*
131  * TODO:
132  * There are a few spots where some tests are done which depend upon ascii
133  * data.  These should be enhanced for full UTF8 support (see particularly
134  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
135  */
136 
137 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
138 
139 /************************************************************************
140  *									*
141  *			Floating point stuff				*
142  *									*
143  ************************************************************************/
144 
145 double xmlXPathNAN = 0.0;
146 double xmlXPathPINF = 0.0;
147 double xmlXPathNINF = 0.0;
148 
149 /**
150  * xmlXPathInit:
151  *
152  * DEPRECATED: Alias for xmlInitParser.
153  */
154 void
xmlXPathInit(void)155 xmlXPathInit(void) {
156     xmlInitParser();
157 }
158 
159 /**
160  * xmlInitXPathInternal:
161  *
162  * Initialize the XPath environment
163  */
164 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
165 void
xmlInitXPathInternal(void)166 xmlInitXPathInternal(void) {
167 #if defined(NAN) && defined(INFINITY)
168     xmlXPathNAN = NAN;
169     xmlXPathPINF = INFINITY;
170     xmlXPathNINF = -INFINITY;
171 #else
172     /* MSVC doesn't allow division by zero in constant expressions. */
173     double zero = 0.0;
174     xmlXPathNAN = 0.0 / zero;
175     xmlXPathPINF = 1.0 / zero;
176     xmlXPathNINF = -xmlXPathPINF;
177 #endif
178 }
179 
180 /**
181  * xmlXPathIsNaN:
182  * @val:  a double value
183  *
184  * Checks whether a double is a NaN.
185  *
186  * Returns 1 if the value is a NaN, 0 otherwise
187  */
188 int
xmlXPathIsNaN(double val)189 xmlXPathIsNaN(double val) {
190 #ifdef isnan
191     return isnan(val);
192 #else
193     return !(val == val);
194 #endif
195 }
196 
197 /**
198  * xmlXPathIsInf:
199  * @val:  a double value
200  *
201  * Checks whether a double is an infinity.
202  *
203  * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
204  */
205 int
xmlXPathIsInf(double val)206 xmlXPathIsInf(double val) {
207 #ifdef isinf
208     return isinf(val) ? (val > 0 ? 1 : -1) : 0;
209 #else
210     if (val >= xmlXPathPINF)
211         return 1;
212     if (val <= -xmlXPathPINF)
213         return -1;
214     return 0;
215 #endif
216 }
217 
218 #endif /* SCHEMAS or XPATH */
219 
220 #ifdef LIBXML_XPATH_ENABLED
221 
222 /*
223  * TODO: when compatibility allows remove all "fake node libxslt" strings
224  *       the test should just be name[0] = ' '
225  */
226 
227 static xmlNs xmlXPathXMLNamespaceStruct = {
228     NULL,
229     XML_NAMESPACE_DECL,
230     XML_XML_NAMESPACE,
231     BAD_CAST "xml",
232     NULL,
233     NULL
234 };
235 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
236 #ifndef LIBXML_THREAD_ENABLED
237 /*
238  * Optimizer is disabled only when threaded apps are detected while
239  * the library ain't compiled for thread safety.
240  */
241 static int xmlXPathDisableOptimizer = 0;
242 #endif
243 
244 static void
245 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes);
246 
247 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
248 /**
249  * xmlXPathCmpNodesExt:
250  * @node1:  the first node
251  * @node2:  the second node
252  *
253  * Compare two nodes w.r.t document order.
254  * This one is optimized for handling of non-element nodes.
255  *
256  * Returns -2 in case of error 1 if first point < second point, 0 if
257  *         it's the same node, -1 otherwise
258  */
259 static int
xmlXPathCmpNodesExt(xmlNodePtr node1,xmlNodePtr node2)260 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
261     int depth1, depth2;
262     int misc = 0, precedence1 = 0, precedence2 = 0;
263     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
264     xmlNodePtr cur, root;
265     ptrdiff_t l1, l2;
266 
267     if ((node1 == NULL) || (node2 == NULL))
268 	return(-2);
269 
270     if (node1 == node2)
271 	return(0);
272 
273     /*
274      * a couple of optimizations which will avoid computations in most cases
275      */
276     switch (node1->type) {
277 	case XML_ELEMENT_NODE:
278 	    if (node2->type == XML_ELEMENT_NODE) {
279 		if ((0 > (ptrdiff_t) node1->content) &&
280 		    (0 > (ptrdiff_t) node2->content) &&
281 		    (node1->doc == node2->doc))
282 		{
283 		    l1 = -((ptrdiff_t) node1->content);
284 		    l2 = -((ptrdiff_t) node2->content);
285 		    if (l1 < l2)
286 			return(1);
287 		    if (l1 > l2)
288 			return(-1);
289 		} else
290 		    goto turtle_comparison;
291 	    }
292 	    break;
293 	case XML_ATTRIBUTE_NODE:
294 	    precedence1 = 1; /* element is owner */
295 	    miscNode1 = node1;
296 	    node1 = node1->parent;
297 	    misc = 1;
298 	    break;
299 	case XML_TEXT_NODE:
300 	case XML_CDATA_SECTION_NODE:
301 	case XML_COMMENT_NODE:
302 	case XML_PI_NODE: {
303 	    miscNode1 = node1;
304 	    /*
305 	    * Find nearest element node.
306 	    */
307 	    if (node1->prev != NULL) {
308 		do {
309 		    node1 = node1->prev;
310 		    if (node1->type == XML_ELEMENT_NODE) {
311 			precedence1 = 3; /* element in prev-sibl axis */
312 			break;
313 		    }
314 		    if (node1->prev == NULL) {
315 			precedence1 = 2; /* element is parent */
316 			/*
317 			* URGENT TODO: Are there any cases, where the
318 			* parent of such a node is not an element node?
319 			*/
320 			node1 = node1->parent;
321 			break;
322 		    }
323 		} while (1);
324 	    } else {
325 		precedence1 = 2; /* element is parent */
326 		node1 = node1->parent;
327 	    }
328 	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
329 		(0 <= (ptrdiff_t) node1->content)) {
330 		/*
331 		* Fallback for whatever case.
332 		*/
333 		node1 = miscNode1;
334 		precedence1 = 0;
335 	    } else
336 		misc = 1;
337 	}
338 	    break;
339 	case XML_NAMESPACE_DECL:
340 	    /*
341 	    * TODO: why do we return 1 for namespace nodes?
342 	    */
343 	    return(1);
344 	default:
345 	    break;
346     }
347     switch (node2->type) {
348 	case XML_ELEMENT_NODE:
349 	    break;
350 	case XML_ATTRIBUTE_NODE:
351 	    precedence2 = 1; /* element is owner */
352 	    miscNode2 = node2;
353 	    node2 = node2->parent;
354 	    misc = 1;
355 	    break;
356 	case XML_TEXT_NODE:
357 	case XML_CDATA_SECTION_NODE:
358 	case XML_COMMENT_NODE:
359 	case XML_PI_NODE: {
360 	    miscNode2 = node2;
361 	    if (node2->prev != NULL) {
362 		do {
363 		    node2 = node2->prev;
364 		    if (node2->type == XML_ELEMENT_NODE) {
365 			precedence2 = 3; /* element in prev-sibl axis */
366 			break;
367 		    }
368 		    if (node2->prev == NULL) {
369 			precedence2 = 2; /* element is parent */
370 			node2 = node2->parent;
371 			break;
372 		    }
373 		} while (1);
374 	    } else {
375 		precedence2 = 2; /* element is parent */
376 		node2 = node2->parent;
377 	    }
378 	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
379 		(0 <= (ptrdiff_t) node2->content))
380 	    {
381 		node2 = miscNode2;
382 		precedence2 = 0;
383 	    } else
384 		misc = 1;
385 	}
386 	    break;
387 	case XML_NAMESPACE_DECL:
388 	    return(1);
389 	default:
390 	    break;
391     }
392     if (misc) {
393 	if (node1 == node2) {
394 	    if (precedence1 == precedence2) {
395 		/*
396 		* The ugly case; but normally there aren't many
397 		* adjacent non-element nodes around.
398 		*/
399 		cur = miscNode2->prev;
400 		while (cur != NULL) {
401 		    if (cur == miscNode1)
402 			return(1);
403 		    if (cur->type == XML_ELEMENT_NODE)
404 			return(-1);
405 		    cur = cur->prev;
406 		}
407 		return (-1);
408 	    } else {
409 		/*
410 		* Evaluate based on higher precedence wrt to the element.
411 		* TODO: This assumes attributes are sorted before content.
412 		*   Is this 100% correct?
413 		*/
414 		if (precedence1 < precedence2)
415 		    return(1);
416 		else
417 		    return(-1);
418 	    }
419 	}
420 	/*
421 	* Special case: One of the helper-elements is contained by the other.
422 	* <foo>
423 	*   <node2>
424 	*     <node1>Text-1(precedence1 == 2)</node1>
425 	*   </node2>
426 	*   Text-6(precedence2 == 3)
427 	* </foo>
428 	*/
429 	if ((precedence2 == 3) && (precedence1 > 1)) {
430 	    cur = node1->parent;
431 	    while (cur) {
432 		if (cur == node2)
433 		    return(1);
434 		cur = cur->parent;
435 	    }
436 	}
437 	if ((precedence1 == 3) && (precedence2 > 1)) {
438 	    cur = node2->parent;
439 	    while (cur) {
440 		if (cur == node1)
441 		    return(-1);
442 		cur = cur->parent;
443 	    }
444 	}
445     }
446 
447     /*
448      * Speedup using document order if available.
449      */
450     if ((node1->type == XML_ELEMENT_NODE) &&
451 	(node2->type == XML_ELEMENT_NODE) &&
452 	(0 > (ptrdiff_t) node1->content) &&
453 	(0 > (ptrdiff_t) node2->content) &&
454 	(node1->doc == node2->doc)) {
455 
456 	l1 = -((ptrdiff_t) node1->content);
457 	l2 = -((ptrdiff_t) node2->content);
458 	if (l1 < l2)
459 	    return(1);
460 	if (l1 > l2)
461 	    return(-1);
462     }
463 
464 turtle_comparison:
465 
466     if (node1 == node2->prev)
467 	return(1);
468     if (node1 == node2->next)
469 	return(-1);
470     /*
471      * compute depth to root
472      */
473     for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
474 	if (cur->parent == node1)
475 	    return(1);
476 	depth2++;
477     }
478     root = cur;
479     for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
480 	if (cur->parent == node2)
481 	    return(-1);
482 	depth1++;
483     }
484     /*
485      * Distinct document (or distinct entities :-( ) case.
486      */
487     if (root != cur) {
488 	return(-2);
489     }
490     /*
491      * get the nearest common ancestor.
492      */
493     while (depth1 > depth2) {
494 	depth1--;
495 	node1 = node1->parent;
496     }
497     while (depth2 > depth1) {
498 	depth2--;
499 	node2 = node2->parent;
500     }
501     while (node1->parent != node2->parent) {
502 	node1 = node1->parent;
503 	node2 = node2->parent;
504 	/* should not happen but just in case ... */
505 	if ((node1 == NULL) || (node2 == NULL))
506 	    return(-2);
507     }
508     /*
509      * Find who's first.
510      */
511     if (node1 == node2->prev)
512 	return(1);
513     if (node1 == node2->next)
514 	return(-1);
515     /*
516      * Speedup using document order if available.
517      */
518     if ((node1->type == XML_ELEMENT_NODE) &&
519 	(node2->type == XML_ELEMENT_NODE) &&
520 	(0 > (ptrdiff_t) node1->content) &&
521 	(0 > (ptrdiff_t) node2->content) &&
522 	(node1->doc == node2->doc)) {
523 
524 	l1 = -((ptrdiff_t) node1->content);
525 	l2 = -((ptrdiff_t) node2->content);
526 	if (l1 < l2)
527 	    return(1);
528 	if (l1 > l2)
529 	    return(-1);
530     }
531 
532     for (cur = node1->next;cur != NULL;cur = cur->next)
533 	if (cur == node2)
534 	    return(1);
535     return(-1); /* assume there is no sibling list corruption */
536 }
537 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
538 
539 /*
540  * Wrapper for the Timsort algorithm from timsort.h
541  */
542 #ifdef WITH_TIM_SORT
543 #define SORT_NAME libxml_domnode
544 #define SORT_TYPE xmlNodePtr
545 /**
546  * wrap_cmp:
547  * @x: a node
548  * @y: another node
549  *
550  * Comparison function for the Timsort implementation
551  *
552  * Returns -2 in case of error -1 if first point < second point, 0 if
553  *         it's the same node, +1 otherwise
554  */
555 static
556 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
557 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
wrap_cmp(xmlNodePtr x,xmlNodePtr y)558     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
559     {
560         int res = xmlXPathCmpNodesExt(x, y);
561         return res == -2 ? res : -res;
562     }
563 #else
wrap_cmp(xmlNodePtr x,xmlNodePtr y)564     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
565     {
566         int res = xmlXPathCmpNodes(x, y);
567         return res == -2 ? res : -res;
568     }
569 #endif
570 #define SORT_CMP(x, y)  (wrap_cmp(x, y))
571 #include "timsort.h"
572 #endif /* WITH_TIM_SORT */
573 
574 /************************************************************************
575  *									*
576  *			Error handling routines				*
577  *									*
578  ************************************************************************/
579 
580 /**
581  * XP_ERRORNULL:
582  * @X:  the error code
583  *
584  * Macro to raise an XPath error and return NULL.
585  */
586 #define XP_ERRORNULL(X)							\
587     { xmlXPathErr(ctxt, X); return(NULL); }
588 
589 /*
590  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
591  */
592 static const char* const xmlXPathErrorMessages[] = {
593     "Ok\n",
594     "Number encoding\n",
595     "Unfinished literal\n",
596     "Start of literal\n",
597     "Expected $ for variable reference\n",
598     "Undefined variable\n",
599     "Invalid predicate\n",
600     "Invalid expression\n",
601     "Missing closing curly brace\n",
602     "Unregistered function\n",
603     "Invalid operand\n",
604     "Invalid type\n",
605     "Invalid number of arguments\n",
606     "Invalid context size\n",
607     "Invalid context position\n",
608     "Memory allocation error\n",
609     "Syntax error\n",
610     "Resource error\n",
611     "Sub resource error\n",
612     "Undefined namespace prefix\n",
613     "Encoding error\n",
614     "Char out of XML range\n",
615     "Invalid or incomplete context\n",
616     "Stack usage error\n",
617     "Forbidden variable\n",
618     "Operation limit exceeded\n",
619     "Recursion limit exceeded\n",
620     "?? Unknown error ??\n"	/* Must be last in the list! */
621 };
622 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
623 		   sizeof(xmlXPathErrorMessages[0])) - 1)
624 /**
625  * xmlXPathErrMemory:
626  * @ctxt:  an XPath context
627  * @extra:  extra information
628  *
629  * Handle a memory allocation failure.
630  */
631 void
xmlXPathErrMemory(xmlXPathContextPtr ctxt)632 xmlXPathErrMemory(xmlXPathContextPtr ctxt)
633 {
634     if (ctxt == NULL)
635         return;
636     xmlRaiseMemoryError(ctxt->error, NULL, ctxt->userData, XML_FROM_XPATH,
637                         &ctxt->lastError);
638 }
639 
640 /**
641  * xmlXPathPErrMemory:
642  * @ctxt:  an XPath parser context
643  * @extra:  extra information
644  *
645  * Handle a memory allocation failure.
646  */
647 void
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt)648 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt)
649 {
650     if (ctxt == NULL)
651         return;
652     ctxt->error = XPATH_MEMORY_ERROR;
653     xmlXPathErrMemory(ctxt->context);
654 }
655 
656 /**
657  * xmlXPathErr:
658  * @ctxt:  a XPath parser context
659  * @error:  the error code
660  *
661  * Handle an XPath error
662  */
663 void
xmlXPathErr(xmlXPathParserContextPtr ctxt,int code)664 xmlXPathErr(xmlXPathParserContextPtr ctxt, int code)
665 {
666     xmlStructuredErrorFunc schannel = NULL;
667     xmlGenericErrorFunc channel = NULL;
668     void *data = NULL;
669     xmlNodePtr node = NULL;
670     int res;
671 
672     if (ctxt == NULL)
673         return;
674     if ((code < 0) || (code > MAXERRNO))
675 	code = MAXERRNO;
676     /* Only report the first error */
677     if (ctxt->error != 0)
678         return;
679 
680     ctxt->error = code;
681 
682     if (ctxt->context != NULL) {
683         xmlErrorPtr err = &ctxt->context->lastError;
684 
685         /* Don't overwrite memory error. */
686         if (err->code == XML_ERR_NO_MEMORY)
687             return;
688 
689         /* cleanup current last error */
690         xmlResetError(err);
691 
692         err->domain = XML_FROM_XPATH;
693         err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK;
694         err->level = XML_ERR_ERROR;
695         if (ctxt->base != NULL) {
696             err->str1 = (char *) xmlStrdup(ctxt->base);
697             if (err->str1 == NULL) {
698                 xmlXPathPErrMemory(ctxt);
699                 return;
700             }
701         }
702         err->int1 = ctxt->cur - ctxt->base;
703         err->node = ctxt->context->debugNode;
704 
705         schannel = ctxt->context->error;
706         data = ctxt->context->userData;
707         node = ctxt->context->debugNode;
708     }
709 
710     if (schannel == NULL) {
711         channel = xmlGenericError;
712         data = xmlGenericErrorContext;
713     }
714 
715     res = __xmlRaiseError(schannel, channel, data, NULL, node, XML_FROM_XPATH,
716                           code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
717                           XML_ERR_ERROR, NULL, 0,
718                           (const char *) ctxt->base, NULL, NULL,
719                           ctxt->cur - ctxt->base, 0,
720                           "%s", xmlXPathErrorMessages[code]);
721     if (res < 0)
722         xmlXPathPErrMemory(ctxt);
723 }
724 
725 /**
726  * xmlXPatherror:
727  * @ctxt:  the XPath Parser context
728  * @file:  the file name
729  * @line:  the line number
730  * @no:  the error number
731  *
732  * Formats an error message.
733  */
734 void
xmlXPatherror(xmlXPathParserContextPtr ctxt,const char * file ATTRIBUTE_UNUSED,int line ATTRIBUTE_UNUSED,int no)735 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
736               int line ATTRIBUTE_UNUSED, int no) {
737     xmlXPathErr(ctxt, no);
738 }
739 
740 /**
741  * xmlXPathCheckOpLimit:
742  * @ctxt:  the XPath Parser context
743  * @opCount:  the number of operations to be added
744  *
745  * Adds opCount to the running total of operations and returns -1 if the
746  * operation limit is exceeded. Returns 0 otherwise.
747  */
748 static int
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt,unsigned long opCount)749 xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
750     xmlXPathContextPtr xpctxt = ctxt->context;
751 
752     if ((opCount > xpctxt->opLimit) ||
753         (xpctxt->opCount > xpctxt->opLimit - opCount)) {
754         xpctxt->opCount = xpctxt->opLimit;
755         xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
756         return(-1);
757     }
758 
759     xpctxt->opCount += opCount;
760     return(0);
761 }
762 
763 #define OP_LIMIT_EXCEEDED(ctxt, n) \
764     ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
765 
766 /************************************************************************
767  *									*
768  *			Parser Types					*
769  *									*
770  ************************************************************************/
771 
772 /*
773  * Types are private:
774  */
775 
776 typedef enum {
777     XPATH_OP_END=0,
778     XPATH_OP_AND,
779     XPATH_OP_OR,
780     XPATH_OP_EQUAL,
781     XPATH_OP_CMP,
782     XPATH_OP_PLUS,
783     XPATH_OP_MULT,
784     XPATH_OP_UNION,
785     XPATH_OP_ROOT,
786     XPATH_OP_NODE,
787     XPATH_OP_COLLECT,
788     XPATH_OP_VALUE, /* 11 */
789     XPATH_OP_VARIABLE,
790     XPATH_OP_FUNCTION,
791     XPATH_OP_ARG,
792     XPATH_OP_PREDICATE,
793     XPATH_OP_FILTER, /* 16 */
794     XPATH_OP_SORT /* 17 */
795 #ifdef LIBXML_XPTR_LOCS_ENABLED
796     ,XPATH_OP_RANGETO
797 #endif
798 } xmlXPathOp;
799 
800 typedef enum {
801     AXIS_ANCESTOR = 1,
802     AXIS_ANCESTOR_OR_SELF,
803     AXIS_ATTRIBUTE,
804     AXIS_CHILD,
805     AXIS_DESCENDANT,
806     AXIS_DESCENDANT_OR_SELF,
807     AXIS_FOLLOWING,
808     AXIS_FOLLOWING_SIBLING,
809     AXIS_NAMESPACE,
810     AXIS_PARENT,
811     AXIS_PRECEDING,
812     AXIS_PRECEDING_SIBLING,
813     AXIS_SELF
814 } xmlXPathAxisVal;
815 
816 typedef enum {
817     NODE_TEST_NONE = 0,
818     NODE_TEST_TYPE = 1,
819     NODE_TEST_PI = 2,
820     NODE_TEST_ALL = 3,
821     NODE_TEST_NS = 4,
822     NODE_TEST_NAME = 5
823 } xmlXPathTestVal;
824 
825 typedef enum {
826     NODE_TYPE_NODE = 0,
827     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
828     NODE_TYPE_TEXT = XML_TEXT_NODE,
829     NODE_TYPE_PI = XML_PI_NODE
830 } xmlXPathTypeVal;
831 
832 typedef struct _xmlXPathStepOp xmlXPathStepOp;
833 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
834 struct _xmlXPathStepOp {
835     xmlXPathOp op;		/* The identifier of the operation */
836     int ch1;			/* First child */
837     int ch2;			/* Second child */
838     int value;
839     int value2;
840     int value3;
841     void *value4;
842     void *value5;
843     xmlXPathFunction cache;
844     void *cacheURI;
845 };
846 
847 struct _xmlXPathCompExpr {
848     int nbStep;			/* Number of steps in this expression */
849     int maxStep;		/* Maximum number of steps allocated */
850     xmlXPathStepOp *steps;	/* ops for computation of this expression */
851     int last;			/* index of last step in expression */
852     xmlChar *expr;		/* the expression being computed */
853     xmlDictPtr dict;		/* the dictionary to use if any */
854 #ifdef XPATH_STREAMING
855     xmlPatternPtr stream;
856 #endif
857 };
858 
859 /************************************************************************
860  *									*
861  *			Forward declarations				*
862  *									*
863  ************************************************************************/
864 
865 static void
866 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
867 static int
868 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
869                         xmlXPathStepOpPtr op, xmlNodePtr *first);
870 static int
871 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
872 			    xmlXPathStepOpPtr op,
873 			    int isPredicate);
874 static void
875 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
876 
877 /************************************************************************
878  *									*
879  *			Parser Type functions				*
880  *									*
881  ************************************************************************/
882 
883 /**
884  * xmlXPathNewCompExpr:
885  *
886  * Create a new Xpath component
887  *
888  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
889  */
890 static xmlXPathCompExprPtr
xmlXPathNewCompExpr(void)891 xmlXPathNewCompExpr(void) {
892     xmlXPathCompExprPtr cur;
893 
894     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
895     if (cur == NULL)
896 	return(NULL);
897     memset(cur, 0, sizeof(xmlXPathCompExpr));
898     cur->maxStep = 10;
899     cur->nbStep = 0;
900     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
901 	                                   sizeof(xmlXPathStepOp));
902     if (cur->steps == NULL) {
903 	xmlFree(cur);
904 	return(NULL);
905     }
906     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
907     cur->last = -1;
908     return(cur);
909 }
910 
911 /**
912  * xmlXPathFreeCompExpr:
913  * @comp:  an XPATH comp
914  *
915  * Free up the memory allocated by @comp
916  */
917 void
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)918 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
919 {
920     xmlXPathStepOpPtr op;
921     int i;
922 
923     if (comp == NULL)
924         return;
925     if (comp->dict == NULL) {
926 	for (i = 0; i < comp->nbStep; i++) {
927 	    op = &comp->steps[i];
928 	    if (op->value4 != NULL) {
929 		if (op->op == XPATH_OP_VALUE)
930 		    xmlXPathFreeObject(op->value4);
931 		else
932 		    xmlFree(op->value4);
933 	    }
934 	    if (op->value5 != NULL)
935 		xmlFree(op->value5);
936 	}
937     } else {
938 	for (i = 0; i < comp->nbStep; i++) {
939 	    op = &comp->steps[i];
940 	    if (op->value4 != NULL) {
941 		if (op->op == XPATH_OP_VALUE)
942 		    xmlXPathFreeObject(op->value4);
943 	    }
944 	}
945         xmlDictFree(comp->dict);
946     }
947     if (comp->steps != NULL) {
948         xmlFree(comp->steps);
949     }
950 #ifdef XPATH_STREAMING
951     if (comp->stream != NULL) {
952         xmlFreePatternList(comp->stream);
953     }
954 #endif
955     if (comp->expr != NULL) {
956         xmlFree(comp->expr);
957     }
958 
959     xmlFree(comp);
960 }
961 
962 /**
963  * xmlXPathCompExprAdd:
964  * @comp:  the compiled expression
965  * @ch1: first child index
966  * @ch2: second child index
967  * @op:  an op
968  * @value:  the first int value
969  * @value2:  the second int value
970  * @value3:  the third int value
971  * @value4:  the first string value
972  * @value5:  the second string value
973  *
974  * Add a step to an XPath Compiled Expression
975  *
976  * Returns -1 in case of failure, the index otherwise
977  */
978 static int
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt,int ch1,int ch2,xmlXPathOp op,int value,int value2,int value3,void * value4,void * value5)979 xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
980    xmlXPathOp op, int value,
981    int value2, int value3, void *value4, void *value5) {
982     xmlXPathCompExprPtr comp = ctxt->comp;
983     if (comp->nbStep >= comp->maxStep) {
984 	xmlXPathStepOp *real;
985 
986         if (comp->maxStep >= XPATH_MAX_STEPS) {
987 	    xmlXPathPErrMemory(ctxt);
988 	    return(-1);
989         }
990 	comp->maxStep *= 2;
991 	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
992 		                      comp->maxStep * sizeof(xmlXPathStepOp));
993 	if (real == NULL) {
994 	    comp->maxStep /= 2;
995 	    xmlXPathPErrMemory(ctxt);
996 	    return(-1);
997 	}
998 	comp->steps = real;
999     }
1000     comp->last = comp->nbStep;
1001     comp->steps[comp->nbStep].ch1 = ch1;
1002     comp->steps[comp->nbStep].ch2 = ch2;
1003     comp->steps[comp->nbStep].op = op;
1004     comp->steps[comp->nbStep].value = value;
1005     comp->steps[comp->nbStep].value2 = value2;
1006     comp->steps[comp->nbStep].value3 = value3;
1007     if ((comp->dict != NULL) &&
1008         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1009 	 (op == XPATH_OP_COLLECT))) {
1010         if (value4 != NULL) {
1011 	    comp->steps[comp->nbStep].value4 = (xmlChar *)
1012 	        (void *)xmlDictLookup(comp->dict, value4, -1);
1013 	    xmlFree(value4);
1014 	} else
1015 	    comp->steps[comp->nbStep].value4 = NULL;
1016         if (value5 != NULL) {
1017 	    comp->steps[comp->nbStep].value5 = (xmlChar *)
1018 	        (void *)xmlDictLookup(comp->dict, value5, -1);
1019 	    xmlFree(value5);
1020 	} else
1021 	    comp->steps[comp->nbStep].value5 = NULL;
1022     } else {
1023 	comp->steps[comp->nbStep].value4 = value4;
1024 	comp->steps[comp->nbStep].value5 = value5;
1025     }
1026     comp->steps[comp->nbStep].cache = NULL;
1027     return(comp->nbStep++);
1028 }
1029 
1030 /**
1031  * xmlXPathCompSwap:
1032  * @comp:  the compiled expression
1033  * @op: operation index
1034  *
1035  * Swaps 2 operations in the compiled expression
1036  */
1037 static void
xmlXPathCompSwap(xmlXPathStepOpPtr op)1038 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1039     int tmp;
1040 
1041 #ifndef LIBXML_THREAD_ENABLED
1042     /*
1043      * Since this manipulates possibly shared variables, this is
1044      * disabled if one detects that the library is used in a multithreaded
1045      * application
1046      */
1047     if (xmlXPathDisableOptimizer)
1048 	return;
1049 #endif
1050 
1051     tmp = op->ch1;
1052     op->ch1 = op->ch2;
1053     op->ch2 = tmp;
1054 }
1055 
1056 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
1057     xmlXPathCompExprAdd(ctxt, (op1), (op2),			\
1058 	                (op), (val), (val2), (val3), (val4), (val5))
1059 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
1060     xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,		\
1061 	                (op), (val), (val2), (val3), (val4), (val5))
1062 
1063 #define PUSH_LEAVE_EXPR(op, val, val2)					\
1064 xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1065 
1066 #define PUSH_UNARY_EXPR(op, ch, val, val2)				\
1067 xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1068 
1069 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
1070 xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),			\
1071 			(val), (val2), 0 ,NULL ,NULL)
1072 
1073 /************************************************************************
1074  *									*
1075  *		XPath object cache structures				*
1076  *									*
1077  ************************************************************************/
1078 
1079 /* #define XP_DEFAULT_CACHE_ON */
1080 
1081 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1082 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1083 struct _xmlXPathContextCache {
1084     xmlXPathObjectPtr nodesetObjs;  /* stringval points to next */
1085     xmlXPathObjectPtr miscObjs;     /* stringval points to next */
1086     int numNodeset;
1087     int maxNodeset;
1088     int numMisc;
1089     int maxMisc;
1090 };
1091 
1092 /************************************************************************
1093  *									*
1094  *		Debugging related functions				*
1095  *									*
1096  ************************************************************************/
1097 
1098 #ifdef LIBXML_DEBUG_ENABLED
1099 static void
xmlXPathDebugDumpNode(FILE * output,xmlNodePtr cur,int depth)1100 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1101     int i;
1102     char shift[100];
1103 
1104     for (i = 0;((i < depth) && (i < 25));i++)
1105         shift[2 * i] = shift[2 * i + 1] = ' ';
1106     shift[2 * i] = shift[2 * i + 1] = 0;
1107     if (cur == NULL) {
1108 	fprintf(output, "%s", shift);
1109 	fprintf(output, "Node is NULL !\n");
1110 	return;
1111 
1112     }
1113 
1114     if ((cur->type == XML_DOCUMENT_NODE) ||
1115 	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
1116 	fprintf(output, "%s", shift);
1117 	fprintf(output, " /\n");
1118     } else if (cur->type == XML_ATTRIBUTE_NODE)
1119 	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1120     else
1121 	xmlDebugDumpOneNode(output, cur, depth);
1122 }
1123 static void
xmlXPathDebugDumpNodeList(FILE * output,xmlNodePtr cur,int depth)1124 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1125     xmlNodePtr tmp;
1126     int i;
1127     char shift[100];
1128 
1129     for (i = 0;((i < depth) && (i < 25));i++)
1130         shift[2 * i] = shift[2 * i + 1] = ' ';
1131     shift[2 * i] = shift[2 * i + 1] = 0;
1132     if (cur == NULL) {
1133 	fprintf(output, "%s", shift);
1134 	fprintf(output, "Node is NULL !\n");
1135 	return;
1136 
1137     }
1138 
1139     while (cur != NULL) {
1140 	tmp = cur;
1141 	cur = cur->next;
1142 	xmlDebugDumpOneNode(output, tmp, depth);
1143     }
1144 }
1145 
1146 static void
xmlXPathDebugDumpNodeSet(FILE * output,xmlNodeSetPtr cur,int depth)1147 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1148     int i;
1149     char shift[100];
1150 
1151     for (i = 0;((i < depth) && (i < 25));i++)
1152         shift[2 * i] = shift[2 * i + 1] = ' ';
1153     shift[2 * i] = shift[2 * i + 1] = 0;
1154 
1155     if (cur == NULL) {
1156 	fprintf(output, "%s", shift);
1157 	fprintf(output, "NodeSet is NULL !\n");
1158 	return;
1159 
1160     }
1161 
1162     if (cur != NULL) {
1163 	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1164 	for (i = 0;i < cur->nodeNr;i++) {
1165 	    fprintf(output, "%s", shift);
1166 	    fprintf(output, "%d", i + 1);
1167 	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1168 	}
1169     }
1170 }
1171 
1172 static void
xmlXPathDebugDumpValueTree(FILE * output,xmlNodeSetPtr cur,int depth)1173 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1174     int i;
1175     char shift[100];
1176 
1177     for (i = 0;((i < depth) && (i < 25));i++)
1178         shift[2 * i] = shift[2 * i + 1] = ' ';
1179     shift[2 * i] = shift[2 * i + 1] = 0;
1180 
1181     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1182 	fprintf(output, "%s", shift);
1183 	fprintf(output, "Value Tree is NULL !\n");
1184 	return;
1185 
1186     }
1187 
1188     fprintf(output, "%s", shift);
1189     fprintf(output, "%d", i + 1);
1190     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1191 }
1192 #if defined(LIBXML_XPTR_LOCS_ENABLED)
1193 static void
xmlXPathDebugDumpLocationSet(FILE * output,xmlLocationSetPtr cur,int depth)1194 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1195     int i;
1196     char shift[100];
1197 
1198     for (i = 0;((i < depth) && (i < 25));i++)
1199         shift[2 * i] = shift[2 * i + 1] = ' ';
1200     shift[2 * i] = shift[2 * i + 1] = 0;
1201 
1202     if (cur == NULL) {
1203 	fprintf(output, "%s", shift);
1204 	fprintf(output, "LocationSet is NULL !\n");
1205 	return;
1206 
1207     }
1208 
1209     for (i = 0;i < cur->locNr;i++) {
1210 	fprintf(output, "%s", shift);
1211         fprintf(output, "%d : ", i + 1);
1212 	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1213     }
1214 }
1215 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1216 
1217 /**
1218  * xmlXPathDebugDumpObject:
1219  * @output:  the FILE * to dump the output
1220  * @cur:  the object to inspect
1221  * @depth:  indentation level
1222  *
1223  * Dump the content of the object for debugging purposes
1224  */
1225 void
xmlXPathDebugDumpObject(FILE * output,xmlXPathObjectPtr cur,int depth)1226 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1227     int i;
1228     char shift[100];
1229 
1230     if (output == NULL) return;
1231 
1232     for (i = 0;((i < depth) && (i < 25));i++)
1233         shift[2 * i] = shift[2 * i + 1] = ' ';
1234     shift[2 * i] = shift[2 * i + 1] = 0;
1235 
1236 
1237     fprintf(output, "%s", shift);
1238 
1239     if (cur == NULL) {
1240         fprintf(output, "Object is empty (NULL)\n");
1241 	return;
1242     }
1243     switch(cur->type) {
1244         case XPATH_UNDEFINED:
1245 	    fprintf(output, "Object is uninitialized\n");
1246 	    break;
1247         case XPATH_NODESET:
1248 	    fprintf(output, "Object is a Node Set :\n");
1249 	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1250 	    break;
1251 	case XPATH_XSLT_TREE:
1252 	    fprintf(output, "Object is an XSLT value tree :\n");
1253 	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1254 	    break;
1255         case XPATH_BOOLEAN:
1256 	    fprintf(output, "Object is a Boolean : ");
1257 	    if (cur->boolval) fprintf(output, "true\n");
1258 	    else fprintf(output, "false\n");
1259 	    break;
1260         case XPATH_NUMBER:
1261 	    switch (xmlXPathIsInf(cur->floatval)) {
1262 	    case 1:
1263 		fprintf(output, "Object is a number : Infinity\n");
1264 		break;
1265 	    case -1:
1266 		fprintf(output, "Object is a number : -Infinity\n");
1267 		break;
1268 	    default:
1269 		if (xmlXPathIsNaN(cur->floatval)) {
1270 		    fprintf(output, "Object is a number : NaN\n");
1271 		} else if (cur->floatval == 0) {
1272                     /* Omit sign for negative zero. */
1273 		    fprintf(output, "Object is a number : 0\n");
1274 		} else {
1275 		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
1276 		}
1277 	    }
1278 	    break;
1279         case XPATH_STRING:
1280 	    fprintf(output, "Object is a string : ");
1281 	    xmlDebugDumpString(output, cur->stringval);
1282 	    fprintf(output, "\n");
1283 	    break;
1284 #ifdef LIBXML_XPTR_LOCS_ENABLED
1285 	case XPATH_POINT:
1286 	    fprintf(output, "Object is a point : index %d in node", cur->index);
1287 	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1288 	    fprintf(output, "\n");
1289 	    break;
1290 	case XPATH_RANGE:
1291 	    if ((cur->user2 == NULL) ||
1292 		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1293 		fprintf(output, "Object is a collapsed range :\n");
1294 		fprintf(output, "%s", shift);
1295 		if (cur->index >= 0)
1296 		    fprintf(output, "index %d in ", cur->index);
1297 		fprintf(output, "node\n");
1298 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1299 			              depth + 1);
1300 	    } else  {
1301 		fprintf(output, "Object is a range :\n");
1302 		fprintf(output, "%s", shift);
1303 		fprintf(output, "From ");
1304 		if (cur->index >= 0)
1305 		    fprintf(output, "index %d in ", cur->index);
1306 		fprintf(output, "node\n");
1307 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1308 			              depth + 1);
1309 		fprintf(output, "%s", shift);
1310 		fprintf(output, "To ");
1311 		if (cur->index2 >= 0)
1312 		    fprintf(output, "index %d in ", cur->index2);
1313 		fprintf(output, "node\n");
1314 		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1315 			              depth + 1);
1316 		fprintf(output, "\n");
1317 	    }
1318 	    break;
1319 	case XPATH_LOCATIONSET:
1320 	    fprintf(output, "Object is a Location Set:\n");
1321 	    xmlXPathDebugDumpLocationSet(output,
1322 		    (xmlLocationSetPtr) cur->user, depth);
1323 	    break;
1324 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1325 	case XPATH_USERS:
1326 	    fprintf(output, "Object is user defined\n");
1327 	    break;
1328     }
1329 }
1330 
1331 static void
xmlXPathDebugDumpStepOp(FILE * output,xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op,int depth)1332 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1333 	                     xmlXPathStepOpPtr op, int depth) {
1334     int i;
1335     char shift[100];
1336 
1337     for (i = 0;((i < depth) && (i < 25));i++)
1338         shift[2 * i] = shift[2 * i + 1] = ' ';
1339     shift[2 * i] = shift[2 * i + 1] = 0;
1340 
1341     fprintf(output, "%s", shift);
1342     if (op == NULL) {
1343 	fprintf(output, "Step is NULL\n");
1344 	return;
1345     }
1346     switch (op->op) {
1347         case XPATH_OP_END:
1348 	    fprintf(output, "END"); break;
1349         case XPATH_OP_AND:
1350 	    fprintf(output, "AND"); break;
1351         case XPATH_OP_OR:
1352 	    fprintf(output, "OR"); break;
1353         case XPATH_OP_EQUAL:
1354 	     if (op->value)
1355 		 fprintf(output, "EQUAL =");
1356 	     else
1357 		 fprintf(output, "EQUAL !=");
1358 	     break;
1359         case XPATH_OP_CMP:
1360 	     if (op->value)
1361 		 fprintf(output, "CMP <");
1362 	     else
1363 		 fprintf(output, "CMP >");
1364 	     if (!op->value2)
1365 		 fprintf(output, "=");
1366 	     break;
1367         case XPATH_OP_PLUS:
1368 	     if (op->value == 0)
1369 		 fprintf(output, "PLUS -");
1370 	     else if (op->value == 1)
1371 		 fprintf(output, "PLUS +");
1372 	     else if (op->value == 2)
1373 		 fprintf(output, "PLUS unary -");
1374 	     else if (op->value == 3)
1375 		 fprintf(output, "PLUS unary - -");
1376 	     break;
1377         case XPATH_OP_MULT:
1378 	     if (op->value == 0)
1379 		 fprintf(output, "MULT *");
1380 	     else if (op->value == 1)
1381 		 fprintf(output, "MULT div");
1382 	     else
1383 		 fprintf(output, "MULT mod");
1384 	     break;
1385         case XPATH_OP_UNION:
1386 	     fprintf(output, "UNION"); break;
1387         case XPATH_OP_ROOT:
1388 	     fprintf(output, "ROOT"); break;
1389         case XPATH_OP_NODE:
1390 	     fprintf(output, "NODE"); break;
1391         case XPATH_OP_SORT:
1392 	     fprintf(output, "SORT"); break;
1393         case XPATH_OP_COLLECT: {
1394 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1395 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1396 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1397 	    const xmlChar *prefix = op->value4;
1398 	    const xmlChar *name = op->value5;
1399 
1400 	    fprintf(output, "COLLECT ");
1401 	    switch (axis) {
1402 		case AXIS_ANCESTOR:
1403 		    fprintf(output, " 'ancestors' "); break;
1404 		case AXIS_ANCESTOR_OR_SELF:
1405 		    fprintf(output, " 'ancestors-or-self' "); break;
1406 		case AXIS_ATTRIBUTE:
1407 		    fprintf(output, " 'attributes' "); break;
1408 		case AXIS_CHILD:
1409 		    fprintf(output, " 'child' "); break;
1410 		case AXIS_DESCENDANT:
1411 		    fprintf(output, " 'descendant' "); break;
1412 		case AXIS_DESCENDANT_OR_SELF:
1413 		    fprintf(output, " 'descendant-or-self' "); break;
1414 		case AXIS_FOLLOWING:
1415 		    fprintf(output, " 'following' "); break;
1416 		case AXIS_FOLLOWING_SIBLING:
1417 		    fprintf(output, " 'following-siblings' "); break;
1418 		case AXIS_NAMESPACE:
1419 		    fprintf(output, " 'namespace' "); break;
1420 		case AXIS_PARENT:
1421 		    fprintf(output, " 'parent' "); break;
1422 		case AXIS_PRECEDING:
1423 		    fprintf(output, " 'preceding' "); break;
1424 		case AXIS_PRECEDING_SIBLING:
1425 		    fprintf(output, " 'preceding-sibling' "); break;
1426 		case AXIS_SELF:
1427 		    fprintf(output, " 'self' "); break;
1428 	    }
1429 	    switch (test) {
1430                 case NODE_TEST_NONE:
1431 		    fprintf(output, "'none' "); break;
1432                 case NODE_TEST_TYPE:
1433 		    fprintf(output, "'type' "); break;
1434                 case NODE_TEST_PI:
1435 		    fprintf(output, "'PI' "); break;
1436                 case NODE_TEST_ALL:
1437 		    fprintf(output, "'all' "); break;
1438                 case NODE_TEST_NS:
1439 		    fprintf(output, "'namespace' "); break;
1440                 case NODE_TEST_NAME:
1441 		    fprintf(output, "'name' "); break;
1442 	    }
1443 	    switch (type) {
1444                 case NODE_TYPE_NODE:
1445 		    fprintf(output, "'node' "); break;
1446                 case NODE_TYPE_COMMENT:
1447 		    fprintf(output, "'comment' "); break;
1448                 case NODE_TYPE_TEXT:
1449 		    fprintf(output, "'text' "); break;
1450                 case NODE_TYPE_PI:
1451 		    fprintf(output, "'PI' "); break;
1452 	    }
1453 	    if (prefix != NULL)
1454 		fprintf(output, "%s:", prefix);
1455 	    if (name != NULL)
1456 		fprintf(output, "%s", (const char *) name);
1457 	    break;
1458 
1459         }
1460 	case XPATH_OP_VALUE: {
1461 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1462 
1463 	    fprintf(output, "ELEM ");
1464 	    xmlXPathDebugDumpObject(output, object, 0);
1465 	    goto finish;
1466 	}
1467 	case XPATH_OP_VARIABLE: {
1468 	    const xmlChar *prefix = op->value5;
1469 	    const xmlChar *name = op->value4;
1470 
1471 	    if (prefix != NULL)
1472 		fprintf(output, "VARIABLE %s:%s", prefix, name);
1473 	    else
1474 		fprintf(output, "VARIABLE %s", name);
1475 	    break;
1476 	}
1477 	case XPATH_OP_FUNCTION: {
1478 	    int nbargs = op->value;
1479 	    const xmlChar *prefix = op->value5;
1480 	    const xmlChar *name = op->value4;
1481 
1482 	    if (prefix != NULL)
1483 		fprintf(output, "FUNCTION %s:%s(%d args)",
1484 			prefix, name, nbargs);
1485 	    else
1486 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1487 	    break;
1488 	}
1489         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1490         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1491         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1492 #ifdef LIBXML_XPTR_LOCS_ENABLED
1493         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1494 #endif
1495 	default:
1496         fprintf(output, "UNKNOWN %d\n", op->op); return;
1497     }
1498     fprintf(output, "\n");
1499 finish:
1500     if (op->ch1 >= 0)
1501 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1502     if (op->ch2 >= 0)
1503 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1504 }
1505 
1506 /**
1507  * xmlXPathDebugDumpCompExpr:
1508  * @output:  the FILE * for the output
1509  * @comp:  the precompiled XPath expression
1510  * @depth:  the indentation level.
1511  *
1512  * Dumps the tree of the compiled XPath expression.
1513  */
1514 void
xmlXPathDebugDumpCompExpr(FILE * output,xmlXPathCompExprPtr comp,int depth)1515 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1516 	                  int depth) {
1517     int i;
1518     char shift[100];
1519 
1520     if ((output == NULL) || (comp == NULL)) return;
1521 
1522     for (i = 0;((i < depth) && (i < 25));i++)
1523         shift[2 * i] = shift[2 * i + 1] = ' ';
1524     shift[2 * i] = shift[2 * i + 1] = 0;
1525 
1526     fprintf(output, "%s", shift);
1527 
1528 #ifdef XPATH_STREAMING
1529     if (comp->stream) {
1530         fprintf(output, "Streaming Expression\n");
1531     } else
1532 #endif
1533     {
1534         fprintf(output, "Compiled Expression : %d elements\n",
1535                 comp->nbStep);
1536         i = comp->last;
1537         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1538     }
1539 }
1540 
1541 #endif /* LIBXML_DEBUG_ENABLED */
1542 
1543 /************************************************************************
1544  *									*
1545  *			XPath object caching				*
1546  *									*
1547  ************************************************************************/
1548 
1549 /**
1550  * xmlXPathNewCache:
1551  *
1552  * Create a new object cache
1553  *
1554  * Returns the xmlXPathCache just allocated.
1555  */
1556 static xmlXPathContextCachePtr
xmlXPathNewCache(void)1557 xmlXPathNewCache(void)
1558 {
1559     xmlXPathContextCachePtr ret;
1560 
1561     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1562     if (ret == NULL)
1563 	return(NULL);
1564     memset(ret, 0 , sizeof(xmlXPathContextCache));
1565     ret->maxNodeset = 100;
1566     ret->maxMisc = 100;
1567     return(ret);
1568 }
1569 
1570 static void
xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)1571 xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)
1572 {
1573     while (list != NULL) {
1574         xmlXPathObjectPtr next;
1575 
1576         next = (void *) list->stringval;
1577 
1578 	if (list->nodesetval != NULL) {
1579 	    if (list->nodesetval->nodeTab != NULL)
1580 		xmlFree(list->nodesetval->nodeTab);
1581 	    xmlFree(list->nodesetval);
1582 	}
1583 	xmlFree(list);
1584 
1585         list = next;
1586     }
1587 }
1588 
1589 static void
xmlXPathFreeCache(xmlXPathContextCachePtr cache)1590 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1591 {
1592     if (cache == NULL)
1593 	return;
1594     if (cache->nodesetObjs)
1595 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1596     if (cache->miscObjs)
1597 	xmlXPathCacheFreeObjectList(cache->miscObjs);
1598     xmlFree(cache);
1599 }
1600 
1601 /**
1602  * xmlXPathContextSetCache:
1603  *
1604  * @ctxt:  the XPath context
1605  * @active: enables/disables (creates/frees) the cache
1606  * @value: a value with semantics dependent on @options
1607  * @options: options (currently only the value 0 is used)
1608  *
1609  * Creates/frees an object cache on the XPath context.
1610  * If activates XPath objects (xmlXPathObject) will be cached internally
1611  * to be reused.
1612  * @options:
1613  *   0: This will set the XPath object caching:
1614  *      @value:
1615  *        This will set the maximum number of XPath objects
1616  *        to be cached per slot
1617  *        There are two slots for node-set and misc objects.
1618  *        Use <0 for the default number (100).
1619  *   Other values for @options have currently no effect.
1620  *
1621  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1622  */
1623 int
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,int active,int value,int options)1624 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1625 			int active,
1626 			int value,
1627 			int options)
1628 {
1629     if (ctxt == NULL)
1630 	return(-1);
1631     if (active) {
1632 	xmlXPathContextCachePtr cache;
1633 
1634 	if (ctxt->cache == NULL) {
1635 	    ctxt->cache = xmlXPathNewCache();
1636 	    if (ctxt->cache == NULL) {
1637                 xmlXPathErrMemory(ctxt);
1638 		return(-1);
1639             }
1640 	}
1641 	cache = (xmlXPathContextCachePtr) ctxt->cache;
1642 	if (options == 0) {
1643 	    if (value < 0)
1644 		value = 100;
1645 	    cache->maxNodeset = value;
1646 	    cache->maxMisc = value;
1647 	}
1648     } else if (ctxt->cache != NULL) {
1649 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1650 	ctxt->cache = NULL;
1651     }
1652     return(0);
1653 }
1654 
1655 /**
1656  * xmlXPathCacheWrapNodeSet:
1657  * @pctxt: the XPath context
1658  * @val:  the NodePtr value
1659  *
1660  * This is the cached version of xmlXPathWrapNodeSet().
1661  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1662  *
1663  * Returns the created or reused object.
1664  *
1665  * In case of error the node set is destroyed and NULL is returned.
1666  */
1667 static xmlXPathObjectPtr
xmlXPathCacheWrapNodeSet(xmlXPathParserContextPtr pctxt,xmlNodeSetPtr val)1668 xmlXPathCacheWrapNodeSet(xmlXPathParserContextPtr pctxt, xmlNodeSetPtr val)
1669 {
1670     xmlXPathObjectPtr ret;
1671     xmlXPathContextPtr ctxt = pctxt->context;
1672 
1673     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1674 	xmlXPathContextCachePtr cache =
1675 	    (xmlXPathContextCachePtr) ctxt->cache;
1676 
1677 	if (cache->miscObjs != NULL) {
1678 	    ret = cache->miscObjs;
1679             cache->miscObjs = (void *) ret->stringval;
1680             cache->numMisc -= 1;
1681             ret->stringval = NULL;
1682 	    ret->type = XPATH_NODESET;
1683 	    ret->nodesetval = val;
1684 	    return(ret);
1685 	}
1686     }
1687 
1688     ret = xmlXPathWrapNodeSet(val);
1689     if (ret == NULL)
1690         xmlXPathPErrMemory(pctxt);
1691     return(ret);
1692 }
1693 
1694 /**
1695  * xmlXPathCacheWrapString:
1696  * @pctxt the XPath context
1697  * @val:  the xmlChar * value
1698  *
1699  * This is the cached version of xmlXPathWrapString().
1700  * Wraps the @val string into an XPath object.
1701  *
1702  * Returns the created or reused object.
1703  */
1704 static xmlXPathObjectPtr
xmlXPathCacheWrapString(xmlXPathParserContextPtr pctxt,xmlChar * val)1705 xmlXPathCacheWrapString(xmlXPathParserContextPtr pctxt, xmlChar *val)
1706 {
1707     xmlXPathObjectPtr ret;
1708     xmlXPathContextPtr ctxt = pctxt->context;
1709 
1710     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1711 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1712 
1713 	if (cache->miscObjs != NULL) {
1714 	    ret = cache->miscObjs;
1715             cache->miscObjs = (void *) ret->stringval;
1716             cache->numMisc -= 1;
1717 	    ret->type = XPATH_STRING;
1718 	    ret->stringval = val;
1719 	    return(ret);
1720 	}
1721     }
1722 
1723     ret = xmlXPathWrapString(val);
1724     if (ret == NULL)
1725         xmlXPathPErrMemory(pctxt);
1726     return(ret);
1727 }
1728 
1729 /**
1730  * xmlXPathCacheNewNodeSet:
1731  * @pctxt the XPath context
1732  * @val:  the NodePtr value
1733  *
1734  * This is the cached version of xmlXPathNewNodeSet().
1735  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
1736  * it with the single Node @val
1737  *
1738  * Returns the created or reused object.
1739  */
1740 static xmlXPathObjectPtr
xmlXPathCacheNewNodeSet(xmlXPathParserContextPtr pctxt,xmlNodePtr val)1741 xmlXPathCacheNewNodeSet(xmlXPathParserContextPtr pctxt, xmlNodePtr val)
1742 {
1743     xmlXPathObjectPtr ret;
1744     xmlXPathContextPtr ctxt = pctxt->context;
1745 
1746     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1747 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1748 
1749 	if (cache->nodesetObjs != NULL) {
1750 	    /*
1751 	    * Use the nodeset-cache.
1752 	    */
1753 	    ret = cache->nodesetObjs;
1754             cache->nodesetObjs = (void *) ret->stringval;
1755             cache->numNodeset -= 1;
1756             ret->stringval = NULL;
1757 	    ret->type = XPATH_NODESET;
1758 	    ret->boolval = 0;
1759 	    if (val) {
1760 		if ((ret->nodesetval->nodeMax == 0) ||
1761 		    (val->type == XML_NAMESPACE_DECL))
1762 		{
1763 		    if (xmlXPathNodeSetAddUnique(ret->nodesetval, val) < 0)
1764                         xmlXPathPErrMemory(pctxt);
1765 		} else {
1766 		    ret->nodesetval->nodeTab[0] = val;
1767 		    ret->nodesetval->nodeNr = 1;
1768 		}
1769 	    }
1770 	    return(ret);
1771 	} else if (cache->miscObjs != NULL) {
1772             xmlNodeSetPtr set;
1773 	    /*
1774 	    * Fallback to misc-cache.
1775 	    */
1776 
1777 	    set = xmlXPathNodeSetCreate(val);
1778 	    if (set == NULL) {
1779                 xmlXPathPErrMemory(pctxt);
1780 		return(NULL);
1781 	    }
1782 
1783 	    ret = cache->miscObjs;
1784             cache->miscObjs = (void *) ret->stringval;
1785             cache->numMisc -= 1;
1786             ret->stringval = NULL;
1787 	    ret->type = XPATH_NODESET;
1788 	    ret->boolval = 0;
1789 	    ret->nodesetval = set;
1790 	    return(ret);
1791 	}
1792     }
1793     ret = xmlXPathNewNodeSet(val);
1794     if (ret == NULL)
1795         xmlXPathPErrMemory(pctxt);
1796     return(ret);
1797 }
1798 
1799 /**
1800  * xmlXPathCacheNewString:
1801  * @pctxt the XPath context
1802  * @val:  the xmlChar * value
1803  *
1804  * This is the cached version of xmlXPathNewString().
1805  * Acquire an xmlXPathObjectPtr of type string and of value @val
1806  *
1807  * Returns the created or reused object.
1808  */
1809 static xmlXPathObjectPtr
xmlXPathCacheNewString(xmlXPathParserContextPtr pctxt,const xmlChar * val)1810 xmlXPathCacheNewString(xmlXPathParserContextPtr pctxt, const xmlChar *val)
1811 {
1812     xmlXPathObjectPtr ret;
1813     xmlXPathContextPtr ctxt = pctxt->context;
1814 
1815     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1816 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1817 
1818 	if (cache->miscObjs != NULL) {
1819             xmlChar *copy;
1820 
1821             if (val == NULL)
1822                 val = BAD_CAST "";
1823             copy = xmlStrdup(val);
1824             if (copy == NULL) {
1825                 xmlXPathPErrMemory(pctxt);
1826                 return(NULL);
1827             }
1828 
1829 	    ret = cache->miscObjs;
1830             cache->miscObjs = (void *) ret->stringval;
1831             cache->numMisc -= 1;
1832 	    ret->type = XPATH_STRING;
1833             ret->stringval = copy;
1834 	    return(ret);
1835 	}
1836     }
1837 
1838     ret = xmlXPathNewString(val);
1839     if (ret == NULL)
1840         xmlXPathPErrMemory(pctxt);
1841     return(ret);
1842 }
1843 
1844 /**
1845  * xmlXPathCacheNewCString:
1846  * @pctxt the XPath context
1847  * @val:  the char * value
1848  *
1849  * This is the cached version of xmlXPathNewCString().
1850  * Acquire an xmlXPathObjectPtr of type string and of value @val
1851  *
1852  * Returns the created or reused object.
1853  */
1854 static xmlXPathObjectPtr
xmlXPathCacheNewCString(xmlXPathParserContextPtr pctxt,const char * val)1855 xmlXPathCacheNewCString(xmlXPathParserContextPtr pctxt, const char *val)
1856 {
1857     return xmlXPathCacheNewString(pctxt, BAD_CAST val);
1858 }
1859 
1860 /**
1861  * xmlXPathCacheNewBoolean:
1862  * @pctxt the XPath context
1863  * @val:  the boolean value
1864  *
1865  * This is the cached version of xmlXPathNewBoolean().
1866  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
1867  *
1868  * Returns the created or reused object.
1869  */
1870 static xmlXPathObjectPtr
xmlXPathCacheNewBoolean(xmlXPathParserContextPtr pctxt,int val)1871 xmlXPathCacheNewBoolean(xmlXPathParserContextPtr pctxt, int val)
1872 {
1873     xmlXPathObjectPtr ret;
1874     xmlXPathContextPtr ctxt = pctxt->context;
1875 
1876     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1877 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1878 
1879 	if (cache->miscObjs != NULL) {
1880 	    ret = cache->miscObjs;
1881             cache->miscObjs = (void *) ret->stringval;
1882             cache->numMisc -= 1;
1883             ret->stringval = NULL;
1884 	    ret->type = XPATH_BOOLEAN;
1885 	    ret->boolval = (val != 0);
1886 	    return(ret);
1887 	}
1888     }
1889 
1890     ret = xmlXPathNewBoolean(val);
1891     if (ret == NULL)
1892         xmlXPathPErrMemory(pctxt);
1893     return(ret);
1894 }
1895 
1896 /**
1897  * xmlXPathCacheNewFloat:
1898  * @pctxt the XPath context
1899  * @val:  the double value
1900  *
1901  * This is the cached version of xmlXPathNewFloat().
1902  * Acquires an xmlXPathObjectPtr of type double and of value @val
1903  *
1904  * Returns the created or reused object.
1905  */
1906 static xmlXPathObjectPtr
xmlXPathCacheNewFloat(xmlXPathParserContextPtr pctxt,double val)1907 xmlXPathCacheNewFloat(xmlXPathParserContextPtr pctxt, double val)
1908 {
1909     xmlXPathObjectPtr ret;
1910     xmlXPathContextPtr ctxt = pctxt->context;
1911 
1912     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1913 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1914 
1915 	if (cache->miscObjs != NULL) {
1916 	    ret = cache->miscObjs;
1917             cache->miscObjs = (void *) ret->stringval;
1918             cache->numMisc -= 1;
1919             ret->stringval = NULL;
1920 	    ret->type = XPATH_NUMBER;
1921 	    ret->floatval = val;
1922 	    return(ret);
1923 	}
1924     }
1925 
1926     ret = xmlXPathNewFloat(val);
1927     if (ret == NULL)
1928         xmlXPathPErrMemory(pctxt);
1929     return(ret);
1930 }
1931 
1932 /**
1933  * xmlXPathCacheObjectCopy:
1934  * @pctxt the XPath context
1935  * @val:  the original object
1936  *
1937  * This is the cached version of xmlXPathObjectCopy().
1938  * Acquire a copy of a given object
1939  *
1940  * Returns a created or reused created object.
1941  */
1942 static xmlXPathObjectPtr
xmlXPathCacheObjectCopy(xmlXPathParserContextPtr pctxt,xmlXPathObjectPtr val)1943 xmlXPathCacheObjectCopy(xmlXPathParserContextPtr pctxt, xmlXPathObjectPtr val)
1944 {
1945     xmlXPathObjectPtr ret;
1946     xmlXPathContextPtr ctxt = pctxt->context;
1947 
1948     if (val == NULL)
1949 	return(NULL);
1950 
1951     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1952 	switch (val->type) {
1953             case XPATH_NODESET: {
1954                 xmlNodeSetPtr set;
1955 
1956                 set = xmlXPathNodeSetMerge(NULL, val->nodesetval);
1957                 if (set == NULL) {
1958                     xmlXPathPErrMemory(pctxt);
1959                     return(NULL);
1960                 }
1961                 return(xmlXPathCacheWrapNodeSet(pctxt, set));
1962             }
1963 	    case XPATH_STRING:
1964 		return(xmlXPathCacheNewString(pctxt, val->stringval));
1965 	    case XPATH_BOOLEAN:
1966 		return(xmlXPathCacheNewBoolean(pctxt, val->boolval));
1967 	    case XPATH_NUMBER:
1968 		return(xmlXPathCacheNewFloat(pctxt, val->floatval));
1969 	    default:
1970 		break;
1971 	}
1972     }
1973     ret = xmlXPathObjectCopy(val);
1974     if (ret == NULL)
1975         xmlXPathPErrMemory(pctxt);
1976     return(ret);
1977 }
1978 
1979 /************************************************************************
1980  *									*
1981  *		Parser stacks related functions and macros		*
1982  *									*
1983  ************************************************************************/
1984 
1985 /**
1986  * xmlXPathCastToNumberInternal:
1987  * @ctxt:  parser context
1988  * @val:  an XPath object
1989  *
1990  * Converts an XPath object to its number value
1991  *
1992  * Returns the number value
1993  */
1994 static double
xmlXPathCastToNumberInternal(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr val)1995 xmlXPathCastToNumberInternal(xmlXPathParserContextPtr ctxt,
1996                              xmlXPathObjectPtr val) {
1997     double ret = 0.0;
1998 
1999     if (val == NULL)
2000 	return(xmlXPathNAN);
2001     switch (val->type) {
2002     case XPATH_UNDEFINED:
2003 	ret = xmlXPathNAN;
2004 	break;
2005     case XPATH_NODESET:
2006     case XPATH_XSLT_TREE: {
2007         xmlChar *str;
2008 
2009 	str = xmlXPathCastNodeSetToString(val->nodesetval);
2010         if (str == NULL) {
2011             xmlXPathPErrMemory(ctxt);
2012             ret = xmlXPathNAN;
2013         } else {
2014 	    ret = xmlXPathCastStringToNumber(str);
2015             xmlFree(str);
2016         }
2017 	break;
2018     }
2019     case XPATH_STRING:
2020 	ret = xmlXPathCastStringToNumber(val->stringval);
2021 	break;
2022     case XPATH_NUMBER:
2023 	ret = val->floatval;
2024 	break;
2025     case XPATH_BOOLEAN:
2026 	ret = xmlXPathCastBooleanToNumber(val->boolval);
2027 	break;
2028     case XPATH_USERS:
2029 #ifdef LIBXML_XPTR_LOCS_ENABLED
2030     case XPATH_POINT:
2031     case XPATH_RANGE:
2032     case XPATH_LOCATIONSET:
2033 #endif /* LIBXML_XPTR_LOCS_ENABLED */
2034 	/* TODO */
2035 	ret = xmlXPathNAN;
2036 	break;
2037     }
2038     return(ret);
2039 }
2040 
2041 /**
2042  * valuePop:
2043  * @ctxt: an XPath evaluation context
2044  *
2045  * Pops the top XPath object from the value stack
2046  *
2047  * Returns the XPath object just removed
2048  */
2049 xmlXPathObjectPtr
valuePop(xmlXPathParserContextPtr ctxt)2050 valuePop(xmlXPathParserContextPtr ctxt)
2051 {
2052     xmlXPathObjectPtr ret;
2053 
2054     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2055         return (NULL);
2056 
2057     ctxt->valueNr--;
2058     if (ctxt->valueNr > 0)
2059         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2060     else
2061         ctxt->value = NULL;
2062     ret = ctxt->valueTab[ctxt->valueNr];
2063     ctxt->valueTab[ctxt->valueNr] = NULL;
2064     return (ret);
2065 }
2066 /**
2067  * valuePush:
2068  * @ctxt:  an XPath evaluation context
2069  * @value:  the XPath object
2070  *
2071  * Pushes a new XPath object on top of the value stack. If value is NULL,
2072  * a memory error is recorded in the parser context.
2073  *
2074  * Returns the number of items on the value stack, or -1 in case of error.
2075  *
2076  * The object is destroyed in case of error.
2077  */
2078 int
valuePush(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr value)2079 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2080 {
2081     if (ctxt == NULL) return(-1);
2082     if (value == NULL) {
2083         /*
2084          * A NULL value typically indicates that a memory allocation failed.
2085          */
2086         xmlXPathPErrMemory(ctxt);
2087         return(-1);
2088     }
2089     if (ctxt->valueNr >= ctxt->valueMax) {
2090         xmlXPathObjectPtr *tmp;
2091 
2092         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2093             xmlXPathPErrMemory(ctxt);
2094             xmlXPathFreeObject(value);
2095             return (-1);
2096         }
2097         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2098                                              2 * ctxt->valueMax *
2099                                              sizeof(ctxt->valueTab[0]));
2100         if (tmp == NULL) {
2101             xmlXPathPErrMemory(ctxt);
2102             xmlXPathFreeObject(value);
2103             return (-1);
2104         }
2105         ctxt->valueMax *= 2;
2106 	ctxt->valueTab = tmp;
2107     }
2108     ctxt->valueTab[ctxt->valueNr] = value;
2109     ctxt->value = value;
2110     return (ctxt->valueNr++);
2111 }
2112 
2113 /**
2114  * xmlXPathPopBoolean:
2115  * @ctxt:  an XPath parser context
2116  *
2117  * Pops a boolean from the stack, handling conversion if needed.
2118  * Check error with #xmlXPathCheckError.
2119  *
2120  * Returns the boolean
2121  */
2122 int
xmlXPathPopBoolean(xmlXPathParserContextPtr ctxt)2123 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2124     xmlXPathObjectPtr obj;
2125     int ret;
2126 
2127     obj = valuePop(ctxt);
2128     if (obj == NULL) {
2129 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2130 	return(0);
2131     }
2132     if (obj->type != XPATH_BOOLEAN)
2133 	ret = xmlXPathCastToBoolean(obj);
2134     else
2135         ret = obj->boolval;
2136     xmlXPathReleaseObject(ctxt->context, obj);
2137     return(ret);
2138 }
2139 
2140 /**
2141  * xmlXPathPopNumber:
2142  * @ctxt:  an XPath parser context
2143  *
2144  * Pops a number from the stack, handling conversion if needed.
2145  * Check error with #xmlXPathCheckError.
2146  *
2147  * Returns the number
2148  */
2149 double
xmlXPathPopNumber(xmlXPathParserContextPtr ctxt)2150 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2151     xmlXPathObjectPtr obj;
2152     double ret;
2153 
2154     obj = valuePop(ctxt);
2155     if (obj == NULL) {
2156 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2157 	return(0);
2158     }
2159     if (obj->type != XPATH_NUMBER)
2160 	ret = xmlXPathCastToNumberInternal(ctxt, obj);
2161     else
2162         ret = obj->floatval;
2163     xmlXPathReleaseObject(ctxt->context, obj);
2164     return(ret);
2165 }
2166 
2167 /**
2168  * xmlXPathPopString:
2169  * @ctxt:  an XPath parser context
2170  *
2171  * Pops a string from the stack, handling conversion if needed.
2172  * Check error with #xmlXPathCheckError.
2173  *
2174  * Returns the string
2175  */
2176 xmlChar *
xmlXPathPopString(xmlXPathParserContextPtr ctxt)2177 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2178     xmlXPathObjectPtr obj;
2179     xmlChar * ret;
2180 
2181     obj = valuePop(ctxt);
2182     if (obj == NULL) {
2183 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2184 	return(NULL);
2185     }
2186     ret = xmlXPathCastToString(obj);
2187     if (ret == NULL)
2188         xmlXPathPErrMemory(ctxt);
2189     xmlXPathReleaseObject(ctxt->context, obj);
2190     return(ret);
2191 }
2192 
2193 /**
2194  * xmlXPathPopNodeSet:
2195  * @ctxt:  an XPath parser context
2196  *
2197  * Pops a node-set from the stack, handling conversion if needed.
2198  * Check error with #xmlXPathCheckError.
2199  *
2200  * Returns the node-set
2201  */
2202 xmlNodeSetPtr
xmlXPathPopNodeSet(xmlXPathParserContextPtr ctxt)2203 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2204     xmlXPathObjectPtr obj;
2205     xmlNodeSetPtr ret;
2206 
2207     if (ctxt == NULL) return(NULL);
2208     if (ctxt->value == NULL) {
2209 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2210 	return(NULL);
2211     }
2212     if (!xmlXPathStackIsNodeSet(ctxt)) {
2213 	xmlXPathSetTypeError(ctxt);
2214 	return(NULL);
2215     }
2216     obj = valuePop(ctxt);
2217     ret = obj->nodesetval;
2218 #if 0
2219     /* to fix memory leak of not clearing obj->user */
2220     if (obj->boolval && obj->user != NULL)
2221         xmlFreeNodeList((xmlNodePtr) obj->user);
2222 #endif
2223     obj->nodesetval = NULL;
2224     xmlXPathReleaseObject(ctxt->context, obj);
2225     return(ret);
2226 }
2227 
2228 /**
2229  * xmlXPathPopExternal:
2230  * @ctxt:  an XPath parser context
2231  *
2232  * Pops an external object from the stack, handling conversion if needed.
2233  * Check error with #xmlXPathCheckError.
2234  *
2235  * Returns the object
2236  */
2237 void *
xmlXPathPopExternal(xmlXPathParserContextPtr ctxt)2238 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2239     xmlXPathObjectPtr obj;
2240     void * ret;
2241 
2242     if ((ctxt == NULL) || (ctxt->value == NULL)) {
2243 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2244 	return(NULL);
2245     }
2246     if (ctxt->value->type != XPATH_USERS) {
2247 	xmlXPathSetTypeError(ctxt);
2248 	return(NULL);
2249     }
2250     obj = valuePop(ctxt);
2251     ret = obj->user;
2252     obj->user = NULL;
2253     xmlXPathReleaseObject(ctxt->context, obj);
2254     return(ret);
2255 }
2256 
2257 /*
2258  * Macros for accessing the content. Those should be used only by the parser,
2259  * and not exported.
2260  *
2261  * Dirty macros, i.e. one need to make assumption on the context to use them
2262  *
2263  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2264  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2265  *           in ISO-Latin or UTF-8.
2266  *           This should be used internally by the parser
2267  *           only to compare to ASCII values otherwise it would break when
2268  *           running with UTF-8 encoding.
2269  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2270  *           to compare on ASCII based substring.
2271  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2272  *           strings within the parser.
2273  *   CURRENT Returns the current char value, with the full decoding of
2274  *           UTF-8 if we are using this mode. It returns an int.
2275  *   NEXT    Skip to the next character, this does the proper decoding
2276  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2277  *           It returns the pointer to the current xmlChar.
2278  */
2279 
2280 #define CUR (*ctxt->cur)
2281 #define SKIP(val) ctxt->cur += (val)
2282 #define NXT(val) ctxt->cur[(val)]
2283 #define CUR_PTR ctxt->cur
2284 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2285 
2286 #define COPY_BUF(l,b,i,v)                                              \
2287     if (l == 1) b[i++] = v;                                            \
2288     else i += xmlCopyChar(l,&b[i],v)
2289 
2290 #define NEXTL(l)  ctxt->cur += l
2291 
2292 #define SKIP_BLANKS							\
2293     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2294 
2295 #define CURRENT (*ctxt->cur)
2296 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
2297 
2298 
2299 #ifndef DBL_DIG
2300 #define DBL_DIG 16
2301 #endif
2302 #ifndef DBL_EPSILON
2303 #define DBL_EPSILON 1E-9
2304 #endif
2305 
2306 #define UPPER_DOUBLE 1E9
2307 #define LOWER_DOUBLE 1E-5
2308 #define	LOWER_DOUBLE_EXP 5
2309 
2310 #define INTEGER_DIGITS DBL_DIG
2311 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2312 #define EXPONENT_DIGITS (3 + 2)
2313 
2314 /**
2315  * xmlXPathFormatNumber:
2316  * @number:     number to format
2317  * @buffer:     output buffer
2318  * @buffersize: size of output buffer
2319  *
2320  * Convert the number into a string representation.
2321  */
2322 static void
xmlXPathFormatNumber(double number,char buffer[],int buffersize)2323 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2324 {
2325     switch (xmlXPathIsInf(number)) {
2326     case 1:
2327 	if (buffersize > (int)sizeof("Infinity"))
2328 	    snprintf(buffer, buffersize, "Infinity");
2329 	break;
2330     case -1:
2331 	if (buffersize > (int)sizeof("-Infinity"))
2332 	    snprintf(buffer, buffersize, "-Infinity");
2333 	break;
2334     default:
2335 	if (xmlXPathIsNaN(number)) {
2336 	    if (buffersize > (int)sizeof("NaN"))
2337 		snprintf(buffer, buffersize, "NaN");
2338 	} else if (number == 0) {
2339             /* Omit sign for negative zero. */
2340 	    snprintf(buffer, buffersize, "0");
2341 	} else if ((number > INT_MIN) && (number < INT_MAX) &&
2342                    (number == (int) number)) {
2343 	    char work[30];
2344 	    char *ptr, *cur;
2345 	    int value = (int) number;
2346 
2347             ptr = &buffer[0];
2348 	    if (value == 0) {
2349 		*ptr++ = '0';
2350 	    } else {
2351 		snprintf(work, 29, "%d", value);
2352 		cur = &work[0];
2353 		while ((*cur) && (ptr - buffer < buffersize)) {
2354 		    *ptr++ = *cur++;
2355 		}
2356 	    }
2357 	    if (ptr - buffer < buffersize) {
2358 		*ptr = 0;
2359 	    } else if (buffersize > 0) {
2360 		ptr--;
2361 		*ptr = 0;
2362 	    }
2363 	} else {
2364 	    /*
2365 	      For the dimension of work,
2366 	          DBL_DIG is number of significant digits
2367 		  EXPONENT is only needed for "scientific notation"
2368 	          3 is sign, decimal point, and terminating zero
2369 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2370 	      Note that this dimension is slightly (a few characters)
2371 	      larger than actually necessary.
2372 	    */
2373 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2374 	    int integer_place, fraction_place;
2375 	    char *ptr;
2376 	    char *after_fraction;
2377 	    double absolute_value;
2378 	    int size;
2379 
2380 	    absolute_value = fabs(number);
2381 
2382 	    /*
2383 	     * First choose format - scientific or regular floating point.
2384 	     * In either case, result is in work, and after_fraction points
2385 	     * just past the fractional part.
2386 	    */
2387 	    if ( ((absolute_value > UPPER_DOUBLE) ||
2388 		  (absolute_value < LOWER_DOUBLE)) &&
2389 		 (absolute_value != 0.0) ) {
2390 		/* Use scientific notation */
2391 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2392 		fraction_place = DBL_DIG - 1;
2393 		size = snprintf(work, sizeof(work),"%*.*e",
2394 			 integer_place, fraction_place, number);
2395 		while ((size > 0) && (work[size] != 'e')) size--;
2396 
2397 	    }
2398 	    else {
2399 		/* Use regular notation */
2400 		if (absolute_value > 0.0) {
2401 		    integer_place = (int)log10(absolute_value);
2402 		    if (integer_place > 0)
2403 		        fraction_place = DBL_DIG - integer_place - 1;
2404 		    else
2405 		        fraction_place = DBL_DIG - integer_place;
2406 		} else {
2407 		    fraction_place = 1;
2408 		}
2409 		size = snprintf(work, sizeof(work), "%0.*f",
2410 				fraction_place, number);
2411 	    }
2412 
2413 	    /* Remove leading spaces sometimes inserted by snprintf */
2414 	    while (work[0] == ' ') {
2415 	        for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2416 		size--;
2417 	    }
2418 
2419 	    /* Remove fractional trailing zeroes */
2420 	    after_fraction = work + size;
2421 	    ptr = after_fraction;
2422 	    while (*(--ptr) == '0')
2423 		;
2424 	    if (*ptr != '.')
2425 	        ptr++;
2426 	    while ((*ptr++ = *after_fraction++) != 0);
2427 
2428 	    /* Finally copy result back to caller */
2429 	    size = strlen(work) + 1;
2430 	    if (size > buffersize) {
2431 		work[buffersize - 1] = 0;
2432 		size = buffersize;
2433 	    }
2434 	    memmove(buffer, work, size);
2435 	}
2436 	break;
2437     }
2438 }
2439 
2440 
2441 /************************************************************************
2442  *									*
2443  *			Routines to handle NodeSets			*
2444  *									*
2445  ************************************************************************/
2446 
2447 /**
2448  * xmlXPathOrderDocElems:
2449  * @doc:  an input document
2450  *
2451  * Call this routine to speed up XPath computation on static documents.
2452  * This stamps all the element nodes with the document order
2453  * Like for line information, the order is kept in the element->content
2454  * field, the value stored is actually - the node number (starting at -1)
2455  * to be able to differentiate from line numbers.
2456  *
2457  * Returns the number of elements found in the document or -1 in case
2458  *    of error.
2459  */
2460 long
xmlXPathOrderDocElems(xmlDocPtr doc)2461 xmlXPathOrderDocElems(xmlDocPtr doc) {
2462     ptrdiff_t count = 0;
2463     xmlNodePtr cur;
2464 
2465     if (doc == NULL)
2466 	return(-1);
2467     cur = doc->children;
2468     while (cur != NULL) {
2469 	if (cur->type == XML_ELEMENT_NODE) {
2470 	    cur->content = (void *) (-(++count));
2471 	    if (cur->children != NULL) {
2472 		cur = cur->children;
2473 		continue;
2474 	    }
2475 	}
2476 	if (cur->next != NULL) {
2477 	    cur = cur->next;
2478 	    continue;
2479 	}
2480 	do {
2481 	    cur = cur->parent;
2482 	    if (cur == NULL)
2483 		break;
2484 	    if (cur == (xmlNodePtr) doc) {
2485 		cur = NULL;
2486 		break;
2487 	    }
2488 	    if (cur->next != NULL) {
2489 		cur = cur->next;
2490 		break;
2491 	    }
2492 	} while (cur != NULL);
2493     }
2494     return(count);
2495 }
2496 
2497 /**
2498  * xmlXPathCmpNodes:
2499  * @node1:  the first node
2500  * @node2:  the second node
2501  *
2502  * Compare two nodes w.r.t document order
2503  *
2504  * Returns -2 in case of error 1 if first point < second point, 0 if
2505  *         it's the same node, -1 otherwise
2506  */
2507 int
xmlXPathCmpNodes(xmlNodePtr node1,xmlNodePtr node2)2508 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2509     int depth1, depth2;
2510     int attr1 = 0, attr2 = 0;
2511     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2512     xmlNodePtr cur, root;
2513 
2514     if ((node1 == NULL) || (node2 == NULL))
2515 	return(-2);
2516     /*
2517      * a couple of optimizations which will avoid computations in most cases
2518      */
2519     if (node1 == node2)		/* trivial case */
2520 	return(0);
2521     if (node1->type == XML_ATTRIBUTE_NODE) {
2522 	attr1 = 1;
2523 	attrNode1 = node1;
2524 	node1 = node1->parent;
2525     }
2526     if (node2->type == XML_ATTRIBUTE_NODE) {
2527 	attr2 = 1;
2528 	attrNode2 = node2;
2529 	node2 = node2->parent;
2530     }
2531     if (node1 == node2) {
2532 	if (attr1 == attr2) {
2533 	    /* not required, but we keep attributes in order */
2534 	    if (attr1 != 0) {
2535 	        cur = attrNode2->prev;
2536 		while (cur != NULL) {
2537 		    if (cur == attrNode1)
2538 		        return (1);
2539 		    cur = cur->prev;
2540 		}
2541 		return (-1);
2542 	    }
2543 	    return(0);
2544 	}
2545 	if (attr2 == 1)
2546 	    return(1);
2547 	return(-1);
2548     }
2549     if ((node1->type == XML_NAMESPACE_DECL) ||
2550         (node2->type == XML_NAMESPACE_DECL))
2551 	return(1);
2552     if (node1 == node2->prev)
2553 	return(1);
2554     if (node1 == node2->next)
2555 	return(-1);
2556 
2557     /*
2558      * Speedup using document order if available.
2559      */
2560     if ((node1->type == XML_ELEMENT_NODE) &&
2561 	(node2->type == XML_ELEMENT_NODE) &&
2562 	(0 > (ptrdiff_t) node1->content) &&
2563 	(0 > (ptrdiff_t) node2->content) &&
2564 	(node1->doc == node2->doc)) {
2565 	ptrdiff_t l1, l2;
2566 
2567 	l1 = -((ptrdiff_t) node1->content);
2568 	l2 = -((ptrdiff_t) node2->content);
2569 	if (l1 < l2)
2570 	    return(1);
2571 	if (l1 > l2)
2572 	    return(-1);
2573     }
2574 
2575     /*
2576      * compute depth to root
2577      */
2578     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2579 	if (cur->parent == node1)
2580 	    return(1);
2581 	depth2++;
2582     }
2583     root = cur;
2584     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2585 	if (cur->parent == node2)
2586 	    return(-1);
2587 	depth1++;
2588     }
2589     /*
2590      * Distinct document (or distinct entities :-( ) case.
2591      */
2592     if (root != cur) {
2593 	return(-2);
2594     }
2595     /*
2596      * get the nearest common ancestor.
2597      */
2598     while (depth1 > depth2) {
2599 	depth1--;
2600 	node1 = node1->parent;
2601     }
2602     while (depth2 > depth1) {
2603 	depth2--;
2604 	node2 = node2->parent;
2605     }
2606     while (node1->parent != node2->parent) {
2607 	node1 = node1->parent;
2608 	node2 = node2->parent;
2609 	/* should not happen but just in case ... */
2610 	if ((node1 == NULL) || (node2 == NULL))
2611 	    return(-2);
2612     }
2613     /*
2614      * Find who's first.
2615      */
2616     if (node1 == node2->prev)
2617 	return(1);
2618     if (node1 == node2->next)
2619 	return(-1);
2620     /*
2621      * Speedup using document order if available.
2622      */
2623     if ((node1->type == XML_ELEMENT_NODE) &&
2624 	(node2->type == XML_ELEMENT_NODE) &&
2625 	(0 > (ptrdiff_t) node1->content) &&
2626 	(0 > (ptrdiff_t) node2->content) &&
2627 	(node1->doc == node2->doc)) {
2628 	ptrdiff_t l1, l2;
2629 
2630 	l1 = -((ptrdiff_t) node1->content);
2631 	l2 = -((ptrdiff_t) node2->content);
2632 	if (l1 < l2)
2633 	    return(1);
2634 	if (l1 > l2)
2635 	    return(-1);
2636     }
2637 
2638     for (cur = node1->next;cur != NULL;cur = cur->next)
2639 	if (cur == node2)
2640 	    return(1);
2641     return(-1); /* assume there is no sibling list corruption */
2642 }
2643 
2644 /**
2645  * xmlXPathNodeSetSort:
2646  * @set:  the node set
2647  *
2648  * Sort the node set in document order
2649  */
2650 void
xmlXPathNodeSetSort(xmlNodeSetPtr set)2651 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
2652 #ifndef WITH_TIM_SORT
2653     int i, j, incr, len;
2654     xmlNodePtr tmp;
2655 #endif
2656 
2657     if (set == NULL)
2658 	return;
2659 
2660 #ifndef WITH_TIM_SORT
2661     /*
2662      * Use the old Shell's sort implementation to sort the node-set
2663      * Timsort ought to be quite faster
2664      */
2665     len = set->nodeNr;
2666     for (incr = len / 2; incr > 0; incr /= 2) {
2667 	for (i = incr; i < len; i++) {
2668 	    j = i - incr;
2669 	    while (j >= 0) {
2670 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2671 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
2672 			set->nodeTab[j + incr]) == -1)
2673 #else
2674 		if (xmlXPathCmpNodes(set->nodeTab[j],
2675 			set->nodeTab[j + incr]) == -1)
2676 #endif
2677 		{
2678 		    tmp = set->nodeTab[j];
2679 		    set->nodeTab[j] = set->nodeTab[j + incr];
2680 		    set->nodeTab[j + incr] = tmp;
2681 		    j -= incr;
2682 		} else
2683 		    break;
2684 	    }
2685 	}
2686     }
2687 #else /* WITH_TIM_SORT */
2688     libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2689 #endif /* WITH_TIM_SORT */
2690 }
2691 
2692 #define XML_NODESET_DEFAULT	10
2693 /**
2694  * xmlXPathNodeSetDupNs:
2695  * @node:  the parent node of the namespace XPath node
2696  * @ns:  the libxml namespace declaration node.
2697  *
2698  * Namespace node in libxml don't match the XPath semantic. In a node set
2699  * the namespace nodes are duplicated and the next pointer is set to the
2700  * parent node in the XPath semantic.
2701  *
2702  * Returns the newly created object.
2703  */
2704 static xmlNodePtr
xmlXPathNodeSetDupNs(xmlNodePtr node,xmlNsPtr ns)2705 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2706     xmlNsPtr cur;
2707 
2708     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2709 	return(NULL);
2710     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
2711 	return((xmlNodePtr) ns);
2712 
2713     /*
2714      * Allocate a new Namespace and fill the fields.
2715      */
2716     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2717     if (cur == NULL)
2718 	return(NULL);
2719     memset(cur, 0, sizeof(xmlNs));
2720     cur->type = XML_NAMESPACE_DECL;
2721     if (ns->href != NULL) {
2722 	cur->href = xmlStrdup(ns->href);
2723         if (cur->href == NULL) {
2724             xmlFree(cur);
2725             return(NULL);
2726         }
2727     }
2728     if (ns->prefix != NULL) {
2729 	cur->prefix = xmlStrdup(ns->prefix);
2730         if (cur->prefix == NULL) {
2731             xmlFree((xmlChar *) cur->href);
2732             xmlFree(cur);
2733             return(NULL);
2734         }
2735     }
2736     cur->next = (xmlNsPtr) node;
2737     return((xmlNodePtr) cur);
2738 }
2739 
2740 /**
2741  * xmlXPathNodeSetFreeNs:
2742  * @ns:  the XPath namespace node found in a nodeset.
2743  *
2744  * Namespace nodes in libxml don't match the XPath semantic. In a node set
2745  * the namespace nodes are duplicated and the next pointer is set to the
2746  * parent node in the XPath semantic. Check if such a node needs to be freed
2747  */
2748 void
xmlXPathNodeSetFreeNs(xmlNsPtr ns)2749 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
2750     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2751 	return;
2752 
2753     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2754 	if (ns->href != NULL)
2755 	    xmlFree((xmlChar *)ns->href);
2756 	if (ns->prefix != NULL)
2757 	    xmlFree((xmlChar *)ns->prefix);
2758 	xmlFree(ns);
2759     }
2760 }
2761 
2762 /**
2763  * xmlXPathNodeSetCreate:
2764  * @val:  an initial xmlNodePtr, or NULL
2765  *
2766  * Create a new xmlNodeSetPtr of type double and of value @val
2767  *
2768  * Returns the newly created object.
2769  */
2770 xmlNodeSetPtr
xmlXPathNodeSetCreate(xmlNodePtr val)2771 xmlXPathNodeSetCreate(xmlNodePtr val) {
2772     xmlNodeSetPtr ret;
2773 
2774     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2775     if (ret == NULL)
2776 	return(NULL);
2777     memset(ret, 0 , sizeof(xmlNodeSet));
2778     if (val != NULL) {
2779         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2780 					     sizeof(xmlNodePtr));
2781 	if (ret->nodeTab == NULL) {
2782 	    xmlFree(ret);
2783 	    return(NULL);
2784 	}
2785 	memset(ret->nodeTab, 0 ,
2786 	       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2787         ret->nodeMax = XML_NODESET_DEFAULT;
2788 	if (val->type == XML_NAMESPACE_DECL) {
2789 	    xmlNsPtr ns = (xmlNsPtr) val;
2790             xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2791 
2792             if (nsNode == NULL) {
2793                 xmlXPathFreeNodeSet(ret);
2794                 return(NULL);
2795             }
2796 	    ret->nodeTab[ret->nodeNr++] = nsNode;
2797 	} else
2798 	    ret->nodeTab[ret->nodeNr++] = val;
2799     }
2800     return(ret);
2801 }
2802 
2803 /**
2804  * xmlXPathNodeSetContains:
2805  * @cur:  the node-set
2806  * @val:  the node
2807  *
2808  * checks whether @cur contains @val
2809  *
2810  * Returns true (1) if @cur contains @val, false (0) otherwise
2811  */
2812 int
xmlXPathNodeSetContains(xmlNodeSetPtr cur,xmlNodePtr val)2813 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
2814     int i;
2815 
2816     if ((cur == NULL) || (val == NULL)) return(0);
2817     if (val->type == XML_NAMESPACE_DECL) {
2818 	for (i = 0; i < cur->nodeNr; i++) {
2819 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2820 		xmlNsPtr ns1, ns2;
2821 
2822 		ns1 = (xmlNsPtr) val;
2823 		ns2 = (xmlNsPtr) cur->nodeTab[i];
2824 		if (ns1 == ns2)
2825 		    return(1);
2826 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
2827 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
2828 		    return(1);
2829 	    }
2830 	}
2831     } else {
2832 	for (i = 0; i < cur->nodeNr; i++) {
2833 	    if (cur->nodeTab[i] == val)
2834 		return(1);
2835 	}
2836     }
2837     return(0);
2838 }
2839 
2840 /**
2841  * xmlXPathNodeSetAddNs:
2842  * @cur:  the initial node set
2843  * @node:  the hosting node
2844  * @ns:  a the namespace node
2845  *
2846  * add a new namespace node to an existing NodeSet
2847  *
2848  * Returns 0 in case of success and -1 in case of error
2849  */
2850 int
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur,xmlNodePtr node,xmlNsPtr ns)2851 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
2852     int i;
2853     xmlNodePtr nsNode;
2854 
2855     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
2856         (ns->type != XML_NAMESPACE_DECL) ||
2857 	(node->type != XML_ELEMENT_NODE))
2858 	return(-1);
2859 
2860     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2861     /*
2862      * prevent duplicates
2863      */
2864     for (i = 0;i < cur->nodeNr;i++) {
2865         if ((cur->nodeTab[i] != NULL) &&
2866 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
2867 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
2868 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
2869 	    return(0);
2870     }
2871 
2872     /*
2873      * grow the nodeTab if needed
2874      */
2875     if (cur->nodeMax == 0) {
2876         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2877 					     sizeof(xmlNodePtr));
2878 	if (cur->nodeTab == NULL)
2879 	    return(-1);
2880 	memset(cur->nodeTab, 0 ,
2881 	       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2882         cur->nodeMax = XML_NODESET_DEFAULT;
2883     } else if (cur->nodeNr == cur->nodeMax) {
2884         xmlNodePtr *temp;
2885 
2886         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2887             return(-1);
2888 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2889 				      sizeof(xmlNodePtr));
2890 	if (temp == NULL)
2891 	    return(-1);
2892         cur->nodeMax *= 2;
2893 	cur->nodeTab = temp;
2894     }
2895     nsNode = xmlXPathNodeSetDupNs(node, ns);
2896     if(nsNode == NULL)
2897         return(-1);
2898     cur->nodeTab[cur->nodeNr++] = nsNode;
2899     return(0);
2900 }
2901 
2902 /**
2903  * xmlXPathNodeSetAdd:
2904  * @cur:  the initial node set
2905  * @val:  a new xmlNodePtr
2906  *
2907  * add a new xmlNodePtr to an existing NodeSet
2908  *
2909  * Returns 0 in case of success, and -1 in case of error
2910  */
2911 int
xmlXPathNodeSetAdd(xmlNodeSetPtr cur,xmlNodePtr val)2912 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
2913     int i;
2914 
2915     if ((cur == NULL) || (val == NULL)) return(-1);
2916 
2917     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2918     /*
2919      * prevent duplicates
2920      */
2921     for (i = 0;i < cur->nodeNr;i++)
2922         if (cur->nodeTab[i] == val) return(0);
2923 
2924     /*
2925      * grow the nodeTab if needed
2926      */
2927     if (cur->nodeMax == 0) {
2928         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2929 					     sizeof(xmlNodePtr));
2930 	if (cur->nodeTab == NULL)
2931 	    return(-1);
2932 	memset(cur->nodeTab, 0 ,
2933 	       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2934         cur->nodeMax = XML_NODESET_DEFAULT;
2935     } else if (cur->nodeNr == cur->nodeMax) {
2936         xmlNodePtr *temp;
2937 
2938         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2939             return(-1);
2940 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2941 				      sizeof(xmlNodePtr));
2942 	if (temp == NULL)
2943 	    return(-1);
2944         cur->nodeMax *= 2;
2945 	cur->nodeTab = temp;
2946     }
2947     if (val->type == XML_NAMESPACE_DECL) {
2948 	xmlNsPtr ns = (xmlNsPtr) val;
2949         xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2950 
2951         if (nsNode == NULL)
2952             return(-1);
2953 	cur->nodeTab[cur->nodeNr++] = nsNode;
2954     } else
2955 	cur->nodeTab[cur->nodeNr++] = val;
2956     return(0);
2957 }
2958 
2959 /**
2960  * xmlXPathNodeSetAddUnique:
2961  * @cur:  the initial node set
2962  * @val:  a new xmlNodePtr
2963  *
2964  * add a new xmlNodePtr to an existing NodeSet, optimized version
2965  * when we are sure the node is not already in the set.
2966  *
2967  * Returns 0 in case of success and -1 in case of failure
2968  */
2969 int
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur,xmlNodePtr val)2970 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
2971     if ((cur == NULL) || (val == NULL)) return(-1);
2972 
2973     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2974     /*
2975      * grow the nodeTab if needed
2976      */
2977     if (cur->nodeMax == 0) {
2978         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2979 					     sizeof(xmlNodePtr));
2980 	if (cur->nodeTab == NULL)
2981 	    return(-1);
2982 	memset(cur->nodeTab, 0 ,
2983 	       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2984         cur->nodeMax = XML_NODESET_DEFAULT;
2985     } else if (cur->nodeNr == cur->nodeMax) {
2986         xmlNodePtr *temp;
2987 
2988         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2989             return(-1);
2990 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2991 				      sizeof(xmlNodePtr));
2992 	if (temp == NULL)
2993 	    return(-1);
2994 	cur->nodeTab = temp;
2995         cur->nodeMax *= 2;
2996     }
2997     if (val->type == XML_NAMESPACE_DECL) {
2998 	xmlNsPtr ns = (xmlNsPtr) val;
2999         xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3000 
3001         if (nsNode == NULL)
3002             return(-1);
3003 	cur->nodeTab[cur->nodeNr++] = nsNode;
3004     } else
3005 	cur->nodeTab[cur->nodeNr++] = val;
3006     return(0);
3007 }
3008 
3009 /**
3010  * xmlXPathNodeSetMerge:
3011  * @val1:  the first NodeSet or NULL
3012  * @val2:  the second NodeSet
3013  *
3014  * Merges two nodesets, all nodes from @val2 are added to @val1
3015  * if @val1 is NULL, a new set is created and copied from @val2
3016  *
3017  * Returns @val1 once extended or NULL in case of error.
3018  *
3019  * Frees @val1 in case of error.
3020  */
3021 xmlNodeSetPtr
xmlXPathNodeSetMerge(xmlNodeSetPtr val1,xmlNodeSetPtr val2)3022 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3023     int i, j, initNr, skip;
3024     xmlNodePtr n1, n2;
3025 
3026     if (val1 == NULL) {
3027 	val1 = xmlXPathNodeSetCreate(NULL);
3028         if (val1 == NULL)
3029             return (NULL);
3030     }
3031     if (val2 == NULL)
3032         return(val1);
3033 
3034     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3035     initNr = val1->nodeNr;
3036 
3037     for (i = 0;i < val2->nodeNr;i++) {
3038 	n2 = val2->nodeTab[i];
3039 	/*
3040 	 * check against duplicates
3041 	 */
3042 	skip = 0;
3043 	for (j = 0; j < initNr; j++) {
3044 	    n1 = val1->nodeTab[j];
3045 	    if (n1 == n2) {
3046 		skip = 1;
3047 		break;
3048 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3049 		       (n2->type == XML_NAMESPACE_DECL)) {
3050 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3051 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3052 			((xmlNsPtr) n2)->prefix)))
3053 		{
3054 		    skip = 1;
3055 		    break;
3056 		}
3057 	    }
3058 	}
3059 	if (skip)
3060 	    continue;
3061 
3062 	/*
3063 	 * grow the nodeTab if needed
3064 	 */
3065 	if (val1->nodeMax == 0) {
3066 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3067 						    sizeof(xmlNodePtr));
3068 	    if (val1->nodeTab == NULL)
3069 		goto error;
3070 	    memset(val1->nodeTab, 0 ,
3071 		   XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3072 	    val1->nodeMax = XML_NODESET_DEFAULT;
3073 	} else if (val1->nodeNr == val1->nodeMax) {
3074 	    xmlNodePtr *temp;
3075 
3076             if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
3077                 goto error;
3078 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3079 					     sizeof(xmlNodePtr));
3080 	    if (temp == NULL)
3081 		goto error;
3082 	    val1->nodeTab = temp;
3083 	    val1->nodeMax *= 2;
3084 	}
3085 	if (n2->type == XML_NAMESPACE_DECL) {
3086 	    xmlNsPtr ns = (xmlNsPtr) n2;
3087             xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3088 
3089             if (nsNode == NULL)
3090                 goto error;
3091 	    val1->nodeTab[val1->nodeNr++] = nsNode;
3092 	} else
3093 	    val1->nodeTab[val1->nodeNr++] = n2;
3094     }
3095 
3096     return(val1);
3097 
3098 error:
3099     xmlXPathFreeNodeSet(val1);
3100     return(NULL);
3101 }
3102 
3103 
3104 /**
3105  * xmlXPathNodeSetMergeAndClear:
3106  * @set1:  the first NodeSet or NULL
3107  * @set2:  the second NodeSet
3108  *
3109  * Merges two nodesets, all nodes from @set2 are added to @set1.
3110  * Checks for duplicate nodes. Clears set2.
3111  *
3112  * Returns @set1 once extended or NULL in case of error.
3113  *
3114  * Frees @set1 in case of error.
3115  */
3116 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1,xmlNodeSetPtr set2)3117 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3118 {
3119     {
3120 	int i, j, initNbSet1;
3121 	xmlNodePtr n1, n2;
3122 
3123 	initNbSet1 = set1->nodeNr;
3124 	for (i = 0;i < set2->nodeNr;i++) {
3125 	    n2 = set2->nodeTab[i];
3126 	    /*
3127 	    * Skip duplicates.
3128 	    */
3129 	    for (j = 0; j < initNbSet1; j++) {
3130 		n1 = set1->nodeTab[j];
3131 		if (n1 == n2) {
3132 		    goto skip_node;
3133 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
3134 		    (n2->type == XML_NAMESPACE_DECL))
3135 		{
3136 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3137 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
3138 			((xmlNsPtr) n2)->prefix)))
3139 		    {
3140 			/*
3141 			* Free the namespace node.
3142 			*/
3143 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3144 			goto skip_node;
3145 		    }
3146 		}
3147 	    }
3148 	    /*
3149 	    * grow the nodeTab if needed
3150 	    */
3151 	    if (set1->nodeMax == 0) {
3152 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3153 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3154 		if (set1->nodeTab == NULL)
3155 		    goto error;
3156 		memset(set1->nodeTab, 0,
3157 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3158 		set1->nodeMax = XML_NODESET_DEFAULT;
3159 	    } else if (set1->nodeNr >= set1->nodeMax) {
3160 		xmlNodePtr *temp;
3161 
3162                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
3163                     goto error;
3164 		temp = (xmlNodePtr *) xmlRealloc(
3165 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3166 		if (temp == NULL)
3167 		    goto error;
3168 		set1->nodeTab = temp;
3169 		set1->nodeMax *= 2;
3170 	    }
3171 	    set1->nodeTab[set1->nodeNr++] = n2;
3172 skip_node:
3173             set2->nodeTab[i] = NULL;
3174 	}
3175     }
3176     set2->nodeNr = 0;
3177     return(set1);
3178 
3179 error:
3180     xmlXPathFreeNodeSet(set1);
3181     xmlXPathNodeSetClear(set2, 1);
3182     return(NULL);
3183 }
3184 
3185 /**
3186  * xmlXPathNodeSetMergeAndClearNoDupls:
3187  * @set1:  the first NodeSet or NULL
3188  * @set2:  the second NodeSet
3189  *
3190  * Merges two nodesets, all nodes from @set2 are added to @set1.
3191  * Doesn't check for duplicate nodes. Clears set2.
3192  *
3193  * Returns @set1 once extended or NULL in case of error.
3194  *
3195  * Frees @set1 in case of error.
3196  */
3197 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1,xmlNodeSetPtr set2)3198 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3199 {
3200     {
3201 	int i;
3202 	xmlNodePtr n2;
3203 
3204 	for (i = 0;i < set2->nodeNr;i++) {
3205 	    n2 = set2->nodeTab[i];
3206 	    if (set1->nodeMax == 0) {
3207 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3208 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3209 		if (set1->nodeTab == NULL)
3210 		    goto error;
3211 		memset(set1->nodeTab, 0,
3212 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3213 		set1->nodeMax = XML_NODESET_DEFAULT;
3214 	    } else if (set1->nodeNr >= set1->nodeMax) {
3215 		xmlNodePtr *temp;
3216 
3217                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
3218                     goto error;
3219 		temp = (xmlNodePtr *) xmlRealloc(
3220 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3221 		if (temp == NULL)
3222 		    goto error;
3223 		set1->nodeTab = temp;
3224 		set1->nodeMax *= 2;
3225 	    }
3226 	    set1->nodeTab[set1->nodeNr++] = n2;
3227             set2->nodeTab[i] = NULL;
3228 	}
3229     }
3230     set2->nodeNr = 0;
3231     return(set1);
3232 
3233 error:
3234     xmlXPathFreeNodeSet(set1);
3235     xmlXPathNodeSetClear(set2, 1);
3236     return(NULL);
3237 }
3238 
3239 /**
3240  * xmlXPathNodeSetDel:
3241  * @cur:  the initial node set
3242  * @val:  an xmlNodePtr
3243  *
3244  * Removes an xmlNodePtr from an existing NodeSet
3245  */
3246 void
xmlXPathNodeSetDel(xmlNodeSetPtr cur,xmlNodePtr val)3247 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3248     int i;
3249 
3250     if (cur == NULL) return;
3251     if (val == NULL) return;
3252 
3253     /*
3254      * find node in nodeTab
3255      */
3256     for (i = 0;i < cur->nodeNr;i++)
3257         if (cur->nodeTab[i] == val) break;
3258 
3259     if (i >= cur->nodeNr) {	/* not found */
3260         return;
3261     }
3262     if ((cur->nodeTab[i] != NULL) &&
3263 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
3264 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
3265     cur->nodeNr--;
3266     for (;i < cur->nodeNr;i++)
3267         cur->nodeTab[i] = cur->nodeTab[i + 1];
3268     cur->nodeTab[cur->nodeNr] = NULL;
3269 }
3270 
3271 /**
3272  * xmlXPathNodeSetRemove:
3273  * @cur:  the initial node set
3274  * @val:  the index to remove
3275  *
3276  * Removes an entry from an existing NodeSet list.
3277  */
3278 void
xmlXPathNodeSetRemove(xmlNodeSetPtr cur,int val)3279 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
3280     if (cur == NULL) return;
3281     if (val >= cur->nodeNr) return;
3282     if ((cur->nodeTab[val] != NULL) &&
3283 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
3284 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
3285     cur->nodeNr--;
3286     for (;val < cur->nodeNr;val++)
3287         cur->nodeTab[val] = cur->nodeTab[val + 1];
3288     cur->nodeTab[cur->nodeNr] = NULL;
3289 }
3290 
3291 /**
3292  * xmlXPathFreeNodeSet:
3293  * @obj:  the xmlNodeSetPtr to free
3294  *
3295  * Free the NodeSet compound (not the actual nodes !).
3296  */
3297 void
xmlXPathFreeNodeSet(xmlNodeSetPtr obj)3298 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
3299     if (obj == NULL) return;
3300     if (obj->nodeTab != NULL) {
3301 	int i;
3302 
3303 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
3304 	for (i = 0;i < obj->nodeNr;i++)
3305 	    if ((obj->nodeTab[i] != NULL) &&
3306 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3307 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3308 	xmlFree(obj->nodeTab);
3309     }
3310     xmlFree(obj);
3311 }
3312 
3313 /**
3314  * xmlXPathNodeSetClearFromPos:
3315  * @set: the node set to be cleared
3316  * @pos: the start position to clear from
3317  *
3318  * Clears the list from temporary XPath objects (e.g. namespace nodes
3319  * are feed) starting with the entry at @pos, but does *not* free the list
3320  * itself. Sets the length of the list to @pos.
3321  */
3322 static void
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set,int pos,int hasNsNodes)3323 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
3324 {
3325     if ((set == NULL) || (pos >= set->nodeNr))
3326 	return;
3327     else if ((hasNsNodes)) {
3328 	int i;
3329 	xmlNodePtr node;
3330 
3331 	for (i = pos; i < set->nodeNr; i++) {
3332 	    node = set->nodeTab[i];
3333 	    if ((node != NULL) &&
3334 		(node->type == XML_NAMESPACE_DECL))
3335 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3336 	}
3337     }
3338     set->nodeNr = pos;
3339 }
3340 
3341 /**
3342  * xmlXPathNodeSetClear:
3343  * @set:  the node set to clear
3344  *
3345  * Clears the list from all temporary XPath objects (e.g. namespace nodes
3346  * are feed), but does *not* free the list itself. Sets the length of the
3347  * list to 0.
3348  */
3349 static void
xmlXPathNodeSetClear(xmlNodeSetPtr set,int hasNsNodes)3350 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
3351 {
3352     xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3353 }
3354 
3355 /**
3356  * xmlXPathNodeSetKeepLast:
3357  * @set: the node set to be cleared
3358  *
3359  * Move the last node to the first position and clear temporary XPath objects
3360  * (e.g. namespace nodes) from all other nodes. Sets the length of the list
3361  * to 1.
3362  */
3363 static void
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)3364 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
3365 {
3366     int i;
3367     xmlNodePtr node;
3368 
3369     if ((set == NULL) || (set->nodeNr <= 1))
3370 	return;
3371     for (i = 0; i < set->nodeNr - 1; i++) {
3372         node = set->nodeTab[i];
3373         if ((node != NULL) &&
3374             (node->type == XML_NAMESPACE_DECL))
3375             xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3376     }
3377     set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
3378     set->nodeNr = 1;
3379 }
3380 
3381 /**
3382  * xmlXPathNewNodeSet:
3383  * @val:  the NodePtr value
3384  *
3385  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3386  * it with the single Node @val
3387  *
3388  * Returns the newly created object.
3389  */
3390 xmlXPathObjectPtr
xmlXPathNewNodeSet(xmlNodePtr val)3391 xmlXPathNewNodeSet(xmlNodePtr val) {
3392     xmlXPathObjectPtr ret;
3393 
3394     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3395     if (ret == NULL)
3396 	return(NULL);
3397     memset(ret, 0 , sizeof(xmlXPathObject));
3398     ret->type = XPATH_NODESET;
3399     ret->boolval = 0;
3400     ret->nodesetval = xmlXPathNodeSetCreate(val);
3401     if (ret->nodesetval == NULL) {
3402         xmlFree(ret);
3403         return(NULL);
3404     }
3405     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3406     return(ret);
3407 }
3408 
3409 /**
3410  * xmlXPathNewValueTree:
3411  * @val:  the NodePtr value
3412  *
3413  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
3414  * it with the tree root @val
3415  *
3416  * Returns the newly created object.
3417  */
3418 xmlXPathObjectPtr
xmlXPathNewValueTree(xmlNodePtr val)3419 xmlXPathNewValueTree(xmlNodePtr val) {
3420     xmlXPathObjectPtr ret;
3421 
3422     ret = xmlXPathNewNodeSet(val);
3423     if (ret == NULL)
3424 	return(NULL);
3425     ret->type = XPATH_XSLT_TREE;
3426 
3427     return(ret);
3428 }
3429 
3430 /**
3431  * xmlXPathNewNodeSetList:
3432  * @val:  an existing NodeSet
3433  *
3434  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3435  * it with the Nodeset @val
3436  *
3437  * Returns the newly created object.
3438  */
3439 xmlXPathObjectPtr
xmlXPathNewNodeSetList(xmlNodeSetPtr val)3440 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
3441 {
3442     xmlXPathObjectPtr ret;
3443 
3444     if (val == NULL)
3445         ret = NULL;
3446     else if (val->nodeTab == NULL)
3447         ret = xmlXPathNewNodeSet(NULL);
3448     else {
3449         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
3450         if (ret) {
3451             ret->nodesetval = xmlXPathNodeSetMerge(NULL, val);
3452             if (ret->nodesetval == NULL) {
3453                 xmlFree(ret);
3454                 return(NULL);
3455             }
3456         }
3457     }
3458 
3459     return (ret);
3460 }
3461 
3462 /**
3463  * xmlXPathWrapNodeSet:
3464  * @val:  the NodePtr value
3465  *
3466  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
3467  *
3468  * Returns the newly created object.
3469  *
3470  * In case of error the node set is destroyed and NULL is returned.
3471  */
3472 xmlXPathObjectPtr
xmlXPathWrapNodeSet(xmlNodeSetPtr val)3473 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
3474     xmlXPathObjectPtr ret;
3475 
3476     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3477     if (ret == NULL) {
3478         xmlXPathFreeNodeSet(val);
3479 	return(NULL);
3480     }
3481     memset(ret, 0 , sizeof(xmlXPathObject));
3482     ret->type = XPATH_NODESET;
3483     ret->nodesetval = val;
3484     return(ret);
3485 }
3486 
3487 /**
3488  * xmlXPathFreeNodeSetList:
3489  * @obj:  an existing NodeSetList object
3490  *
3491  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
3492  * the list contrary to xmlXPathFreeObject().
3493  */
3494 void
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj)3495 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
3496     if (obj == NULL) return;
3497     xmlFree(obj);
3498 }
3499 
3500 /**
3501  * xmlXPathDifference:
3502  * @nodes1:  a node-set
3503  * @nodes2:  a node-set
3504  *
3505  * Implements the EXSLT - Sets difference() function:
3506  *    node-set set:difference (node-set, node-set)
3507  *
3508  * Returns the difference between the two node sets, or nodes1 if
3509  *         nodes2 is empty
3510  */
3511 xmlNodeSetPtr
xmlXPathDifference(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3512 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3513     xmlNodeSetPtr ret;
3514     int i, l1;
3515     xmlNodePtr cur;
3516 
3517     if (xmlXPathNodeSetIsEmpty(nodes2))
3518 	return(nodes1);
3519 
3520     ret = xmlXPathNodeSetCreate(NULL);
3521     if (ret == NULL)
3522         return(NULL);
3523     if (xmlXPathNodeSetIsEmpty(nodes1))
3524 	return(ret);
3525 
3526     l1 = xmlXPathNodeSetGetLength(nodes1);
3527 
3528     for (i = 0; i < l1; i++) {
3529 	cur = xmlXPathNodeSetItem(nodes1, i);
3530 	if (!xmlXPathNodeSetContains(nodes2, cur)) {
3531 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3532                 xmlXPathFreeNodeSet(ret);
3533 	        return(NULL);
3534             }
3535 	}
3536     }
3537     return(ret);
3538 }
3539 
3540 /**
3541  * xmlXPathIntersection:
3542  * @nodes1:  a node-set
3543  * @nodes2:  a node-set
3544  *
3545  * Implements the EXSLT - Sets intersection() function:
3546  *    node-set set:intersection (node-set, node-set)
3547  *
3548  * Returns a node set comprising the nodes that are within both the
3549  *         node sets passed as arguments
3550  */
3551 xmlNodeSetPtr
xmlXPathIntersection(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3552 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3553     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
3554     int i, l1;
3555     xmlNodePtr cur;
3556 
3557     if (ret == NULL)
3558         return(ret);
3559     if (xmlXPathNodeSetIsEmpty(nodes1))
3560 	return(ret);
3561     if (xmlXPathNodeSetIsEmpty(nodes2))
3562 	return(ret);
3563 
3564     l1 = xmlXPathNodeSetGetLength(nodes1);
3565 
3566     for (i = 0; i < l1; i++) {
3567 	cur = xmlXPathNodeSetItem(nodes1, i);
3568 	if (xmlXPathNodeSetContains(nodes2, cur)) {
3569 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3570                 xmlXPathFreeNodeSet(ret);
3571 	        return(NULL);
3572             }
3573 	}
3574     }
3575     return(ret);
3576 }
3577 
3578 /**
3579  * xmlXPathDistinctSorted:
3580  * @nodes:  a node-set, sorted by document order
3581  *
3582  * Implements the EXSLT - Sets distinct() function:
3583  *    node-set set:distinct (node-set)
3584  *
3585  * Returns a subset of the nodes contained in @nodes, or @nodes if
3586  *         it is empty
3587  */
3588 xmlNodeSetPtr
xmlXPathDistinctSorted(xmlNodeSetPtr nodes)3589 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
3590     xmlNodeSetPtr ret;
3591     xmlHashTablePtr hash;
3592     int i, l;
3593     xmlChar * strval;
3594     xmlNodePtr cur;
3595 
3596     if (xmlXPathNodeSetIsEmpty(nodes))
3597 	return(nodes);
3598 
3599     ret = xmlXPathNodeSetCreate(NULL);
3600     if (ret == NULL)
3601         return(ret);
3602     l = xmlXPathNodeSetGetLength(nodes);
3603     hash = xmlHashCreate (l);
3604     for (i = 0; i < l; i++) {
3605 	cur = xmlXPathNodeSetItem(nodes, i);
3606 	strval = xmlXPathCastNodeToString(cur);
3607 	if (xmlHashLookup(hash, strval) == NULL) {
3608 	    if (xmlHashAddEntry(hash, strval, strval) < 0) {
3609                 xmlFree(strval);
3610                 goto error;
3611             }
3612 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3613 	        goto error;
3614 	} else {
3615 	    xmlFree(strval);
3616 	}
3617     }
3618     xmlHashFree(hash, xmlHashDefaultDeallocator);
3619     return(ret);
3620 
3621 error:
3622     xmlHashFree(hash, xmlHashDefaultDeallocator);
3623     xmlXPathFreeNodeSet(ret);
3624     return(NULL);
3625 }
3626 
3627 /**
3628  * xmlXPathDistinct:
3629  * @nodes:  a node-set
3630  *
3631  * Implements the EXSLT - Sets distinct() function:
3632  *    node-set set:distinct (node-set)
3633  * @nodes is sorted by document order, then #exslSetsDistinctSorted
3634  * is called with the sorted node-set
3635  *
3636  * Returns a subset of the nodes contained in @nodes, or @nodes if
3637  *         it is empty
3638  */
3639 xmlNodeSetPtr
xmlXPathDistinct(xmlNodeSetPtr nodes)3640 xmlXPathDistinct (xmlNodeSetPtr nodes) {
3641     if (xmlXPathNodeSetIsEmpty(nodes))
3642 	return(nodes);
3643 
3644     xmlXPathNodeSetSort(nodes);
3645     return(xmlXPathDistinctSorted(nodes));
3646 }
3647 
3648 /**
3649  * xmlXPathHasSameNodes:
3650  * @nodes1:  a node-set
3651  * @nodes2:  a node-set
3652  *
3653  * Implements the EXSLT - Sets has-same-nodes function:
3654  *    boolean set:has-same-node(node-set, node-set)
3655  *
3656  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
3657  *         otherwise
3658  */
3659 int
xmlXPathHasSameNodes(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3660 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3661     int i, l;
3662     xmlNodePtr cur;
3663 
3664     if (xmlXPathNodeSetIsEmpty(nodes1) ||
3665 	xmlXPathNodeSetIsEmpty(nodes2))
3666 	return(0);
3667 
3668     l = xmlXPathNodeSetGetLength(nodes1);
3669     for (i = 0; i < l; i++) {
3670 	cur = xmlXPathNodeSetItem(nodes1, i);
3671 	if (xmlXPathNodeSetContains(nodes2, cur))
3672 	    return(1);
3673     }
3674     return(0);
3675 }
3676 
3677 /**
3678  * xmlXPathNodeLeadingSorted:
3679  * @nodes: a node-set, sorted by document order
3680  * @node: a node
3681  *
3682  * Implements the EXSLT - Sets leading() function:
3683  *    node-set set:leading (node-set, node-set)
3684  *
3685  * Returns the nodes in @nodes that precede @node in document order,
3686  *         @nodes if @node is NULL or an empty node-set if @nodes
3687  *         doesn't contain @node
3688  */
3689 xmlNodeSetPtr
xmlXPathNodeLeadingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)3690 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3691     int i, l;
3692     xmlNodePtr cur;
3693     xmlNodeSetPtr ret;
3694 
3695     if (node == NULL)
3696 	return(nodes);
3697 
3698     ret = xmlXPathNodeSetCreate(NULL);
3699     if (ret == NULL)
3700         return(ret);
3701     if (xmlXPathNodeSetIsEmpty(nodes) ||
3702 	(!xmlXPathNodeSetContains(nodes, node)))
3703 	return(ret);
3704 
3705     l = xmlXPathNodeSetGetLength(nodes);
3706     for (i = 0; i < l; i++) {
3707 	cur = xmlXPathNodeSetItem(nodes, i);
3708 	if (cur == node)
3709 	    break;
3710 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3711             xmlXPathFreeNodeSet(ret);
3712 	    return(NULL);
3713         }
3714     }
3715     return(ret);
3716 }
3717 
3718 /**
3719  * xmlXPathNodeLeading:
3720  * @nodes:  a node-set
3721  * @node:  a node
3722  *
3723  * Implements the EXSLT - Sets leading() function:
3724  *    node-set set:leading (node-set, node-set)
3725  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
3726  * is called.
3727  *
3728  * Returns the nodes in @nodes that precede @node in document order,
3729  *         @nodes if @node is NULL or an empty node-set if @nodes
3730  *         doesn't contain @node
3731  */
3732 xmlNodeSetPtr
xmlXPathNodeLeading(xmlNodeSetPtr nodes,xmlNodePtr node)3733 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
3734     xmlXPathNodeSetSort(nodes);
3735     return(xmlXPathNodeLeadingSorted(nodes, node));
3736 }
3737 
3738 /**
3739  * xmlXPathLeadingSorted:
3740  * @nodes1:  a node-set, sorted by document order
3741  * @nodes2:  a node-set, sorted by document order
3742  *
3743  * Implements the EXSLT - Sets leading() function:
3744  *    node-set set:leading (node-set, node-set)
3745  *
3746  * Returns the nodes in @nodes1 that precede the first node in @nodes2
3747  *         in document order, @nodes1 if @nodes2 is NULL or empty or
3748  *         an empty node-set if @nodes1 doesn't contain @nodes2
3749  */
3750 xmlNodeSetPtr
xmlXPathLeadingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3751 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3752     if (xmlXPathNodeSetIsEmpty(nodes2))
3753 	return(nodes1);
3754     return(xmlXPathNodeLeadingSorted(nodes1,
3755 				     xmlXPathNodeSetItem(nodes2, 1)));
3756 }
3757 
3758 /**
3759  * xmlXPathLeading:
3760  * @nodes1:  a node-set
3761  * @nodes2:  a node-set
3762  *
3763  * Implements the EXSLT - Sets leading() function:
3764  *    node-set set:leading (node-set, node-set)
3765  * @nodes1 and @nodes2 are sorted by document order, then
3766  * #exslSetsLeadingSorted is called.
3767  *
3768  * Returns the nodes in @nodes1 that precede the first node in @nodes2
3769  *         in document order, @nodes1 if @nodes2 is NULL or empty or
3770  *         an empty node-set if @nodes1 doesn't contain @nodes2
3771  */
3772 xmlNodeSetPtr
xmlXPathLeading(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3773 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3774     if (xmlXPathNodeSetIsEmpty(nodes2))
3775 	return(nodes1);
3776     if (xmlXPathNodeSetIsEmpty(nodes1))
3777 	return(xmlXPathNodeSetCreate(NULL));
3778     xmlXPathNodeSetSort(nodes1);
3779     xmlXPathNodeSetSort(nodes2);
3780     return(xmlXPathNodeLeadingSorted(nodes1,
3781 				     xmlXPathNodeSetItem(nodes2, 1)));
3782 }
3783 
3784 /**
3785  * xmlXPathNodeTrailingSorted:
3786  * @nodes: a node-set, sorted by document order
3787  * @node: a node
3788  *
3789  * Implements the EXSLT - Sets trailing() function:
3790  *    node-set set:trailing (node-set, node-set)
3791  *
3792  * Returns the nodes in @nodes that follow @node in document order,
3793  *         @nodes if @node is NULL or an empty node-set if @nodes
3794  *         doesn't contain @node
3795  */
3796 xmlNodeSetPtr
xmlXPathNodeTrailingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)3797 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3798     int i, l;
3799     xmlNodePtr cur;
3800     xmlNodeSetPtr ret;
3801 
3802     if (node == NULL)
3803 	return(nodes);
3804 
3805     ret = xmlXPathNodeSetCreate(NULL);
3806     if (ret == NULL)
3807         return(ret);
3808     if (xmlXPathNodeSetIsEmpty(nodes) ||
3809 	(!xmlXPathNodeSetContains(nodes, node)))
3810 	return(ret);
3811 
3812     l = xmlXPathNodeSetGetLength(nodes);
3813     for (i = l - 1; i >= 0; i--) {
3814 	cur = xmlXPathNodeSetItem(nodes, i);
3815 	if (cur == node)
3816 	    break;
3817 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3818             xmlXPathFreeNodeSet(ret);
3819 	    return(NULL);
3820         }
3821     }
3822     xmlXPathNodeSetSort(ret);	/* bug 413451 */
3823     return(ret);
3824 }
3825 
3826 /**
3827  * xmlXPathNodeTrailing:
3828  * @nodes:  a node-set
3829  * @node:  a node
3830  *
3831  * Implements the EXSLT - Sets trailing() function:
3832  *    node-set set:trailing (node-set, node-set)
3833  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
3834  * is called.
3835  *
3836  * Returns the nodes in @nodes that follow @node in document order,
3837  *         @nodes if @node is NULL or an empty node-set if @nodes
3838  *         doesn't contain @node
3839  */
3840 xmlNodeSetPtr
xmlXPathNodeTrailing(xmlNodeSetPtr nodes,xmlNodePtr node)3841 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
3842     xmlXPathNodeSetSort(nodes);
3843     return(xmlXPathNodeTrailingSorted(nodes, node));
3844 }
3845 
3846 /**
3847  * xmlXPathTrailingSorted:
3848  * @nodes1:  a node-set, sorted by document order
3849  * @nodes2:  a node-set, sorted by document order
3850  *
3851  * Implements the EXSLT - Sets trailing() function:
3852  *    node-set set:trailing (node-set, node-set)
3853  *
3854  * Returns the nodes in @nodes1 that follow the first node in @nodes2
3855  *         in document order, @nodes1 if @nodes2 is NULL or empty or
3856  *         an empty node-set if @nodes1 doesn't contain @nodes2
3857  */
3858 xmlNodeSetPtr
xmlXPathTrailingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3859 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3860     if (xmlXPathNodeSetIsEmpty(nodes2))
3861 	return(nodes1);
3862     return(xmlXPathNodeTrailingSorted(nodes1,
3863 				      xmlXPathNodeSetItem(nodes2, 0)));
3864 }
3865 
3866 /**
3867  * xmlXPathTrailing:
3868  * @nodes1:  a node-set
3869  * @nodes2:  a node-set
3870  *
3871  * Implements the EXSLT - Sets trailing() function:
3872  *    node-set set:trailing (node-set, node-set)
3873  * @nodes1 and @nodes2 are sorted by document order, then
3874  * #xmlXPathTrailingSorted is called.
3875  *
3876  * Returns the nodes in @nodes1 that follow the first node in @nodes2
3877  *         in document order, @nodes1 if @nodes2 is NULL or empty or
3878  *         an empty node-set if @nodes1 doesn't contain @nodes2
3879  */
3880 xmlNodeSetPtr
xmlXPathTrailing(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3881 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3882     if (xmlXPathNodeSetIsEmpty(nodes2))
3883 	return(nodes1);
3884     if (xmlXPathNodeSetIsEmpty(nodes1))
3885 	return(xmlXPathNodeSetCreate(NULL));
3886     xmlXPathNodeSetSort(nodes1);
3887     xmlXPathNodeSetSort(nodes2);
3888     return(xmlXPathNodeTrailingSorted(nodes1,
3889 				      xmlXPathNodeSetItem(nodes2, 0)));
3890 }
3891 
3892 /************************************************************************
3893  *									*
3894  *		Routines to handle extra functions			*
3895  *									*
3896  ************************************************************************/
3897 
3898 /**
3899  * xmlXPathRegisterFunc:
3900  * @ctxt:  the XPath context
3901  * @name:  the function name
3902  * @f:  the function implementation or NULL
3903  *
3904  * Register a new function. If @f is NULL it unregisters the function
3905  *
3906  * Returns 0 in case of success, -1 in case of error
3907  */
3908 int
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathFunction f)3909 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
3910 		     xmlXPathFunction f) {
3911     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
3912 }
3913 
3914 /**
3915  * xmlXPathRegisterFuncNS:
3916  * @ctxt:  the XPath context
3917  * @name:  the function name
3918  * @ns_uri:  the function namespace URI
3919  * @f:  the function implementation or NULL
3920  *
3921  * Register a new function. If @f is NULL it unregisters the function
3922  *
3923  * Returns 0 in case of success, -1 in case of error
3924  */
3925 int
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathFunction f)3926 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3927 		       const xmlChar *ns_uri, xmlXPathFunction f) {
3928     int ret;
3929 
3930     if (ctxt == NULL)
3931 	return(-1);
3932     if (name == NULL)
3933 	return(-1);
3934 
3935     if (ctxt->funcHash == NULL)
3936 	ctxt->funcHash = xmlHashCreate(0);
3937     if (ctxt->funcHash == NULL) {
3938         xmlXPathErrMemory(ctxt);
3939 	return(-1);
3940     }
3941     if (f == NULL)
3942         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
3943 XML_IGNORE_FPTR_CAST_WARNINGS
3944     ret = xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f);
3945 XML_POP_WARNINGS
3946     if (ret < 0) {
3947         xmlXPathErrMemory(ctxt);
3948         return(-1);
3949     }
3950 
3951     return(0);
3952 }
3953 
3954 /**
3955  * xmlXPathRegisterFuncLookup:
3956  * @ctxt:  the XPath context
3957  * @f:  the lookup function
3958  * @funcCtxt:  the lookup data
3959  *
3960  * Registers an external mechanism to do function lookup.
3961  */
3962 void
xmlXPathRegisterFuncLookup(xmlXPathContextPtr ctxt,xmlXPathFuncLookupFunc f,void * funcCtxt)3963 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
3964 			    xmlXPathFuncLookupFunc f,
3965 			    void *funcCtxt) {
3966     if (ctxt == NULL)
3967 	return;
3968     ctxt->funcLookupFunc = f;
3969     ctxt->funcLookupData = funcCtxt;
3970 }
3971 
3972 /**
3973  * xmlXPathFunctionLookup:
3974  * @ctxt:  the XPath context
3975  * @name:  the function name
3976  *
3977  * Search in the Function array of the context for the given
3978  * function.
3979  *
3980  * Returns the xmlXPathFunction or NULL if not found
3981  */
3982 xmlXPathFunction
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt,const xmlChar * name)3983 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
3984     if (ctxt == NULL)
3985 	return (NULL);
3986 
3987     if (ctxt->funcLookupFunc != NULL) {
3988 	xmlXPathFunction ret;
3989 	xmlXPathFuncLookupFunc f;
3990 
3991 	f = ctxt->funcLookupFunc;
3992 	ret = f(ctxt->funcLookupData, name, NULL);
3993 	if (ret != NULL)
3994 	    return(ret);
3995     }
3996     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
3997 }
3998 
3999 /**
4000  * xmlXPathFunctionLookupNS:
4001  * @ctxt:  the XPath context
4002  * @name:  the function name
4003  * @ns_uri:  the function namespace URI
4004  *
4005  * Search in the Function array of the context for the given
4006  * function.
4007  *
4008  * Returns the xmlXPathFunction or NULL if not found
4009  */
4010 xmlXPathFunction
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4011 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4012 			 const xmlChar *ns_uri) {
4013     xmlXPathFunction ret;
4014 
4015     if (ctxt == NULL)
4016 	return(NULL);
4017     if (name == NULL)
4018 	return(NULL);
4019 
4020     if (ctxt->funcLookupFunc != NULL) {
4021 	xmlXPathFuncLookupFunc f;
4022 
4023 	f = ctxt->funcLookupFunc;
4024 	ret = f(ctxt->funcLookupData, name, ns_uri);
4025 	if (ret != NULL)
4026 	    return(ret);
4027     }
4028 
4029     if (ctxt->funcHash == NULL)
4030 	return(NULL);
4031 
4032 XML_IGNORE_FPTR_CAST_WARNINGS
4033     ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4034 XML_POP_WARNINGS
4035     return(ret);
4036 }
4037 
4038 /**
4039  * xmlXPathRegisteredFuncsCleanup:
4040  * @ctxt:  the XPath context
4041  *
4042  * Cleanup the XPath context data associated to registered functions
4043  */
4044 void
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt)4045 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4046     if (ctxt == NULL)
4047 	return;
4048 
4049     xmlHashFree(ctxt->funcHash, NULL);
4050     ctxt->funcHash = NULL;
4051 }
4052 
4053 /************************************************************************
4054  *									*
4055  *			Routines to handle Variables			*
4056  *									*
4057  ************************************************************************/
4058 
4059 /**
4060  * xmlXPathRegisterVariable:
4061  * @ctxt:  the XPath context
4062  * @name:  the variable name
4063  * @value:  the variable value or NULL
4064  *
4065  * Register a new variable value. If @value is NULL it unregisters
4066  * the variable
4067  *
4068  * Returns 0 in case of success, -1 in case of error
4069  */
4070 int
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathObjectPtr value)4071 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4072 			 xmlXPathObjectPtr value) {
4073     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4074 }
4075 
4076 /**
4077  * xmlXPathRegisterVariableNS:
4078  * @ctxt:  the XPath context
4079  * @name:  the variable name
4080  * @ns_uri:  the variable namespace URI
4081  * @value:  the variable value or NULL
4082  *
4083  * Register a new variable value. If @value is NULL it unregisters
4084  * the variable
4085  *
4086  * Returns 0 in case of success, -1 in case of error
4087  */
4088 int
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathObjectPtr value)4089 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4090 			   const xmlChar *ns_uri,
4091 			   xmlXPathObjectPtr value) {
4092     if (ctxt == NULL)
4093 	return(-1);
4094     if (name == NULL)
4095 	return(-1);
4096 
4097     if (ctxt->varHash == NULL)
4098 	ctxt->varHash = xmlHashCreate(0);
4099     if (ctxt->varHash == NULL)
4100 	return(-1);
4101     if (value == NULL)
4102         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4103 	                           xmlXPathFreeObjectEntry));
4104     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4105 			       (void *) value, xmlXPathFreeObjectEntry));
4106 }
4107 
4108 /**
4109  * xmlXPathRegisterVariableLookup:
4110  * @ctxt:  the XPath context
4111  * @f:  the lookup function
4112  * @data:  the lookup data
4113  *
4114  * register an external mechanism to do variable lookup
4115  */
4116 void
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,xmlXPathVariableLookupFunc f,void * data)4117 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4118 	 xmlXPathVariableLookupFunc f, void *data) {
4119     if (ctxt == NULL)
4120 	return;
4121     ctxt->varLookupFunc = f;
4122     ctxt->varLookupData = data;
4123 }
4124 
4125 /**
4126  * xmlXPathVariableLookup:
4127  * @ctxt:  the XPath context
4128  * @name:  the variable name
4129  *
4130  * Search in the Variable array of the context for the given
4131  * variable value.
4132  *
4133  * Returns a copy of the value or NULL if not found
4134  */
4135 xmlXPathObjectPtr
xmlXPathVariableLookup(xmlXPathContextPtr ctxt,const xmlChar * name)4136 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4137     if (ctxt == NULL)
4138 	return(NULL);
4139 
4140     if (ctxt->varLookupFunc != NULL) {
4141 	xmlXPathObjectPtr ret;
4142 
4143 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4144 	        (ctxt->varLookupData, name, NULL);
4145 	return(ret);
4146     }
4147     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4148 }
4149 
4150 /**
4151  * xmlXPathVariableLookupNS:
4152  * @ctxt:  the XPath context
4153  * @name:  the variable name
4154  * @ns_uri:  the variable namespace URI
4155  *
4156  * Search in the Variable array of the context for the given
4157  * variable value.
4158  *
4159  * Returns the a copy of the value or NULL if not found
4160  */
4161 xmlXPathObjectPtr
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4162 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4163 			 const xmlChar *ns_uri) {
4164     if (ctxt == NULL)
4165 	return(NULL);
4166 
4167     if (ctxt->varLookupFunc != NULL) {
4168 	xmlXPathObjectPtr ret;
4169 
4170 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4171 	        (ctxt->varLookupData, name, ns_uri);
4172 	if (ret != NULL) return(ret);
4173     }
4174 
4175     if (ctxt->varHash == NULL)
4176 	return(NULL);
4177     if (name == NULL)
4178 	return(NULL);
4179 
4180     return(xmlXPathObjectCopy(xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4181 }
4182 
4183 /**
4184  * xmlXPathRegisteredVariablesCleanup:
4185  * @ctxt:  the XPath context
4186  *
4187  * Cleanup the XPath context data associated to registered variables
4188  */
4189 void
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt)4190 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4191     if (ctxt == NULL)
4192 	return;
4193 
4194     xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
4195     ctxt->varHash = NULL;
4196 }
4197 
4198 /**
4199  * xmlXPathRegisterNs:
4200  * @ctxt:  the XPath context
4201  * @prefix:  the namespace prefix cannot be NULL or empty string
4202  * @ns_uri:  the namespace name
4203  *
4204  * Register a new namespace. If @ns_uri is NULL it unregisters
4205  * the namespace
4206  *
4207  * Returns 0 in case of success, -1 in case of error
4208  */
4209 int
xmlXPathRegisterNs(xmlXPathContextPtr ctxt,const xmlChar * prefix,const xmlChar * ns_uri)4210 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4211 			   const xmlChar *ns_uri) {
4212     xmlChar *copy;
4213 
4214     if (ctxt == NULL)
4215 	return(-1);
4216     if (prefix == NULL)
4217 	return(-1);
4218     if (prefix[0] == 0)
4219 	return(-1);
4220 
4221     if (ctxt->nsHash == NULL)
4222 	ctxt->nsHash = xmlHashCreate(10);
4223     if (ctxt->nsHash == NULL) {
4224         xmlXPathErrMemory(ctxt);
4225 	return(-1);
4226     }
4227     if (ns_uri == NULL)
4228         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
4229 	                          xmlHashDefaultDeallocator));
4230 
4231     copy = xmlStrdup(ns_uri);
4232     if (copy == NULL) {
4233         xmlXPathErrMemory(ctxt);
4234         return(-1);
4235     }
4236     if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
4237                            xmlHashDefaultDeallocator) < 0) {
4238         xmlXPathErrMemory(ctxt);
4239         xmlFree(copy);
4240         return(-1);
4241     }
4242 
4243     return(0);
4244 }
4245 
4246 /**
4247  * xmlXPathNsLookup:
4248  * @ctxt:  the XPath context
4249  * @prefix:  the namespace prefix value
4250  *
4251  * Search in the namespace declaration array of the context for the given
4252  * namespace name associated to the given prefix
4253  *
4254  * Returns the value or NULL if not found
4255  */
4256 const xmlChar *
xmlXPathNsLookup(xmlXPathContextPtr ctxt,const xmlChar * prefix)4257 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
4258     if (ctxt == NULL)
4259 	return(NULL);
4260     if (prefix == NULL)
4261 	return(NULL);
4262 
4263 #ifdef XML_XML_NAMESPACE
4264     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4265 	return(XML_XML_NAMESPACE);
4266 #endif
4267 
4268     if (ctxt->namespaces != NULL) {
4269 	int i;
4270 
4271 	for (i = 0;i < ctxt->nsNr;i++) {
4272 	    if ((ctxt->namespaces[i] != NULL) &&
4273 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4274 		return(ctxt->namespaces[i]->href);
4275 	}
4276     }
4277 
4278     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4279 }
4280 
4281 /**
4282  * xmlXPathRegisteredNsCleanup:
4283  * @ctxt:  the XPath context
4284  *
4285  * Cleanup the XPath context data associated to registered variables
4286  */
4287 void
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt)4288 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
4289     if (ctxt == NULL)
4290 	return;
4291 
4292     xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4293     ctxt->nsHash = NULL;
4294 }
4295 
4296 /************************************************************************
4297  *									*
4298  *			Routines to handle Values			*
4299  *									*
4300  ************************************************************************/
4301 
4302 /* Allocations are terrible, one needs to optimize all this !!! */
4303 
4304 /**
4305  * xmlXPathNewFloat:
4306  * @val:  the double value
4307  *
4308  * Create a new xmlXPathObjectPtr of type double and of value @val
4309  *
4310  * Returns the newly created object.
4311  */
4312 xmlXPathObjectPtr
xmlXPathNewFloat(double val)4313 xmlXPathNewFloat(double val) {
4314     xmlXPathObjectPtr ret;
4315 
4316     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4317     if (ret == NULL)
4318 	return(NULL);
4319     memset(ret, 0 , sizeof(xmlXPathObject));
4320     ret->type = XPATH_NUMBER;
4321     ret->floatval = val;
4322     return(ret);
4323 }
4324 
4325 /**
4326  * xmlXPathNewBoolean:
4327  * @val:  the boolean value
4328  *
4329  * Create a new xmlXPathObjectPtr of type boolean and of value @val
4330  *
4331  * Returns the newly created object.
4332  */
4333 xmlXPathObjectPtr
xmlXPathNewBoolean(int val)4334 xmlXPathNewBoolean(int val) {
4335     xmlXPathObjectPtr ret;
4336 
4337     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4338     if (ret == NULL)
4339 	return(NULL);
4340     memset(ret, 0 , sizeof(xmlXPathObject));
4341     ret->type = XPATH_BOOLEAN;
4342     ret->boolval = (val != 0);
4343     return(ret);
4344 }
4345 
4346 /**
4347  * xmlXPathNewString:
4348  * @val:  the xmlChar * value
4349  *
4350  * Create a new xmlXPathObjectPtr of type string and of value @val
4351  *
4352  * Returns the newly created object.
4353  */
4354 xmlXPathObjectPtr
xmlXPathNewString(const xmlChar * val)4355 xmlXPathNewString(const xmlChar *val) {
4356     xmlXPathObjectPtr ret;
4357 
4358     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4359     if (ret == NULL)
4360 	return(NULL);
4361     memset(ret, 0 , sizeof(xmlXPathObject));
4362     ret->type = XPATH_STRING;
4363     if (val == NULL)
4364         val = BAD_CAST "";
4365     ret->stringval = xmlStrdup(val);
4366     if (ret->stringval == NULL) {
4367         xmlFree(ret);
4368         return(NULL);
4369     }
4370     return(ret);
4371 }
4372 
4373 /**
4374  * xmlXPathWrapString:
4375  * @val:  the xmlChar * value
4376  *
4377  * Wraps the @val string into an XPath object.
4378  *
4379  * Returns the newly created object.
4380  *
4381  * Frees @val in case of error.
4382  */
4383 xmlXPathObjectPtr
xmlXPathWrapString(xmlChar * val)4384 xmlXPathWrapString (xmlChar *val) {
4385     xmlXPathObjectPtr ret;
4386 
4387     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4388     if (ret == NULL) {
4389         xmlFree(val);
4390 	return(NULL);
4391     }
4392     memset(ret, 0 , sizeof(xmlXPathObject));
4393     ret->type = XPATH_STRING;
4394     ret->stringval = val;
4395     return(ret);
4396 }
4397 
4398 /**
4399  * xmlXPathNewCString:
4400  * @val:  the char * value
4401  *
4402  * Create a new xmlXPathObjectPtr of type string and of value @val
4403  *
4404  * Returns the newly created object.
4405  */
4406 xmlXPathObjectPtr
xmlXPathNewCString(const char * val)4407 xmlXPathNewCString(const char *val) {
4408     return(xmlXPathNewString(BAD_CAST val));
4409 }
4410 
4411 /**
4412  * xmlXPathWrapCString:
4413  * @val:  the char * value
4414  *
4415  * Wraps a string into an XPath object.
4416  *
4417  * Returns the newly created object.
4418  */
4419 xmlXPathObjectPtr
xmlXPathWrapCString(char * val)4420 xmlXPathWrapCString (char * val) {
4421     return(xmlXPathWrapString((xmlChar *)(val)));
4422 }
4423 
4424 /**
4425  * xmlXPathWrapExternal:
4426  * @val:  the user data
4427  *
4428  * Wraps the @val data into an XPath object.
4429  *
4430  * Returns the newly created object.
4431  */
4432 xmlXPathObjectPtr
xmlXPathWrapExternal(void * val)4433 xmlXPathWrapExternal (void *val) {
4434     xmlXPathObjectPtr ret;
4435 
4436     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4437     if (ret == NULL)
4438 	return(NULL);
4439     memset(ret, 0 , sizeof(xmlXPathObject));
4440     ret->type = XPATH_USERS;
4441     ret->user = val;
4442     return(ret);
4443 }
4444 
4445 /**
4446  * xmlXPathObjectCopy:
4447  * @val:  the original object
4448  *
4449  * allocate a new copy of a given object
4450  *
4451  * Returns the newly created object.
4452  */
4453 xmlXPathObjectPtr
xmlXPathObjectCopy(xmlXPathObjectPtr val)4454 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
4455     xmlXPathObjectPtr ret;
4456 
4457     if (val == NULL)
4458 	return(NULL);
4459 
4460     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4461     if (ret == NULL)
4462 	return(NULL);
4463     memcpy(ret, val , sizeof(xmlXPathObject));
4464     switch (val->type) {
4465 	case XPATH_BOOLEAN:
4466 	case XPATH_NUMBER:
4467 #ifdef LIBXML_XPTR_LOCS_ENABLED
4468 	case XPATH_POINT:
4469 	case XPATH_RANGE:
4470 #endif /* LIBXML_XPTR_LOCS_ENABLED */
4471 	    break;
4472 	case XPATH_STRING:
4473 	    ret->stringval = xmlStrdup(val->stringval);
4474             if (ret->stringval == NULL) {
4475                 xmlFree(ret);
4476                 return(NULL);
4477             }
4478 	    break;
4479 	case XPATH_XSLT_TREE:
4480 #if 0
4481 /*
4482   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
4483   this previous handling is no longer correct, and can cause some serious
4484   problems (ref. bug 145547)
4485 */
4486 	    if ((val->nodesetval != NULL) &&
4487 		(val->nodesetval->nodeTab != NULL)) {
4488 		xmlNodePtr cur, tmp;
4489 		xmlDocPtr top;
4490 
4491 		ret->boolval = 1;
4492 		top =  xmlNewDoc(NULL);
4493 		top->name = (char *)
4494 		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
4495 		ret->user = top;
4496 		if (top != NULL) {
4497 		    top->doc = top;
4498 		    cur = val->nodesetval->nodeTab[0]->children;
4499 		    while (cur != NULL) {
4500 			tmp = xmlDocCopyNode(cur, top, 1);
4501 			xmlAddChild((xmlNodePtr) top, tmp);
4502 			cur = cur->next;
4503 		    }
4504 		}
4505 
4506 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
4507 	    } else
4508 		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
4509 	    /* Deallocate the copied tree value */
4510 	    break;
4511 #endif
4512 	case XPATH_NODESET:
4513 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
4514             if (ret->nodesetval == NULL) {
4515                 xmlFree(ret);
4516                 return(NULL);
4517             }
4518 	    /* Do not deallocate the copied tree value */
4519 	    ret->boolval = 0;
4520 	    break;
4521 #ifdef LIBXML_XPTR_LOCS_ENABLED
4522 	case XPATH_LOCATIONSET:
4523 	{
4524 	    xmlLocationSetPtr loc = val->user;
4525 	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
4526 	    break;
4527 	}
4528 #endif
4529         case XPATH_USERS:
4530 	    ret->user = val->user;
4531 	    break;
4532         default:
4533             xmlFree(ret);
4534             ret = NULL;
4535 	    break;
4536     }
4537     return(ret);
4538 }
4539 
4540 /**
4541  * xmlXPathFreeObject:
4542  * @obj:  the object to free
4543  *
4544  * Free up an xmlXPathObjectPtr object.
4545  */
4546 void
xmlXPathFreeObject(xmlXPathObjectPtr obj)4547 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
4548     if (obj == NULL) return;
4549     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4550         if (obj->nodesetval != NULL)
4551             xmlXPathFreeNodeSet(obj->nodesetval);
4552 #ifdef LIBXML_XPTR_LOCS_ENABLED
4553     } else if (obj->type == XPATH_LOCATIONSET) {
4554 	if (obj->user != NULL)
4555 	    xmlXPtrFreeLocationSet(obj->user);
4556 #endif
4557     } else if (obj->type == XPATH_STRING) {
4558 	if (obj->stringval != NULL)
4559 	    xmlFree(obj->stringval);
4560     }
4561     xmlFree(obj);
4562 }
4563 
4564 static void
xmlXPathFreeObjectEntry(void * obj,const xmlChar * name ATTRIBUTE_UNUSED)4565 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
4566     xmlXPathFreeObject((xmlXPathObjectPtr) obj);
4567 }
4568 
4569 /**
4570  * xmlXPathReleaseObject:
4571  * @obj:  the xmlXPathObjectPtr to free or to cache
4572  *
4573  * Depending on the state of the cache this frees the given
4574  * XPath object or stores it in the cache.
4575  */
4576 static void
xmlXPathReleaseObject(xmlXPathContextPtr ctxt,xmlXPathObjectPtr obj)4577 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
4578 {
4579     if (obj == NULL)
4580 	return;
4581     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4582 	 xmlXPathFreeObject(obj);
4583     } else {
4584 	xmlXPathContextCachePtr cache =
4585 	    (xmlXPathContextCachePtr) ctxt->cache;
4586 
4587 	switch (obj->type) {
4588 	    case XPATH_NODESET:
4589 	    case XPATH_XSLT_TREE:
4590 		if (obj->nodesetval != NULL) {
4591 		    if ((obj->nodesetval->nodeMax <= 40) &&
4592 			(cache->numNodeset < cache->maxNodeset)) {
4593                         obj->stringval = (void *) cache->nodesetObjs;
4594                         cache->nodesetObjs = obj;
4595                         cache->numNodeset += 1;
4596 			goto obj_cached;
4597 		    } else {
4598 			xmlXPathFreeNodeSet(obj->nodesetval);
4599 			obj->nodesetval = NULL;
4600 		    }
4601 		}
4602 		break;
4603 	    case XPATH_STRING:
4604 		if (obj->stringval != NULL)
4605 		    xmlFree(obj->stringval);
4606                 obj->stringval = NULL;
4607 		break;
4608 	    case XPATH_BOOLEAN:
4609 	    case XPATH_NUMBER:
4610 		break;
4611 #ifdef LIBXML_XPTR_LOCS_ENABLED
4612 	    case XPATH_LOCATIONSET:
4613 		if (obj->user != NULL) {
4614 		    xmlXPtrFreeLocationSet(obj->user);
4615 		}
4616 		goto free_obj;
4617 #endif
4618 	    default:
4619 		goto free_obj;
4620 	}
4621 
4622 	/*
4623 	* Fallback to adding to the misc-objects slot.
4624 	*/
4625         if (cache->numMisc >= cache->maxMisc)
4626 	    goto free_obj;
4627         obj->stringval = (void *) cache->miscObjs;
4628         cache->miscObjs = obj;
4629         cache->numMisc += 1;
4630 
4631 obj_cached:
4632         obj->boolval = 0;
4633 	if (obj->nodesetval != NULL) {
4634 	    xmlNodeSetPtr tmpset = obj->nodesetval;
4635 
4636 	    /*
4637 	    * Due to those nasty ns-nodes, we need to traverse
4638 	    * the list and free the ns-nodes.
4639 	    */
4640 	    if (tmpset->nodeNr > 0) {
4641 		int i;
4642 		xmlNodePtr node;
4643 
4644 		for (i = 0; i < tmpset->nodeNr; i++) {
4645 		    node = tmpset->nodeTab[i];
4646 		    if ((node != NULL) &&
4647 			(node->type == XML_NAMESPACE_DECL))
4648 		    {
4649 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4650 		    }
4651 		}
4652 	    }
4653 	    tmpset->nodeNr = 0;
4654         }
4655 
4656 	return;
4657 
4658 free_obj:
4659 	/*
4660 	* Cache is full; free the object.
4661 	*/
4662 	if (obj->nodesetval != NULL)
4663 	    xmlXPathFreeNodeSet(obj->nodesetval);
4664 	xmlFree(obj);
4665     }
4666     return;
4667 }
4668 
4669 
4670 /************************************************************************
4671  *									*
4672  *			Type Casting Routines				*
4673  *									*
4674  ************************************************************************/
4675 
4676 /**
4677  * xmlXPathCastBooleanToString:
4678  * @val:  a boolean
4679  *
4680  * Converts a boolean to its string value.
4681  *
4682  * Returns a newly allocated string.
4683  */
4684 xmlChar *
xmlXPathCastBooleanToString(int val)4685 xmlXPathCastBooleanToString (int val) {
4686     xmlChar *ret;
4687     if (val)
4688 	ret = xmlStrdup((const xmlChar *) "true");
4689     else
4690 	ret = xmlStrdup((const xmlChar *) "false");
4691     return(ret);
4692 }
4693 
4694 /**
4695  * xmlXPathCastNumberToString:
4696  * @val:  a number
4697  *
4698  * Converts a number to its string value.
4699  *
4700  * Returns a newly allocated string.
4701  */
4702 xmlChar *
xmlXPathCastNumberToString(double val)4703 xmlXPathCastNumberToString (double val) {
4704     xmlChar *ret;
4705     switch (xmlXPathIsInf(val)) {
4706     case 1:
4707 	ret = xmlStrdup((const xmlChar *) "Infinity");
4708 	break;
4709     case -1:
4710 	ret = xmlStrdup((const xmlChar *) "-Infinity");
4711 	break;
4712     default:
4713 	if (xmlXPathIsNaN(val)) {
4714 	    ret = xmlStrdup((const xmlChar *) "NaN");
4715 	} else if (val == 0) {
4716             /* Omit sign for negative zero. */
4717 	    ret = xmlStrdup((const xmlChar *) "0");
4718 	} else {
4719 	    /* could be improved */
4720 	    char buf[100];
4721 	    xmlXPathFormatNumber(val, buf, 99);
4722 	    buf[99] = 0;
4723 	    ret = xmlStrdup((const xmlChar *) buf);
4724 	}
4725     }
4726     return(ret);
4727 }
4728 
4729 /**
4730  * xmlXPathCastNodeToString:
4731  * @node:  a node
4732  *
4733  * Converts a node to its string value.
4734  *
4735  * Returns a newly allocated string.
4736  */
4737 xmlChar *
xmlXPathCastNodeToString(xmlNodePtr node)4738 xmlXPathCastNodeToString (xmlNodePtr node) {
4739     return(xmlNodeGetContent(node));
4740 }
4741 
4742 /**
4743  * xmlXPathCastNodeSetToString:
4744  * @ns:  a node-set
4745  *
4746  * Converts a node-set to its string value.
4747  *
4748  * Returns a newly allocated string.
4749  */
4750 xmlChar *
xmlXPathCastNodeSetToString(xmlNodeSetPtr ns)4751 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
4752     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
4753 	return(xmlStrdup((const xmlChar *) ""));
4754 
4755     if (ns->nodeNr > 1)
4756 	xmlXPathNodeSetSort(ns);
4757     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
4758 }
4759 
4760 /**
4761  * xmlXPathCastToString:
4762  * @val:  an XPath object
4763  *
4764  * Converts an existing object to its string() equivalent
4765  *
4766  * Returns the allocated string value of the object, NULL in case of error.
4767  *         It's up to the caller to free the string memory with xmlFree().
4768  */
4769 xmlChar *
xmlXPathCastToString(xmlXPathObjectPtr val)4770 xmlXPathCastToString(xmlXPathObjectPtr val) {
4771     xmlChar *ret = NULL;
4772 
4773     if (val == NULL)
4774 	return(xmlStrdup((const xmlChar *) ""));
4775     switch (val->type) {
4776 	case XPATH_UNDEFINED:
4777 	    ret = xmlStrdup((const xmlChar *) "");
4778 	    break;
4779         case XPATH_NODESET:
4780         case XPATH_XSLT_TREE:
4781 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
4782 	    break;
4783 	case XPATH_STRING:
4784 	    return(xmlStrdup(val->stringval));
4785         case XPATH_BOOLEAN:
4786 	    ret = xmlXPathCastBooleanToString(val->boolval);
4787 	    break;
4788 	case XPATH_NUMBER: {
4789 	    ret = xmlXPathCastNumberToString(val->floatval);
4790 	    break;
4791 	}
4792 	case XPATH_USERS:
4793 #ifdef LIBXML_XPTR_LOCS_ENABLED
4794 	case XPATH_POINT:
4795 	case XPATH_RANGE:
4796 	case XPATH_LOCATIONSET:
4797 #endif /* LIBXML_XPTR_LOCS_ENABLED */
4798 	    /* TODO */
4799 	    ret = xmlStrdup((const xmlChar *) "");
4800 	    break;
4801     }
4802     return(ret);
4803 }
4804 
4805 /**
4806  * xmlXPathConvertString:
4807  * @val:  an XPath object
4808  *
4809  * Converts an existing object to its string() equivalent
4810  *
4811  * Returns the new object, the old one is freed (or the operation
4812  *         is done directly on @val)
4813  */
4814 xmlXPathObjectPtr
xmlXPathConvertString(xmlXPathObjectPtr val)4815 xmlXPathConvertString(xmlXPathObjectPtr val) {
4816     xmlChar *res = NULL;
4817 
4818     if (val == NULL)
4819 	return(xmlXPathNewCString(""));
4820 
4821     switch (val->type) {
4822     case XPATH_UNDEFINED:
4823 	break;
4824     case XPATH_NODESET:
4825     case XPATH_XSLT_TREE:
4826 	res = xmlXPathCastNodeSetToString(val->nodesetval);
4827 	break;
4828     case XPATH_STRING:
4829 	return(val);
4830     case XPATH_BOOLEAN:
4831 	res = xmlXPathCastBooleanToString(val->boolval);
4832 	break;
4833     case XPATH_NUMBER:
4834 	res = xmlXPathCastNumberToString(val->floatval);
4835 	break;
4836     case XPATH_USERS:
4837 #ifdef LIBXML_XPTR_LOCS_ENABLED
4838     case XPATH_POINT:
4839     case XPATH_RANGE:
4840     case XPATH_LOCATIONSET:
4841 #endif /* LIBXML_XPTR_LOCS_ENABLED */
4842 	/* TODO */
4843 	break;
4844     }
4845     xmlXPathFreeObject(val);
4846     if (res == NULL)
4847 	return(xmlXPathNewCString(""));
4848     return(xmlXPathWrapString(res));
4849 }
4850 
4851 /**
4852  * xmlXPathCastBooleanToNumber:
4853  * @val:  a boolean
4854  *
4855  * Converts a boolean to its number value
4856  *
4857  * Returns the number value
4858  */
4859 double
xmlXPathCastBooleanToNumber(int val)4860 xmlXPathCastBooleanToNumber(int val) {
4861     if (val)
4862 	return(1.0);
4863     return(0.0);
4864 }
4865 
4866 /**
4867  * xmlXPathCastStringToNumber:
4868  * @val:  a string
4869  *
4870  * Converts a string to its number value
4871  *
4872  * Returns the number value
4873  */
4874 double
xmlXPathCastStringToNumber(const xmlChar * val)4875 xmlXPathCastStringToNumber(const xmlChar * val) {
4876     return(xmlXPathStringEvalNumber(val));
4877 }
4878 
4879 /**
4880  * xmlXPathNodeToNumberInternal:
4881  * @node:  a node
4882  *
4883  * Converts a node to its number value
4884  *
4885  * Returns the number value
4886  */
4887 static double
xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr node)4888 xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt, xmlNodePtr node) {
4889     xmlChar *strval;
4890     double ret;
4891 
4892     if (node == NULL)
4893 	return(xmlXPathNAN);
4894     strval = xmlXPathCastNodeToString(node);
4895     if (strval == NULL) {
4896         xmlXPathPErrMemory(ctxt);
4897 	return(xmlXPathNAN);
4898     }
4899     ret = xmlXPathCastStringToNumber(strval);
4900     xmlFree(strval);
4901 
4902     return(ret);
4903 }
4904 
4905 /**
4906  * xmlXPathCastNodeToNumber:
4907  * @node:  a node
4908  *
4909  * Converts a node to its number value
4910  *
4911  * Returns the number value
4912  */
4913 double
xmlXPathCastNodeToNumber(xmlNodePtr node)4914 xmlXPathCastNodeToNumber (xmlNodePtr node) {
4915     return(xmlXPathNodeToNumberInternal(NULL, node));
4916 }
4917 
4918 /**
4919  * xmlXPathCastNodeSetToNumber:
4920  * @ns:  a node-set
4921  *
4922  * Converts a node-set to its number value
4923  *
4924  * Returns the number value
4925  */
4926 double
xmlXPathCastNodeSetToNumber(xmlNodeSetPtr ns)4927 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
4928     xmlChar *str;
4929     double ret;
4930 
4931     if (ns == NULL)
4932 	return(xmlXPathNAN);
4933     str = xmlXPathCastNodeSetToString(ns);
4934     ret = xmlXPathCastStringToNumber(str);
4935     xmlFree(str);
4936     return(ret);
4937 }
4938 
4939 /**
4940  * xmlXPathCastToNumber:
4941  * @val:  an XPath object
4942  *
4943  * Converts an XPath object to its number value
4944  *
4945  * Returns the number value
4946  */
4947 double
xmlXPathCastToNumber(xmlXPathObjectPtr val)4948 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
4949     return(xmlXPathCastToNumberInternal(NULL, val));
4950 }
4951 
4952 /**
4953  * xmlXPathConvertNumber:
4954  * @val:  an XPath object
4955  *
4956  * Converts an existing object to its number() equivalent
4957  *
4958  * Returns the new object, the old one is freed (or the operation
4959  *         is done directly on @val)
4960  */
4961 xmlXPathObjectPtr
xmlXPathConvertNumber(xmlXPathObjectPtr val)4962 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
4963     xmlXPathObjectPtr ret;
4964 
4965     if (val == NULL)
4966 	return(xmlXPathNewFloat(0.0));
4967     if (val->type == XPATH_NUMBER)
4968 	return(val);
4969     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
4970     xmlXPathFreeObject(val);
4971     return(ret);
4972 }
4973 
4974 /**
4975  * xmlXPathCastNumberToBoolean:
4976  * @val:  a number
4977  *
4978  * Converts a number to its boolean value
4979  *
4980  * Returns the boolean value
4981  */
4982 int
xmlXPathCastNumberToBoolean(double val)4983 xmlXPathCastNumberToBoolean (double val) {
4984      if (xmlXPathIsNaN(val) || (val == 0.0))
4985 	 return(0);
4986      return(1);
4987 }
4988 
4989 /**
4990  * xmlXPathCastStringToBoolean:
4991  * @val:  a string
4992  *
4993  * Converts a string to its boolean value
4994  *
4995  * Returns the boolean value
4996  */
4997 int
xmlXPathCastStringToBoolean(const xmlChar * val)4998 xmlXPathCastStringToBoolean (const xmlChar *val) {
4999     if ((val == NULL) || (xmlStrlen(val) == 0))
5000 	return(0);
5001     return(1);
5002 }
5003 
5004 /**
5005  * xmlXPathCastNodeSetToBoolean:
5006  * @ns:  a node-set
5007  *
5008  * Converts a node-set to its boolean value
5009  *
5010  * Returns the boolean value
5011  */
5012 int
xmlXPathCastNodeSetToBoolean(xmlNodeSetPtr ns)5013 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5014     if ((ns == NULL) || (ns->nodeNr == 0))
5015 	return(0);
5016     return(1);
5017 }
5018 
5019 /**
5020  * xmlXPathCastToBoolean:
5021  * @val:  an XPath object
5022  *
5023  * Converts an XPath object to its boolean value
5024  *
5025  * Returns the boolean value
5026  */
5027 int
xmlXPathCastToBoolean(xmlXPathObjectPtr val)5028 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5029     int ret = 0;
5030 
5031     if (val == NULL)
5032 	return(0);
5033     switch (val->type) {
5034     case XPATH_UNDEFINED:
5035 	ret = 0;
5036 	break;
5037     case XPATH_NODESET:
5038     case XPATH_XSLT_TREE:
5039 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5040 	break;
5041     case XPATH_STRING:
5042 	ret = xmlXPathCastStringToBoolean(val->stringval);
5043 	break;
5044     case XPATH_NUMBER:
5045 	ret = xmlXPathCastNumberToBoolean(val->floatval);
5046 	break;
5047     case XPATH_BOOLEAN:
5048 	ret = val->boolval;
5049 	break;
5050     case XPATH_USERS:
5051 #ifdef LIBXML_XPTR_LOCS_ENABLED
5052     case XPATH_POINT:
5053     case XPATH_RANGE:
5054     case XPATH_LOCATIONSET:
5055 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5056 	/* TODO */
5057 	ret = 0;
5058 	break;
5059     }
5060     return(ret);
5061 }
5062 
5063 
5064 /**
5065  * xmlXPathConvertBoolean:
5066  * @val:  an XPath object
5067  *
5068  * Converts an existing object to its boolean() equivalent
5069  *
5070  * Returns the new object, the old one is freed (or the operation
5071  *         is done directly on @val)
5072  */
5073 xmlXPathObjectPtr
xmlXPathConvertBoolean(xmlXPathObjectPtr val)5074 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5075     xmlXPathObjectPtr ret;
5076 
5077     if (val == NULL)
5078 	return(xmlXPathNewBoolean(0));
5079     if (val->type == XPATH_BOOLEAN)
5080 	return(val);
5081     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5082     xmlXPathFreeObject(val);
5083     return(ret);
5084 }
5085 
5086 /************************************************************************
5087  *									*
5088  *		Routines to handle XPath contexts			*
5089  *									*
5090  ************************************************************************/
5091 
5092 /**
5093  * xmlXPathNewContext:
5094  * @doc:  the XML document
5095  *
5096  * Create a new xmlXPathContext
5097  *
5098  * Returns the xmlXPathContext just allocated. The caller will need to free it.
5099  */
5100 xmlXPathContextPtr
xmlXPathNewContext(xmlDocPtr doc)5101 xmlXPathNewContext(xmlDocPtr doc) {
5102     xmlXPathContextPtr ret;
5103 
5104     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5105     if (ret == NULL)
5106 	return(NULL);
5107     memset(ret, 0 , sizeof(xmlXPathContext));
5108     ret->doc = doc;
5109     ret->node = NULL;
5110 
5111     ret->varHash = NULL;
5112 
5113     ret->nb_types = 0;
5114     ret->max_types = 0;
5115     ret->types = NULL;
5116 
5117     ret->nb_axis = 0;
5118     ret->max_axis = 0;
5119     ret->axis = NULL;
5120 
5121     ret->nsHash = NULL;
5122     ret->user = NULL;
5123 
5124     ret->contextSize = -1;
5125     ret->proximityPosition = -1;
5126 
5127 #ifdef XP_DEFAULT_CACHE_ON
5128     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
5129 	xmlXPathFreeContext(ret);
5130 	return(NULL);
5131     }
5132 #endif
5133 
5134     xmlXPathRegisterAllFunctions(ret);
5135 
5136     if (ret->lastError.code != XML_ERR_OK) {
5137 	xmlXPathFreeContext(ret);
5138 	return(NULL);
5139     }
5140 
5141     return(ret);
5142 }
5143 
5144 /**
5145  * xmlXPathFreeContext:
5146  * @ctxt:  the context to free
5147  *
5148  * Free up an xmlXPathContext
5149  */
5150 void
xmlXPathFreeContext(xmlXPathContextPtr ctxt)5151 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
5152     if (ctxt == NULL) return;
5153 
5154     if (ctxt->cache != NULL)
5155 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
5156     xmlXPathRegisteredNsCleanup(ctxt);
5157     xmlXPathRegisteredFuncsCleanup(ctxt);
5158     xmlXPathRegisteredVariablesCleanup(ctxt);
5159     xmlResetError(&ctxt->lastError);
5160     xmlFree(ctxt);
5161 }
5162 
5163 /**
5164  * xmlXPathSetErrorHandler:
5165  * @ctxt:  the XPath context
5166  * @handler:  error handler
5167  * @data:  user data which will be passed to the handler
5168  *
5169  * Register a callback function that will be called on errors and
5170  * warnings. If handler is NULL, the error handler will be deactivated.
5171  *
5172  * Available since 2.13.0.
5173  */
5174 void
xmlXPathSetErrorHandler(xmlXPathContextPtr ctxt,xmlStructuredErrorFunc handler,void * data)5175 xmlXPathSetErrorHandler(xmlXPathContextPtr ctxt,
5176                         xmlStructuredErrorFunc handler, void *data) {
5177     if (ctxt == NULL)
5178         return;
5179 
5180     ctxt->error = handler;
5181     ctxt->userData = data;
5182 }
5183 
5184 /************************************************************************
5185  *									*
5186  *		Routines to handle XPath parser contexts		*
5187  *									*
5188  ************************************************************************/
5189 
5190 /**
5191  * xmlXPathNewParserContext:
5192  * @str:  the XPath expression
5193  * @ctxt:  the XPath context
5194  *
5195  * Create a new xmlXPathParserContext
5196  *
5197  * Returns the xmlXPathParserContext just allocated.
5198  */
5199 xmlXPathParserContextPtr
xmlXPathNewParserContext(const xmlChar * str,xmlXPathContextPtr ctxt)5200 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
5201     xmlXPathParserContextPtr ret;
5202 
5203     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5204     if (ret == NULL) {
5205         xmlXPathErrMemory(ctxt);
5206 	return(NULL);
5207     }
5208     memset(ret, 0 , sizeof(xmlXPathParserContext));
5209     ret->cur = ret->base = str;
5210     ret->context = ctxt;
5211 
5212     ret->comp = xmlXPathNewCompExpr();
5213     if (ret->comp == NULL) {
5214         xmlXPathErrMemory(ctxt);
5215 	xmlFree(ret->valueTab);
5216 	xmlFree(ret);
5217 	return(NULL);
5218     }
5219     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
5220         ret->comp->dict = ctxt->dict;
5221 	xmlDictReference(ret->comp->dict);
5222     }
5223 
5224     return(ret);
5225 }
5226 
5227 /**
5228  * xmlXPathCompParserContext:
5229  * @comp:  the XPath compiled expression
5230  * @ctxt:  the XPath context
5231  *
5232  * Create a new xmlXPathParserContext when processing a compiled expression
5233  *
5234  * Returns the xmlXPathParserContext just allocated.
5235  */
5236 static xmlXPathParserContextPtr
xmlXPathCompParserContext(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)5237 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
5238     xmlXPathParserContextPtr ret;
5239 
5240     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5241     if (ret == NULL) {
5242         xmlXPathErrMemory(ctxt);
5243 	return(NULL);
5244     }
5245     memset(ret, 0 , sizeof(xmlXPathParserContext));
5246 
5247     /* Allocate the value stack */
5248     ret->valueTab = (xmlXPathObjectPtr *)
5249                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
5250     if (ret->valueTab == NULL) {
5251 	xmlFree(ret);
5252 	xmlXPathErrMemory(ctxt);
5253 	return(NULL);
5254     }
5255     ret->valueNr = 0;
5256     ret->valueMax = 10;
5257     ret->value = NULL;
5258 
5259     ret->context = ctxt;
5260     ret->comp = comp;
5261 
5262     return(ret);
5263 }
5264 
5265 /**
5266  * xmlXPathFreeParserContext:
5267  * @ctxt:  the context to free
5268  *
5269  * Free up an xmlXPathParserContext
5270  */
5271 void
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt)5272 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
5273     int i;
5274 
5275     if (ctxt->valueTab != NULL) {
5276         for (i = 0; i < ctxt->valueNr; i++) {
5277             if (ctxt->context)
5278                 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
5279             else
5280                 xmlXPathFreeObject(ctxt->valueTab[i]);
5281         }
5282         xmlFree(ctxt->valueTab);
5283     }
5284     if (ctxt->comp != NULL) {
5285 #ifdef XPATH_STREAMING
5286 	if (ctxt->comp->stream != NULL) {
5287 	    xmlFreePatternList(ctxt->comp->stream);
5288 	    ctxt->comp->stream = NULL;
5289 	}
5290 #endif
5291 	xmlXPathFreeCompExpr(ctxt->comp);
5292     }
5293     xmlFree(ctxt);
5294 }
5295 
5296 /************************************************************************
5297  *									*
5298  *		The implicit core function library			*
5299  *									*
5300  ************************************************************************/
5301 
5302 /**
5303  * xmlXPathNodeValHash:
5304  * @node:  a node pointer
5305  *
5306  * Function computing the beginning of the string value of the node,
5307  * used to speed up comparisons
5308  *
5309  * Returns an int usable as a hash
5310  */
5311 static unsigned int
xmlXPathNodeValHash(xmlNodePtr node)5312 xmlXPathNodeValHash(xmlNodePtr node) {
5313     int len = 2;
5314     const xmlChar * string = NULL;
5315     xmlNodePtr tmp = NULL;
5316     unsigned int ret = 0;
5317 
5318     if (node == NULL)
5319 	return(0);
5320 
5321     if (node->type == XML_DOCUMENT_NODE) {
5322 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
5323 	if (tmp == NULL)
5324 	    node = node->children;
5325 	else
5326 	    node = tmp;
5327 
5328 	if (node == NULL)
5329 	    return(0);
5330     }
5331 
5332     switch (node->type) {
5333 	case XML_COMMENT_NODE:
5334 	case XML_PI_NODE:
5335 	case XML_CDATA_SECTION_NODE:
5336 	case XML_TEXT_NODE:
5337 	    string = node->content;
5338 	    if (string == NULL)
5339 		return(0);
5340 	    if (string[0] == 0)
5341 		return(0);
5342 	    return(string[0] + (string[1] << 8));
5343 	case XML_NAMESPACE_DECL:
5344 	    string = ((xmlNsPtr)node)->href;
5345 	    if (string == NULL)
5346 		return(0);
5347 	    if (string[0] == 0)
5348 		return(0);
5349 	    return(string[0] + (string[1] << 8));
5350 	case XML_ATTRIBUTE_NODE:
5351 	    tmp = ((xmlAttrPtr) node)->children;
5352 	    break;
5353 	case XML_ELEMENT_NODE:
5354 	    tmp = node->children;
5355 	    break;
5356 	default:
5357 	    return(0);
5358     }
5359     while (tmp != NULL) {
5360 	switch (tmp->type) {
5361 	    case XML_CDATA_SECTION_NODE:
5362 	    case XML_TEXT_NODE:
5363 		string = tmp->content;
5364 		break;
5365 	    default:
5366                 string = NULL;
5367 		break;
5368 	}
5369 	if ((string != NULL) && (string[0] != 0)) {
5370 	    if (len == 1) {
5371 		return(ret + (string[0] << 8));
5372 	    }
5373 	    if (string[1] == 0) {
5374 		len = 1;
5375 		ret = string[0];
5376 	    } else {
5377 		return(string[0] + (string[1] << 8));
5378 	    }
5379 	}
5380 	/*
5381 	 * Skip to next node
5382 	 */
5383         if ((tmp->children != NULL) &&
5384             (tmp->type != XML_DTD_NODE) &&
5385             (tmp->type != XML_ENTITY_REF_NODE) &&
5386             (tmp->children->type != XML_ENTITY_DECL)) {
5387             tmp = tmp->children;
5388             continue;
5389 	}
5390 	if (tmp == node)
5391 	    break;
5392 
5393 	if (tmp->next != NULL) {
5394 	    tmp = tmp->next;
5395 	    continue;
5396 	}
5397 
5398 	do {
5399 	    tmp = tmp->parent;
5400 	    if (tmp == NULL)
5401 		break;
5402 	    if (tmp == node) {
5403 		tmp = NULL;
5404 		break;
5405 	    }
5406 	    if (tmp->next != NULL) {
5407 		tmp = tmp->next;
5408 		break;
5409 	    }
5410 	} while (tmp != NULL);
5411     }
5412     return(ret);
5413 }
5414 
5415 /**
5416  * xmlXPathStringHash:
5417  * @string:  a string
5418  *
5419  * Function computing the beginning of the string value of the node,
5420  * used to speed up comparisons
5421  *
5422  * Returns an int usable as a hash
5423  */
5424 static unsigned int
xmlXPathStringHash(const xmlChar * string)5425 xmlXPathStringHash(const xmlChar * string) {
5426     if (string == NULL)
5427 	return(0);
5428     if (string[0] == 0)
5429 	return(0);
5430     return(string[0] + (string[1] << 8));
5431 }
5432 
5433 /**
5434  * xmlXPathCompareNodeSetFloat:
5435  * @ctxt:  the XPath Parser context
5436  * @inf:  less than (1) or greater than (0)
5437  * @strict:  is the comparison strict
5438  * @arg:  the node set
5439  * @f:  the value
5440  *
5441  * Implement the compare operation between a nodeset and a number
5442  *     @ns < @val    (1, 1, ...
5443  *     @ns <= @val   (1, 0, ...
5444  *     @ns > @val    (0, 1, ...
5445  *     @ns >= @val   (0, 0, ...
5446  *
5447  * If one object to be compared is a node-set and the other is a number,
5448  * then the comparison will be true if and only if there is a node in the
5449  * node-set such that the result of performing the comparison on the number
5450  * to be compared and on the result of converting the string-value of that
5451  * node to a number using the number function is true.
5452  *
5453  * Returns 0 or 1 depending on the results of the test.
5454  */
5455 static int
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr f)5456 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
5457 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5458     int i, ret = 0;
5459     xmlNodeSetPtr ns;
5460     xmlChar *str2;
5461 
5462     if ((f == NULL) || (arg == NULL) ||
5463 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5464 	xmlXPathReleaseObject(ctxt->context, arg);
5465 	xmlXPathReleaseObject(ctxt->context, f);
5466         return(0);
5467     }
5468     ns = arg->nodesetval;
5469     if (ns != NULL) {
5470 	for (i = 0;i < ns->nodeNr;i++) {
5471 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5472 	     if (str2 != NULL) {
5473 		 valuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5474 		 xmlFree(str2);
5475 		 xmlXPathNumberFunction(ctxt, 1);
5476 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, f));
5477 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
5478 		 if (ret)
5479 		     break;
5480 	     } else {
5481                  xmlXPathPErrMemory(ctxt);
5482              }
5483 	}
5484     }
5485     xmlXPathReleaseObject(ctxt->context, arg);
5486     xmlXPathReleaseObject(ctxt->context, f);
5487     return(ret);
5488 }
5489 
5490 /**
5491  * xmlXPathCompareNodeSetString:
5492  * @ctxt:  the XPath Parser context
5493  * @inf:  less than (1) or greater than (0)
5494  * @strict:  is the comparison strict
5495  * @arg:  the node set
5496  * @s:  the value
5497  *
5498  * Implement the compare operation between a nodeset and a string
5499  *     @ns < @val    (1, 1, ...
5500  *     @ns <= @val   (1, 0, ...
5501  *     @ns > @val    (0, 1, ...
5502  *     @ns >= @val   (0, 0, ...
5503  *
5504  * If one object to be compared is a node-set and the other is a string,
5505  * then the comparison will be true if and only if there is a node in
5506  * the node-set such that the result of performing the comparison on the
5507  * string-value of the node and the other string is true.
5508  *
5509  * Returns 0 or 1 depending on the results of the test.
5510  */
5511 static int
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr s)5512 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
5513 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5514     int i, ret = 0;
5515     xmlNodeSetPtr ns;
5516     xmlChar *str2;
5517 
5518     if ((s == NULL) || (arg == NULL) ||
5519 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5520 	xmlXPathReleaseObject(ctxt->context, arg);
5521 	xmlXPathReleaseObject(ctxt->context, s);
5522         return(0);
5523     }
5524     ns = arg->nodesetval;
5525     if (ns != NULL) {
5526 	for (i = 0;i < ns->nodeNr;i++) {
5527 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5528 	     if (str2 != NULL) {
5529 		 valuePush(ctxt,
5530 			   xmlXPathCacheNewString(ctxt, str2));
5531 		 xmlFree(str2);
5532 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, s));
5533 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
5534 		 if (ret)
5535 		     break;
5536 	     } else {
5537                  xmlXPathPErrMemory(ctxt);
5538              }
5539 	}
5540     }
5541     xmlXPathReleaseObject(ctxt->context, arg);
5542     xmlXPathReleaseObject(ctxt->context, s);
5543     return(ret);
5544 }
5545 
5546 /**
5547  * xmlXPathCompareNodeSets:
5548  * @inf:  less than (1) or greater than (0)
5549  * @strict:  is the comparison strict
5550  * @arg1:  the first node set object
5551  * @arg2:  the second node set object
5552  *
5553  * Implement the compare operation on nodesets:
5554  *
5555  * If both objects to be compared are node-sets, then the comparison
5556  * will be true if and only if there is a node in the first node-set
5557  * and a node in the second node-set such that the result of performing
5558  * the comparison on the string-values of the two nodes is true.
5559  * ....
5560  * When neither object to be compared is a node-set and the operator
5561  * is <=, <, >= or >, then the objects are compared by converting both
5562  * objects to numbers and comparing the numbers according to IEEE 754.
5563  * ....
5564  * The number function converts its argument to a number as follows:
5565  *  - a string that consists of optional whitespace followed by an
5566  *    optional minus sign followed by a Number followed by whitespace
5567  *    is converted to the IEEE 754 number that is nearest (according
5568  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
5569  *    represented by the string; any other string is converted to NaN
5570  *
5571  * Conclusion all nodes need to be converted first to their string value
5572  * and then the comparison must be done when possible
5573  */
5574 static int
xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)5575 xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt, int inf, int strict,
5576 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5577     int i, j, init = 0;
5578     double val1;
5579     double *values2;
5580     int ret = 0;
5581     xmlNodeSetPtr ns1;
5582     xmlNodeSetPtr ns2;
5583 
5584     if ((arg1 == NULL) ||
5585 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5586 	xmlXPathFreeObject(arg2);
5587         return(0);
5588     }
5589     if ((arg2 == NULL) ||
5590 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
5591 	xmlXPathFreeObject(arg1);
5592 	xmlXPathFreeObject(arg2);
5593         return(0);
5594     }
5595 
5596     ns1 = arg1->nodesetval;
5597     ns2 = arg2->nodesetval;
5598 
5599     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5600 	xmlXPathFreeObject(arg1);
5601 	xmlXPathFreeObject(arg2);
5602 	return(0);
5603     }
5604     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5605 	xmlXPathFreeObject(arg1);
5606 	xmlXPathFreeObject(arg2);
5607 	return(0);
5608     }
5609 
5610     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5611     if (values2 == NULL) {
5612         xmlXPathPErrMemory(ctxt);
5613 	xmlXPathFreeObject(arg1);
5614 	xmlXPathFreeObject(arg2);
5615 	return(0);
5616     }
5617     for (i = 0;i < ns1->nodeNr;i++) {
5618 	val1 = xmlXPathNodeToNumberInternal(ctxt, ns1->nodeTab[i]);
5619 	if (xmlXPathIsNaN(val1))
5620 	    continue;
5621 	for (j = 0;j < ns2->nodeNr;j++) {
5622 	    if (init == 0) {
5623 		values2[j] = xmlXPathNodeToNumberInternal(ctxt,
5624                                                           ns2->nodeTab[j]);
5625 	    }
5626 	    if (xmlXPathIsNaN(values2[j]))
5627 		continue;
5628 	    if (inf && strict)
5629 		ret = (val1 < values2[j]);
5630 	    else if (inf && !strict)
5631 		ret = (val1 <= values2[j]);
5632 	    else if (!inf && strict)
5633 		ret = (val1 > values2[j]);
5634 	    else if (!inf && !strict)
5635 		ret = (val1 >= values2[j]);
5636 	    if (ret)
5637 		break;
5638 	}
5639 	if (ret)
5640 	    break;
5641 	init = 1;
5642     }
5643     xmlFree(values2);
5644     xmlXPathFreeObject(arg1);
5645     xmlXPathFreeObject(arg2);
5646     return(ret);
5647 }
5648 
5649 /**
5650  * xmlXPathCompareNodeSetValue:
5651  * @ctxt:  the XPath Parser context
5652  * @inf:  less than (1) or greater than (0)
5653  * @strict:  is the comparison strict
5654  * @arg:  the node set
5655  * @val:  the value
5656  *
5657  * Implement the compare operation between a nodeset and a value
5658  *     @ns < @val    (1, 1, ...
5659  *     @ns <= @val   (1, 0, ...
5660  *     @ns > @val    (0, 1, ...
5661  *     @ns >= @val   (0, 0, ...
5662  *
5663  * If one object to be compared is a node-set and the other is a boolean,
5664  * then the comparison will be true if and only if the result of performing
5665  * the comparison on the boolean and on the result of converting
5666  * the node-set to a boolean using the boolean function is true.
5667  *
5668  * Returns 0 or 1 depending on the results of the test.
5669  */
5670 static int
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr val)5671 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
5672 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
5673     if ((val == NULL) || (arg == NULL) ||
5674 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5675         return(0);
5676 
5677     switch(val->type) {
5678         case XPATH_NUMBER:
5679 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
5680         case XPATH_NODESET:
5681         case XPATH_XSLT_TREE:
5682 	    return(xmlXPathCompareNodeSets(ctxt, inf, strict, arg, val));
5683         case XPATH_STRING:
5684 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
5685         case XPATH_BOOLEAN:
5686 	    valuePush(ctxt, arg);
5687 	    xmlXPathBooleanFunction(ctxt, 1);
5688 	    valuePush(ctxt, val);
5689 	    return(xmlXPathCompareValues(ctxt, inf, strict));
5690 	default:
5691             xmlXPathReleaseObject(ctxt->context, arg);
5692             xmlXPathReleaseObject(ctxt->context, val);
5693             XP_ERROR0(XPATH_INVALID_TYPE);
5694     }
5695     return(0);
5696 }
5697 
5698 /**
5699  * xmlXPathEqualNodeSetString:
5700  * @arg:  the nodeset object argument
5701  * @str:  the string to compare to.
5702  * @neq:  flag to show whether for '=' (0) or '!=' (1)
5703  *
5704  * Implement the equal operation on XPath objects content: @arg1 == @arg2
5705  * If one object to be compared is a node-set and the other is a string,
5706  * then the comparison will be true if and only if there is a node in
5707  * the node-set such that the result of performing the comparison on the
5708  * string-value of the node and the other string is true.
5709  *
5710  * Returns 0 or 1 depending on the results of the test.
5711  */
5712 static int
xmlXPathEqualNodeSetString(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,const xmlChar * str,int neq)5713 xmlXPathEqualNodeSetString(xmlXPathParserContextPtr ctxt,
5714                            xmlXPathObjectPtr arg, const xmlChar * str, int neq)
5715 {
5716     int i;
5717     xmlNodeSetPtr ns;
5718     xmlChar *str2;
5719     unsigned int hash;
5720 
5721     if ((str == NULL) || (arg == NULL) ||
5722         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5723         return (0);
5724     ns = arg->nodesetval;
5725     /*
5726      * A NULL nodeset compared with a string is always false
5727      * (since there is no node equal, and no node not equal)
5728      */
5729     if ((ns == NULL) || (ns->nodeNr <= 0) )
5730         return (0);
5731     hash = xmlXPathStringHash(str);
5732     for (i = 0; i < ns->nodeNr; i++) {
5733         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
5734             str2 = xmlNodeGetContent(ns->nodeTab[i]);
5735             if (str2 == NULL) {
5736                 xmlXPathPErrMemory(ctxt);
5737                 return(0);
5738             }
5739             if (xmlStrEqual(str, str2)) {
5740                 xmlFree(str2);
5741 		if (neq)
5742 		    continue;
5743                 return (1);
5744             } else if (neq) {
5745 		xmlFree(str2);
5746 		return (1);
5747 	    }
5748             xmlFree(str2);
5749         } else if (neq)
5750 	    return (1);
5751     }
5752     return (0);
5753 }
5754 
5755 /**
5756  * xmlXPathEqualNodeSetFloat:
5757  * @arg:  the nodeset object argument
5758  * @f:  the float to compare to
5759  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
5760  *
5761  * Implement the equal operation on XPath objects content: @arg1 == @arg2
5762  * If one object to be compared is a node-set and the other is a number,
5763  * then the comparison will be true if and only if there is a node in
5764  * the node-set such that the result of performing the comparison on the
5765  * number to be compared and on the result of converting the string-value
5766  * of that node to a number using the number function is true.
5767  *
5768  * Returns 0 or 1 depending on the results of the test.
5769  */
5770 static int
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,double f,int neq)5771 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
5772     xmlXPathObjectPtr arg, double f, int neq) {
5773   int i, ret=0;
5774   xmlNodeSetPtr ns;
5775   xmlChar *str2;
5776   xmlXPathObjectPtr val;
5777   double v;
5778 
5779     if ((arg == NULL) ||
5780 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5781         return(0);
5782 
5783     ns = arg->nodesetval;
5784     if (ns != NULL) {
5785 	for (i=0;i<ns->nodeNr;i++) {
5786 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5787 	    if (str2 != NULL) {
5788 		valuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5789 		xmlFree(str2);
5790 		xmlXPathNumberFunction(ctxt, 1);
5791                 CHECK_ERROR0;
5792 		val = valuePop(ctxt);
5793 		v = val->floatval;
5794 		xmlXPathReleaseObject(ctxt->context, val);
5795 		if (!xmlXPathIsNaN(v)) {
5796 		    if ((!neq) && (v==f)) {
5797 			ret = 1;
5798 			break;
5799 		    } else if ((neq) && (v!=f)) {
5800 			ret = 1;
5801 			break;
5802 		    }
5803 		} else {	/* NaN is unequal to any value */
5804 		    if (neq)
5805 			ret = 1;
5806 		}
5807 	    } else {
5808                 xmlXPathPErrMemory(ctxt);
5809             }
5810 	}
5811     }
5812 
5813     return(ret);
5814 }
5815 
5816 
5817 /**
5818  * xmlXPathEqualNodeSets:
5819  * @arg1:  first nodeset object argument
5820  * @arg2:  second nodeset object argument
5821  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
5822  *
5823  * Implement the equal / not equal operation on XPath nodesets:
5824  * @arg1 == @arg2  or  @arg1 != @arg2
5825  * If both objects to be compared are node-sets, then the comparison
5826  * will be true if and only if there is a node in the first node-set and
5827  * a node in the second node-set such that the result of performing the
5828  * comparison on the string-values of the two nodes is true.
5829  *
5830  * (needless to say, this is a costly operation)
5831  *
5832  * Returns 0 or 1 depending on the results of the test.
5833  */
5834 static int
xmlXPathEqualNodeSets(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2,int neq)5835 xmlXPathEqualNodeSets(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr arg1,
5836                       xmlXPathObjectPtr arg2, int neq) {
5837     int i, j;
5838     unsigned int *hashs1;
5839     unsigned int *hashs2;
5840     xmlChar **values1;
5841     xmlChar **values2;
5842     int ret = 0;
5843     xmlNodeSetPtr ns1;
5844     xmlNodeSetPtr ns2;
5845 
5846     if ((arg1 == NULL) ||
5847 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
5848         return(0);
5849     if ((arg2 == NULL) ||
5850 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
5851         return(0);
5852 
5853     ns1 = arg1->nodesetval;
5854     ns2 = arg2->nodesetval;
5855 
5856     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
5857 	return(0);
5858     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
5859 	return(0);
5860 
5861     /*
5862      * for equal, check if there is a node pertaining to both sets
5863      */
5864     if (neq == 0)
5865 	for (i = 0;i < ns1->nodeNr;i++)
5866 	    for (j = 0;j < ns2->nodeNr;j++)
5867 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
5868 		    return(1);
5869 
5870     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
5871     if (values1 == NULL) {
5872         xmlXPathPErrMemory(ctxt);
5873 	return(0);
5874     }
5875     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
5876     if (hashs1 == NULL) {
5877         xmlXPathPErrMemory(ctxt);
5878 	xmlFree(values1);
5879 	return(0);
5880     }
5881     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
5882     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
5883     if (values2 == NULL) {
5884         xmlXPathPErrMemory(ctxt);
5885 	xmlFree(hashs1);
5886 	xmlFree(values1);
5887 	return(0);
5888     }
5889     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
5890     if (hashs2 == NULL) {
5891         xmlXPathPErrMemory(ctxt);
5892 	xmlFree(hashs1);
5893 	xmlFree(values1);
5894 	xmlFree(values2);
5895 	return(0);
5896     }
5897     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
5898     for (i = 0;i < ns1->nodeNr;i++) {
5899 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
5900 	for (j = 0;j < ns2->nodeNr;j++) {
5901 	    if (i == 0)
5902 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
5903 	    if (hashs1[i] != hashs2[j]) {
5904 		if (neq) {
5905 		    ret = 1;
5906 		    break;
5907 		}
5908 	    }
5909 	    else {
5910 		if (values1[i] == NULL) {
5911 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
5912                     if (values1[i] == NULL)
5913                         xmlXPathPErrMemory(ctxt);
5914                 }
5915 		if (values2[j] == NULL) {
5916 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
5917                     if (values2[j] == NULL)
5918                         xmlXPathPErrMemory(ctxt);
5919                 }
5920 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
5921 		if (ret)
5922 		    break;
5923 	    }
5924 	}
5925 	if (ret)
5926 	    break;
5927     }
5928     for (i = 0;i < ns1->nodeNr;i++)
5929 	if (values1[i] != NULL)
5930 	    xmlFree(values1[i]);
5931     for (j = 0;j < ns2->nodeNr;j++)
5932 	if (values2[j] != NULL)
5933 	    xmlFree(values2[j]);
5934     xmlFree(values1);
5935     xmlFree(values2);
5936     xmlFree(hashs1);
5937     xmlFree(hashs2);
5938     return(ret);
5939 }
5940 
5941 static int
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)5942 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
5943   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5944     int ret = 0;
5945     /*
5946      *At this point we are assured neither arg1 nor arg2
5947      *is a nodeset, so we can just pick the appropriate routine.
5948      */
5949     switch (arg1->type) {
5950         case XPATH_UNDEFINED:
5951 	    break;
5952         case XPATH_BOOLEAN:
5953 	    switch (arg2->type) {
5954 	        case XPATH_UNDEFINED:
5955 		    break;
5956 		case XPATH_BOOLEAN:
5957 		    ret = (arg1->boolval == arg2->boolval);
5958 		    break;
5959 		case XPATH_NUMBER:
5960 		    ret = (arg1->boolval ==
5961 			   xmlXPathCastNumberToBoolean(arg2->floatval));
5962 		    break;
5963 		case XPATH_STRING:
5964 		    if ((arg2->stringval == NULL) ||
5965 			(arg2->stringval[0] == 0)) ret = 0;
5966 		    else
5967 			ret = 1;
5968 		    ret = (arg1->boolval == ret);
5969 		    break;
5970 		case XPATH_USERS:
5971 #ifdef LIBXML_XPTR_LOCS_ENABLED
5972 		case XPATH_POINT:
5973 		case XPATH_RANGE:
5974 		case XPATH_LOCATIONSET:
5975 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5976 		    /* TODO */
5977 		    break;
5978 		case XPATH_NODESET:
5979 		case XPATH_XSLT_TREE:
5980 		    break;
5981 	    }
5982 	    break;
5983         case XPATH_NUMBER:
5984 	    switch (arg2->type) {
5985 	        case XPATH_UNDEFINED:
5986 		    break;
5987 		case XPATH_BOOLEAN:
5988 		    ret = (arg2->boolval==
5989 			   xmlXPathCastNumberToBoolean(arg1->floatval));
5990 		    break;
5991 		case XPATH_STRING:
5992 		    valuePush(ctxt, arg2);
5993 		    xmlXPathNumberFunction(ctxt, 1);
5994 		    arg2 = valuePop(ctxt);
5995                     if (ctxt->error)
5996                         break;
5997                     /* Falls through. */
5998 		case XPATH_NUMBER:
5999 		    /* Hand check NaN and Infinity equalities */
6000 		    if (xmlXPathIsNaN(arg1->floatval) ||
6001 			    xmlXPathIsNaN(arg2->floatval)) {
6002 		        ret = 0;
6003 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6004 		        if (xmlXPathIsInf(arg2->floatval) == 1)
6005 			    ret = 1;
6006 			else
6007 			    ret = 0;
6008 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6009 			if (xmlXPathIsInf(arg2->floatval) == -1)
6010 			    ret = 1;
6011 			else
6012 			    ret = 0;
6013 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6014 			if (xmlXPathIsInf(arg1->floatval) == 1)
6015 			    ret = 1;
6016 			else
6017 			    ret = 0;
6018 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6019 			if (xmlXPathIsInf(arg1->floatval) == -1)
6020 			    ret = 1;
6021 			else
6022 			    ret = 0;
6023 		    } else {
6024 		        ret = (arg1->floatval == arg2->floatval);
6025 		    }
6026 		    break;
6027 		case XPATH_USERS:
6028 #ifdef LIBXML_XPTR_LOCS_ENABLED
6029 		case XPATH_POINT:
6030 		case XPATH_RANGE:
6031 		case XPATH_LOCATIONSET:
6032 #endif /* LIBXML_XPTR_LOCS_ENABLED */
6033 		    /* TODO */
6034 		    break;
6035 		case XPATH_NODESET:
6036 		case XPATH_XSLT_TREE:
6037 		    break;
6038 	    }
6039 	    break;
6040         case XPATH_STRING:
6041 	    switch (arg2->type) {
6042 	        case XPATH_UNDEFINED:
6043 		    break;
6044 		case XPATH_BOOLEAN:
6045 		    if ((arg1->stringval == NULL) ||
6046 			(arg1->stringval[0] == 0)) ret = 0;
6047 		    else
6048 			ret = 1;
6049 		    ret = (arg2->boolval == ret);
6050 		    break;
6051 		case XPATH_STRING:
6052 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6053 		    break;
6054 		case XPATH_NUMBER:
6055 		    valuePush(ctxt, arg1);
6056 		    xmlXPathNumberFunction(ctxt, 1);
6057 		    arg1 = valuePop(ctxt);
6058                     if (ctxt->error)
6059                         break;
6060 		    /* Hand check NaN and Infinity equalities */
6061 		    if (xmlXPathIsNaN(arg1->floatval) ||
6062 			    xmlXPathIsNaN(arg2->floatval)) {
6063 		        ret = 0;
6064 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6065 			if (xmlXPathIsInf(arg2->floatval) == 1)
6066 			    ret = 1;
6067 			else
6068 			    ret = 0;
6069 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6070 			if (xmlXPathIsInf(arg2->floatval) == -1)
6071 			    ret = 1;
6072 			else
6073 			    ret = 0;
6074 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6075 			if (xmlXPathIsInf(arg1->floatval) == 1)
6076 			    ret = 1;
6077 			else
6078 			    ret = 0;
6079 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6080 			if (xmlXPathIsInf(arg1->floatval) == -1)
6081 			    ret = 1;
6082 			else
6083 			    ret = 0;
6084 		    } else {
6085 		        ret = (arg1->floatval == arg2->floatval);
6086 		    }
6087 		    break;
6088 		case XPATH_USERS:
6089 #ifdef LIBXML_XPTR_LOCS_ENABLED
6090 		case XPATH_POINT:
6091 		case XPATH_RANGE:
6092 		case XPATH_LOCATIONSET:
6093 #endif /* LIBXML_XPTR_LOCS_ENABLED */
6094 		    /* TODO */
6095 		    break;
6096 		case XPATH_NODESET:
6097 		case XPATH_XSLT_TREE:
6098 		    break;
6099 	    }
6100 	    break;
6101         case XPATH_USERS:
6102 #ifdef LIBXML_XPTR_LOCS_ENABLED
6103 	case XPATH_POINT:
6104 	case XPATH_RANGE:
6105 	case XPATH_LOCATIONSET:
6106 #endif /* LIBXML_XPTR_LOCS_ENABLED */
6107 	    /* TODO */
6108 	    break;
6109 	case XPATH_NODESET:
6110 	case XPATH_XSLT_TREE:
6111 	    break;
6112     }
6113     xmlXPathReleaseObject(ctxt->context, arg1);
6114     xmlXPathReleaseObject(ctxt->context, arg2);
6115     return(ret);
6116 }
6117 
6118 /**
6119  * xmlXPathEqualValues:
6120  * @ctxt:  the XPath Parser context
6121  *
6122  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6123  *
6124  * Returns 0 or 1 depending on the results of the test.
6125  */
6126 int
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt)6127 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
6128     xmlXPathObjectPtr arg1, arg2, argtmp;
6129     int ret = 0;
6130 
6131     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6132     arg2 = valuePop(ctxt);
6133     arg1 = valuePop(ctxt);
6134     if ((arg1 == NULL) || (arg2 == NULL)) {
6135 	if (arg1 != NULL)
6136 	    xmlXPathReleaseObject(ctxt->context, arg1);
6137 	else
6138 	    xmlXPathReleaseObject(ctxt->context, arg2);
6139 	XP_ERROR0(XPATH_INVALID_OPERAND);
6140     }
6141 
6142     if (arg1 == arg2) {
6143 	xmlXPathFreeObject(arg1);
6144         return(1);
6145     }
6146 
6147     /*
6148      *If either argument is a nodeset, it's a 'special case'
6149      */
6150     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6151       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6152 	/*
6153 	 *Hack it to assure arg1 is the nodeset
6154 	 */
6155 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6156 		argtmp = arg2;
6157 		arg2 = arg1;
6158 		arg1 = argtmp;
6159 	}
6160 	switch (arg2->type) {
6161 	    case XPATH_UNDEFINED:
6162 		break;
6163 	    case XPATH_NODESET:
6164 	    case XPATH_XSLT_TREE:
6165 		ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 0);
6166 		break;
6167 	    case XPATH_BOOLEAN:
6168 		if ((arg1->nodesetval == NULL) ||
6169 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
6170 		else
6171 		    ret = 1;
6172 		ret = (ret == arg2->boolval);
6173 		break;
6174 	    case XPATH_NUMBER:
6175 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
6176 		break;
6177 	    case XPATH_STRING:
6178 		ret = xmlXPathEqualNodeSetString(ctxt, arg1,
6179                                                  arg2->stringval, 0);
6180 		break;
6181 	    case XPATH_USERS:
6182 #ifdef LIBXML_XPTR_LOCS_ENABLED
6183 	    case XPATH_POINT:
6184 	    case XPATH_RANGE:
6185 	    case XPATH_LOCATIONSET:
6186 #endif /* LIBXML_XPTR_LOCS_ENABLED */
6187 		/* TODO */
6188 		break;
6189 	}
6190 	xmlXPathReleaseObject(ctxt->context, arg1);
6191 	xmlXPathReleaseObject(ctxt->context, arg2);
6192 	return(ret);
6193     }
6194 
6195     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6196 }
6197 
6198 /**
6199  * xmlXPathNotEqualValues:
6200  * @ctxt:  the XPath Parser context
6201  *
6202  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6203  *
6204  * Returns 0 or 1 depending on the results of the test.
6205  */
6206 int
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt)6207 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
6208     xmlXPathObjectPtr arg1, arg2, argtmp;
6209     int ret = 0;
6210 
6211     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6212     arg2 = valuePop(ctxt);
6213     arg1 = valuePop(ctxt);
6214     if ((arg1 == NULL) || (arg2 == NULL)) {
6215 	if (arg1 != NULL)
6216 	    xmlXPathReleaseObject(ctxt->context, arg1);
6217 	else
6218 	    xmlXPathReleaseObject(ctxt->context, arg2);
6219 	XP_ERROR0(XPATH_INVALID_OPERAND);
6220     }
6221 
6222     if (arg1 == arg2) {
6223 	xmlXPathReleaseObject(ctxt->context, arg1);
6224         return(0);
6225     }
6226 
6227     /*
6228      *If either argument is a nodeset, it's a 'special case'
6229      */
6230     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6231       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6232 	/*
6233 	 *Hack it to assure arg1 is the nodeset
6234 	 */
6235 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6236 		argtmp = arg2;
6237 		arg2 = arg1;
6238 		arg1 = argtmp;
6239 	}
6240 	switch (arg2->type) {
6241 	    case XPATH_UNDEFINED:
6242 		break;
6243 	    case XPATH_NODESET:
6244 	    case XPATH_XSLT_TREE:
6245 		ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 1);
6246 		break;
6247 	    case XPATH_BOOLEAN:
6248 		if ((arg1->nodesetval == NULL) ||
6249 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
6250 		else
6251 		    ret = 1;
6252 		ret = (ret != arg2->boolval);
6253 		break;
6254 	    case XPATH_NUMBER:
6255 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
6256 		break;
6257 	    case XPATH_STRING:
6258 		ret = xmlXPathEqualNodeSetString(ctxt, arg1,
6259                                                  arg2->stringval, 1);
6260 		break;
6261 	    case XPATH_USERS:
6262 #ifdef LIBXML_XPTR_LOCS_ENABLED
6263 	    case XPATH_POINT:
6264 	    case XPATH_RANGE:
6265 	    case XPATH_LOCATIONSET:
6266 #endif /* LIBXML_XPTR_LOCS_ENABLED */
6267 		/* TODO */
6268 		break;
6269 	}
6270 	xmlXPathReleaseObject(ctxt->context, arg1);
6271 	xmlXPathReleaseObject(ctxt->context, arg2);
6272 	return(ret);
6273     }
6274 
6275     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6276 }
6277 
6278 /**
6279  * xmlXPathCompareValues:
6280  * @ctxt:  the XPath Parser context
6281  * @inf:  less than (1) or greater than (0)
6282  * @strict:  is the comparison strict
6283  *
6284  * Implement the compare operation on XPath objects:
6285  *     @arg1 < @arg2    (1, 1, ...
6286  *     @arg1 <= @arg2   (1, 0, ...
6287  *     @arg1 > @arg2    (0, 1, ...
6288  *     @arg1 >= @arg2   (0, 0, ...
6289  *
6290  * When neither object to be compared is a node-set and the operator is
6291  * <=, <, >=, >, then the objects are compared by converted both objects
6292  * to numbers and comparing the numbers according to IEEE 754. The <
6293  * comparison will be true if and only if the first number is less than the
6294  * second number. The <= comparison will be true if and only if the first
6295  * number is less than or equal to the second number. The > comparison
6296  * will be true if and only if the first number is greater than the second
6297  * number. The >= comparison will be true if and only if the first number
6298  * is greater than or equal to the second number.
6299  *
6300  * Returns 1 if the comparison succeeded, 0 if it failed
6301  */
6302 int
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt,int inf,int strict)6303 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
6304     int ret = 0, arg1i = 0, arg2i = 0;
6305     xmlXPathObjectPtr arg1, arg2;
6306 
6307     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6308     arg2 = valuePop(ctxt);
6309     arg1 = valuePop(ctxt);
6310     if ((arg1 == NULL) || (arg2 == NULL)) {
6311 	if (arg1 != NULL)
6312 	    xmlXPathReleaseObject(ctxt->context, arg1);
6313 	else
6314 	    xmlXPathReleaseObject(ctxt->context, arg2);
6315 	XP_ERROR0(XPATH_INVALID_OPERAND);
6316     }
6317 
6318     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6319       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6320 	/*
6321 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
6322 	 * are not freed from within this routine; they will be freed from the
6323 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
6324 	 */
6325 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
6326 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
6327 	    ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
6328 	} else {
6329 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6330 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
6331 			                          arg1, arg2);
6332 	    } else {
6333 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
6334 			                          arg2, arg1);
6335 	    }
6336 	}
6337 	return(ret);
6338     }
6339 
6340     if (arg1->type != XPATH_NUMBER) {
6341 	valuePush(ctxt, arg1);
6342 	xmlXPathNumberFunction(ctxt, 1);
6343 	arg1 = valuePop(ctxt);
6344     }
6345     if (arg2->type != XPATH_NUMBER) {
6346 	valuePush(ctxt, arg2);
6347 	xmlXPathNumberFunction(ctxt, 1);
6348 	arg2 = valuePop(ctxt);
6349     }
6350     if (ctxt->error)
6351         goto error;
6352     /*
6353      * Add tests for infinity and nan
6354      * => feedback on 3.4 for Inf and NaN
6355      */
6356     /* Hand check NaN and Infinity comparisons */
6357     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
6358 	ret=0;
6359     } else {
6360 	arg1i=xmlXPathIsInf(arg1->floatval);
6361 	arg2i=xmlXPathIsInf(arg2->floatval);
6362 	if (inf && strict) {
6363 	    if ((arg1i == -1 && arg2i != -1) ||
6364 		(arg2i == 1 && arg1i != 1)) {
6365 		ret = 1;
6366 	    } else if (arg1i == 0 && arg2i == 0) {
6367 		ret = (arg1->floatval < arg2->floatval);
6368 	    } else {
6369 		ret = 0;
6370 	    }
6371 	}
6372 	else if (inf && !strict) {
6373 	    if (arg1i == -1 || arg2i == 1) {
6374 		ret = 1;
6375 	    } else if (arg1i == 0 && arg2i == 0) {
6376 		ret = (arg1->floatval <= arg2->floatval);
6377 	    } else {
6378 		ret = 0;
6379 	    }
6380 	}
6381 	else if (!inf && strict) {
6382 	    if ((arg1i == 1 && arg2i != 1) ||
6383 		(arg2i == -1 && arg1i != -1)) {
6384 		ret = 1;
6385 	    } else if (arg1i == 0 && arg2i == 0) {
6386 		ret = (arg1->floatval > arg2->floatval);
6387 	    } else {
6388 		ret = 0;
6389 	    }
6390 	}
6391 	else if (!inf && !strict) {
6392 	    if (arg1i == 1 || arg2i == -1) {
6393 		ret = 1;
6394 	    } else if (arg1i == 0 && arg2i == 0) {
6395 		ret = (arg1->floatval >= arg2->floatval);
6396 	    } else {
6397 		ret = 0;
6398 	    }
6399 	}
6400     }
6401 error:
6402     xmlXPathReleaseObject(ctxt->context, arg1);
6403     xmlXPathReleaseObject(ctxt->context, arg2);
6404     return(ret);
6405 }
6406 
6407 /**
6408  * xmlXPathValueFlipSign:
6409  * @ctxt:  the XPath Parser context
6410  *
6411  * Implement the unary - operation on an XPath object
6412  * The numeric operators convert their operands to numbers as if
6413  * by calling the number function.
6414  */
6415 void
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt)6416 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
6417     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
6418     CAST_TO_NUMBER;
6419     CHECK_TYPE(XPATH_NUMBER);
6420     ctxt->value->floatval = -ctxt->value->floatval;
6421 }
6422 
6423 /**
6424  * xmlXPathAddValues:
6425  * @ctxt:  the XPath Parser context
6426  *
6427  * Implement the add operation on XPath objects:
6428  * The numeric operators convert their operands to numbers as if
6429  * by calling the number function.
6430  */
6431 void
xmlXPathAddValues(xmlXPathParserContextPtr ctxt)6432 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
6433     xmlXPathObjectPtr arg;
6434     double val;
6435 
6436     arg = valuePop(ctxt);
6437     if (arg == NULL)
6438 	XP_ERROR(XPATH_INVALID_OPERAND);
6439     val = xmlXPathCastToNumberInternal(ctxt, arg);
6440     xmlXPathReleaseObject(ctxt->context, arg);
6441     CAST_TO_NUMBER;
6442     CHECK_TYPE(XPATH_NUMBER);
6443     ctxt->value->floatval += val;
6444 }
6445 
6446 /**
6447  * xmlXPathSubValues:
6448  * @ctxt:  the XPath Parser context
6449  *
6450  * Implement the subtraction operation on XPath objects:
6451  * The numeric operators convert their operands to numbers as if
6452  * by calling the number function.
6453  */
6454 void
xmlXPathSubValues(xmlXPathParserContextPtr ctxt)6455 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
6456     xmlXPathObjectPtr arg;
6457     double val;
6458 
6459     arg = valuePop(ctxt);
6460     if (arg == NULL)
6461 	XP_ERROR(XPATH_INVALID_OPERAND);
6462     val = xmlXPathCastToNumberInternal(ctxt, arg);
6463     xmlXPathReleaseObject(ctxt->context, arg);
6464     CAST_TO_NUMBER;
6465     CHECK_TYPE(XPATH_NUMBER);
6466     ctxt->value->floatval -= val;
6467 }
6468 
6469 /**
6470  * xmlXPathMultValues:
6471  * @ctxt:  the XPath Parser context
6472  *
6473  * Implement the multiply operation on XPath objects:
6474  * The numeric operators convert their operands to numbers as if
6475  * by calling the number function.
6476  */
6477 void
xmlXPathMultValues(xmlXPathParserContextPtr ctxt)6478 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
6479     xmlXPathObjectPtr arg;
6480     double val;
6481 
6482     arg = valuePop(ctxt);
6483     if (arg == NULL)
6484 	XP_ERROR(XPATH_INVALID_OPERAND);
6485     val = xmlXPathCastToNumberInternal(ctxt, arg);
6486     xmlXPathReleaseObject(ctxt->context, arg);
6487     CAST_TO_NUMBER;
6488     CHECK_TYPE(XPATH_NUMBER);
6489     ctxt->value->floatval *= val;
6490 }
6491 
6492 /**
6493  * xmlXPathDivValues:
6494  * @ctxt:  the XPath Parser context
6495  *
6496  * Implement the div operation on XPath objects @arg1 / @arg2:
6497  * The numeric operators convert their operands to numbers as if
6498  * by calling the number function.
6499  */
6500 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
6501 void
xmlXPathDivValues(xmlXPathParserContextPtr ctxt)6502 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
6503     xmlXPathObjectPtr arg;
6504     double val;
6505 
6506     arg = valuePop(ctxt);
6507     if (arg == NULL)
6508 	XP_ERROR(XPATH_INVALID_OPERAND);
6509     val = xmlXPathCastToNumberInternal(ctxt, arg);
6510     xmlXPathReleaseObject(ctxt->context, arg);
6511     CAST_TO_NUMBER;
6512     CHECK_TYPE(XPATH_NUMBER);
6513     ctxt->value->floatval /= val;
6514 }
6515 
6516 /**
6517  * xmlXPathModValues:
6518  * @ctxt:  the XPath Parser context
6519  *
6520  * Implement the mod operation on XPath objects: @arg1 / @arg2
6521  * The numeric operators convert their operands to numbers as if
6522  * by calling the number function.
6523  */
6524 void
xmlXPathModValues(xmlXPathParserContextPtr ctxt)6525 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
6526     xmlXPathObjectPtr arg;
6527     double arg1, arg2;
6528 
6529     arg = valuePop(ctxt);
6530     if (arg == NULL)
6531 	XP_ERROR(XPATH_INVALID_OPERAND);
6532     arg2 = xmlXPathCastToNumberInternal(ctxt, arg);
6533     xmlXPathReleaseObject(ctxt->context, arg);
6534     CAST_TO_NUMBER;
6535     CHECK_TYPE(XPATH_NUMBER);
6536     arg1 = ctxt->value->floatval;
6537     if (arg2 == 0)
6538 	ctxt->value->floatval = xmlXPathNAN;
6539     else {
6540 	ctxt->value->floatval = fmod(arg1, arg2);
6541     }
6542 }
6543 
6544 /************************************************************************
6545  *									*
6546  *		The traversal functions					*
6547  *									*
6548  ************************************************************************/
6549 
6550 /*
6551  * A traversal function enumerates nodes along an axis.
6552  * Initially it must be called with NULL, and it indicates
6553  * termination on the axis by returning NULL.
6554  */
6555 typedef xmlNodePtr (*xmlXPathTraversalFunction)
6556                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
6557 
6558 /*
6559  * xmlXPathTraversalFunctionExt:
6560  * A traversal function enumerates nodes along an axis.
6561  * Initially it must be called with NULL, and it indicates
6562  * termination on the axis by returning NULL.
6563  * The context node of the traversal is specified via @contextNode.
6564  */
6565 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
6566                     (xmlNodePtr cur, xmlNodePtr contextNode);
6567 
6568 /*
6569  * xmlXPathNodeSetMergeFunction:
6570  * Used for merging node sets in xmlXPathCollectAndTest().
6571  */
6572 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
6573 		    (xmlNodeSetPtr, xmlNodeSetPtr);
6574 
6575 
6576 /**
6577  * xmlXPathNextSelf:
6578  * @ctxt:  the XPath Parser context
6579  * @cur:  the current node in the traversal
6580  *
6581  * Traversal function for the "self" direction
6582  * The self axis contains just the context node itself
6583  *
6584  * Returns the next element following that axis
6585  */
6586 xmlNodePtr
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6587 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6588     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6589     if (cur == NULL)
6590         return(ctxt->context->node);
6591     return(NULL);
6592 }
6593 
6594 /**
6595  * xmlXPathNextChild:
6596  * @ctxt:  the XPath Parser context
6597  * @cur:  the current node in the traversal
6598  *
6599  * Traversal function for the "child" direction
6600  * The child axis contains the children of the context node in document order.
6601  *
6602  * Returns the next element following that axis
6603  */
6604 xmlNodePtr
xmlXPathNextChild(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6605 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6606     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6607     if (cur == NULL) {
6608 	if (ctxt->context->node == NULL) return(NULL);
6609 	switch (ctxt->context->node->type) {
6610             case XML_ELEMENT_NODE:
6611             case XML_TEXT_NODE:
6612             case XML_CDATA_SECTION_NODE:
6613             case XML_ENTITY_REF_NODE:
6614             case XML_ENTITY_NODE:
6615             case XML_PI_NODE:
6616             case XML_COMMENT_NODE:
6617             case XML_NOTATION_NODE:
6618             case XML_DTD_NODE:
6619 		return(ctxt->context->node->children);
6620             case XML_DOCUMENT_NODE:
6621             case XML_DOCUMENT_TYPE_NODE:
6622             case XML_DOCUMENT_FRAG_NODE:
6623             case XML_HTML_DOCUMENT_NODE:
6624 		return(((xmlDocPtr) ctxt->context->node)->children);
6625 	    case XML_ELEMENT_DECL:
6626 	    case XML_ATTRIBUTE_DECL:
6627 	    case XML_ENTITY_DECL:
6628             case XML_ATTRIBUTE_NODE:
6629 	    case XML_NAMESPACE_DECL:
6630 	    case XML_XINCLUDE_START:
6631 	    case XML_XINCLUDE_END:
6632 		return(NULL);
6633 	}
6634 	return(NULL);
6635     }
6636     if ((cur->type == XML_DOCUMENT_NODE) ||
6637         (cur->type == XML_HTML_DOCUMENT_NODE))
6638 	return(NULL);
6639     return(cur->next);
6640 }
6641 
6642 /**
6643  * xmlXPathNextChildElement:
6644  * @ctxt:  the XPath Parser context
6645  * @cur:  the current node in the traversal
6646  *
6647  * Traversal function for the "child" direction and nodes of type element.
6648  * The child axis contains the children of the context node in document order.
6649  *
6650  * Returns the next element following that axis
6651  */
6652 static xmlNodePtr
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6653 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6654     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6655     if (cur == NULL) {
6656 	cur = ctxt->context->node;
6657 	if (cur == NULL) return(NULL);
6658 	/*
6659 	* Get the first element child.
6660 	*/
6661 	switch (cur->type) {
6662             case XML_ELEMENT_NODE:
6663 	    case XML_DOCUMENT_FRAG_NODE:
6664 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
6665             case XML_ENTITY_NODE:
6666 		cur = cur->children;
6667 		if (cur != NULL) {
6668 		    if (cur->type == XML_ELEMENT_NODE)
6669 			return(cur);
6670 		    do {
6671 			cur = cur->next;
6672 		    } while ((cur != NULL) &&
6673 			(cur->type != XML_ELEMENT_NODE));
6674 		    return(cur);
6675 		}
6676 		return(NULL);
6677             case XML_DOCUMENT_NODE:
6678             case XML_HTML_DOCUMENT_NODE:
6679 		return(xmlDocGetRootElement((xmlDocPtr) cur));
6680 	    default:
6681 		return(NULL);
6682 	}
6683 	return(NULL);
6684     }
6685     /*
6686     * Get the next sibling element node.
6687     */
6688     switch (cur->type) {
6689 	case XML_ELEMENT_NODE:
6690 	case XML_TEXT_NODE:
6691 	case XML_ENTITY_REF_NODE:
6692 	case XML_ENTITY_NODE:
6693 	case XML_CDATA_SECTION_NODE:
6694 	case XML_PI_NODE:
6695 	case XML_COMMENT_NODE:
6696 	case XML_XINCLUDE_END:
6697 	    break;
6698 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
6699 	default:
6700 	    return(NULL);
6701     }
6702     if (cur->next != NULL) {
6703 	if (cur->next->type == XML_ELEMENT_NODE)
6704 	    return(cur->next);
6705 	cur = cur->next;
6706 	do {
6707 	    cur = cur->next;
6708 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
6709 	return(cur);
6710     }
6711     return(NULL);
6712 }
6713 
6714 #if 0
6715 /**
6716  * xmlXPathNextDescendantOrSelfElemParent:
6717  * @ctxt:  the XPath Parser context
6718  * @cur:  the current node in the traversal
6719  *
6720  * Traversal function for the "descendant-or-self" axis.
6721  * Additionally it returns only nodes which can be parents of
6722  * element nodes.
6723  *
6724  *
6725  * Returns the next element following that axis
6726  */
6727 static xmlNodePtr
6728 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
6729 				       xmlNodePtr contextNode)
6730 {
6731     if (cur == NULL) {
6732 	if (contextNode == NULL)
6733 	    return(NULL);
6734 	switch (contextNode->type) {
6735 	    case XML_ELEMENT_NODE:
6736 	    case XML_XINCLUDE_START:
6737 	    case XML_DOCUMENT_FRAG_NODE:
6738 	    case XML_DOCUMENT_NODE:
6739 	    case XML_HTML_DOCUMENT_NODE:
6740 		return(contextNode);
6741 	    default:
6742 		return(NULL);
6743 	}
6744 	return(NULL);
6745     } else {
6746 	xmlNodePtr start = cur;
6747 
6748 	while (cur != NULL) {
6749 	    switch (cur->type) {
6750 		case XML_ELEMENT_NODE:
6751 		/* TODO: OK to have XInclude here? */
6752 		case XML_XINCLUDE_START:
6753 		case XML_DOCUMENT_FRAG_NODE:
6754 		    if (cur != start)
6755 			return(cur);
6756 		    if (cur->children != NULL) {
6757 			cur = cur->children;
6758 			continue;
6759 		    }
6760 		    break;
6761 		/* Not sure if we need those here. */
6762 		case XML_DOCUMENT_NODE:
6763 		case XML_HTML_DOCUMENT_NODE:
6764 		    if (cur != start)
6765 			return(cur);
6766 		    return(xmlDocGetRootElement((xmlDocPtr) cur));
6767 		default:
6768 		    break;
6769 	    }
6770 
6771 next_sibling:
6772 	    if ((cur == NULL) || (cur == contextNode))
6773 		return(NULL);
6774 	    if (cur->next != NULL) {
6775 		cur = cur->next;
6776 	    } else {
6777 		cur = cur->parent;
6778 		goto next_sibling;
6779 	    }
6780 	}
6781     }
6782     return(NULL);
6783 }
6784 #endif
6785 
6786 /**
6787  * xmlXPathNextDescendant:
6788  * @ctxt:  the XPath Parser context
6789  * @cur:  the current node in the traversal
6790  *
6791  * Traversal function for the "descendant" direction
6792  * the descendant axis contains the descendants of the context node in document
6793  * order; a descendant is a child or a child of a child and so on.
6794  *
6795  * Returns the next element following that axis
6796  */
6797 xmlNodePtr
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6798 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6799     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6800     if (cur == NULL) {
6801 	if (ctxt->context->node == NULL)
6802 	    return(NULL);
6803 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6804 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
6805 	    return(NULL);
6806 
6807         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6808 	    return(ctxt->context->doc->children);
6809         return(ctxt->context->node->children);
6810     }
6811 
6812     if (cur->type == XML_NAMESPACE_DECL)
6813         return(NULL);
6814     if (cur->children != NULL) {
6815 	/*
6816 	 * Do not descend on entities declarations
6817 	 */
6818 	if (cur->children->type != XML_ENTITY_DECL) {
6819 	    cur = cur->children;
6820 	    /*
6821 	     * Skip DTDs
6822 	     */
6823 	    if (cur->type != XML_DTD_NODE)
6824 		return(cur);
6825 	}
6826     }
6827 
6828     if (cur == ctxt->context->node) return(NULL);
6829 
6830     while (cur->next != NULL) {
6831 	cur = cur->next;
6832 	if ((cur->type != XML_ENTITY_DECL) &&
6833 	    (cur->type != XML_DTD_NODE))
6834 	    return(cur);
6835     }
6836 
6837     do {
6838         cur = cur->parent;
6839 	if (cur == NULL) break;
6840 	if (cur == ctxt->context->node) return(NULL);
6841 	if (cur->next != NULL) {
6842 	    cur = cur->next;
6843 	    return(cur);
6844 	}
6845     } while (cur != NULL);
6846     return(cur);
6847 }
6848 
6849 /**
6850  * xmlXPathNextDescendantOrSelf:
6851  * @ctxt:  the XPath Parser context
6852  * @cur:  the current node in the traversal
6853  *
6854  * Traversal function for the "descendant-or-self" direction
6855  * the descendant-or-self axis contains the context node and the descendants
6856  * of the context node in document order; thus the context node is the first
6857  * node on the axis, and the first child of the context node is the second node
6858  * on the axis
6859  *
6860  * Returns the next element following that axis
6861  */
6862 xmlNodePtr
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6863 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6864     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6865     if (cur == NULL)
6866         return(ctxt->context->node);
6867 
6868     if (ctxt->context->node == NULL)
6869         return(NULL);
6870     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6871         (ctxt->context->node->type == XML_NAMESPACE_DECL))
6872         return(NULL);
6873 
6874     return(xmlXPathNextDescendant(ctxt, cur));
6875 }
6876 
6877 /**
6878  * xmlXPathNextParent:
6879  * @ctxt:  the XPath Parser context
6880  * @cur:  the current node in the traversal
6881  *
6882  * Traversal function for the "parent" direction
6883  * The parent axis contains the parent of the context node, if there is one.
6884  *
6885  * Returns the next element following that axis
6886  */
6887 xmlNodePtr
xmlXPathNextParent(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6888 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6889     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6890     /*
6891      * the parent of an attribute or namespace node is the element
6892      * to which the attribute or namespace node is attached
6893      * Namespace handling !!!
6894      */
6895     if (cur == NULL) {
6896 	if (ctxt->context->node == NULL) return(NULL);
6897 	switch (ctxt->context->node->type) {
6898             case XML_ELEMENT_NODE:
6899             case XML_TEXT_NODE:
6900             case XML_CDATA_SECTION_NODE:
6901             case XML_ENTITY_REF_NODE:
6902             case XML_ENTITY_NODE:
6903             case XML_PI_NODE:
6904             case XML_COMMENT_NODE:
6905             case XML_NOTATION_NODE:
6906             case XML_DTD_NODE:
6907 	    case XML_ELEMENT_DECL:
6908 	    case XML_ATTRIBUTE_DECL:
6909 	    case XML_XINCLUDE_START:
6910 	    case XML_XINCLUDE_END:
6911 	    case XML_ENTITY_DECL:
6912 		if (ctxt->context->node->parent == NULL)
6913 		    return((xmlNodePtr) ctxt->context->doc);
6914 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6915 		    ((ctxt->context->node->parent->name[0] == ' ') ||
6916 		     (xmlStrEqual(ctxt->context->node->parent->name,
6917 				 BAD_CAST "fake node libxslt"))))
6918 		    return(NULL);
6919 		return(ctxt->context->node->parent);
6920             case XML_ATTRIBUTE_NODE: {
6921 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
6922 
6923 		return(att->parent);
6924 	    }
6925             case XML_DOCUMENT_NODE:
6926             case XML_DOCUMENT_TYPE_NODE:
6927             case XML_DOCUMENT_FRAG_NODE:
6928             case XML_HTML_DOCUMENT_NODE:
6929                 return(NULL);
6930 	    case XML_NAMESPACE_DECL: {
6931 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6932 
6933 		if ((ns->next != NULL) &&
6934 		    (ns->next->type != XML_NAMESPACE_DECL))
6935 		    return((xmlNodePtr) ns->next);
6936                 return(NULL);
6937 	    }
6938 	}
6939     }
6940     return(NULL);
6941 }
6942 
6943 /**
6944  * xmlXPathNextAncestor:
6945  * @ctxt:  the XPath Parser context
6946  * @cur:  the current node in the traversal
6947  *
6948  * Traversal function for the "ancestor" direction
6949  * the ancestor axis contains the ancestors of the context node; the ancestors
6950  * of the context node consist of the parent of context node and the parent's
6951  * parent and so on; the nodes are ordered in reverse document order; thus the
6952  * parent is the first node on the axis, and the parent's parent is the second
6953  * node on the axis
6954  *
6955  * Returns the next element following that axis
6956  */
6957 xmlNodePtr
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6958 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6959     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6960     /*
6961      * the parent of an attribute or namespace node is the element
6962      * to which the attribute or namespace node is attached
6963      * !!!!!!!!!!!!!
6964      */
6965     if (cur == NULL) {
6966 	if (ctxt->context->node == NULL) return(NULL);
6967 	switch (ctxt->context->node->type) {
6968             case XML_ELEMENT_NODE:
6969             case XML_TEXT_NODE:
6970             case XML_CDATA_SECTION_NODE:
6971             case XML_ENTITY_REF_NODE:
6972             case XML_ENTITY_NODE:
6973             case XML_PI_NODE:
6974             case XML_COMMENT_NODE:
6975 	    case XML_DTD_NODE:
6976 	    case XML_ELEMENT_DECL:
6977 	    case XML_ATTRIBUTE_DECL:
6978 	    case XML_ENTITY_DECL:
6979             case XML_NOTATION_NODE:
6980 	    case XML_XINCLUDE_START:
6981 	    case XML_XINCLUDE_END:
6982 		if (ctxt->context->node->parent == NULL)
6983 		    return((xmlNodePtr) ctxt->context->doc);
6984 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6985 		    ((ctxt->context->node->parent->name[0] == ' ') ||
6986 		     (xmlStrEqual(ctxt->context->node->parent->name,
6987 				 BAD_CAST "fake node libxslt"))))
6988 		    return(NULL);
6989 		return(ctxt->context->node->parent);
6990             case XML_ATTRIBUTE_NODE: {
6991 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
6992 
6993 		return(tmp->parent);
6994 	    }
6995             case XML_DOCUMENT_NODE:
6996             case XML_DOCUMENT_TYPE_NODE:
6997             case XML_DOCUMENT_FRAG_NODE:
6998             case XML_HTML_DOCUMENT_NODE:
6999                 return(NULL);
7000 	    case XML_NAMESPACE_DECL: {
7001 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7002 
7003 		if ((ns->next != NULL) &&
7004 		    (ns->next->type != XML_NAMESPACE_DECL))
7005 		    return((xmlNodePtr) ns->next);
7006 		/* Bad, how did that namespace end up here ? */
7007                 return(NULL);
7008 	    }
7009 	}
7010 	return(NULL);
7011     }
7012     if (cur == ctxt->context->doc->children)
7013 	return((xmlNodePtr) ctxt->context->doc);
7014     if (cur == (xmlNodePtr) ctxt->context->doc)
7015 	return(NULL);
7016     switch (cur->type) {
7017 	case XML_ELEMENT_NODE:
7018 	case XML_TEXT_NODE:
7019 	case XML_CDATA_SECTION_NODE:
7020 	case XML_ENTITY_REF_NODE:
7021 	case XML_ENTITY_NODE:
7022 	case XML_PI_NODE:
7023 	case XML_COMMENT_NODE:
7024 	case XML_NOTATION_NODE:
7025 	case XML_DTD_NODE:
7026         case XML_ELEMENT_DECL:
7027         case XML_ATTRIBUTE_DECL:
7028         case XML_ENTITY_DECL:
7029 	case XML_XINCLUDE_START:
7030 	case XML_XINCLUDE_END:
7031 	    if (cur->parent == NULL)
7032 		return(NULL);
7033 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
7034 		((cur->parent->name[0] == ' ') ||
7035 		 (xmlStrEqual(cur->parent->name,
7036 			      BAD_CAST "fake node libxslt"))))
7037 		return(NULL);
7038 	    return(cur->parent);
7039 	case XML_ATTRIBUTE_NODE: {
7040 	    xmlAttrPtr att = (xmlAttrPtr) cur;
7041 
7042 	    return(att->parent);
7043 	}
7044 	case XML_NAMESPACE_DECL: {
7045 	    xmlNsPtr ns = (xmlNsPtr) cur;
7046 
7047 	    if ((ns->next != NULL) &&
7048 	        (ns->next->type != XML_NAMESPACE_DECL))
7049 	        return((xmlNodePtr) ns->next);
7050 	    /* Bad, how did that namespace end up here ? */
7051             return(NULL);
7052 	}
7053 	case XML_DOCUMENT_NODE:
7054 	case XML_DOCUMENT_TYPE_NODE:
7055 	case XML_DOCUMENT_FRAG_NODE:
7056 	case XML_HTML_DOCUMENT_NODE:
7057 	    return(NULL);
7058     }
7059     return(NULL);
7060 }
7061 
7062 /**
7063  * xmlXPathNextAncestorOrSelf:
7064  * @ctxt:  the XPath Parser context
7065  * @cur:  the current node in the traversal
7066  *
7067  * Traversal function for the "ancestor-or-self" direction
7068  * he ancestor-or-self axis contains the context node and ancestors of
7069  * the context node in reverse document order; thus the context node is
7070  * the first node on the axis, and the context node's parent the second;
7071  * parent here is defined the same as with the parent axis.
7072  *
7073  * Returns the next element following that axis
7074  */
7075 xmlNodePtr
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7076 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7077     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7078     if (cur == NULL)
7079         return(ctxt->context->node);
7080     return(xmlXPathNextAncestor(ctxt, cur));
7081 }
7082 
7083 /**
7084  * xmlXPathNextFollowingSibling:
7085  * @ctxt:  the XPath Parser context
7086  * @cur:  the current node in the traversal
7087  *
7088  * Traversal function for the "following-sibling" direction
7089  * The following-sibling axis contains the following siblings of the context
7090  * node in document order.
7091  *
7092  * Returns the next element following that axis
7093  */
7094 xmlNodePtr
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7095 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7096     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7097     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7098 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
7099 	return(NULL);
7100     if (cur == (xmlNodePtr) ctxt->context->doc)
7101         return(NULL);
7102     if (cur == NULL)
7103         return(ctxt->context->node->next);
7104     return(cur->next);
7105 }
7106 
7107 /**
7108  * xmlXPathNextPrecedingSibling:
7109  * @ctxt:  the XPath Parser context
7110  * @cur:  the current node in the traversal
7111  *
7112  * Traversal function for the "preceding-sibling" direction
7113  * The preceding-sibling axis contains the preceding siblings of the context
7114  * node in reverse document order; the first preceding sibling is first on the
7115  * axis; the sibling preceding that node is the second on the axis and so on.
7116  *
7117  * Returns the next element following that axis
7118  */
7119 xmlNodePtr
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7120 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7121     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7122     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7123 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
7124 	return(NULL);
7125     if (cur == (xmlNodePtr) ctxt->context->doc)
7126         return(NULL);
7127     if (cur == NULL)
7128         return(ctxt->context->node->prev);
7129     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
7130 	cur = cur->prev;
7131 	if (cur == NULL)
7132 	    return(ctxt->context->node->prev);
7133     }
7134     return(cur->prev);
7135 }
7136 
7137 /**
7138  * xmlXPathNextFollowing:
7139  * @ctxt:  the XPath Parser context
7140  * @cur:  the current node in the traversal
7141  *
7142  * Traversal function for the "following" direction
7143  * The following axis contains all nodes in the same document as the context
7144  * node that are after the context node in document order, excluding any
7145  * descendants and excluding attribute nodes and namespace nodes; the nodes
7146  * are ordered in document order
7147  *
7148  * Returns the next element following that axis
7149  */
7150 xmlNodePtr
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7151 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7152     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7153     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
7154         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
7155         return(cur->children);
7156 
7157     if (cur == NULL) {
7158         cur = ctxt->context->node;
7159         if (cur->type == XML_ATTRIBUTE_NODE) {
7160             cur = cur->parent;
7161         } else if (cur->type == XML_NAMESPACE_DECL) {
7162             xmlNsPtr ns = (xmlNsPtr) cur;
7163 
7164             if ((ns->next == NULL) ||
7165                 (ns->next->type == XML_NAMESPACE_DECL))
7166                 return (NULL);
7167             cur = (xmlNodePtr) ns->next;
7168         }
7169     }
7170     if (cur == NULL) return(NULL) ; /* ERROR */
7171     if (cur->next != NULL) return(cur->next) ;
7172     do {
7173         cur = cur->parent;
7174         if (cur == NULL) break;
7175         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
7176         if (cur->next != NULL) return(cur->next);
7177     } while (cur != NULL);
7178     return(cur);
7179 }
7180 
7181 /*
7182  * xmlXPathIsAncestor:
7183  * @ancestor:  the ancestor node
7184  * @node:  the current node
7185  *
7186  * Check that @ancestor is a @node's ancestor
7187  *
7188  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
7189  */
7190 static int
xmlXPathIsAncestor(xmlNodePtr ancestor,xmlNodePtr node)7191 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
7192     if ((ancestor == NULL) || (node == NULL)) return(0);
7193     if (node->type == XML_NAMESPACE_DECL)
7194         return(0);
7195     if (ancestor->type == XML_NAMESPACE_DECL)
7196         return(0);
7197     /* nodes need to be in the same document */
7198     if (ancestor->doc != node->doc) return(0);
7199     /* avoid searching if ancestor or node is the root node */
7200     if (ancestor == (xmlNodePtr) node->doc) return(1);
7201     if (node == (xmlNodePtr) ancestor->doc) return(0);
7202     while (node->parent != NULL) {
7203         if (node->parent == ancestor)
7204             return(1);
7205 	node = node->parent;
7206     }
7207     return(0);
7208 }
7209 
7210 /**
7211  * xmlXPathNextPreceding:
7212  * @ctxt:  the XPath Parser context
7213  * @cur:  the current node in the traversal
7214  *
7215  * Traversal function for the "preceding" direction
7216  * the preceding axis contains all nodes in the same document as the context
7217  * node that are before the context node in document order, excluding any
7218  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7219  * ordered in reverse document order
7220  *
7221  * Returns the next element following that axis
7222  */
7223 xmlNodePtr
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7224 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
7225 {
7226     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7227     if (cur == NULL) {
7228         cur = ctxt->context->node;
7229         if (cur->type == XML_ATTRIBUTE_NODE) {
7230             cur = cur->parent;
7231         } else if (cur->type == XML_NAMESPACE_DECL) {
7232             xmlNsPtr ns = (xmlNsPtr) cur;
7233 
7234             if ((ns->next == NULL) ||
7235                 (ns->next->type == XML_NAMESPACE_DECL))
7236                 return (NULL);
7237             cur = (xmlNodePtr) ns->next;
7238         }
7239     }
7240     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
7241 	return (NULL);
7242     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7243 	cur = cur->prev;
7244     do {
7245         if (cur->prev != NULL) {
7246             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
7247             return (cur);
7248         }
7249 
7250         cur = cur->parent;
7251         if (cur == NULL)
7252             return (NULL);
7253         if (cur == ctxt->context->doc->children)
7254             return (NULL);
7255     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
7256     return (cur);
7257 }
7258 
7259 /**
7260  * xmlXPathNextPrecedingInternal:
7261  * @ctxt:  the XPath Parser context
7262  * @cur:  the current node in the traversal
7263  *
7264  * Traversal function for the "preceding" direction
7265  * the preceding axis contains all nodes in the same document as the context
7266  * node that are before the context node in document order, excluding any
7267  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7268  * ordered in reverse document order
7269  * This is a faster implementation but internal only since it requires a
7270  * state kept in the parser context: ctxt->ancestor.
7271  *
7272  * Returns the next element following that axis
7273  */
7274 static xmlNodePtr
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7275 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
7276                               xmlNodePtr cur)
7277 {
7278     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7279     if (cur == NULL) {
7280         cur = ctxt->context->node;
7281         if (cur == NULL)
7282             return (NULL);
7283         if (cur->type == XML_ATTRIBUTE_NODE) {
7284             cur = cur->parent;
7285         } else if (cur->type == XML_NAMESPACE_DECL) {
7286             xmlNsPtr ns = (xmlNsPtr) cur;
7287 
7288             if ((ns->next == NULL) ||
7289                 (ns->next->type == XML_NAMESPACE_DECL))
7290                 return (NULL);
7291             cur = (xmlNodePtr) ns->next;
7292         }
7293         ctxt->ancestor = cur->parent;
7294     }
7295     if (cur->type == XML_NAMESPACE_DECL)
7296         return(NULL);
7297     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7298 	cur = cur->prev;
7299     while (cur->prev == NULL) {
7300         cur = cur->parent;
7301         if (cur == NULL)
7302             return (NULL);
7303         if (cur == ctxt->context->doc->children)
7304             return (NULL);
7305         if (cur != ctxt->ancestor)
7306             return (cur);
7307         ctxt->ancestor = cur->parent;
7308     }
7309     cur = cur->prev;
7310     while (cur->last != NULL)
7311         cur = cur->last;
7312     return (cur);
7313 }
7314 
7315 /**
7316  * xmlXPathNextNamespace:
7317  * @ctxt:  the XPath Parser context
7318  * @cur:  the current attribute in the traversal
7319  *
7320  * Traversal function for the "namespace" direction
7321  * the namespace axis contains the namespace nodes of the context node;
7322  * the order of nodes on this axis is implementation-defined; the axis will
7323  * be empty unless the context node is an element
7324  *
7325  * We keep the XML namespace node at the end of the list.
7326  *
7327  * Returns the next element following that axis
7328  */
7329 xmlNodePtr
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7330 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7331     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7332     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
7333     if (cur == NULL) {
7334         if (ctxt->context->tmpNsList != NULL)
7335 	    xmlFree(ctxt->context->tmpNsList);
7336 	ctxt->context->tmpNsNr = 0;
7337         if (xmlGetNsListSafe(ctxt->context->doc, ctxt->context->node,
7338                              &ctxt->context->tmpNsList) < 0) {
7339             xmlXPathPErrMemory(ctxt);
7340             return(NULL);
7341         }
7342         if (ctxt->context->tmpNsList != NULL) {
7343             while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
7344                 ctxt->context->tmpNsNr++;
7345             }
7346         }
7347 	return((xmlNodePtr) xmlXPathXMLNamespace);
7348     }
7349     if (ctxt->context->tmpNsNr > 0) {
7350 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
7351     } else {
7352 	if (ctxt->context->tmpNsList != NULL)
7353 	    xmlFree(ctxt->context->tmpNsList);
7354 	ctxt->context->tmpNsList = NULL;
7355 	return(NULL);
7356     }
7357 }
7358 
7359 /**
7360  * xmlXPathNextAttribute:
7361  * @ctxt:  the XPath Parser context
7362  * @cur:  the current attribute in the traversal
7363  *
7364  * Traversal function for the "attribute" direction
7365  * TODO: support DTD inherited default attributes
7366  *
7367  * Returns the next element following that axis
7368  */
7369 xmlNodePtr
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7370 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7371     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7372     if (ctxt->context->node == NULL)
7373 	return(NULL);
7374     if (ctxt->context->node->type != XML_ELEMENT_NODE)
7375 	return(NULL);
7376     if (cur == NULL) {
7377         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7378 	    return(NULL);
7379         return((xmlNodePtr)ctxt->context->node->properties);
7380     }
7381     return((xmlNodePtr)cur->next);
7382 }
7383 
7384 /************************************************************************
7385  *									*
7386  *		NodeTest Functions					*
7387  *									*
7388  ************************************************************************/
7389 
7390 #define IS_FUNCTION			200
7391 
7392 
7393 /************************************************************************
7394  *									*
7395  *		Implicit tree core function library			*
7396  *									*
7397  ************************************************************************/
7398 
7399 /**
7400  * xmlXPathRoot:
7401  * @ctxt:  the XPath Parser context
7402  *
7403  * Initialize the context to the root of the document
7404  */
7405 void
xmlXPathRoot(xmlXPathParserContextPtr ctxt)7406 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
7407     if ((ctxt == NULL) || (ctxt->context == NULL))
7408 	return;
7409     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7410                                             (xmlNodePtr) ctxt->context->doc));
7411 }
7412 
7413 /************************************************************************
7414  *									*
7415  *		The explicit core function library			*
7416  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
7417  *									*
7418  ************************************************************************/
7419 
7420 
7421 /**
7422  * xmlXPathLastFunction:
7423  * @ctxt:  the XPath Parser context
7424  * @nargs:  the number of arguments
7425  *
7426  * Implement the last() XPath function
7427  *    number last()
7428  * The last function returns the number of nodes in the context node list.
7429  */
7430 void
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt,int nargs)7431 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7432     CHECK_ARITY(0);
7433     if (ctxt->context->contextSize >= 0) {
7434 	valuePush(ctxt,
7435 	    xmlXPathCacheNewFloat(ctxt, (double) ctxt->context->contextSize));
7436     } else {
7437 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
7438     }
7439 }
7440 
7441 /**
7442  * xmlXPathPositionFunction:
7443  * @ctxt:  the XPath Parser context
7444  * @nargs:  the number of arguments
7445  *
7446  * Implement the position() XPath function
7447  *    number position()
7448  * The position function returns the position of the context node in the
7449  * context node list. The first position is 1, and so the last position
7450  * will be equal to last().
7451  */
7452 void
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt,int nargs)7453 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7454     CHECK_ARITY(0);
7455     if (ctxt->context->proximityPosition >= 0) {
7456 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7457             (double) ctxt->context->proximityPosition));
7458     } else {
7459 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
7460     }
7461 }
7462 
7463 /**
7464  * xmlXPathCountFunction:
7465  * @ctxt:  the XPath Parser context
7466  * @nargs:  the number of arguments
7467  *
7468  * Implement the count() XPath function
7469  *    number count(node-set)
7470  */
7471 void
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt,int nargs)7472 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7473     xmlXPathObjectPtr cur;
7474 
7475     CHECK_ARITY(1);
7476     if ((ctxt->value == NULL) ||
7477 	((ctxt->value->type != XPATH_NODESET) &&
7478 	 (ctxt->value->type != XPATH_XSLT_TREE)))
7479 	XP_ERROR(XPATH_INVALID_TYPE);
7480     cur = valuePop(ctxt);
7481 
7482     if ((cur == NULL) || (cur->nodesetval == NULL))
7483 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
7484     else
7485 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7486 	    (double) cur->nodesetval->nodeNr));
7487     xmlXPathReleaseObject(ctxt->context, cur);
7488 }
7489 
7490 /**
7491  * xmlXPathGetElementsByIds:
7492  * @doc:  the document
7493  * @ids:  a whitespace separated list of IDs
7494  *
7495  * Selects elements by their unique ID.
7496  *
7497  * Returns a node-set of selected elements.
7498  */
7499 static xmlNodeSetPtr
xmlXPathGetElementsByIds(xmlDocPtr doc,const xmlChar * ids)7500 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
7501     xmlNodeSetPtr ret;
7502     const xmlChar *cur = ids;
7503     xmlChar *ID;
7504     xmlAttrPtr attr;
7505     xmlNodePtr elem = NULL;
7506 
7507     if (ids == NULL) return(NULL);
7508 
7509     ret = xmlXPathNodeSetCreate(NULL);
7510     if (ret == NULL)
7511         return(ret);
7512 
7513     while (IS_BLANK_CH(*cur)) cur++;
7514     while (*cur != 0) {
7515 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
7516 	    cur++;
7517 
7518         ID = xmlStrndup(ids, cur - ids);
7519 	if (ID == NULL) {
7520             xmlXPathFreeNodeSet(ret);
7521             return(NULL);
7522         }
7523         /*
7524          * We used to check the fact that the value passed
7525          * was an NCName, but this generated much troubles for
7526          * me and Aleksey Sanin, people blatantly violated that
7527          * constraint, like Visa3D spec.
7528          * if (xmlValidateNCName(ID, 1) == 0)
7529          */
7530         attr = xmlGetID(doc, ID);
7531         xmlFree(ID);
7532         if (attr != NULL) {
7533             if (attr->type == XML_ATTRIBUTE_NODE)
7534                 elem = attr->parent;
7535             else if (attr->type == XML_ELEMENT_NODE)
7536                 elem = (xmlNodePtr) attr;
7537             else
7538                 elem = NULL;
7539             if (elem != NULL) {
7540                 if (xmlXPathNodeSetAdd(ret, elem) < 0) {
7541                     xmlXPathFreeNodeSet(ret);
7542                     return(NULL);
7543                 }
7544             }
7545         }
7546 
7547 	while (IS_BLANK_CH(*cur)) cur++;
7548 	ids = cur;
7549     }
7550     return(ret);
7551 }
7552 
7553 /**
7554  * xmlXPathIdFunction:
7555  * @ctxt:  the XPath Parser context
7556  * @nargs:  the number of arguments
7557  *
7558  * Implement the id() XPath function
7559  *    node-set id(object)
7560  * The id function selects elements by their unique ID
7561  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
7562  * then the result is the union of the result of applying id to the
7563  * string value of each of the nodes in the argument node-set. When the
7564  * argument to id is of any other type, the argument is converted to a
7565  * string as if by a call to the string function; the string is split
7566  * into a whitespace-separated list of tokens (whitespace is any sequence
7567  * of characters matching the production S); the result is a node-set
7568  * containing the elements in the same document as the context node that
7569  * have a unique ID equal to any of the tokens in the list.
7570  */
7571 void
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt,int nargs)7572 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7573     xmlChar *tokens;
7574     xmlNodeSetPtr ret;
7575     xmlXPathObjectPtr obj;
7576 
7577     CHECK_ARITY(1);
7578     obj = valuePop(ctxt);
7579     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7580     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7581 	xmlNodeSetPtr ns;
7582 	int i;
7583 
7584 	ret = xmlXPathNodeSetCreate(NULL);
7585         if (ret == NULL)
7586             xmlXPathPErrMemory(ctxt);
7587 
7588 	if (obj->nodesetval != NULL) {
7589 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7590 		tokens =
7591 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7592                 if (tokens == NULL)
7593                     xmlXPathPErrMemory(ctxt);
7594 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7595                 if (ns == NULL)
7596                     xmlXPathPErrMemory(ctxt);
7597 		ret = xmlXPathNodeSetMerge(ret, ns);
7598                 if (ret == NULL)
7599                     xmlXPathPErrMemory(ctxt);
7600 		xmlXPathFreeNodeSet(ns);
7601 		if (tokens != NULL)
7602 		    xmlFree(tokens);
7603 	    }
7604 	}
7605 	xmlXPathReleaseObject(ctxt->context, obj);
7606 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7607 	return;
7608     }
7609     tokens = xmlXPathCastToString(obj);
7610     if (tokens == NULL)
7611         xmlXPathPErrMemory(ctxt);
7612     xmlXPathReleaseObject(ctxt->context, obj);
7613     ret = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7614     if (ret == NULL)
7615         xmlXPathPErrMemory(ctxt);
7616     xmlFree(tokens);
7617     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7618     return;
7619 }
7620 
7621 /**
7622  * xmlXPathLocalNameFunction:
7623  * @ctxt:  the XPath Parser context
7624  * @nargs:  the number of arguments
7625  *
7626  * Implement the local-name() XPath function
7627  *    string local-name(node-set?)
7628  * The local-name function returns a string containing the local part
7629  * of the name of the node in the argument node-set that is first in
7630  * document order. If the node-set is empty or the first node has no
7631  * name, an empty string is returned. If the argument is omitted it
7632  * defaults to the context node.
7633  */
7634 void
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt,int nargs)7635 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7636     xmlXPathObjectPtr cur;
7637 
7638     if (ctxt == NULL) return;
7639 
7640     if (nargs == 0) {
7641 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7642 	nargs = 1;
7643     }
7644 
7645     CHECK_ARITY(1);
7646     if ((ctxt->value == NULL) ||
7647 	((ctxt->value->type != XPATH_NODESET) &&
7648 	 (ctxt->value->type != XPATH_XSLT_TREE)))
7649 	XP_ERROR(XPATH_INVALID_TYPE);
7650     cur = valuePop(ctxt);
7651 
7652     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7653 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7654     } else {
7655 	int i = 0; /* Should be first in document order !!!!! */
7656 	switch (cur->nodesetval->nodeTab[i]->type) {
7657 	case XML_ELEMENT_NODE:
7658 	case XML_ATTRIBUTE_NODE:
7659 	case XML_PI_NODE:
7660 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7661 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7662 	    else
7663 		valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7664 			cur->nodesetval->nodeTab[i]->name));
7665 	    break;
7666 	case XML_NAMESPACE_DECL:
7667 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7668 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
7669 	    break;
7670 	default:
7671 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7672 	}
7673     }
7674     xmlXPathReleaseObject(ctxt->context, cur);
7675 }
7676 
7677 /**
7678  * xmlXPathNamespaceURIFunction:
7679  * @ctxt:  the XPath Parser context
7680  * @nargs:  the number of arguments
7681  *
7682  * Implement the namespace-uri() XPath function
7683  *    string namespace-uri(node-set?)
7684  * The namespace-uri function returns a string containing the
7685  * namespace URI of the expanded name of the node in the argument
7686  * node-set that is first in document order. If the node-set is empty,
7687  * the first node has no name, or the expanded name has no namespace
7688  * URI, an empty string is returned. If the argument is omitted it
7689  * defaults to the context node.
7690  */
7691 void
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt,int nargs)7692 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7693     xmlXPathObjectPtr cur;
7694 
7695     if (ctxt == NULL) return;
7696 
7697     if (nargs == 0) {
7698 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7699 	nargs = 1;
7700     }
7701     CHECK_ARITY(1);
7702     if ((ctxt->value == NULL) ||
7703 	((ctxt->value->type != XPATH_NODESET) &&
7704 	 (ctxt->value->type != XPATH_XSLT_TREE)))
7705 	XP_ERROR(XPATH_INVALID_TYPE);
7706     cur = valuePop(ctxt);
7707 
7708     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7709 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7710     } else {
7711 	int i = 0; /* Should be first in document order !!!!! */
7712 	switch (cur->nodesetval->nodeTab[i]->type) {
7713 	case XML_ELEMENT_NODE:
7714 	case XML_ATTRIBUTE_NODE:
7715 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
7716 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7717 	    else
7718 		valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7719 			  cur->nodesetval->nodeTab[i]->ns->href));
7720 	    break;
7721 	default:
7722 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7723 	}
7724     }
7725     xmlXPathReleaseObject(ctxt->context, cur);
7726 }
7727 
7728 /**
7729  * xmlXPathNameFunction:
7730  * @ctxt:  the XPath Parser context
7731  * @nargs:  the number of arguments
7732  *
7733  * Implement the name() XPath function
7734  *    string name(node-set?)
7735  * The name function returns a string containing a QName representing
7736  * the name of the node in the argument node-set that is first in document
7737  * order. The QName must represent the name with respect to the namespace
7738  * declarations in effect on the node whose name is being represented.
7739  * Typically, this will be the form in which the name occurred in the XML
7740  * source. This need not be the case if there are namespace declarations
7741  * in effect on the node that associate multiple prefixes with the same
7742  * namespace. However, an implementation may include information about
7743  * the original prefix in its representation of nodes; in this case, an
7744  * implementation can ensure that the returned string is always the same
7745  * as the QName used in the XML source. If the argument it omitted it
7746  * defaults to the context node.
7747  * Libxml keep the original prefix so the "real qualified name" used is
7748  * returned.
7749  */
7750 static void
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt,int nargs)7751 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
7752 {
7753     xmlXPathObjectPtr cur;
7754 
7755     if (nargs == 0) {
7756 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7757         nargs = 1;
7758     }
7759 
7760     CHECK_ARITY(1);
7761     if ((ctxt->value == NULL) ||
7762         ((ctxt->value->type != XPATH_NODESET) &&
7763          (ctxt->value->type != XPATH_XSLT_TREE)))
7764         XP_ERROR(XPATH_INVALID_TYPE);
7765     cur = valuePop(ctxt);
7766 
7767     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7768         valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7769     } else {
7770         int i = 0;              /* Should be first in document order !!!!! */
7771 
7772         switch (cur->nodesetval->nodeTab[i]->type) {
7773             case XML_ELEMENT_NODE:
7774             case XML_ATTRIBUTE_NODE:
7775 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7776 		    valuePush(ctxt,
7777 			xmlXPathCacheNewCString(ctxt, ""));
7778 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
7779                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
7780 		    valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7781 			    cur->nodesetval->nodeTab[i]->name));
7782 		} else {
7783 		    xmlChar *fullname;
7784 
7785 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
7786 				     cur->nodesetval->nodeTab[i]->ns->prefix,
7787 				     NULL, 0);
7788 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
7789 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
7790 		    if (fullname == NULL)
7791                         xmlXPathPErrMemory(ctxt);
7792 		    valuePush(ctxt, xmlXPathCacheWrapString(ctxt, fullname));
7793                 }
7794                 break;
7795             default:
7796 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7797 		    cur->nodesetval->nodeTab[i]));
7798                 xmlXPathLocalNameFunction(ctxt, 1);
7799         }
7800     }
7801     xmlXPathReleaseObject(ctxt->context, cur);
7802 }
7803 
7804 
7805 /**
7806  * xmlXPathStringFunction:
7807  * @ctxt:  the XPath Parser context
7808  * @nargs:  the number of arguments
7809  *
7810  * Implement the string() XPath function
7811  *    string string(object?)
7812  * The string function converts an object to a string as follows:
7813  *    - A node-set is converted to a string by returning the value of
7814  *      the node in the node-set that is first in document order.
7815  *      If the node-set is empty, an empty string is returned.
7816  *    - A number is converted to a string as follows
7817  *      + NaN is converted to the string NaN
7818  *      + positive zero is converted to the string 0
7819  *      + negative zero is converted to the string 0
7820  *      + positive infinity is converted to the string Infinity
7821  *      + negative infinity is converted to the string -Infinity
7822  *      + if the number is an integer, the number is represented in
7823  *        decimal form as a Number with no decimal point and no leading
7824  *        zeros, preceded by a minus sign (-) if the number is negative
7825  *      + otherwise, the number is represented in decimal form as a
7826  *        Number including a decimal point with at least one digit
7827  *        before the decimal point and at least one digit after the
7828  *        decimal point, preceded by a minus sign (-) if the number
7829  *        is negative; there must be no leading zeros before the decimal
7830  *        point apart possibly from the one required digit immediately
7831  *        before the decimal point; beyond the one required digit
7832  *        after the decimal point there must be as many, but only as
7833  *        many, more digits as are needed to uniquely distinguish the
7834  *        number from all other IEEE 754 numeric values.
7835  *    - The boolean false value is converted to the string false.
7836  *      The boolean true value is converted to the string true.
7837  *
7838  * If the argument is omitted, it defaults to a node-set with the
7839  * context node as its only member.
7840  */
7841 void
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt,int nargs)7842 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7843     xmlXPathObjectPtr cur;
7844     xmlChar *stringval;
7845 
7846     if (ctxt == NULL) return;
7847     if (nargs == 0) {
7848         stringval = xmlXPathCastNodeToString(ctxt->context->node);
7849         if (stringval == NULL)
7850             xmlXPathPErrMemory(ctxt);
7851         valuePush(ctxt, xmlXPathCacheWrapString(ctxt, stringval));
7852 	return;
7853     }
7854 
7855     CHECK_ARITY(1);
7856     cur = valuePop(ctxt);
7857     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7858     if (cur->type != XPATH_STRING) {
7859         stringval = xmlXPathCastToString(cur);
7860         if (stringval == NULL)
7861             xmlXPathPErrMemory(ctxt);
7862         xmlXPathReleaseObject(ctxt->context, cur);
7863         cur = xmlXPathCacheWrapString(ctxt, stringval);
7864     }
7865     valuePush(ctxt, cur);
7866 }
7867 
7868 /**
7869  * xmlXPathStringLengthFunction:
7870  * @ctxt:  the XPath Parser context
7871  * @nargs:  the number of arguments
7872  *
7873  * Implement the string-length() XPath function
7874  *    number string-length(string?)
7875  * The string-length returns the number of characters in the string
7876  * (see [3.6 Strings]). If the argument is omitted, it defaults to
7877  * the context node converted to a string, in other words the value
7878  * of the context node.
7879  */
7880 void
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt,int nargs)7881 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7882     xmlXPathObjectPtr cur;
7883 
7884     if (nargs == 0) {
7885         if ((ctxt == NULL) || (ctxt->context == NULL))
7886 	    return;
7887 	if (ctxt->context->node == NULL) {
7888 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0));
7889 	} else {
7890 	    xmlChar *content;
7891 
7892 	    content = xmlXPathCastNodeToString(ctxt->context->node);
7893             if (content == NULL)
7894                 xmlXPathPErrMemory(ctxt);
7895 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7896 		xmlUTF8Strlen(content)));
7897 	    xmlFree(content);
7898 	}
7899 	return;
7900     }
7901     CHECK_ARITY(1);
7902     CAST_TO_STRING;
7903     CHECK_TYPE(XPATH_STRING);
7904     cur = valuePop(ctxt);
7905     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7906 	xmlUTF8Strlen(cur->stringval)));
7907     xmlXPathReleaseObject(ctxt->context, cur);
7908 }
7909 
7910 /**
7911  * xmlXPathConcatFunction:
7912  * @ctxt:  the XPath Parser context
7913  * @nargs:  the number of arguments
7914  *
7915  * Implement the concat() XPath function
7916  *    string concat(string, string, string*)
7917  * The concat function returns the concatenation of its arguments.
7918  */
7919 void
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt,int nargs)7920 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7921     xmlXPathObjectPtr cur, newobj;
7922     xmlChar *tmp;
7923 
7924     if (ctxt == NULL) return;
7925     if (nargs < 2) {
7926 	CHECK_ARITY(2);
7927     }
7928 
7929     CAST_TO_STRING;
7930     cur = valuePop(ctxt);
7931     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
7932 	xmlXPathReleaseObject(ctxt->context, cur);
7933 	return;
7934     }
7935     nargs--;
7936 
7937     while (nargs > 0) {
7938 	CAST_TO_STRING;
7939 	newobj = valuePop(ctxt);
7940 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
7941 	    xmlXPathReleaseObject(ctxt->context, newobj);
7942 	    xmlXPathReleaseObject(ctxt->context, cur);
7943 	    XP_ERROR(XPATH_INVALID_TYPE);
7944 	}
7945 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
7946         if (tmp == NULL)
7947             xmlXPathPErrMemory(ctxt);
7948 	newobj->stringval = cur->stringval;
7949 	cur->stringval = tmp;
7950 	xmlXPathReleaseObject(ctxt->context, newobj);
7951 	nargs--;
7952     }
7953     valuePush(ctxt, cur);
7954 }
7955 
7956 /**
7957  * xmlXPathContainsFunction:
7958  * @ctxt:  the XPath Parser context
7959  * @nargs:  the number of arguments
7960  *
7961  * Implement the contains() XPath function
7962  *    boolean contains(string, string)
7963  * The contains function returns true if the first argument string
7964  * contains the second argument string, and otherwise returns false.
7965  */
7966 void
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt,int nargs)7967 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7968     xmlXPathObjectPtr hay, needle;
7969 
7970     CHECK_ARITY(2);
7971     CAST_TO_STRING;
7972     CHECK_TYPE(XPATH_STRING);
7973     needle = valuePop(ctxt);
7974     CAST_TO_STRING;
7975     hay = valuePop(ctxt);
7976 
7977     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7978 	xmlXPathReleaseObject(ctxt->context, hay);
7979 	xmlXPathReleaseObject(ctxt->context, needle);
7980 	XP_ERROR(XPATH_INVALID_TYPE);
7981     }
7982     if (xmlStrstr(hay->stringval, needle->stringval))
7983 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7984     else
7985 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7986     xmlXPathReleaseObject(ctxt->context, hay);
7987     xmlXPathReleaseObject(ctxt->context, needle);
7988 }
7989 
7990 /**
7991  * xmlXPathStartsWithFunction:
7992  * @ctxt:  the XPath Parser context
7993  * @nargs:  the number of arguments
7994  *
7995  * Implement the starts-with() XPath function
7996  *    boolean starts-with(string, string)
7997  * The starts-with function returns true if the first argument string
7998  * starts with the second argument string, and otherwise returns false.
7999  */
8000 void
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt,int nargs)8001 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8002     xmlXPathObjectPtr hay, needle;
8003     int n;
8004 
8005     CHECK_ARITY(2);
8006     CAST_TO_STRING;
8007     CHECK_TYPE(XPATH_STRING);
8008     needle = valuePop(ctxt);
8009     CAST_TO_STRING;
8010     hay = valuePop(ctxt);
8011 
8012     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8013 	xmlXPathReleaseObject(ctxt->context, hay);
8014 	xmlXPathReleaseObject(ctxt->context, needle);
8015 	XP_ERROR(XPATH_INVALID_TYPE);
8016     }
8017     n = xmlStrlen(needle->stringval);
8018     if (xmlStrncmp(hay->stringval, needle->stringval, n))
8019         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
8020     else
8021         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
8022     xmlXPathReleaseObject(ctxt->context, hay);
8023     xmlXPathReleaseObject(ctxt->context, needle);
8024 }
8025 
8026 /**
8027  * xmlXPathSubstringFunction:
8028  * @ctxt:  the XPath Parser context
8029  * @nargs:  the number of arguments
8030  *
8031  * Implement the substring() XPath function
8032  *    string substring(string, number, number?)
8033  * The substring function returns the substring of the first argument
8034  * starting at the position specified in the second argument with
8035  * length specified in the third argument. For example,
8036  * substring("12345",2,3) returns "234". If the third argument is not
8037  * specified, it returns the substring starting at the position specified
8038  * in the second argument and continuing to the end of the string. For
8039  * example, substring("12345",2) returns "2345".  More precisely, each
8040  * character in the string (see [3.6 Strings]) is considered to have a
8041  * numeric position: the position of the first character is 1, the position
8042  * of the second character is 2 and so on. The returned substring contains
8043  * those characters for which the position of the character is greater than
8044  * or equal to the second argument and, if the third argument is specified,
8045  * less than the sum of the second and third arguments; the comparisons
8046  * and addition used for the above follow the standard IEEE 754 rules. Thus:
8047  *  - substring("12345", 1.5, 2.6) returns "234"
8048  *  - substring("12345", 0, 3) returns "12"
8049  *  - substring("12345", 0 div 0, 3) returns ""
8050  *  - substring("12345", 1, 0 div 0) returns ""
8051  *  - substring("12345", -42, 1 div 0) returns "12345"
8052  *  - substring("12345", -1 div 0, 1 div 0) returns ""
8053  */
8054 void
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt,int nargs)8055 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8056     xmlXPathObjectPtr str, start, len;
8057     double le=0, in;
8058     int i = 1, j = INT_MAX;
8059 
8060     if (nargs < 2) {
8061 	CHECK_ARITY(2);
8062     }
8063     if (nargs > 3) {
8064 	CHECK_ARITY(3);
8065     }
8066     /*
8067      * take care of possible last (position) argument
8068     */
8069     if (nargs == 3) {
8070 	CAST_TO_NUMBER;
8071 	CHECK_TYPE(XPATH_NUMBER);
8072 	len = valuePop(ctxt);
8073 	le = len->floatval;
8074 	xmlXPathReleaseObject(ctxt->context, len);
8075     }
8076 
8077     CAST_TO_NUMBER;
8078     CHECK_TYPE(XPATH_NUMBER);
8079     start = valuePop(ctxt);
8080     in = start->floatval;
8081     xmlXPathReleaseObject(ctxt->context, start);
8082     CAST_TO_STRING;
8083     CHECK_TYPE(XPATH_STRING);
8084     str = valuePop(ctxt);
8085 
8086     if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
8087         i = INT_MAX;
8088     } else if (in >= 1.0) {
8089         i = (int)in;
8090         if (in - floor(in) >= 0.5)
8091             i += 1;
8092     }
8093 
8094     if (nargs == 3) {
8095         double rin, rle, end;
8096 
8097         rin = floor(in);
8098         if (in - rin >= 0.5)
8099             rin += 1.0;
8100 
8101         rle = floor(le);
8102         if (le - rle >= 0.5)
8103             rle += 1.0;
8104 
8105         end = rin + rle;
8106         if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
8107             j = 1;
8108         } else if (end < INT_MAX) {
8109             j = (int)end;
8110         }
8111     }
8112 
8113     i -= 1;
8114     j -= 1;
8115 
8116     if ((i < j) && (i < xmlUTF8Strlen(str->stringval))) {
8117         xmlChar *ret = xmlUTF8Strsub(str->stringval, i, j - i);
8118         if (ret == NULL)
8119             xmlXPathPErrMemory(ctxt);
8120 	valuePush(ctxt, xmlXPathCacheNewString(ctxt, ret));
8121 	xmlFree(ret);
8122     } else {
8123 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
8124     }
8125 
8126     xmlXPathReleaseObject(ctxt->context, str);
8127 }
8128 
8129 /**
8130  * xmlXPathSubstringBeforeFunction:
8131  * @ctxt:  the XPath Parser context
8132  * @nargs:  the number of arguments
8133  *
8134  * Implement the substring-before() XPath function
8135  *    string substring-before(string, string)
8136  * The substring-before function returns the substring of the first
8137  * argument string that precedes the first occurrence of the second
8138  * argument string in the first argument string, or the empty string
8139  * if the first argument string does not contain the second argument
8140  * string. For example, substring-before("1999/04/01","/") returns 1999.
8141  */
8142 void
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt,int nargs)8143 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8144     xmlXPathObjectPtr str = NULL;
8145     xmlXPathObjectPtr find = NULL;
8146     const xmlChar *point;
8147     xmlChar *result;
8148 
8149     CHECK_ARITY(2);
8150     CAST_TO_STRING;
8151     find = valuePop(ctxt);
8152     CAST_TO_STRING;
8153     str = valuePop(ctxt);
8154     if (ctxt->error != 0)
8155         goto error;
8156 
8157     point = xmlStrstr(str->stringval, find->stringval);
8158     if (point == NULL) {
8159         result = xmlStrdup(BAD_CAST "");
8160     } else {
8161         result = xmlStrndup(str->stringval, point - str->stringval);
8162     }
8163     if (result == NULL) {
8164         xmlXPathPErrMemory(ctxt);
8165         goto error;
8166     }
8167     valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
8168 
8169 error:
8170     xmlXPathReleaseObject(ctxt->context, str);
8171     xmlXPathReleaseObject(ctxt->context, find);
8172 }
8173 
8174 /**
8175  * xmlXPathSubstringAfterFunction:
8176  * @ctxt:  the XPath Parser context
8177  * @nargs:  the number of arguments
8178  *
8179  * Implement the substring-after() XPath function
8180  *    string substring-after(string, string)
8181  * The substring-after function returns the substring of the first
8182  * argument string that follows the first occurrence of the second
8183  * argument string in the first argument string, or the empty string
8184  * if the first argument string does not contain the second argument
8185  * string. For example, substring-after("1999/04/01","/") returns 04/01,
8186  * and substring-after("1999/04/01","19") returns 99/04/01.
8187  */
8188 void
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt,int nargs)8189 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8190     xmlXPathObjectPtr str = NULL;
8191     xmlXPathObjectPtr find = NULL;
8192     const xmlChar *point;
8193     xmlChar *result;
8194 
8195     CHECK_ARITY(2);
8196     CAST_TO_STRING;
8197     find = valuePop(ctxt);
8198     CAST_TO_STRING;
8199     str = valuePop(ctxt);
8200     if (ctxt->error != 0)
8201         goto error;
8202 
8203     point = xmlStrstr(str->stringval, find->stringval);
8204     if (point == NULL) {
8205         result = xmlStrdup(BAD_CAST "");
8206     } else {
8207         result = xmlStrdup(point + xmlStrlen(find->stringval));
8208     }
8209     if (result == NULL) {
8210         xmlXPathPErrMemory(ctxt);
8211         goto error;
8212     }
8213     valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
8214 
8215 error:
8216     xmlXPathReleaseObject(ctxt->context, str);
8217     xmlXPathReleaseObject(ctxt->context, find);
8218 }
8219 
8220 /**
8221  * xmlXPathNormalizeFunction:
8222  * @ctxt:  the XPath Parser context
8223  * @nargs:  the number of arguments
8224  *
8225  * Implement the normalize-space() XPath function
8226  *    string normalize-space(string?)
8227  * The normalize-space function returns the argument string with white
8228  * space normalized by stripping leading and trailing whitespace
8229  * and replacing sequences of whitespace characters by a single
8230  * space. Whitespace characters are the same allowed by the S production
8231  * in XML. If the argument is omitted, it defaults to the context
8232  * node converted to a string, in other words the value of the context node.
8233  */
8234 void
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt,int nargs)8235 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8236     xmlChar *source, *target;
8237     int blank;
8238 
8239     if (ctxt == NULL) return;
8240     if (nargs == 0) {
8241         /* Use current context node */
8242         source = xmlXPathCastNodeToString(ctxt->context->node);
8243         if (source == NULL)
8244             xmlXPathPErrMemory(ctxt);
8245         valuePush(ctxt, xmlXPathCacheWrapString(ctxt, source));
8246         nargs = 1;
8247     }
8248 
8249     CHECK_ARITY(1);
8250     CAST_TO_STRING;
8251     CHECK_TYPE(XPATH_STRING);
8252     source = ctxt->value->stringval;
8253     if (source == NULL)
8254         return;
8255     target = source;
8256 
8257     /* Skip leading whitespaces */
8258     while (IS_BLANK_CH(*source))
8259         source++;
8260 
8261     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
8262     blank = 0;
8263     while (*source) {
8264         if (IS_BLANK_CH(*source)) {
8265 	    blank = 1;
8266         } else {
8267             if (blank) {
8268                 *target++ = 0x20;
8269                 blank = 0;
8270             }
8271             *target++ = *source;
8272         }
8273         source++;
8274     }
8275     *target = 0;
8276 }
8277 
8278 /**
8279  * xmlXPathTranslateFunction:
8280  * @ctxt:  the XPath Parser context
8281  * @nargs:  the number of arguments
8282  *
8283  * Implement the translate() XPath function
8284  *    string translate(string, string, string)
8285  * The translate function returns the first argument string with
8286  * occurrences of characters in the second argument string replaced
8287  * by the character at the corresponding position in the third argument
8288  * string. For example, translate("bar","abc","ABC") returns the string
8289  * BAr. If there is a character in the second argument string with no
8290  * character at a corresponding position in the third argument string
8291  * (because the second argument string is longer than the third argument
8292  * string), then occurrences of that character in the first argument
8293  * string are removed. For example, translate("--aaa--","abc-","ABC")
8294  * returns "AAA". If a character occurs more than once in second
8295  * argument string, then the first occurrence determines the replacement
8296  * character. If the third argument string is longer than the second
8297  * argument string, then excess characters are ignored.
8298  */
8299 void
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt,int nargs)8300 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8301     xmlXPathObjectPtr str = NULL;
8302     xmlXPathObjectPtr from = NULL;
8303     xmlXPathObjectPtr to = NULL;
8304     xmlBufPtr target;
8305     int offset, max;
8306     int ch;
8307     const xmlChar *point;
8308     xmlChar *cptr, *content;
8309 
8310     CHECK_ARITY(3);
8311 
8312     CAST_TO_STRING;
8313     to = valuePop(ctxt);
8314     CAST_TO_STRING;
8315     from = valuePop(ctxt);
8316     CAST_TO_STRING;
8317     str = valuePop(ctxt);
8318     if (ctxt->error != 0)
8319         goto error;
8320 
8321     target = xmlBufCreate();
8322     if (target == NULL) {
8323         xmlXPathPErrMemory(ctxt);
8324         goto error;
8325     }
8326 
8327     max = xmlUTF8Strlen(to->stringval);
8328     for (cptr = str->stringval; (ch=*cptr); ) {
8329         offset = xmlUTF8Strloc(from->stringval, cptr);
8330         if (offset >= 0) {
8331             if (offset < max) {
8332                 point = xmlUTF8Strpos(to->stringval, offset);
8333                 if (point)
8334                     xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
8335             }
8336         } else
8337             xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
8338 
8339         /* Step to next character in input */
8340         cptr++;
8341         if ( ch & 0x80 ) {
8342             /* if not simple ascii, verify proper format */
8343             if ( (ch & 0xc0) != 0xc0 ) {
8344                 xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
8345                 break;
8346             }
8347             /* then skip over remaining bytes for this char */
8348             while ( (ch <<= 1) & 0x80 )
8349                 if ( (*cptr++ & 0xc0) != 0x80 ) {
8350                     xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
8351                     break;
8352                 }
8353             if (ch & 0x80) /* must have had error encountered */
8354                 break;
8355         }
8356     }
8357 
8358     content = xmlBufDetach(target);
8359     if (content == NULL)
8360         xmlXPathPErrMemory(ctxt);
8361     else
8362         valuePush(ctxt, xmlXPathCacheWrapString(ctxt, content));
8363     xmlBufFree(target);
8364 error:
8365     xmlXPathReleaseObject(ctxt->context, str);
8366     xmlXPathReleaseObject(ctxt->context, from);
8367     xmlXPathReleaseObject(ctxt->context, to);
8368 }
8369 
8370 /**
8371  * xmlXPathBooleanFunction:
8372  * @ctxt:  the XPath Parser context
8373  * @nargs:  the number of arguments
8374  *
8375  * Implement the boolean() XPath function
8376  *    boolean boolean(object)
8377  * The boolean function converts its argument to a boolean as follows:
8378  *    - a number is true if and only if it is neither positive or
8379  *      negative zero nor NaN
8380  *    - a node-set is true if and only if it is non-empty
8381  *    - a string is true if and only if its length is non-zero
8382  */
8383 void
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt,int nargs)8384 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8385     xmlXPathObjectPtr cur;
8386 
8387     CHECK_ARITY(1);
8388     cur = valuePop(ctxt);
8389     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8390     if (cur->type != XPATH_BOOLEAN) {
8391         int boolval = xmlXPathCastToBoolean(cur);
8392 
8393         xmlXPathReleaseObject(ctxt->context, cur);
8394         cur = xmlXPathCacheNewBoolean(ctxt, boolval);
8395     }
8396     valuePush(ctxt, cur);
8397 }
8398 
8399 /**
8400  * xmlXPathNotFunction:
8401  * @ctxt:  the XPath Parser context
8402  * @nargs:  the number of arguments
8403  *
8404  * Implement the not() XPath function
8405  *    boolean not(boolean)
8406  * The not function returns true if its argument is false,
8407  * and false otherwise.
8408  */
8409 void
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt,int nargs)8410 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8411     CHECK_ARITY(1);
8412     CAST_TO_BOOLEAN;
8413     CHECK_TYPE(XPATH_BOOLEAN);
8414     ctxt->value->boolval = ! ctxt->value->boolval;
8415 }
8416 
8417 /**
8418  * xmlXPathTrueFunction:
8419  * @ctxt:  the XPath Parser context
8420  * @nargs:  the number of arguments
8421  *
8422  * Implement the true() XPath function
8423  *    boolean true()
8424  */
8425 void
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt,int nargs)8426 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8427     CHECK_ARITY(0);
8428     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
8429 }
8430 
8431 /**
8432  * xmlXPathFalseFunction:
8433  * @ctxt:  the XPath Parser context
8434  * @nargs:  the number of arguments
8435  *
8436  * Implement the false() XPath function
8437  *    boolean false()
8438  */
8439 void
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt,int nargs)8440 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8441     CHECK_ARITY(0);
8442     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
8443 }
8444 
8445 /**
8446  * xmlXPathLangFunction:
8447  * @ctxt:  the XPath Parser context
8448  * @nargs:  the number of arguments
8449  *
8450  * Implement the lang() XPath function
8451  *    boolean lang(string)
8452  * The lang function returns true or false depending on whether the
8453  * language of the context node as specified by xml:lang attributes
8454  * is the same as or is a sublanguage of the language specified by
8455  * the argument string. The language of the context node is determined
8456  * by the value of the xml:lang attribute on the context node, or, if
8457  * the context node has no xml:lang attribute, by the value of the
8458  * xml:lang attribute on the nearest ancestor of the context node that
8459  * has an xml:lang attribute. If there is no such attribute, then lang
8460  * returns false. If there is such an attribute, then lang returns
8461  * true if the attribute value is equal to the argument ignoring case,
8462  * or if there is some suffix starting with - such that the attribute
8463  * value is equal to the argument ignoring that suffix of the attribute
8464  * value and ignoring case.
8465  */
8466 void
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt,int nargs)8467 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8468     xmlXPathObjectPtr val;
8469     xmlNodePtr cur;
8470     xmlChar *theLang;
8471     const xmlChar *lang;
8472     int ret = 0;
8473     int i;
8474 
8475     CHECK_ARITY(1);
8476     CAST_TO_STRING;
8477     CHECK_TYPE(XPATH_STRING);
8478     val = valuePop(ctxt);
8479     lang = val->stringval;
8480     cur = ctxt->context->node;
8481     while (cur != NULL) {
8482         if (xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE,
8483                                 &theLang) < 0)
8484             xmlXPathPErrMemory(ctxt);
8485         if (theLang != NULL)
8486             break;
8487         cur = cur->parent;
8488     }
8489     if ((theLang != NULL) && (lang != NULL)) {
8490         for (i = 0;lang[i] != 0;i++)
8491             if (toupper(lang[i]) != toupper(theLang[i]))
8492                 goto not_equal;
8493         if ((theLang[i] == 0) || (theLang[i] == '-'))
8494             ret = 1;
8495     }
8496 not_equal:
8497     if (theLang != NULL)
8498 	xmlFree((void *)theLang);
8499 
8500     xmlXPathReleaseObject(ctxt->context, val);
8501     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
8502 }
8503 
8504 /**
8505  * xmlXPathNumberFunction:
8506  * @ctxt:  the XPath Parser context
8507  * @nargs:  the number of arguments
8508  *
8509  * Implement the number() XPath function
8510  *    number number(object?)
8511  */
8512 void
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt,int nargs)8513 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8514     xmlXPathObjectPtr cur;
8515     double res;
8516 
8517     if (ctxt == NULL) return;
8518     if (nargs == 0) {
8519 	if (ctxt->context->node == NULL) {
8520 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
8521 	} else {
8522 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
8523             if (content == NULL)
8524                 xmlXPathPErrMemory(ctxt);
8525 
8526 	    res = xmlXPathStringEvalNumber(content);
8527 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8528 	    xmlFree(content);
8529 	}
8530 	return;
8531     }
8532 
8533     CHECK_ARITY(1);
8534     cur = valuePop(ctxt);
8535     if (cur->type != XPATH_NUMBER) {
8536         double floatval;
8537 
8538         floatval = xmlXPathCastToNumberInternal(ctxt, cur);
8539         xmlXPathReleaseObject(ctxt->context, cur);
8540         cur = xmlXPathCacheNewFloat(ctxt, floatval);
8541     }
8542     valuePush(ctxt, cur);
8543 }
8544 
8545 /**
8546  * xmlXPathSumFunction:
8547  * @ctxt:  the XPath Parser context
8548  * @nargs:  the number of arguments
8549  *
8550  * Implement the sum() XPath function
8551  *    number sum(node-set)
8552  * The sum function returns the sum of the values of the nodes in
8553  * the argument node-set.
8554  */
8555 void
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt,int nargs)8556 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8557     xmlXPathObjectPtr cur;
8558     int i;
8559     double res = 0.0;
8560 
8561     CHECK_ARITY(1);
8562     if ((ctxt->value == NULL) ||
8563 	((ctxt->value->type != XPATH_NODESET) &&
8564 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8565 	XP_ERROR(XPATH_INVALID_TYPE);
8566     cur = valuePop(ctxt);
8567 
8568     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
8569 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
8570 	    res += xmlXPathNodeToNumberInternal(ctxt,
8571                                                 cur->nodesetval->nodeTab[i]);
8572 	}
8573     }
8574     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8575     xmlXPathReleaseObject(ctxt->context, cur);
8576 }
8577 
8578 /**
8579  * xmlXPathFloorFunction:
8580  * @ctxt:  the XPath Parser context
8581  * @nargs:  the number of arguments
8582  *
8583  * Implement the floor() XPath function
8584  *    number floor(number)
8585  * The floor function returns the largest (closest to positive infinity)
8586  * number that is not greater than the argument and that is an integer.
8587  */
8588 void
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt,int nargs)8589 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8590     CHECK_ARITY(1);
8591     CAST_TO_NUMBER;
8592     CHECK_TYPE(XPATH_NUMBER);
8593 
8594     ctxt->value->floatval = floor(ctxt->value->floatval);
8595 }
8596 
8597 /**
8598  * xmlXPathCeilingFunction:
8599  * @ctxt:  the XPath Parser context
8600  * @nargs:  the number of arguments
8601  *
8602  * Implement the ceiling() XPath function
8603  *    number ceiling(number)
8604  * The ceiling function returns the smallest (closest to negative infinity)
8605  * number that is not less than the argument and that is an integer.
8606  */
8607 void
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt,int nargs)8608 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8609     CHECK_ARITY(1);
8610     CAST_TO_NUMBER;
8611     CHECK_TYPE(XPATH_NUMBER);
8612 
8613 #ifdef _AIX
8614     /* Work around buggy ceil() function on AIX */
8615     ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
8616 #else
8617     ctxt->value->floatval = ceil(ctxt->value->floatval);
8618 #endif
8619 }
8620 
8621 /**
8622  * xmlXPathRoundFunction:
8623  * @ctxt:  the XPath Parser context
8624  * @nargs:  the number of arguments
8625  *
8626  * Implement the round() XPath function
8627  *    number round(number)
8628  * The round function returns the number that is closest to the
8629  * argument and that is an integer. If there are two such numbers,
8630  * then the one that is closest to positive infinity is returned.
8631  */
8632 void
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt,int nargs)8633 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8634     double f;
8635 
8636     CHECK_ARITY(1);
8637     CAST_TO_NUMBER;
8638     CHECK_TYPE(XPATH_NUMBER);
8639 
8640     f = ctxt->value->floatval;
8641 
8642     if ((f >= -0.5) && (f < 0.5)) {
8643         /* Handles negative zero. */
8644         ctxt->value->floatval *= 0.0;
8645     }
8646     else {
8647         double rounded = floor(f);
8648         if (f - rounded >= 0.5)
8649             rounded += 1.0;
8650         ctxt->value->floatval = rounded;
8651     }
8652 }
8653 
8654 /************************************************************************
8655  *									*
8656  *			The Parser					*
8657  *									*
8658  ************************************************************************/
8659 
8660 /*
8661  * a few forward declarations since we use a recursive call based
8662  * implementation.
8663  */
8664 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
8665 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
8666 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
8667 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
8668 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
8669 	                                  int qualified);
8670 
8671 /**
8672  * xmlXPathCurrentChar:
8673  * @ctxt:  the XPath parser context
8674  * @cur:  pointer to the beginning of the char
8675  * @len:  pointer to the length of the char read
8676  *
8677  * The current char value, if using UTF-8 this may actually span multiple
8678  * bytes in the input buffer.
8679  *
8680  * Returns the current char value and its length
8681  */
8682 
8683 static int
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt,int * len)8684 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
8685     unsigned char c;
8686     unsigned int val;
8687     const xmlChar *cur;
8688 
8689     if (ctxt == NULL)
8690 	return(0);
8691     cur = ctxt->cur;
8692 
8693     /*
8694      * We are supposed to handle UTF8, check it's valid
8695      * From rfc2044: encoding of the Unicode values on UTF-8:
8696      *
8697      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
8698      * 0000 0000-0000 007F   0xxxxxxx
8699      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
8700      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
8701      *
8702      * Check for the 0x110000 limit too
8703      */
8704     c = *cur;
8705     if (c & 0x80) {
8706 	if ((cur[1] & 0xc0) != 0x80)
8707 	    goto encoding_error;
8708 	if ((c & 0xe0) == 0xe0) {
8709 
8710 	    if ((cur[2] & 0xc0) != 0x80)
8711 		goto encoding_error;
8712 	    if ((c & 0xf0) == 0xf0) {
8713 		if (((c & 0xf8) != 0xf0) ||
8714 		    ((cur[3] & 0xc0) != 0x80))
8715 		    goto encoding_error;
8716 		/* 4-byte code */
8717 		*len = 4;
8718 		val = (cur[0] & 0x7) << 18;
8719 		val |= (cur[1] & 0x3f) << 12;
8720 		val |= (cur[2] & 0x3f) << 6;
8721 		val |= cur[3] & 0x3f;
8722 	    } else {
8723 	      /* 3-byte code */
8724 		*len = 3;
8725 		val = (cur[0] & 0xf) << 12;
8726 		val |= (cur[1] & 0x3f) << 6;
8727 		val |= cur[2] & 0x3f;
8728 	    }
8729 	} else {
8730 	  /* 2-byte code */
8731 	    *len = 2;
8732 	    val = (cur[0] & 0x1f) << 6;
8733 	    val |= cur[1] & 0x3f;
8734 	}
8735 	if (!IS_CHAR(val)) {
8736 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
8737 	}
8738 	return(val);
8739     } else {
8740 	/* 1-byte code */
8741 	*len = 1;
8742 	return(*cur);
8743     }
8744 encoding_error:
8745     /*
8746      * If we detect an UTF8 error that probably means that the
8747      * input encoding didn't get properly advertised in the
8748      * declaration header. Report the error and switch the encoding
8749      * to ISO-Latin-1 (if you don't like this policy, just declare the
8750      * encoding !)
8751      */
8752     *len = 0;
8753     XP_ERROR0(XPATH_ENCODING_ERROR);
8754 }
8755 
8756 /**
8757  * xmlXPathParseNCName:
8758  * @ctxt:  the XPath Parser context
8759  *
8760  * parse an XML namespace non qualified name.
8761  *
8762  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
8763  *
8764  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
8765  *                       CombiningChar | Extender
8766  *
8767  * Returns the namespace name or NULL
8768  */
8769 
8770 xmlChar *
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt)8771 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
8772     const xmlChar *in;
8773     xmlChar *ret;
8774     int count = 0;
8775 
8776     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8777     /*
8778      * Accelerator for simple ASCII names
8779      */
8780     in = ctxt->cur;
8781     if (((*in >= 0x61) && (*in <= 0x7A)) ||
8782 	((*in >= 0x41) && (*in <= 0x5A)) ||
8783 	(*in == '_')) {
8784 	in++;
8785 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
8786 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
8787 	       ((*in >= 0x30) && (*in <= 0x39)) ||
8788 	       (*in == '_') || (*in == '.') ||
8789 	       (*in == '-'))
8790 	    in++;
8791 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
8792             (*in == '[') || (*in == ']') || (*in == ':') ||
8793             (*in == '@') || (*in == '*')) {
8794 	    count = in - ctxt->cur;
8795 	    if (count == 0)
8796 		return(NULL);
8797 	    ret = xmlStrndup(ctxt->cur, count);
8798             if (ret == NULL)
8799                 xmlXPathPErrMemory(ctxt);
8800 	    ctxt->cur = in;
8801 	    return(ret);
8802 	}
8803     }
8804     return(xmlXPathParseNameComplex(ctxt, 0));
8805 }
8806 
8807 
8808 /**
8809  * xmlXPathParseQName:
8810  * @ctxt:  the XPath Parser context
8811  * @prefix:  a xmlChar **
8812  *
8813  * parse an XML qualified name
8814  *
8815  * [NS 5] QName ::= (Prefix ':')? LocalPart
8816  *
8817  * [NS 6] Prefix ::= NCName
8818  *
8819  * [NS 7] LocalPart ::= NCName
8820  *
8821  * Returns the function returns the local part, and prefix is updated
8822  *   to get the Prefix if any.
8823  */
8824 
8825 static xmlChar *
xmlXPathParseQName(xmlXPathParserContextPtr ctxt,xmlChar ** prefix)8826 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
8827     xmlChar *ret = NULL;
8828 
8829     *prefix = NULL;
8830     ret = xmlXPathParseNCName(ctxt);
8831     if (ret && CUR == ':') {
8832         *prefix = ret;
8833 	NEXT;
8834 	ret = xmlXPathParseNCName(ctxt);
8835     }
8836     return(ret);
8837 }
8838 
8839 /**
8840  * xmlXPathParseName:
8841  * @ctxt:  the XPath Parser context
8842  *
8843  * parse an XML name
8844  *
8845  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8846  *                  CombiningChar | Extender
8847  *
8848  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8849  *
8850  * Returns the namespace name or NULL
8851  */
8852 
8853 xmlChar *
xmlXPathParseName(xmlXPathParserContextPtr ctxt)8854 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
8855     const xmlChar *in;
8856     xmlChar *ret;
8857     size_t count = 0;
8858 
8859     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8860     /*
8861      * Accelerator for simple ASCII names
8862      */
8863     in = ctxt->cur;
8864     if (((*in >= 0x61) && (*in <= 0x7A)) ||
8865 	((*in >= 0x41) && (*in <= 0x5A)) ||
8866 	(*in == '_') || (*in == ':')) {
8867 	in++;
8868 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
8869 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
8870 	       ((*in >= 0x30) && (*in <= 0x39)) ||
8871 	       (*in == '_') || (*in == '-') ||
8872 	       (*in == ':') || (*in == '.'))
8873 	    in++;
8874 	if ((*in > 0) && (*in < 0x80)) {
8875 	    count = in - ctxt->cur;
8876             if (count > XML_MAX_NAME_LENGTH) {
8877                 ctxt->cur = in;
8878                 XP_ERRORNULL(XPATH_EXPR_ERROR);
8879             }
8880 	    ret = xmlStrndup(ctxt->cur, count);
8881             if (ret == NULL)
8882                 xmlXPathPErrMemory(ctxt);
8883 	    ctxt->cur = in;
8884 	    return(ret);
8885 	}
8886     }
8887     return(xmlXPathParseNameComplex(ctxt, 1));
8888 }
8889 
8890 static xmlChar *
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,int qualified)8891 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
8892     xmlChar *ret;
8893     xmlChar buf[XML_MAX_NAMELEN + 5];
8894     int len = 0, l;
8895     int c;
8896 
8897     /*
8898      * Handler for more complex cases
8899      */
8900     c = CUR_CHAR(l);
8901     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8902         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
8903         (c == '*') || /* accelerators */
8904 	(!IS_LETTER(c) && (c != '_') &&
8905          ((!qualified) || (c != ':')))) {
8906 	return(NULL);
8907     }
8908 
8909     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8910 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8911             (c == '.') || (c == '-') ||
8912 	    (c == '_') || ((qualified) && (c == ':')) ||
8913 	    (IS_COMBINING(c)) ||
8914 	    (IS_EXTENDER(c)))) {
8915 	COPY_BUF(l,buf,len,c);
8916 	NEXTL(l);
8917 	c = CUR_CHAR(l);
8918 	if (len >= XML_MAX_NAMELEN) {
8919 	    /*
8920 	     * Okay someone managed to make a huge name, so he's ready to pay
8921 	     * for the processing speed.
8922 	     */
8923 	    xmlChar *buffer;
8924 	    int max = len * 2;
8925 
8926             if (len > XML_MAX_NAME_LENGTH) {
8927                 XP_ERRORNULL(XPATH_EXPR_ERROR);
8928             }
8929 	    buffer = (xmlChar *) xmlMallocAtomic(max);
8930 	    if (buffer == NULL) {
8931                 xmlXPathPErrMemory(ctxt);
8932                 return(NULL);
8933 	    }
8934 	    memcpy(buffer, buf, len);
8935 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
8936 		   (c == '.') || (c == '-') ||
8937 		   (c == '_') || ((qualified) && (c == ':')) ||
8938 		   (IS_COMBINING(c)) ||
8939 		   (IS_EXTENDER(c))) {
8940 		if (len + 10 > max) {
8941                     xmlChar *tmp;
8942                     if (max > XML_MAX_NAME_LENGTH) {
8943                         xmlFree(buffer);
8944                         XP_ERRORNULL(XPATH_EXPR_ERROR);
8945                     }
8946 		    max *= 2;
8947 		    tmp = (xmlChar *) xmlRealloc(buffer, max);
8948 		    if (tmp == NULL) {
8949                         xmlFree(buffer);
8950                         xmlXPathPErrMemory(ctxt);
8951                         return(NULL);
8952 		    }
8953                     buffer = tmp;
8954 		}
8955 		COPY_BUF(l,buffer,len,c);
8956 		NEXTL(l);
8957 		c = CUR_CHAR(l);
8958 	    }
8959 	    buffer[len] = 0;
8960 	    return(buffer);
8961 	}
8962     }
8963     if (len == 0)
8964 	return(NULL);
8965     ret = xmlStrndup(buf, len);
8966     if (ret == NULL)
8967         xmlXPathPErrMemory(ctxt);
8968     return(ret);
8969 }
8970 
8971 #define MAX_FRAC 20
8972 
8973 /**
8974  * xmlXPathStringEvalNumber:
8975  * @str:  A string to scan
8976  *
8977  *  [30a]  Float  ::= Number ('e' Digits?)?
8978  *
8979  *  [30]   Number ::=   Digits ('.' Digits?)?
8980  *                    | '.' Digits
8981  *  [31]   Digits ::=   [0-9]+
8982  *
8983  * Compile a Number in the string
8984  * In complement of the Number expression, this function also handles
8985  * negative values : '-' Number.
8986  *
8987  * Returns the double value.
8988  */
8989 double
xmlXPathStringEvalNumber(const xmlChar * str)8990 xmlXPathStringEvalNumber(const xmlChar *str) {
8991     const xmlChar *cur = str;
8992     double ret;
8993     int ok = 0;
8994     int isneg = 0;
8995     int exponent = 0;
8996     int is_exponent_negative = 0;
8997 #ifdef __GNUC__
8998     unsigned long tmp = 0;
8999     double temp;
9000 #endif
9001     if (cur == NULL) return(0);
9002     while (IS_BLANK_CH(*cur)) cur++;
9003     if (*cur == '-') {
9004 	isneg = 1;
9005 	cur++;
9006     }
9007     if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
9008         return(xmlXPathNAN);
9009     }
9010 
9011 #ifdef __GNUC__
9012     /*
9013      * tmp/temp is a workaround against a gcc compiler bug
9014      * http://veillard.com/gcc.bug
9015      */
9016     ret = 0;
9017     while ((*cur >= '0') && (*cur <= '9')) {
9018 	ret = ret * 10;
9019 	tmp = (*cur - '0');
9020 	ok = 1;
9021 	cur++;
9022 	temp = (double) tmp;
9023 	ret = ret + temp;
9024     }
9025 #else
9026     ret = 0;
9027     while ((*cur >= '0') && (*cur <= '9')) {
9028 	ret = ret * 10 + (*cur - '0');
9029 	ok = 1;
9030 	cur++;
9031     }
9032 #endif
9033 
9034     if (*cur == '.') {
9035 	int v, frac = 0, max;
9036 	double fraction = 0;
9037 
9038         cur++;
9039 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9040 	    return(xmlXPathNAN);
9041 	}
9042         while (*cur == '0') {
9043 	    frac = frac + 1;
9044 	    cur++;
9045         }
9046         max = frac + MAX_FRAC;
9047 	while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
9048 	    v = (*cur - '0');
9049 	    fraction = fraction * 10 + v;
9050 	    frac = frac + 1;
9051 	    cur++;
9052 	}
9053 	fraction /= pow(10.0, frac);
9054 	ret = ret + fraction;
9055 	while ((*cur >= '0') && (*cur <= '9'))
9056 	    cur++;
9057     }
9058     if ((*cur == 'e') || (*cur == 'E')) {
9059       cur++;
9060       if (*cur == '-') {
9061 	is_exponent_negative = 1;
9062 	cur++;
9063       } else if (*cur == '+') {
9064         cur++;
9065       }
9066       while ((*cur >= '0') && (*cur <= '9')) {
9067         if (exponent < 1000000)
9068 	  exponent = exponent * 10 + (*cur - '0');
9069 	cur++;
9070       }
9071     }
9072     while (IS_BLANK_CH(*cur)) cur++;
9073     if (*cur != 0) return(xmlXPathNAN);
9074     if (isneg) ret = -ret;
9075     if (is_exponent_negative) exponent = -exponent;
9076     ret *= pow(10.0, (double)exponent);
9077     return(ret);
9078 }
9079 
9080 /**
9081  * xmlXPathCompNumber:
9082  * @ctxt:  the XPath Parser context
9083  *
9084  *  [30]   Number ::=   Digits ('.' Digits?)?
9085  *                    | '.' Digits
9086  *  [31]   Digits ::=   [0-9]+
9087  *
9088  * Compile a Number, then push it on the stack
9089  *
9090  */
9091 static void
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)9092 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
9093 {
9094     double ret = 0.0;
9095     int ok = 0;
9096     int exponent = 0;
9097     int is_exponent_negative = 0;
9098     xmlXPathObjectPtr num;
9099 #ifdef __GNUC__
9100     unsigned long tmp = 0;
9101     double temp;
9102 #endif
9103 
9104     CHECK_ERROR;
9105     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
9106         XP_ERROR(XPATH_NUMBER_ERROR);
9107     }
9108 #ifdef __GNUC__
9109     /*
9110      * tmp/temp is a workaround against a gcc compiler bug
9111      * http://veillard.com/gcc.bug
9112      */
9113     ret = 0;
9114     while ((CUR >= '0') && (CUR <= '9')) {
9115 	ret = ret * 10;
9116 	tmp = (CUR - '0');
9117         ok = 1;
9118         NEXT;
9119 	temp = (double) tmp;
9120 	ret = ret + temp;
9121     }
9122 #else
9123     ret = 0;
9124     while ((CUR >= '0') && (CUR <= '9')) {
9125 	ret = ret * 10 + (CUR - '0');
9126 	ok = 1;
9127 	NEXT;
9128     }
9129 #endif
9130     if (CUR == '.') {
9131 	int v, frac = 0, max;
9132 	double fraction = 0;
9133 
9134         NEXT;
9135         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
9136             XP_ERROR(XPATH_NUMBER_ERROR);
9137         }
9138         while (CUR == '0') {
9139             frac = frac + 1;
9140             NEXT;
9141         }
9142         max = frac + MAX_FRAC;
9143         while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
9144 	    v = (CUR - '0');
9145 	    fraction = fraction * 10 + v;
9146 	    frac = frac + 1;
9147             NEXT;
9148         }
9149         fraction /= pow(10.0, frac);
9150         ret = ret + fraction;
9151         while ((CUR >= '0') && (CUR <= '9'))
9152             NEXT;
9153     }
9154     if ((CUR == 'e') || (CUR == 'E')) {
9155         NEXT;
9156         if (CUR == '-') {
9157             is_exponent_negative = 1;
9158             NEXT;
9159         } else if (CUR == '+') {
9160 	    NEXT;
9161 	}
9162         while ((CUR >= '0') && (CUR <= '9')) {
9163             if (exponent < 1000000)
9164                 exponent = exponent * 10 + (CUR - '0');
9165             NEXT;
9166         }
9167         if (is_exponent_negative)
9168             exponent = -exponent;
9169         ret *= pow(10.0, (double) exponent);
9170     }
9171     num = xmlXPathCacheNewFloat(ctxt, ret);
9172     if (num == NULL) {
9173 	ctxt->error = XPATH_MEMORY_ERROR;
9174     } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
9175                               NULL) == -1) {
9176         xmlXPathReleaseObject(ctxt->context, num);
9177     }
9178 }
9179 
9180 /**
9181  * xmlXPathParseLiteral:
9182  * @ctxt:  the XPath Parser context
9183  *
9184  * Parse a Literal
9185  *
9186  *  [29]   Literal ::=   '"' [^"]* '"'
9187  *                    | "'" [^']* "'"
9188  *
9189  * Returns the value found or NULL in case of error
9190  */
9191 static xmlChar *
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt)9192 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
9193     const xmlChar *q;
9194     xmlChar *ret = NULL;
9195     int quote;
9196 
9197     if (CUR == '"') {
9198         quote = '"';
9199     } else if (CUR == '\'') {
9200         quote = '\'';
9201     } else {
9202 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
9203     }
9204 
9205     NEXT;
9206     q = CUR_PTR;
9207     while (CUR != quote) {
9208         int ch;
9209         int len = 4;
9210 
9211         if (CUR == 0)
9212             XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
9213         ch = xmlGetUTF8Char(CUR_PTR, &len);
9214         if ((ch < 0) || (IS_CHAR(ch) == 0))
9215             XP_ERRORNULL(XPATH_INVALID_CHAR_ERROR);
9216         CUR_PTR += len;
9217     }
9218     ret = xmlStrndup(q, CUR_PTR - q);
9219     if (ret == NULL)
9220         xmlXPathPErrMemory(ctxt);
9221     NEXT;
9222     return(ret);
9223 }
9224 
9225 /**
9226  * xmlXPathCompLiteral:
9227  * @ctxt:  the XPath Parser context
9228  *
9229  * Parse a Literal and push it on the stack.
9230  *
9231  *  [29]   Literal ::=   '"' [^"]* '"'
9232  *                    | "'" [^']* "'"
9233  *
9234  * TODO: xmlXPathCompLiteral memory allocation could be improved.
9235  */
9236 static void
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt)9237 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
9238     xmlChar *ret = NULL;
9239     xmlXPathObjectPtr lit;
9240 
9241     ret = xmlXPathParseLiteral(ctxt);
9242     if (ret == NULL)
9243         return;
9244     lit = xmlXPathCacheNewString(ctxt, ret);
9245     if (lit == NULL) {
9246         ctxt->error = XPATH_MEMORY_ERROR;
9247     } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
9248                               NULL) == -1) {
9249         xmlXPathReleaseObject(ctxt->context, lit);
9250     }
9251     xmlFree(ret);
9252 }
9253 
9254 /**
9255  * xmlXPathCompVariableReference:
9256  * @ctxt:  the XPath Parser context
9257  *
9258  * Parse a VariableReference, evaluate it and push it on the stack.
9259  *
9260  * The variable bindings consist of a mapping from variable names
9261  * to variable values. The value of a variable is an object, which can be
9262  * of any of the types that are possible for the value of an expression,
9263  * and may also be of additional types not specified here.
9264  *
9265  * Early evaluation is possible since:
9266  * The variable bindings [...] used to evaluate a subexpression are
9267  * always the same as those used to evaluate the containing expression.
9268  *
9269  *  [36]   VariableReference ::=   '$' QName
9270  */
9271 static void
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt)9272 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
9273     xmlChar *name;
9274     xmlChar *prefix;
9275 
9276     SKIP_BLANKS;
9277     if (CUR != '$') {
9278 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9279     }
9280     NEXT;
9281     name = xmlXPathParseQName(ctxt, &prefix);
9282     if (name == NULL) {
9283         xmlFree(prefix);
9284 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9285     }
9286     ctxt->comp->last = -1;
9287     if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
9288         xmlFree(prefix);
9289         xmlFree(name);
9290     }
9291     SKIP_BLANKS;
9292     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
9293 	XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
9294     }
9295 }
9296 
9297 /**
9298  * xmlXPathIsNodeType:
9299  * @name:  a name string
9300  *
9301  * Is the name given a NodeType one.
9302  *
9303  *  [38]   NodeType ::=   'comment'
9304  *                    | 'text'
9305  *                    | 'processing-instruction'
9306  *                    | 'node'
9307  *
9308  * Returns 1 if true 0 otherwise
9309  */
9310 int
xmlXPathIsNodeType(const xmlChar * name)9311 xmlXPathIsNodeType(const xmlChar *name) {
9312     if (name == NULL)
9313 	return(0);
9314 
9315     if (xmlStrEqual(name, BAD_CAST "node"))
9316 	return(1);
9317     if (xmlStrEqual(name, BAD_CAST "text"))
9318 	return(1);
9319     if (xmlStrEqual(name, BAD_CAST "comment"))
9320 	return(1);
9321     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9322 	return(1);
9323     return(0);
9324 }
9325 
9326 /**
9327  * xmlXPathCompFunctionCall:
9328  * @ctxt:  the XPath Parser context
9329  *
9330  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
9331  *  [17]   Argument ::=   Expr
9332  *
9333  * Compile a function call, the evaluation of all arguments are
9334  * pushed on the stack
9335  */
9336 static void
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt)9337 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
9338     xmlChar *name;
9339     xmlChar *prefix;
9340     int nbargs = 0;
9341     int sort = 1;
9342 
9343     name = xmlXPathParseQName(ctxt, &prefix);
9344     if (name == NULL) {
9345 	xmlFree(prefix);
9346 	XP_ERROR(XPATH_EXPR_ERROR);
9347     }
9348     SKIP_BLANKS;
9349 
9350     if (CUR != '(') {
9351 	xmlFree(name);
9352 	xmlFree(prefix);
9353 	XP_ERROR(XPATH_EXPR_ERROR);
9354     }
9355     NEXT;
9356     SKIP_BLANKS;
9357 
9358     /*
9359     * Optimization for count(): we don't need the node-set to be sorted.
9360     */
9361     if ((prefix == NULL) && (name[0] == 'c') &&
9362 	xmlStrEqual(name, BAD_CAST "count"))
9363     {
9364 	sort = 0;
9365     }
9366     ctxt->comp->last = -1;
9367     if (CUR != ')') {
9368 	while (CUR != 0) {
9369 	    int op1 = ctxt->comp->last;
9370 	    ctxt->comp->last = -1;
9371 	    xmlXPathCompileExpr(ctxt, sort);
9372 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
9373 		xmlFree(name);
9374 		xmlFree(prefix);
9375 		return;
9376 	    }
9377 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
9378 	    nbargs++;
9379 	    if (CUR == ')') break;
9380 	    if (CUR != ',') {
9381 		xmlFree(name);
9382 		xmlFree(prefix);
9383 		XP_ERROR(XPATH_EXPR_ERROR);
9384 	    }
9385 	    NEXT;
9386 	    SKIP_BLANKS;
9387 	}
9388     }
9389     if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
9390         xmlFree(prefix);
9391         xmlFree(name);
9392     }
9393     NEXT;
9394     SKIP_BLANKS;
9395 }
9396 
9397 /**
9398  * xmlXPathCompPrimaryExpr:
9399  * @ctxt:  the XPath Parser context
9400  *
9401  *  [15]   PrimaryExpr ::=   VariableReference
9402  *                | '(' Expr ')'
9403  *                | Literal
9404  *                | Number
9405  *                | FunctionCall
9406  *
9407  * Compile a primary expression.
9408  */
9409 static void
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt)9410 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
9411     SKIP_BLANKS;
9412     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
9413     else if (CUR == '(') {
9414 	NEXT;
9415 	SKIP_BLANKS;
9416 	xmlXPathCompileExpr(ctxt, 1);
9417 	CHECK_ERROR;
9418 	if (CUR != ')') {
9419 	    XP_ERROR(XPATH_EXPR_ERROR);
9420 	}
9421 	NEXT;
9422 	SKIP_BLANKS;
9423     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9424 	xmlXPathCompNumber(ctxt);
9425     } else if ((CUR == '\'') || (CUR == '"')) {
9426 	xmlXPathCompLiteral(ctxt);
9427     } else {
9428 	xmlXPathCompFunctionCall(ctxt);
9429     }
9430     SKIP_BLANKS;
9431 }
9432 
9433 /**
9434  * xmlXPathCompFilterExpr:
9435  * @ctxt:  the XPath Parser context
9436  *
9437  *  [20]   FilterExpr ::=   PrimaryExpr
9438  *               | FilterExpr Predicate
9439  *
9440  * Compile a filter expression.
9441  * Square brackets are used to filter expressions in the same way that
9442  * they are used in location paths. It is an error if the expression to
9443  * be filtered does not evaluate to a node-set. The context node list
9444  * used for evaluating the expression in square brackets is the node-set
9445  * to be filtered listed in document order.
9446  */
9447 
9448 static void
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt)9449 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
9450     xmlXPathCompPrimaryExpr(ctxt);
9451     CHECK_ERROR;
9452     SKIP_BLANKS;
9453 
9454     while (CUR == '[') {
9455 	xmlXPathCompPredicate(ctxt, 1);
9456 	SKIP_BLANKS;
9457     }
9458 
9459 
9460 }
9461 
9462 /**
9463  * xmlXPathScanName:
9464  * @ctxt:  the XPath Parser context
9465  *
9466  * Trickery: parse an XML name but without consuming the input flow
9467  * Needed to avoid insanity in the parser state.
9468  *
9469  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9470  *                  CombiningChar | Extender
9471  *
9472  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9473  *
9474  * [6] Names ::= Name (S Name)*
9475  *
9476  * Returns the Name parsed or NULL
9477  */
9478 
9479 static xmlChar *
xmlXPathScanName(xmlXPathParserContextPtr ctxt)9480 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
9481     int l;
9482     int c;
9483     const xmlChar *cur;
9484     xmlChar *ret;
9485 
9486     cur = ctxt->cur;
9487 
9488     c = CUR_CHAR(l);
9489     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9490 	(!IS_LETTER(c) && (c != '_') &&
9491          (c != ':'))) {
9492 	return(NULL);
9493     }
9494 
9495     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9496 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9497             (c == '.') || (c == '-') ||
9498 	    (c == '_') || (c == ':') ||
9499 	    (IS_COMBINING(c)) ||
9500 	    (IS_EXTENDER(c)))) {
9501 	NEXTL(l);
9502 	c = CUR_CHAR(l);
9503     }
9504     ret = xmlStrndup(cur, ctxt->cur - cur);
9505     if (ret == NULL)
9506         xmlXPathPErrMemory(ctxt);
9507     ctxt->cur = cur;
9508     return(ret);
9509 }
9510 
9511 /**
9512  * xmlXPathCompPathExpr:
9513  * @ctxt:  the XPath Parser context
9514  *
9515  *  [19]   PathExpr ::=   LocationPath
9516  *               | FilterExpr
9517  *               | FilterExpr '/' RelativeLocationPath
9518  *               | FilterExpr '//' RelativeLocationPath
9519  *
9520  * Compile a path expression.
9521  * The / operator and // operators combine an arbitrary expression
9522  * and a relative location path. It is an error if the expression
9523  * does not evaluate to a node-set.
9524  * The / operator does composition in the same way as when / is
9525  * used in a location path. As in location paths, // is short for
9526  * /descendant-or-self::node()/.
9527  */
9528 
9529 static void
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt)9530 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
9531     int lc = 1;           /* Should we branch to LocationPath ?         */
9532     xmlChar *name = NULL; /* we may have to preparse a name to find out */
9533 
9534     SKIP_BLANKS;
9535     if ((CUR == '$') || (CUR == '(') ||
9536 	(IS_ASCII_DIGIT(CUR)) ||
9537         (CUR == '\'') || (CUR == '"') ||
9538 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9539 	lc = 0;
9540     } else if (CUR == '*') {
9541 	/* relative or absolute location path */
9542 	lc = 1;
9543     } else if (CUR == '/') {
9544 	/* relative or absolute location path */
9545 	lc = 1;
9546     } else if (CUR == '@') {
9547 	/* relative abbreviated attribute location path */
9548 	lc = 1;
9549     } else if (CUR == '.') {
9550 	/* relative abbreviated attribute location path */
9551 	lc = 1;
9552     } else {
9553 	/*
9554 	 * Problem is finding if we have a name here whether it's:
9555 	 *   - a nodetype
9556 	 *   - a function call in which case it's followed by '('
9557 	 *   - an axis in which case it's followed by ':'
9558 	 *   - a element name
9559 	 * We do an a priori analysis here rather than having to
9560 	 * maintain parsed token content through the recursive function
9561 	 * calls. This looks uglier but makes the code easier to
9562 	 * read/write/debug.
9563 	 */
9564 	SKIP_BLANKS;
9565 	name = xmlXPathScanName(ctxt);
9566 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
9567 	    lc = 1;
9568 	    xmlFree(name);
9569 	} else if (name != NULL) {
9570 	    int len =xmlStrlen(name);
9571 
9572 
9573 	    while (NXT(len) != 0) {
9574 		if (NXT(len) == '/') {
9575 		    /* element name */
9576 		    lc = 1;
9577 		    break;
9578 		} else if (IS_BLANK_CH(NXT(len))) {
9579 		    /* ignore blanks */
9580 		    ;
9581 		} else if (NXT(len) == ':') {
9582 		    lc = 1;
9583 		    break;
9584 		} else if ((NXT(len) == '(')) {
9585 		    /* Node Type or Function */
9586 		    if (xmlXPathIsNodeType(name)) {
9587 			lc = 1;
9588 #ifdef LIBXML_XPTR_LOCS_ENABLED
9589                     } else if (ctxt->xptr &&
9590                                xmlStrEqual(name, BAD_CAST "range-to")) {
9591                         lc = 1;
9592 #endif
9593 		    } else {
9594 			lc = 0;
9595 		    }
9596                     break;
9597 		} else if ((NXT(len) == '[')) {
9598 		    /* element name */
9599 		    lc = 1;
9600 		    break;
9601 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
9602 			   (NXT(len) == '=')) {
9603 		    lc = 1;
9604 		    break;
9605 		} else {
9606 		    lc = 1;
9607 		    break;
9608 		}
9609 		len++;
9610 	    }
9611 	    if (NXT(len) == 0) {
9612 		/* element name */
9613 		lc = 1;
9614 	    }
9615 	    xmlFree(name);
9616 	} else {
9617 	    /* make sure all cases are covered explicitly */
9618 	    XP_ERROR(XPATH_EXPR_ERROR);
9619 	}
9620     }
9621 
9622     if (lc) {
9623 	if (CUR == '/') {
9624 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
9625 	} else {
9626 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9627 	}
9628 	xmlXPathCompLocationPath(ctxt);
9629     } else {
9630 	xmlXPathCompFilterExpr(ctxt);
9631 	CHECK_ERROR;
9632 	if ((CUR == '/') && (NXT(1) == '/')) {
9633 	    SKIP(2);
9634 	    SKIP_BLANKS;
9635 
9636 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9637 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9638 
9639 	    xmlXPathCompRelativeLocationPath(ctxt);
9640 	} else if (CUR == '/') {
9641 	    xmlXPathCompRelativeLocationPath(ctxt);
9642 	}
9643     }
9644     SKIP_BLANKS;
9645 }
9646 
9647 /**
9648  * xmlXPathCompUnionExpr:
9649  * @ctxt:  the XPath Parser context
9650  *
9651  *  [18]   UnionExpr ::=   PathExpr
9652  *               | UnionExpr '|' PathExpr
9653  *
9654  * Compile an union expression.
9655  */
9656 
9657 static void
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt)9658 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
9659     xmlXPathCompPathExpr(ctxt);
9660     CHECK_ERROR;
9661     SKIP_BLANKS;
9662     while (CUR == '|') {
9663 	int op1 = ctxt->comp->last;
9664 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9665 
9666 	NEXT;
9667 	SKIP_BLANKS;
9668 	xmlXPathCompPathExpr(ctxt);
9669 
9670 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
9671 
9672 	SKIP_BLANKS;
9673     }
9674 }
9675 
9676 /**
9677  * xmlXPathCompUnaryExpr:
9678  * @ctxt:  the XPath Parser context
9679  *
9680  *  [27]   UnaryExpr ::=   UnionExpr
9681  *                   | '-' UnaryExpr
9682  *
9683  * Compile an unary expression.
9684  */
9685 
9686 static void
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt)9687 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
9688     int minus = 0;
9689     int found = 0;
9690 
9691     SKIP_BLANKS;
9692     while (CUR == '-') {
9693         minus = 1 - minus;
9694 	found = 1;
9695 	NEXT;
9696 	SKIP_BLANKS;
9697     }
9698 
9699     xmlXPathCompUnionExpr(ctxt);
9700     CHECK_ERROR;
9701     if (found) {
9702 	if (minus)
9703 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
9704 	else
9705 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
9706     }
9707 }
9708 
9709 /**
9710  * xmlXPathCompMultiplicativeExpr:
9711  * @ctxt:  the XPath Parser context
9712  *
9713  *  [26]   MultiplicativeExpr ::=   UnaryExpr
9714  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
9715  *                   | MultiplicativeExpr 'div' UnaryExpr
9716  *                   | MultiplicativeExpr 'mod' UnaryExpr
9717  *  [34]   MultiplyOperator ::=   '*'
9718  *
9719  * Compile an Additive expression.
9720  */
9721 
9722 static void
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt)9723 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
9724     xmlXPathCompUnaryExpr(ctxt);
9725     CHECK_ERROR;
9726     SKIP_BLANKS;
9727     while ((CUR == '*') ||
9728            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
9729            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
9730 	int op = -1;
9731 	int op1 = ctxt->comp->last;
9732 
9733         if (CUR == '*') {
9734 	    op = 0;
9735 	    NEXT;
9736 	} else if (CUR == 'd') {
9737 	    op = 1;
9738 	    SKIP(3);
9739 	} else if (CUR == 'm') {
9740 	    op = 2;
9741 	    SKIP(3);
9742 	}
9743 	SKIP_BLANKS;
9744         xmlXPathCompUnaryExpr(ctxt);
9745 	CHECK_ERROR;
9746 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
9747 	SKIP_BLANKS;
9748     }
9749 }
9750 
9751 /**
9752  * xmlXPathCompAdditiveExpr:
9753  * @ctxt:  the XPath Parser context
9754  *
9755  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
9756  *                   | AdditiveExpr '+' MultiplicativeExpr
9757  *                   | AdditiveExpr '-' MultiplicativeExpr
9758  *
9759  * Compile an Additive expression.
9760  */
9761 
9762 static void
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt)9763 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
9764 
9765     xmlXPathCompMultiplicativeExpr(ctxt);
9766     CHECK_ERROR;
9767     SKIP_BLANKS;
9768     while ((CUR == '+') || (CUR == '-')) {
9769 	int plus;
9770 	int op1 = ctxt->comp->last;
9771 
9772         if (CUR == '+') plus = 1;
9773 	else plus = 0;
9774 	NEXT;
9775 	SKIP_BLANKS;
9776         xmlXPathCompMultiplicativeExpr(ctxt);
9777 	CHECK_ERROR;
9778 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
9779 	SKIP_BLANKS;
9780     }
9781 }
9782 
9783 /**
9784  * xmlXPathCompRelationalExpr:
9785  * @ctxt:  the XPath Parser context
9786  *
9787  *  [24]   RelationalExpr ::=   AdditiveExpr
9788  *                 | RelationalExpr '<' AdditiveExpr
9789  *                 | RelationalExpr '>' AdditiveExpr
9790  *                 | RelationalExpr '<=' AdditiveExpr
9791  *                 | RelationalExpr '>=' AdditiveExpr
9792  *
9793  *  A <= B > C is allowed ? Answer from James, yes with
9794  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
9795  *  which is basically what got implemented.
9796  *
9797  * Compile a Relational expression, then push the result
9798  * on the stack
9799  */
9800 
9801 static void
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt)9802 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
9803     xmlXPathCompAdditiveExpr(ctxt);
9804     CHECK_ERROR;
9805     SKIP_BLANKS;
9806     while ((CUR == '<') || (CUR == '>')) {
9807 	int inf, strict;
9808 	int op1 = ctxt->comp->last;
9809 
9810         if (CUR == '<') inf = 1;
9811 	else inf = 0;
9812 	if (NXT(1) == '=') strict = 0;
9813 	else strict = 1;
9814 	NEXT;
9815 	if (!strict) NEXT;
9816 	SKIP_BLANKS;
9817         xmlXPathCompAdditiveExpr(ctxt);
9818 	CHECK_ERROR;
9819 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
9820 	SKIP_BLANKS;
9821     }
9822 }
9823 
9824 /**
9825  * xmlXPathCompEqualityExpr:
9826  * @ctxt:  the XPath Parser context
9827  *
9828  *  [23]   EqualityExpr ::=   RelationalExpr
9829  *                 | EqualityExpr '=' RelationalExpr
9830  *                 | EqualityExpr '!=' RelationalExpr
9831  *
9832  *  A != B != C is allowed ? Answer from James, yes with
9833  *  (RelationalExpr = RelationalExpr) = RelationalExpr
9834  *  (RelationalExpr != RelationalExpr) != RelationalExpr
9835  *  which is basically what got implemented.
9836  *
9837  * Compile an Equality expression.
9838  *
9839  */
9840 static void
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt)9841 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
9842     xmlXPathCompRelationalExpr(ctxt);
9843     CHECK_ERROR;
9844     SKIP_BLANKS;
9845     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
9846 	int eq;
9847 	int op1 = ctxt->comp->last;
9848 
9849         if (CUR == '=') eq = 1;
9850 	else eq = 0;
9851 	NEXT;
9852 	if (!eq) NEXT;
9853 	SKIP_BLANKS;
9854         xmlXPathCompRelationalExpr(ctxt);
9855 	CHECK_ERROR;
9856 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
9857 	SKIP_BLANKS;
9858     }
9859 }
9860 
9861 /**
9862  * xmlXPathCompAndExpr:
9863  * @ctxt:  the XPath Parser context
9864  *
9865  *  [22]   AndExpr ::=   EqualityExpr
9866  *                 | AndExpr 'and' EqualityExpr
9867  *
9868  * Compile an AND expression.
9869  *
9870  */
9871 static void
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt)9872 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
9873     xmlXPathCompEqualityExpr(ctxt);
9874     CHECK_ERROR;
9875     SKIP_BLANKS;
9876     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
9877 	int op1 = ctxt->comp->last;
9878         SKIP(3);
9879 	SKIP_BLANKS;
9880         xmlXPathCompEqualityExpr(ctxt);
9881 	CHECK_ERROR;
9882 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
9883 	SKIP_BLANKS;
9884     }
9885 }
9886 
9887 /**
9888  * xmlXPathCompileExpr:
9889  * @ctxt:  the XPath Parser context
9890  *
9891  *  [14]   Expr ::=   OrExpr
9892  *  [21]   OrExpr ::=   AndExpr
9893  *                 | OrExpr 'or' AndExpr
9894  *
9895  * Parse and compile an expression
9896  */
9897 static void
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt,int sort)9898 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
9899     xmlXPathContextPtr xpctxt = ctxt->context;
9900 
9901     if (xpctxt != NULL) {
9902         if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
9903             XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9904         /*
9905          * Parsing a single '(' pushes about 10 functions on the call stack
9906          * before recursing!
9907          */
9908         xpctxt->depth += 10;
9909     }
9910 
9911     xmlXPathCompAndExpr(ctxt);
9912     CHECK_ERROR;
9913     SKIP_BLANKS;
9914     while ((CUR == 'o') && (NXT(1) == 'r')) {
9915 	int op1 = ctxt->comp->last;
9916         SKIP(2);
9917 	SKIP_BLANKS;
9918         xmlXPathCompAndExpr(ctxt);
9919 	CHECK_ERROR;
9920 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
9921 	SKIP_BLANKS;
9922     }
9923     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
9924 	/* more ops could be optimized too */
9925 	/*
9926 	* This is the main place to eliminate sorting for
9927 	* operations which don't require a sorted node-set.
9928 	* E.g. count().
9929 	*/
9930 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
9931     }
9932 
9933     if (xpctxt != NULL)
9934         xpctxt->depth -= 10;
9935 }
9936 
9937 /**
9938  * xmlXPathCompPredicate:
9939  * @ctxt:  the XPath Parser context
9940  * @filter:  act as a filter
9941  *
9942  *  [8]   Predicate ::=   '[' PredicateExpr ']'
9943  *  [9]   PredicateExpr ::=   Expr
9944  *
9945  * Compile a predicate expression
9946  */
9947 static void
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt,int filter)9948 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
9949     int op1 = ctxt->comp->last;
9950 
9951     SKIP_BLANKS;
9952     if (CUR != '[') {
9953 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9954     }
9955     NEXT;
9956     SKIP_BLANKS;
9957 
9958     ctxt->comp->last = -1;
9959     /*
9960     * This call to xmlXPathCompileExpr() will deactivate sorting
9961     * of the predicate result.
9962     * TODO: Sorting is still activated for filters, since I'm not
9963     *  sure if needed. Normally sorting should not be needed, since
9964     *  a filter can only diminish the number of items in a sequence,
9965     *  but won't change its order; so if the initial sequence is sorted,
9966     *  subsequent sorting is not needed.
9967     */
9968     if (! filter)
9969 	xmlXPathCompileExpr(ctxt, 0);
9970     else
9971 	xmlXPathCompileExpr(ctxt, 1);
9972     CHECK_ERROR;
9973 
9974     if (CUR != ']') {
9975 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9976     }
9977 
9978     if (filter)
9979 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
9980     else
9981 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
9982 
9983     NEXT;
9984     SKIP_BLANKS;
9985 }
9986 
9987 /**
9988  * xmlXPathCompNodeTest:
9989  * @ctxt:  the XPath Parser context
9990  * @test:  pointer to a xmlXPathTestVal
9991  * @type:  pointer to a xmlXPathTypeVal
9992  * @prefix:  placeholder for a possible name prefix
9993  *
9994  * [7] NodeTest ::=   NameTest
9995  *		    | NodeType '(' ')'
9996  *		    | 'processing-instruction' '(' Literal ')'
9997  *
9998  * [37] NameTest ::=  '*'
9999  *		    | NCName ':' '*'
10000  *		    | QName
10001  * [38] NodeType ::= 'comment'
10002  *		   | 'text'
10003  *		   | 'processing-instruction'
10004  *		   | 'node'
10005  *
10006  * Returns the name found and updates @test, @type and @prefix appropriately
10007  */
10008 static xmlChar *
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt,xmlXPathTestVal * test,xmlXPathTypeVal * type,xmlChar ** prefix,xmlChar * name)10009 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10010 	             xmlXPathTypeVal *type, xmlChar **prefix,
10011 		     xmlChar *name) {
10012     int blanks;
10013 
10014     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10015 	return(NULL);
10016     }
10017     *type = (xmlXPathTypeVal) 0;
10018     *test = (xmlXPathTestVal) 0;
10019     *prefix = NULL;
10020     SKIP_BLANKS;
10021 
10022     if ((name == NULL) && (CUR == '*')) {
10023 	/*
10024 	 * All elements
10025 	 */
10026 	NEXT;
10027 	*test = NODE_TEST_ALL;
10028 	return(NULL);
10029     }
10030 
10031     if (name == NULL)
10032 	name = xmlXPathParseNCName(ctxt);
10033     if (name == NULL) {
10034 	XP_ERRORNULL(XPATH_EXPR_ERROR);
10035     }
10036 
10037     blanks = IS_BLANK_CH(CUR);
10038     SKIP_BLANKS;
10039     if (CUR == '(') {
10040 	NEXT;
10041 	/*
10042 	 * NodeType or PI search
10043 	 */
10044 	if (xmlStrEqual(name, BAD_CAST "comment"))
10045 	    *type = NODE_TYPE_COMMENT;
10046 	else if (xmlStrEqual(name, BAD_CAST "node"))
10047 	    *type = NODE_TYPE_NODE;
10048 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10049 	    *type = NODE_TYPE_PI;
10050 	else if (xmlStrEqual(name, BAD_CAST "text"))
10051 	    *type = NODE_TYPE_TEXT;
10052 	else {
10053 	    if (name != NULL)
10054 		xmlFree(name);
10055 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
10056 	}
10057 
10058 	*test = NODE_TEST_TYPE;
10059 
10060 	SKIP_BLANKS;
10061 	if (*type == NODE_TYPE_PI) {
10062 	    /*
10063 	     * Specific case: search a PI by name.
10064 	     */
10065 	    if (name != NULL)
10066 		xmlFree(name);
10067 	    name = NULL;
10068 	    if (CUR != ')') {
10069 		name = xmlXPathParseLiteral(ctxt);
10070 		*test = NODE_TEST_PI;
10071 		SKIP_BLANKS;
10072 	    }
10073 	}
10074 	if (CUR != ')') {
10075 	    if (name != NULL)
10076 		xmlFree(name);
10077 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
10078 	}
10079 	NEXT;
10080 	return(name);
10081     }
10082     *test = NODE_TEST_NAME;
10083     if ((!blanks) && (CUR == ':')) {
10084 	NEXT;
10085 
10086 	/*
10087 	 * Since currently the parser context don't have a
10088 	 * namespace list associated:
10089 	 * The namespace name for this prefix can be computed
10090 	 * only at evaluation time. The compilation is done
10091 	 * outside of any context.
10092 	 */
10093 #if 0
10094 	*prefix = xmlXPathNsLookup(ctxt->context, name);
10095 	if (name != NULL)
10096 	    xmlFree(name);
10097 	if (*prefix == NULL) {
10098 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10099 	}
10100 #else
10101 	*prefix = name;
10102 #endif
10103 
10104 	if (CUR == '*') {
10105 	    /*
10106 	     * All elements
10107 	     */
10108 	    NEXT;
10109 	    *test = NODE_TEST_ALL;
10110 	    return(NULL);
10111 	}
10112 
10113 	name = xmlXPathParseNCName(ctxt);
10114 	if (name == NULL) {
10115 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
10116 	}
10117     }
10118     return(name);
10119 }
10120 
10121 /**
10122  * xmlXPathIsAxisName:
10123  * @name:  a preparsed name token
10124  *
10125  * [6] AxisName ::=   'ancestor'
10126  *                  | 'ancestor-or-self'
10127  *                  | 'attribute'
10128  *                  | 'child'
10129  *                  | 'descendant'
10130  *                  | 'descendant-or-self'
10131  *                  | 'following'
10132  *                  | 'following-sibling'
10133  *                  | 'namespace'
10134  *                  | 'parent'
10135  *                  | 'preceding'
10136  *                  | 'preceding-sibling'
10137  *                  | 'self'
10138  *
10139  * Returns the axis or 0
10140  */
10141 static xmlXPathAxisVal
xmlXPathIsAxisName(const xmlChar * name)10142 xmlXPathIsAxisName(const xmlChar *name) {
10143     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
10144     switch (name[0]) {
10145 	case 'a':
10146 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
10147 		ret = AXIS_ANCESTOR;
10148 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
10149 		ret = AXIS_ANCESTOR_OR_SELF;
10150 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
10151 		ret = AXIS_ATTRIBUTE;
10152 	    break;
10153 	case 'c':
10154 	    if (xmlStrEqual(name, BAD_CAST "child"))
10155 		ret = AXIS_CHILD;
10156 	    break;
10157 	case 'd':
10158 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
10159 		ret = AXIS_DESCENDANT;
10160 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
10161 		ret = AXIS_DESCENDANT_OR_SELF;
10162 	    break;
10163 	case 'f':
10164 	    if (xmlStrEqual(name, BAD_CAST "following"))
10165 		ret = AXIS_FOLLOWING;
10166 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
10167 		ret = AXIS_FOLLOWING_SIBLING;
10168 	    break;
10169 	case 'n':
10170 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
10171 		ret = AXIS_NAMESPACE;
10172 	    break;
10173 	case 'p':
10174 	    if (xmlStrEqual(name, BAD_CAST "parent"))
10175 		ret = AXIS_PARENT;
10176 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
10177 		ret = AXIS_PRECEDING;
10178 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
10179 		ret = AXIS_PRECEDING_SIBLING;
10180 	    break;
10181 	case 's':
10182 	    if (xmlStrEqual(name, BAD_CAST "self"))
10183 		ret = AXIS_SELF;
10184 	    break;
10185     }
10186     return(ret);
10187 }
10188 
10189 /**
10190  * xmlXPathCompStep:
10191  * @ctxt:  the XPath Parser context
10192  *
10193  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
10194  *                  | AbbreviatedStep
10195  *
10196  * [12] AbbreviatedStep ::=   '.' | '..'
10197  *
10198  * [5] AxisSpecifier ::= AxisName '::'
10199  *                  | AbbreviatedAxisSpecifier
10200  *
10201  * [13] AbbreviatedAxisSpecifier ::= '@'?
10202  *
10203  * Modified for XPtr range support as:
10204  *
10205  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
10206  *                     | AbbreviatedStep
10207  *                     | 'range-to' '(' Expr ')' Predicate*
10208  *
10209  * Compile one step in a Location Path
10210  * A location step of . is short for self::node(). This is
10211  * particularly useful in conjunction with //. For example, the
10212  * location path .//para is short for
10213  * self::node()/descendant-or-self::node()/child::para
10214  * and so will select all para descendant elements of the context
10215  * node.
10216  * Similarly, a location step of .. is short for parent::node().
10217  * For example, ../title is short for parent::node()/child::title
10218  * and so will select the title children of the parent of the context
10219  * node.
10220  */
10221 static void
xmlXPathCompStep(xmlXPathParserContextPtr ctxt)10222 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
10223 #ifdef LIBXML_XPTR_LOCS_ENABLED
10224     int rangeto = 0;
10225     int op2 = -1;
10226 #endif
10227 
10228     SKIP_BLANKS;
10229     if ((CUR == '.') && (NXT(1) == '.')) {
10230 	SKIP(2);
10231 	SKIP_BLANKS;
10232 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
10233 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10234     } else if (CUR == '.') {
10235 	NEXT;
10236 	SKIP_BLANKS;
10237     } else {
10238 	xmlChar *name = NULL;
10239 	xmlChar *prefix = NULL;
10240 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
10241 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
10242 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
10243 	int op1;
10244 
10245 	/*
10246 	 * The modification needed for XPointer change to the production
10247 	 */
10248 #ifdef LIBXML_XPTR_LOCS_ENABLED
10249 	if (ctxt->xptr) {
10250 	    name = xmlXPathParseNCName(ctxt);
10251 	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
10252                 op2 = ctxt->comp->last;
10253 		xmlFree(name);
10254 		SKIP_BLANKS;
10255 		if (CUR != '(') {
10256 		    XP_ERROR(XPATH_EXPR_ERROR);
10257 		}
10258 		NEXT;
10259 		SKIP_BLANKS;
10260 
10261 		xmlXPathCompileExpr(ctxt, 1);
10262 		/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
10263 		CHECK_ERROR;
10264 
10265 		SKIP_BLANKS;
10266 		if (CUR != ')') {
10267 		    XP_ERROR(XPATH_EXPR_ERROR);
10268 		}
10269 		NEXT;
10270 		rangeto = 1;
10271 		goto eval_predicates;
10272 	    }
10273 	}
10274 #endif
10275 	if (CUR == '*') {
10276 	    axis = AXIS_CHILD;
10277 	} else {
10278 	    if (name == NULL)
10279 		name = xmlXPathParseNCName(ctxt);
10280 	    if (name != NULL) {
10281 		axis = xmlXPathIsAxisName(name);
10282 		if (axis != 0) {
10283 		    SKIP_BLANKS;
10284 		    if ((CUR == ':') && (NXT(1) == ':')) {
10285 			SKIP(2);
10286 			xmlFree(name);
10287 			name = NULL;
10288 		    } else {
10289 			/* an element name can conflict with an axis one :-\ */
10290 			axis = AXIS_CHILD;
10291 		    }
10292 		} else {
10293 		    axis = AXIS_CHILD;
10294 		}
10295 	    } else if (CUR == '@') {
10296 		NEXT;
10297 		axis = AXIS_ATTRIBUTE;
10298 	    } else {
10299 		axis = AXIS_CHILD;
10300 	    }
10301 	}
10302 
10303         if (ctxt->error != XPATH_EXPRESSION_OK) {
10304             xmlFree(name);
10305             return;
10306         }
10307 
10308 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
10309 	if (test == 0)
10310 	    return;
10311 
10312         if ((prefix != NULL) && (ctxt->context != NULL) &&
10313 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
10314 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
10315 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
10316 	    }
10317 	}
10318 
10319 #ifdef LIBXML_XPTR_LOCS_ENABLED
10320 eval_predicates:
10321 #endif
10322 	op1 = ctxt->comp->last;
10323 	ctxt->comp->last = -1;
10324 
10325 	SKIP_BLANKS;
10326 	while (CUR == '[') {
10327 	    xmlXPathCompPredicate(ctxt, 0);
10328 	}
10329 
10330 #ifdef LIBXML_XPTR_LOCS_ENABLED
10331 	if (rangeto) {
10332 	    PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
10333 	} else
10334 #endif
10335         if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
10336                            test, type, (void *)prefix, (void *)name) == -1) {
10337             xmlFree(prefix);
10338             xmlFree(name);
10339         }
10340     }
10341 }
10342 
10343 /**
10344  * xmlXPathCompRelativeLocationPath:
10345  * @ctxt:  the XPath Parser context
10346  *
10347  *  [3]   RelativeLocationPath ::=   Step
10348  *                     | RelativeLocationPath '/' Step
10349  *                     | AbbreviatedRelativeLocationPath
10350  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
10351  *
10352  * Compile a relative location path.
10353  */
10354 static void
xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt)10355 xmlXPathCompRelativeLocationPath
10356 (xmlXPathParserContextPtr ctxt) {
10357     SKIP_BLANKS;
10358     if ((CUR == '/') && (NXT(1) == '/')) {
10359 	SKIP(2);
10360 	SKIP_BLANKS;
10361 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10362 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10363     } else if (CUR == '/') {
10364 	    NEXT;
10365 	SKIP_BLANKS;
10366     }
10367     xmlXPathCompStep(ctxt);
10368     CHECK_ERROR;
10369     SKIP_BLANKS;
10370     while (CUR == '/') {
10371 	if ((CUR == '/') && (NXT(1) == '/')) {
10372 	    SKIP(2);
10373 	    SKIP_BLANKS;
10374 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10375 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10376 	    xmlXPathCompStep(ctxt);
10377 	} else if (CUR == '/') {
10378 	    NEXT;
10379 	    SKIP_BLANKS;
10380 	    xmlXPathCompStep(ctxt);
10381 	}
10382 	SKIP_BLANKS;
10383     }
10384 }
10385 
10386 /**
10387  * xmlXPathCompLocationPath:
10388  * @ctxt:  the XPath Parser context
10389  *
10390  *  [1]   LocationPath ::=   RelativeLocationPath
10391  *                     | AbsoluteLocationPath
10392  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
10393  *                     | AbbreviatedAbsoluteLocationPath
10394  *  [10]   AbbreviatedAbsoluteLocationPath ::=
10395  *                           '//' RelativeLocationPath
10396  *
10397  * Compile a location path
10398  *
10399  * // is short for /descendant-or-self::node()/. For example,
10400  * //para is short for /descendant-or-self::node()/child::para and
10401  * so will select any para element in the document (even a para element
10402  * that is a document element will be selected by //para since the
10403  * document element node is a child of the root node); div//para is
10404  * short for div/descendant-or-self::node()/child::para and so will
10405  * select all para descendants of div children.
10406  */
10407 static void
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt)10408 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
10409     SKIP_BLANKS;
10410     if (CUR != '/') {
10411         xmlXPathCompRelativeLocationPath(ctxt);
10412     } else {
10413 	while (CUR == '/') {
10414 	    if ((CUR == '/') && (NXT(1) == '/')) {
10415 		SKIP(2);
10416 		SKIP_BLANKS;
10417 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10418 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10419 		xmlXPathCompRelativeLocationPath(ctxt);
10420 	    } else if (CUR == '/') {
10421 		NEXT;
10422 		SKIP_BLANKS;
10423 		if ((CUR != 0 ) &&
10424 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
10425 		     (CUR == '@') || (CUR == '*')))
10426 		    xmlXPathCompRelativeLocationPath(ctxt);
10427 	    }
10428 	    CHECK_ERROR;
10429 	}
10430     }
10431 }
10432 
10433 /************************************************************************
10434  *									*
10435  *		XPath precompiled expression evaluation			*
10436  *									*
10437  ************************************************************************/
10438 
10439 static int
10440 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
10441 
10442 /**
10443  * xmlXPathNodeSetFilter:
10444  * @ctxt:  the XPath Parser context
10445  * @set: the node set to filter
10446  * @filterOpIndex: the index of the predicate/filter op
10447  * @minPos: minimum position in the filtered set (1-based)
10448  * @maxPos: maximum position in the filtered set (1-based)
10449  * @hasNsNodes: true if the node set may contain namespace nodes
10450  *
10451  * Filter a node set, keeping only nodes for which the predicate expression
10452  * matches. Afterwards, keep only nodes between minPos and maxPos in the
10453  * filtered result.
10454  */
10455 static void
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,xmlNodeSetPtr set,int filterOpIndex,int minPos,int maxPos,int hasNsNodes)10456 xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
10457 		      xmlNodeSetPtr set,
10458 		      int filterOpIndex,
10459                       int minPos, int maxPos,
10460 		      int hasNsNodes)
10461 {
10462     xmlXPathContextPtr xpctxt;
10463     xmlNodePtr oldnode;
10464     xmlDocPtr olddoc;
10465     xmlXPathStepOpPtr filterOp;
10466     int oldcs, oldpp;
10467     int i, j, pos;
10468 
10469     if ((set == NULL) || (set->nodeNr == 0))
10470         return;
10471 
10472     /*
10473     * Check if the node set contains a sufficient number of nodes for
10474     * the requested range.
10475     */
10476     if (set->nodeNr < minPos) {
10477         xmlXPathNodeSetClear(set, hasNsNodes);
10478         return;
10479     }
10480 
10481     xpctxt = ctxt->context;
10482     oldnode = xpctxt->node;
10483     olddoc = xpctxt->doc;
10484     oldcs = xpctxt->contextSize;
10485     oldpp = xpctxt->proximityPosition;
10486     filterOp = &ctxt->comp->steps[filterOpIndex];
10487 
10488     xpctxt->contextSize = set->nodeNr;
10489 
10490     for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
10491         xmlNodePtr node = set->nodeTab[i];
10492         int res;
10493 
10494         xpctxt->node = node;
10495         xpctxt->proximityPosition = i + 1;
10496 
10497         /*
10498         * Also set the xpath document in case things like
10499         * key() are evaluated in the predicate.
10500         *
10501         * TODO: Get real doc for namespace nodes.
10502         */
10503         if ((node->type != XML_NAMESPACE_DECL) &&
10504             (node->doc != NULL))
10505             xpctxt->doc = node->doc;
10506 
10507         res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
10508 
10509         if (ctxt->error != XPATH_EXPRESSION_OK)
10510             break;
10511         if (res < 0) {
10512             /* Shouldn't happen */
10513             xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
10514             break;
10515         }
10516 
10517         if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
10518             if (i != j) {
10519                 set->nodeTab[j] = node;
10520                 set->nodeTab[i] = NULL;
10521             }
10522 
10523             j += 1;
10524         } else {
10525             /* Remove the entry from the initial node set. */
10526             set->nodeTab[i] = NULL;
10527             if (node->type == XML_NAMESPACE_DECL)
10528                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10529         }
10530 
10531         if (res != 0) {
10532             if (pos == maxPos) {
10533                 i += 1;
10534                 break;
10535             }
10536 
10537             pos += 1;
10538         }
10539     }
10540 
10541     /* Free remaining nodes. */
10542     if (hasNsNodes) {
10543         for (; i < set->nodeNr; i++) {
10544             xmlNodePtr node = set->nodeTab[i];
10545             if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
10546                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10547         }
10548     }
10549 
10550     set->nodeNr = j;
10551 
10552     /* If too many elements were removed, shrink table to preserve memory. */
10553     if ((set->nodeMax > XML_NODESET_DEFAULT) &&
10554         (set->nodeNr < set->nodeMax / 2)) {
10555         xmlNodePtr *tmp;
10556         int nodeMax = set->nodeNr;
10557 
10558         if (nodeMax < XML_NODESET_DEFAULT)
10559             nodeMax = XML_NODESET_DEFAULT;
10560         tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
10561                 nodeMax * sizeof(xmlNodePtr));
10562         if (tmp == NULL) {
10563             xmlXPathPErrMemory(ctxt);
10564         } else {
10565             set->nodeTab = tmp;
10566             set->nodeMax = nodeMax;
10567         }
10568     }
10569 
10570     xpctxt->node = oldnode;
10571     xpctxt->doc = olddoc;
10572     xpctxt->contextSize = oldcs;
10573     xpctxt->proximityPosition = oldpp;
10574 }
10575 
10576 #ifdef LIBXML_XPTR_LOCS_ENABLED
10577 /**
10578  * xmlXPathLocationSetFilter:
10579  * @ctxt:  the XPath Parser context
10580  * @locset: the location set to filter
10581  * @filterOpIndex: the index of the predicate/filter op
10582  * @minPos: minimum position in the filtered set (1-based)
10583  * @maxPos: maximum position in the filtered set (1-based)
10584  *
10585  * Filter a location set, keeping only nodes for which the predicate
10586  * expression matches. Afterwards, keep only nodes between minPos and maxPos
10587  * in the filtered result.
10588  */
10589 static void
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,xmlLocationSetPtr locset,int filterOpIndex,int minPos,int maxPos)10590 xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
10591 		          xmlLocationSetPtr locset,
10592 		          int filterOpIndex,
10593                           int minPos, int maxPos)
10594 {
10595     xmlXPathContextPtr xpctxt;
10596     xmlNodePtr oldnode;
10597     xmlDocPtr olddoc;
10598     xmlXPathStepOpPtr filterOp;
10599     int oldcs, oldpp;
10600     int i, j, pos;
10601 
10602     if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
10603         return;
10604 
10605     xpctxt = ctxt->context;
10606     oldnode = xpctxt->node;
10607     olddoc = xpctxt->doc;
10608     oldcs = xpctxt->contextSize;
10609     oldpp = xpctxt->proximityPosition;
10610     filterOp = &ctxt->comp->steps[filterOpIndex];
10611 
10612     xpctxt->contextSize = locset->locNr;
10613 
10614     for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
10615         xmlNodePtr contextNode = locset->locTab[i]->user;
10616         int res;
10617 
10618         xpctxt->node = contextNode;
10619         xpctxt->proximityPosition = i + 1;
10620 
10621         /*
10622         * Also set the xpath document in case things like
10623         * key() are evaluated in the predicate.
10624         *
10625         * TODO: Get real doc for namespace nodes.
10626         */
10627         if ((contextNode->type != XML_NAMESPACE_DECL) &&
10628             (contextNode->doc != NULL))
10629             xpctxt->doc = contextNode->doc;
10630 
10631         res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
10632 
10633         if (ctxt->error != XPATH_EXPRESSION_OK)
10634             break;
10635         if (res < 0) {
10636             /* Shouldn't happen */
10637             xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
10638             break;
10639         }
10640 
10641         if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
10642             if (i != j) {
10643                 locset->locTab[j] = locset->locTab[i];
10644                 locset->locTab[i] = NULL;
10645             }
10646 
10647             j += 1;
10648         } else {
10649             /* Remove the entry from the initial location set. */
10650             xmlXPathFreeObject(locset->locTab[i]);
10651             locset->locTab[i] = NULL;
10652         }
10653 
10654         if (res != 0) {
10655             if (pos == maxPos) {
10656                 i += 1;
10657                 break;
10658             }
10659 
10660             pos += 1;
10661         }
10662     }
10663 
10664     /* Free remaining nodes. */
10665     for (; i < locset->locNr; i++)
10666         xmlXPathFreeObject(locset->locTab[i]);
10667 
10668     locset->locNr = j;
10669 
10670     /* If too many elements were removed, shrink table to preserve memory. */
10671     if ((locset->locMax > XML_NODESET_DEFAULT) &&
10672         (locset->locNr < locset->locMax / 2)) {
10673         xmlXPathObjectPtr *tmp;
10674         int locMax = locset->locNr;
10675 
10676         if (locMax < XML_NODESET_DEFAULT)
10677             locMax = XML_NODESET_DEFAULT;
10678         tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
10679                 locMax * sizeof(xmlXPathObjectPtr));
10680         if (tmp == NULL) {
10681             xmlXPathPErrMemory(ctxt);
10682         } else {
10683             locset->locTab = tmp;
10684             locset->locMax = locMax;
10685         }
10686     }
10687 
10688     xpctxt->node = oldnode;
10689     xpctxt->doc = olddoc;
10690     xpctxt->contextSize = oldcs;
10691     xpctxt->proximityPosition = oldpp;
10692 }
10693 #endif /* LIBXML_XPTR_LOCS_ENABLED */
10694 
10695 /**
10696  * xmlXPathCompOpEvalPredicate:
10697  * @ctxt:  the XPath Parser context
10698  * @op: the predicate op
10699  * @set: the node set to filter
10700  * @minPos: minimum position in the filtered set (1-based)
10701  * @maxPos: maximum position in the filtered set (1-based)
10702  * @hasNsNodes: true if the node set may contain namespace nodes
10703  *
10704  * Filter a node set, keeping only nodes for which the sequence of predicate
10705  * expressions matches. Afterwards, keep only nodes between minPos and maxPos
10706  * in the filtered result.
10707  */
10708 static void
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int minPos,int maxPos,int hasNsNodes)10709 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
10710 			    xmlXPathStepOpPtr op,
10711 			    xmlNodeSetPtr set,
10712                             int minPos, int maxPos,
10713 			    int hasNsNodes)
10714 {
10715     if (op->ch1 != -1) {
10716 	xmlXPathCompExprPtr comp = ctxt->comp;
10717 	/*
10718 	* Process inner predicates first.
10719 	*/
10720 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
10721             XP_ERROR(XPATH_INVALID_OPERAND);
10722 	}
10723         if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10724             XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10725         ctxt->context->depth += 1;
10726 	xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
10727                                     1, set->nodeNr, hasNsNodes);
10728         ctxt->context->depth -= 1;
10729 	CHECK_ERROR;
10730     }
10731 
10732     if (op->ch2 != -1)
10733         xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
10734 }
10735 
10736 static int
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int * maxPos)10737 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
10738 			    xmlXPathStepOpPtr op,
10739 			    int *maxPos)
10740 {
10741 
10742     xmlXPathStepOpPtr exprOp;
10743 
10744     /*
10745     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
10746     */
10747 
10748     /*
10749     * If not -1, then ch1 will point to:
10750     * 1) For predicates (XPATH_OP_PREDICATE):
10751     *    - an inner predicate operator
10752     * 2) For filters (XPATH_OP_FILTER):
10753     *    - an inner filter operator OR
10754     *    - an expression selecting the node set.
10755     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
10756     */
10757     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
10758 	return(0);
10759 
10760     if (op->ch2 != -1) {
10761 	exprOp = &ctxt->comp->steps[op->ch2];
10762     } else
10763 	return(0);
10764 
10765     if ((exprOp != NULL) &&
10766 	(exprOp->op == XPATH_OP_VALUE) &&
10767 	(exprOp->value4 != NULL) &&
10768 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
10769     {
10770         double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
10771 
10772 	/*
10773 	* We have a "[n]" predicate here.
10774 	* TODO: Unfortunately this simplistic test here is not
10775 	* able to detect a position() predicate in compound
10776 	* expressions like "[@attr = 'a" and position() = 1],
10777 	* and even not the usage of position() in
10778 	* "[position() = 1]"; thus - obviously - a position-range,
10779 	* like it "[position() < 5]", is also not detected.
10780 	* Maybe we could rewrite the AST to ease the optimization.
10781 	*/
10782 
10783         if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
10784 	    *maxPos = (int) floatval;
10785             if (floatval == (double) *maxPos)
10786                 return(1);
10787         }
10788     }
10789     return(0);
10790 }
10791 
10792 static int
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first,xmlNodePtr * last,int toBool)10793 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
10794                            xmlXPathStepOpPtr op,
10795 			   xmlNodePtr * first, xmlNodePtr * last,
10796 			   int toBool)
10797 {
10798 
10799 #define XP_TEST_HIT \
10800     if (hasAxisRange != 0) { \
10801 	if (++pos == maxPos) { \
10802 	    if (addNode(seq, cur) < 0) \
10803 	        xmlXPathPErrMemory(ctxt); \
10804 	    goto axis_range_end; } \
10805     } else { \
10806 	if (addNode(seq, cur) < 0) \
10807 	    xmlXPathPErrMemory(ctxt); \
10808 	if (breakOnFirstHit) goto first_hit; }
10809 
10810 #define XP_TEST_HIT_NS \
10811     if (hasAxisRange != 0) { \
10812 	if (++pos == maxPos) { \
10813 	    hasNsNodes = 1; \
10814 	    if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
10815 	        xmlXPathPErrMemory(ctxt); \
10816 	goto axis_range_end; } \
10817     } else { \
10818 	hasNsNodes = 1; \
10819 	if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
10820 	    xmlXPathPErrMemory(ctxt); \
10821 	if (breakOnFirstHit) goto first_hit; }
10822 
10823     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
10824     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
10825     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
10826     const xmlChar *prefix = op->value4;
10827     const xmlChar *name = op->value5;
10828     const xmlChar *URI = NULL;
10829 
10830     int total = 0, hasNsNodes = 0;
10831     /* The popped object holding the context nodes */
10832     xmlXPathObjectPtr obj;
10833     /* The set of context nodes for the node tests */
10834     xmlNodeSetPtr contextSeq;
10835     int contextIdx;
10836     xmlNodePtr contextNode;
10837     /* The final resulting node set wrt to all context nodes */
10838     xmlNodeSetPtr outSeq;
10839     /*
10840     * The temporary resulting node set wrt 1 context node.
10841     * Used to feed predicate evaluation.
10842     */
10843     xmlNodeSetPtr seq;
10844     xmlNodePtr cur;
10845     /* First predicate operator */
10846     xmlXPathStepOpPtr predOp;
10847     int maxPos; /* The requested position() (when a "[n]" predicate) */
10848     int hasPredicateRange, hasAxisRange, pos;
10849     int breakOnFirstHit;
10850 
10851     xmlXPathTraversalFunction next = NULL;
10852     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
10853     xmlXPathNodeSetMergeFunction mergeAndClear;
10854     xmlNodePtr oldContextNode;
10855     xmlXPathContextPtr xpctxt = ctxt->context;
10856 
10857 
10858     CHECK_TYPE0(XPATH_NODESET);
10859     obj = valuePop(ctxt);
10860     /*
10861     * Setup namespaces.
10862     */
10863     if (prefix != NULL) {
10864         URI = xmlXPathNsLookup(xpctxt, prefix);
10865         if (URI == NULL) {
10866 	    xmlXPathReleaseObject(xpctxt, obj);
10867             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10868 	}
10869     }
10870     /*
10871     * Setup axis.
10872     *
10873     * MAYBE FUTURE TODO: merging optimizations:
10874     * - If the nodes to be traversed wrt to the initial nodes and
10875     *   the current axis cannot overlap, then we could avoid searching
10876     *   for duplicates during the merge.
10877     *   But the question is how/when to evaluate if they cannot overlap.
10878     *   Example: if we know that for two initial nodes, the one is
10879     *   not in the ancestor-or-self axis of the other, then we could safely
10880     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
10881     *   the descendant-or-self axis.
10882     */
10883     mergeAndClear = xmlXPathNodeSetMergeAndClear;
10884     switch (axis) {
10885         case AXIS_ANCESTOR:
10886             first = NULL;
10887             next = xmlXPathNextAncestor;
10888             break;
10889         case AXIS_ANCESTOR_OR_SELF:
10890             first = NULL;
10891             next = xmlXPathNextAncestorOrSelf;
10892             break;
10893         case AXIS_ATTRIBUTE:
10894             first = NULL;
10895 	    last = NULL;
10896             next = xmlXPathNextAttribute;
10897 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10898             break;
10899         case AXIS_CHILD:
10900 	    last = NULL;
10901 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
10902 		(type == NODE_TYPE_NODE))
10903 	    {
10904 		/*
10905 		* Optimization if an element node type is 'element'.
10906 		*/
10907 		next = xmlXPathNextChildElement;
10908 	    } else
10909 		next = xmlXPathNextChild;
10910 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10911             break;
10912         case AXIS_DESCENDANT:
10913 	    last = NULL;
10914             next = xmlXPathNextDescendant;
10915             break;
10916         case AXIS_DESCENDANT_OR_SELF:
10917 	    last = NULL;
10918             next = xmlXPathNextDescendantOrSelf;
10919             break;
10920         case AXIS_FOLLOWING:
10921 	    last = NULL;
10922             next = xmlXPathNextFollowing;
10923             break;
10924         case AXIS_FOLLOWING_SIBLING:
10925 	    last = NULL;
10926             next = xmlXPathNextFollowingSibling;
10927             break;
10928         case AXIS_NAMESPACE:
10929             first = NULL;
10930 	    last = NULL;
10931             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
10932 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10933             break;
10934         case AXIS_PARENT:
10935             first = NULL;
10936             next = xmlXPathNextParent;
10937             break;
10938         case AXIS_PRECEDING:
10939             first = NULL;
10940             next = xmlXPathNextPrecedingInternal;
10941             break;
10942         case AXIS_PRECEDING_SIBLING:
10943             first = NULL;
10944             next = xmlXPathNextPrecedingSibling;
10945             break;
10946         case AXIS_SELF:
10947             first = NULL;
10948 	    last = NULL;
10949             next = xmlXPathNextSelf;
10950 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10951             break;
10952     }
10953 
10954     if (next == NULL) {
10955 	xmlXPathReleaseObject(xpctxt, obj);
10956         return(0);
10957     }
10958     contextSeq = obj->nodesetval;
10959     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
10960         valuePush(ctxt, obj);
10961         return(0);
10962     }
10963     /*
10964     * Predicate optimization ---------------------------------------------
10965     * If this step has a last predicate, which contains a position(),
10966     * then we'll optimize (although not exactly "position()", but only
10967     * the  short-hand form, i.e., "[n]".
10968     *
10969     * Example - expression "/foo[parent::bar][1]":
10970     *
10971     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
10972     *   ROOT                               -- op->ch1
10973     *   PREDICATE                          -- op->ch2 (predOp)
10974     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
10975     *       SORT
10976     *         COLLECT  'parent' 'name' 'node' bar
10977     *           NODE
10978     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
10979     *
10980     */
10981     maxPos = 0;
10982     predOp = NULL;
10983     hasPredicateRange = 0;
10984     hasAxisRange = 0;
10985     if (op->ch2 != -1) {
10986 	/*
10987 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
10988 	*/
10989 	predOp = &ctxt->comp->steps[op->ch2];
10990 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
10991 	    if (predOp->ch1 != -1) {
10992 		/*
10993 		* Use the next inner predicate operator.
10994 		*/
10995 		predOp = &ctxt->comp->steps[predOp->ch1];
10996 		hasPredicateRange = 1;
10997 	    } else {
10998 		/*
10999 		* There's no other predicate than the [n] predicate.
11000 		*/
11001 		predOp = NULL;
11002 		hasAxisRange = 1;
11003 	    }
11004 	}
11005     }
11006     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
11007     /*
11008     * Axis traversal -----------------------------------------------------
11009     */
11010     /*
11011      * 2.3 Node Tests
11012      *  - For the attribute axis, the principal node type is attribute.
11013      *  - For the namespace axis, the principal node type is namespace.
11014      *  - For other axes, the principal node type is element.
11015      *
11016      * A node test * is true for any node of the
11017      * principal node type. For example, child::* will
11018      * select all element children of the context node
11019      */
11020     oldContextNode = xpctxt->node;
11021     addNode = xmlXPathNodeSetAddUnique;
11022     outSeq = NULL;
11023     seq = NULL;
11024     contextNode = NULL;
11025     contextIdx = 0;
11026 
11027 
11028     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
11029            (ctxt->error == XPATH_EXPRESSION_OK)) {
11030 	xpctxt->node = contextSeq->nodeTab[contextIdx++];
11031 
11032 	if (seq == NULL) {
11033 	    seq = xmlXPathNodeSetCreate(NULL);
11034 	    if (seq == NULL) {
11035                 xmlXPathPErrMemory(ctxt);
11036 		total = 0;
11037 		goto error;
11038 	    }
11039 	}
11040 	/*
11041 	* Traverse the axis and test the nodes.
11042 	*/
11043 	pos = 0;
11044 	cur = NULL;
11045 	hasNsNodes = 0;
11046         do {
11047             if (OP_LIMIT_EXCEEDED(ctxt, 1))
11048                 goto error;
11049 
11050             cur = next(ctxt, cur);
11051             if (cur == NULL)
11052                 break;
11053 
11054 	    /*
11055 	    * QUESTION TODO: What does the "first" and "last" stuff do?
11056 	    */
11057             if ((first != NULL) && (*first != NULL)) {
11058 		if (*first == cur)
11059 		    break;
11060 		if (((total % 256) == 0) &&
11061 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11062 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
11063 #else
11064 		    (xmlXPathCmpNodes(*first, cur) >= 0))
11065 #endif
11066 		{
11067 		    break;
11068 		}
11069 	    }
11070 	    if ((last != NULL) && (*last != NULL)) {
11071 		if (*last == cur)
11072 		    break;
11073 		if (((total % 256) == 0) &&
11074 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11075 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
11076 #else
11077 		    (xmlXPathCmpNodes(cur, *last) >= 0))
11078 #endif
11079 		{
11080 		    break;
11081 		}
11082 	    }
11083 
11084             total++;
11085 
11086 	    switch (test) {
11087                 case NODE_TEST_NONE:
11088 		    total = 0;
11089 		    goto error;
11090                 case NODE_TEST_TYPE:
11091 		    if (type == NODE_TYPE_NODE) {
11092 			switch (cur->type) {
11093 			    case XML_DOCUMENT_NODE:
11094 			    case XML_HTML_DOCUMENT_NODE:
11095 			    case XML_ELEMENT_NODE:
11096 			    case XML_ATTRIBUTE_NODE:
11097 			    case XML_PI_NODE:
11098 			    case XML_COMMENT_NODE:
11099 			    case XML_CDATA_SECTION_NODE:
11100 			    case XML_TEXT_NODE:
11101 				XP_TEST_HIT
11102 				break;
11103 			    case XML_NAMESPACE_DECL: {
11104 				if (axis == AXIS_NAMESPACE) {
11105 				    XP_TEST_HIT_NS
11106 				} else {
11107 	                            hasNsNodes = 1;
11108 				    XP_TEST_HIT
11109 				}
11110 				break;
11111                             }
11112 			    default:
11113 				break;
11114 			}
11115 		    } else if (cur->type == (xmlElementType) type) {
11116 			if (cur->type == XML_NAMESPACE_DECL)
11117 			    XP_TEST_HIT_NS
11118 			else
11119 			    XP_TEST_HIT
11120 		    } else if ((type == NODE_TYPE_TEXT) &&
11121 			 (cur->type == XML_CDATA_SECTION_NODE))
11122 		    {
11123 			XP_TEST_HIT
11124 		    }
11125 		    break;
11126                 case NODE_TEST_PI:
11127                     if ((cur->type == XML_PI_NODE) &&
11128                         ((name == NULL) || xmlStrEqual(name, cur->name)))
11129 		    {
11130 			XP_TEST_HIT
11131                     }
11132                     break;
11133                 case NODE_TEST_ALL:
11134                     if (axis == AXIS_ATTRIBUTE) {
11135                         if (cur->type == XML_ATTRIBUTE_NODE)
11136 			{
11137                             if (prefix == NULL)
11138 			    {
11139 				XP_TEST_HIT
11140                             } else if ((cur->ns != NULL) &&
11141 				(xmlStrEqual(URI, cur->ns->href)))
11142 			    {
11143 				XP_TEST_HIT
11144                             }
11145                         }
11146                     } else if (axis == AXIS_NAMESPACE) {
11147                         if (cur->type == XML_NAMESPACE_DECL)
11148 			{
11149 			    XP_TEST_HIT_NS
11150                         }
11151                     } else {
11152                         if (cur->type == XML_ELEMENT_NODE) {
11153                             if (prefix == NULL)
11154 			    {
11155 				XP_TEST_HIT
11156 
11157                             } else if ((cur->ns != NULL) &&
11158 				(xmlStrEqual(URI, cur->ns->href)))
11159 			    {
11160 				XP_TEST_HIT
11161                             }
11162                         }
11163                     }
11164                     break;
11165                 case NODE_TEST_NS:{
11166                         /* TODO */
11167                         break;
11168                     }
11169                 case NODE_TEST_NAME:
11170                     if (axis == AXIS_ATTRIBUTE) {
11171                         if (cur->type != XML_ATTRIBUTE_NODE)
11172 			    break;
11173 		    } else if (axis == AXIS_NAMESPACE) {
11174                         if (cur->type != XML_NAMESPACE_DECL)
11175 			    break;
11176 		    } else {
11177 		        if (cur->type != XML_ELEMENT_NODE)
11178 			    break;
11179 		    }
11180                     switch (cur->type) {
11181                         case XML_ELEMENT_NODE:
11182                             if (xmlStrEqual(name, cur->name)) {
11183                                 if (prefix == NULL) {
11184                                     if (cur->ns == NULL)
11185 				    {
11186 					XP_TEST_HIT
11187                                     }
11188                                 } else {
11189                                     if ((cur->ns != NULL) &&
11190                                         (xmlStrEqual(URI, cur->ns->href)))
11191 				    {
11192 					XP_TEST_HIT
11193                                     }
11194                                 }
11195                             }
11196                             break;
11197                         case XML_ATTRIBUTE_NODE:{
11198                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
11199 
11200                                 if (xmlStrEqual(name, attr->name)) {
11201                                     if (prefix == NULL) {
11202                                         if ((attr->ns == NULL) ||
11203                                             (attr->ns->prefix == NULL))
11204 					{
11205 					    XP_TEST_HIT
11206                                         }
11207                                     } else {
11208                                         if ((attr->ns != NULL) &&
11209                                             (xmlStrEqual(URI,
11210 					      attr->ns->href)))
11211 					{
11212 					    XP_TEST_HIT
11213                                         }
11214                                     }
11215                                 }
11216                                 break;
11217                             }
11218                         case XML_NAMESPACE_DECL:
11219                             if (cur->type == XML_NAMESPACE_DECL) {
11220                                 xmlNsPtr ns = (xmlNsPtr) cur;
11221 
11222                                 if ((ns->prefix != NULL) && (name != NULL)
11223                                     && (xmlStrEqual(ns->prefix, name)))
11224 				{
11225 				    XP_TEST_HIT_NS
11226                                 }
11227                             }
11228                             break;
11229                         default:
11230                             break;
11231                     }
11232                     break;
11233 	    } /* switch(test) */
11234         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
11235 
11236 	goto apply_predicates;
11237 
11238 axis_range_end: /* ----------------------------------------------------- */
11239 	/*
11240 	* We have a "/foo[n]", and position() = n was reached.
11241 	* Note that we can have as well "/foo/::parent::foo[1]", so
11242 	* a duplicate-aware merge is still needed.
11243 	* Merge with the result.
11244 	*/
11245 	if (outSeq == NULL) {
11246 	    outSeq = seq;
11247 	    seq = NULL;
11248 	} else {
11249 	    outSeq = mergeAndClear(outSeq, seq);
11250             if (outSeq == NULL)
11251                 xmlXPathPErrMemory(ctxt);
11252         }
11253 	/*
11254 	* Break if only a true/false result was requested.
11255 	*/
11256 	if (toBool)
11257 	    break;
11258 	continue;
11259 
11260 first_hit: /* ---------------------------------------------------------- */
11261 	/*
11262 	* Break if only a true/false result was requested and
11263 	* no predicates existed and a node test succeeded.
11264 	*/
11265 	if (outSeq == NULL) {
11266 	    outSeq = seq;
11267 	    seq = NULL;
11268 	} else {
11269 	    outSeq = mergeAndClear(outSeq, seq);
11270             if (outSeq == NULL)
11271                 xmlXPathPErrMemory(ctxt);
11272         }
11273 	break;
11274 
11275 apply_predicates: /* --------------------------------------------------- */
11276         if (ctxt->error != XPATH_EXPRESSION_OK)
11277 	    goto error;
11278 
11279         /*
11280 	* Apply predicates.
11281 	*/
11282         if ((predOp != NULL) && (seq->nodeNr > 0)) {
11283 	    /*
11284 	    * E.g. when we have a "/foo[some expression][n]".
11285 	    */
11286 	    /*
11287 	    * QUESTION TODO: The old predicate evaluation took into
11288 	    *  account location-sets.
11289 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
11290 	    *  Do we expect such a set here?
11291 	    *  All what I learned now from the evaluation semantics
11292 	    *  does not indicate that a location-set will be processed
11293 	    *  here, so this looks OK.
11294 	    */
11295 	    /*
11296 	    * Iterate over all predicates, starting with the outermost
11297 	    * predicate.
11298 	    * TODO: Problem: we cannot execute the inner predicates first
11299 	    *  since we cannot go back *up* the operator tree!
11300 	    *  Options we have:
11301 	    *  1) Use of recursive functions (like is it currently done
11302 	    *     via xmlXPathCompOpEval())
11303 	    *  2) Add a predicate evaluation information stack to the
11304 	    *     context struct
11305 	    *  3) Change the way the operators are linked; we need a
11306 	    *     "parent" field on xmlXPathStepOp
11307 	    *
11308 	    * For the moment, I'll try to solve this with a recursive
11309 	    * function: xmlXPathCompOpEvalPredicate().
11310 	    */
11311 	    if (hasPredicateRange != 0)
11312 		xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
11313 					    hasNsNodes);
11314 	    else
11315 		xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
11316 					    hasNsNodes);
11317 
11318 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
11319 		total = 0;
11320 		goto error;
11321 	    }
11322         }
11323 
11324         if (seq->nodeNr > 0) {
11325 	    /*
11326 	    * Add to result set.
11327 	    */
11328 	    if (outSeq == NULL) {
11329 		outSeq = seq;
11330 		seq = NULL;
11331 	    } else {
11332 		outSeq = mergeAndClear(outSeq, seq);
11333                 if (outSeq == NULL)
11334                     xmlXPathPErrMemory(ctxt);
11335 	    }
11336 
11337             if (toBool)
11338                 break;
11339 	}
11340     }
11341 
11342 error:
11343     if ((obj->boolval) && (obj->user != NULL)) {
11344 	/*
11345 	* QUESTION TODO: What does this do and why?
11346 	* TODO: Do we have to do this also for the "error"
11347 	* cleanup further down?
11348 	*/
11349 	ctxt->value->boolval = 1;
11350 	ctxt->value->user = obj->user;
11351 	obj->user = NULL;
11352 	obj->boolval = 0;
11353     }
11354     xmlXPathReleaseObject(xpctxt, obj);
11355 
11356     /*
11357     * Ensure we return at least an empty set.
11358     */
11359     if (outSeq == NULL) {
11360 	if ((seq != NULL) && (seq->nodeNr == 0)) {
11361 	    outSeq = seq;
11362         } else {
11363 	    outSeq = xmlXPathNodeSetCreate(NULL);
11364             if (outSeq == NULL)
11365                 xmlXPathPErrMemory(ctxt);
11366         }
11367     }
11368     if ((seq != NULL) && (seq != outSeq)) {
11369 	 xmlXPathFreeNodeSet(seq);
11370     }
11371     /*
11372     * Hand over the result. Better to push the set also in
11373     * case of errors.
11374     */
11375     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, outSeq));
11376     /*
11377     * Reset the context node.
11378     */
11379     xpctxt->node = oldContextNode;
11380     /*
11381     * When traversing the namespace axis in "toBool" mode, it's
11382     * possible that tmpNsList wasn't freed.
11383     */
11384     if (xpctxt->tmpNsList != NULL) {
11385         xmlFree(xpctxt->tmpNsList);
11386         xpctxt->tmpNsList = NULL;
11387     }
11388 
11389     return(total);
11390 }
11391 
11392 static int
11393 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11394 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
11395 
11396 /**
11397  * xmlXPathCompOpEvalFirst:
11398  * @ctxt:  the XPath parser context with the compiled expression
11399  * @op:  an XPath compiled operation
11400  * @first:  the first elem found so far
11401  *
11402  * Evaluate the Precompiled XPath operation searching only the first
11403  * element in document order
11404  *
11405  * Returns the number of examined objects.
11406  */
11407 static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)11408 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
11409                         xmlXPathStepOpPtr op, xmlNodePtr * first)
11410 {
11411     int total = 0, cur;
11412     xmlXPathCompExprPtr comp;
11413     xmlXPathObjectPtr arg1, arg2;
11414 
11415     CHECK_ERROR0;
11416     if (OP_LIMIT_EXCEEDED(ctxt, 1))
11417         return(0);
11418     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11419         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11420     ctxt->context->depth += 1;
11421     comp = ctxt->comp;
11422     switch (op->op) {
11423         case XPATH_OP_END:
11424             break;
11425         case XPATH_OP_UNION:
11426             total =
11427                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11428                                         first);
11429 	    CHECK_ERROR0;
11430             if ((ctxt->value != NULL)
11431                 && (ctxt->value->type == XPATH_NODESET)
11432                 && (ctxt->value->nodesetval != NULL)
11433                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
11434                 /*
11435                  * limit tree traversing to first node in the result
11436                  */
11437 		/*
11438 		* OPTIMIZE TODO: This implicitly sorts
11439 		*  the result, even if not needed. E.g. if the argument
11440 		*  of the count() function, no sorting is needed.
11441 		* OPTIMIZE TODO: How do we know if the node-list wasn't
11442 		*  already sorted?
11443 		*/
11444 		if (ctxt->value->nodesetval->nodeNr > 1)
11445 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
11446                 *first = ctxt->value->nodesetval->nodeTab[0];
11447             }
11448             cur =
11449                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
11450                                         first);
11451 	    CHECK_ERROR0;
11452 
11453             arg2 = valuePop(ctxt);
11454             arg1 = valuePop(ctxt);
11455             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11456                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11457 	        xmlXPathReleaseObject(ctxt->context, arg1);
11458 	        xmlXPathReleaseObject(ctxt->context, arg2);
11459                 XP_ERROR0(XPATH_INVALID_TYPE);
11460             }
11461             if ((ctxt->context->opLimit != 0) &&
11462                 (((arg1->nodesetval != NULL) &&
11463                   (xmlXPathCheckOpLimit(ctxt,
11464                                         arg1->nodesetval->nodeNr) < 0)) ||
11465                  ((arg2->nodesetval != NULL) &&
11466                   (xmlXPathCheckOpLimit(ctxt,
11467                                         arg2->nodesetval->nodeNr) < 0)))) {
11468 	        xmlXPathReleaseObject(ctxt->context, arg1);
11469 	        xmlXPathReleaseObject(ctxt->context, arg2);
11470                 break;
11471             }
11472 
11473             if ((arg2->nodesetval != NULL) &&
11474                 (arg2->nodesetval->nodeNr != 0)) {
11475                 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11476                                                         arg2->nodesetval);
11477                 if (arg1->nodesetval == NULL)
11478                     xmlXPathPErrMemory(ctxt);
11479             }
11480             valuePush(ctxt, arg1);
11481 	    xmlXPathReleaseObject(ctxt->context, arg2);
11482             /* optimizer */
11483 	    if (total > cur)
11484 		xmlXPathCompSwap(op);
11485             total += cur;
11486             break;
11487         case XPATH_OP_ROOT:
11488             xmlXPathRoot(ctxt);
11489             break;
11490         case XPATH_OP_NODE:
11491             if (op->ch1 != -1)
11492                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11493 	    CHECK_ERROR0;
11494             if (op->ch2 != -1)
11495                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11496 	    CHECK_ERROR0;
11497 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11498 		ctxt->context->node));
11499             break;
11500         case XPATH_OP_COLLECT:{
11501                 if (op->ch1 == -1)
11502                     break;
11503 
11504                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11505 		CHECK_ERROR0;
11506 
11507                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
11508                 break;
11509             }
11510         case XPATH_OP_VALUE:
11511             valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11512             break;
11513         case XPATH_OP_SORT:
11514             if (op->ch1 != -1)
11515                 total +=
11516                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11517                                             first);
11518 	    CHECK_ERROR0;
11519             if ((ctxt->value != NULL)
11520                 && (ctxt->value->type == XPATH_NODESET)
11521                 && (ctxt->value->nodesetval != NULL)
11522 		&& (ctxt->value->nodesetval->nodeNr > 1))
11523                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11524             break;
11525 #ifdef XP_OPTIMIZED_FILTER_FIRST
11526 	case XPATH_OP_FILTER:
11527                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
11528             break;
11529 #endif
11530         default:
11531             total += xmlXPathCompOpEval(ctxt, op);
11532             break;
11533     }
11534 
11535     ctxt->context->depth -= 1;
11536     return(total);
11537 }
11538 
11539 /**
11540  * xmlXPathCompOpEvalLast:
11541  * @ctxt:  the XPath parser context with the compiled expression
11542  * @op:  an XPath compiled operation
11543  * @last:  the last elem found so far
11544  *
11545  * Evaluate the Precompiled XPath operation searching only the last
11546  * element in document order
11547  *
11548  * Returns the number of nodes traversed
11549  */
11550 static int
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * last)11551 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
11552                        xmlNodePtr * last)
11553 {
11554     int total = 0, cur;
11555     xmlXPathCompExprPtr comp;
11556     xmlXPathObjectPtr arg1, arg2;
11557 
11558     CHECK_ERROR0;
11559     if (OP_LIMIT_EXCEEDED(ctxt, 1))
11560         return(0);
11561     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11562         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11563     ctxt->context->depth += 1;
11564     comp = ctxt->comp;
11565     switch (op->op) {
11566         case XPATH_OP_END:
11567             break;
11568         case XPATH_OP_UNION:
11569             total =
11570                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
11571 	    CHECK_ERROR0;
11572             if ((ctxt->value != NULL)
11573                 && (ctxt->value->type == XPATH_NODESET)
11574                 && (ctxt->value->nodesetval != NULL)
11575                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
11576                 /*
11577                  * limit tree traversing to first node in the result
11578                  */
11579 		if (ctxt->value->nodesetval->nodeNr > 1)
11580 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
11581                 *last =
11582                     ctxt->value->nodesetval->nodeTab[ctxt->value->
11583                                                      nodesetval->nodeNr -
11584                                                      1];
11585             }
11586             cur =
11587                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
11588 	    CHECK_ERROR0;
11589             if ((ctxt->value != NULL)
11590                 && (ctxt->value->type == XPATH_NODESET)
11591                 && (ctxt->value->nodesetval != NULL)
11592                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
11593             }
11594 
11595             arg2 = valuePop(ctxt);
11596             arg1 = valuePop(ctxt);
11597             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11598                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11599 	        xmlXPathReleaseObject(ctxt->context, arg1);
11600 	        xmlXPathReleaseObject(ctxt->context, arg2);
11601                 XP_ERROR0(XPATH_INVALID_TYPE);
11602             }
11603             if ((ctxt->context->opLimit != 0) &&
11604                 (((arg1->nodesetval != NULL) &&
11605                   (xmlXPathCheckOpLimit(ctxt,
11606                                         arg1->nodesetval->nodeNr) < 0)) ||
11607                  ((arg2->nodesetval != NULL) &&
11608                   (xmlXPathCheckOpLimit(ctxt,
11609                                         arg2->nodesetval->nodeNr) < 0)))) {
11610 	        xmlXPathReleaseObject(ctxt->context, arg1);
11611 	        xmlXPathReleaseObject(ctxt->context, arg2);
11612                 break;
11613             }
11614 
11615             if ((arg2->nodesetval != NULL) &&
11616                 (arg2->nodesetval->nodeNr != 0)) {
11617                 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11618                                                         arg2->nodesetval);
11619                 if (arg1->nodesetval == NULL)
11620                     xmlXPathPErrMemory(ctxt);
11621             }
11622             valuePush(ctxt, arg1);
11623 	    xmlXPathReleaseObject(ctxt->context, arg2);
11624             /* optimizer */
11625 	    if (total > cur)
11626 		xmlXPathCompSwap(op);
11627             total += cur;
11628             break;
11629         case XPATH_OP_ROOT:
11630             xmlXPathRoot(ctxt);
11631             break;
11632         case XPATH_OP_NODE:
11633             if (op->ch1 != -1)
11634                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11635 	    CHECK_ERROR0;
11636             if (op->ch2 != -1)
11637                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11638 	    CHECK_ERROR0;
11639 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11640 		ctxt->context->node));
11641             break;
11642         case XPATH_OP_COLLECT:{
11643                 if (op->ch1 == -1)
11644                     break;
11645 
11646                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11647 		CHECK_ERROR0;
11648 
11649                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
11650                 break;
11651             }
11652         case XPATH_OP_VALUE:
11653             valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11654             break;
11655         case XPATH_OP_SORT:
11656             if (op->ch1 != -1)
11657                 total +=
11658                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
11659                                            last);
11660 	    CHECK_ERROR0;
11661             if ((ctxt->value != NULL)
11662                 && (ctxt->value->type == XPATH_NODESET)
11663                 && (ctxt->value->nodesetval != NULL)
11664 		&& (ctxt->value->nodesetval->nodeNr > 1))
11665                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11666             break;
11667         default:
11668             total += xmlXPathCompOpEval(ctxt, op);
11669             break;
11670     }
11671 
11672     ctxt->context->depth -= 1;
11673     return (total);
11674 }
11675 
11676 #ifdef XP_OPTIMIZED_FILTER_FIRST
11677 static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)11678 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11679 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
11680 {
11681     int total = 0;
11682     xmlXPathCompExprPtr comp;
11683     xmlXPathObjectPtr obj;
11684     xmlNodeSetPtr set;
11685 
11686     CHECK_ERROR0;
11687     comp = ctxt->comp;
11688     /*
11689     * Optimization for ()[last()] selection i.e. the last elem
11690     */
11691     if ((op->ch1 != -1) && (op->ch2 != -1) &&
11692 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11693 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11694 	int f = comp->steps[op->ch2].ch1;
11695 
11696 	if ((f != -1) &&
11697 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11698 	    (comp->steps[f].value5 == NULL) &&
11699 	    (comp->steps[f].value == 0) &&
11700 	    (comp->steps[f].value4 != NULL) &&
11701 	    (xmlStrEqual
11702 	    (comp->steps[f].value4, BAD_CAST "last"))) {
11703 	    xmlNodePtr last = NULL;
11704 
11705 	    total +=
11706 		xmlXPathCompOpEvalLast(ctxt,
11707 		    &comp->steps[op->ch1],
11708 		    &last);
11709 	    CHECK_ERROR0;
11710 	    /*
11711 	    * The nodeset should be in document order,
11712 	    * Keep only the last value
11713 	    */
11714 	    if ((ctxt->value != NULL) &&
11715 		(ctxt->value->type == XPATH_NODESET) &&
11716 		(ctxt->value->nodesetval != NULL) &&
11717 		(ctxt->value->nodesetval->nodeTab != NULL) &&
11718 		(ctxt->value->nodesetval->nodeNr > 1)) {
11719                 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11720 		*first = *(ctxt->value->nodesetval->nodeTab);
11721 	    }
11722 	    return (total);
11723 	}
11724     }
11725 
11726     if (op->ch1 != -1)
11727 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11728     CHECK_ERROR0;
11729     if (op->ch2 == -1)
11730 	return (total);
11731     if (ctxt->value == NULL)
11732 	return (total);
11733 
11734 #ifdef LIBXML_XPTR_LOCS_ENABLED
11735     /*
11736     * Hum are we filtering the result of an XPointer expression
11737     */
11738     if (ctxt->value->type == XPATH_LOCATIONSET) {
11739         xmlLocationSetPtr locset = ctxt->value->user;
11740 
11741         if (locset != NULL) {
11742             xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
11743             if (locset->locNr > 0)
11744                 *first = (xmlNodePtr) locset->locTab[0]->user;
11745         }
11746 
11747 	return (total);
11748     }
11749 #endif /* LIBXML_XPTR_LOCS_ENABLED */
11750 
11751     /*
11752      * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
11753      * the stack. We have to temporarily remove the nodeset object from the
11754      * stack to avoid freeing it prematurely.
11755      */
11756     CHECK_TYPE0(XPATH_NODESET);
11757     obj = valuePop(ctxt);
11758     set = obj->nodesetval;
11759     if (set != NULL) {
11760         xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
11761         if (set->nodeNr > 0)
11762             *first = set->nodeTab[0];
11763     }
11764     valuePush(ctxt, obj);
11765 
11766     return (total);
11767 }
11768 #endif /* XP_OPTIMIZED_FILTER_FIRST */
11769 
11770 /**
11771  * xmlXPathCompOpEval:
11772  * @ctxt:  the XPath parser context with the compiled expression
11773  * @op:  an XPath compiled operation
11774  *
11775  * Evaluate the Precompiled XPath operation
11776  * Returns the number of nodes traversed
11777  */
11778 static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op)11779 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
11780 {
11781     int total = 0;
11782     int equal, ret;
11783     xmlXPathCompExprPtr comp;
11784     xmlXPathObjectPtr arg1, arg2;
11785 
11786     CHECK_ERROR0;
11787     if (OP_LIMIT_EXCEEDED(ctxt, 1))
11788         return(0);
11789     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11790         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11791     ctxt->context->depth += 1;
11792     comp = ctxt->comp;
11793     switch (op->op) {
11794         case XPATH_OP_END:
11795             break;
11796         case XPATH_OP_AND:
11797             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11798 	    CHECK_ERROR0;
11799             xmlXPathBooleanFunction(ctxt, 1);
11800             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
11801                 break;
11802             arg2 = valuePop(ctxt);
11803             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11804 	    if (ctxt->error) {
11805 		xmlXPathFreeObject(arg2);
11806 		break;
11807 	    }
11808             xmlXPathBooleanFunction(ctxt, 1);
11809             if (ctxt->value != NULL)
11810                 ctxt->value->boolval &= arg2->boolval;
11811 	    xmlXPathReleaseObject(ctxt->context, arg2);
11812             break;
11813         case XPATH_OP_OR:
11814             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11815 	    CHECK_ERROR0;
11816             xmlXPathBooleanFunction(ctxt, 1);
11817             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
11818                 break;
11819             arg2 = valuePop(ctxt);
11820             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11821 	    if (ctxt->error) {
11822 		xmlXPathFreeObject(arg2);
11823 		break;
11824 	    }
11825             xmlXPathBooleanFunction(ctxt, 1);
11826             if (ctxt->value != NULL)
11827                 ctxt->value->boolval |= arg2->boolval;
11828 	    xmlXPathReleaseObject(ctxt->context, arg2);
11829             break;
11830         case XPATH_OP_EQUAL:
11831             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11832 	    CHECK_ERROR0;
11833             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11834 	    CHECK_ERROR0;
11835 	    if (op->value)
11836 		equal = xmlXPathEqualValues(ctxt);
11837 	    else
11838 		equal = xmlXPathNotEqualValues(ctxt);
11839 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, equal));
11840             break;
11841         case XPATH_OP_CMP:
11842             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11843 	    CHECK_ERROR0;
11844             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11845 	    CHECK_ERROR0;
11846             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
11847 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
11848             break;
11849         case XPATH_OP_PLUS:
11850             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11851 	    CHECK_ERROR0;
11852             if (op->ch2 != -1) {
11853                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11854 	    }
11855 	    CHECK_ERROR0;
11856             if (op->value == 0)
11857                 xmlXPathSubValues(ctxt);
11858             else if (op->value == 1)
11859                 xmlXPathAddValues(ctxt);
11860             else if (op->value == 2)
11861                 xmlXPathValueFlipSign(ctxt);
11862             else if (op->value == 3) {
11863                 CAST_TO_NUMBER;
11864                 CHECK_TYPE0(XPATH_NUMBER);
11865             }
11866             break;
11867         case XPATH_OP_MULT:
11868             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11869 	    CHECK_ERROR0;
11870             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11871 	    CHECK_ERROR0;
11872             if (op->value == 0)
11873                 xmlXPathMultValues(ctxt);
11874             else if (op->value == 1)
11875                 xmlXPathDivValues(ctxt);
11876             else if (op->value == 2)
11877                 xmlXPathModValues(ctxt);
11878             break;
11879         case XPATH_OP_UNION:
11880             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11881 	    CHECK_ERROR0;
11882             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11883 	    CHECK_ERROR0;
11884 
11885             arg2 = valuePop(ctxt);
11886             arg1 = valuePop(ctxt);
11887             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11888                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11889 	        xmlXPathReleaseObject(ctxt->context, arg1);
11890 	        xmlXPathReleaseObject(ctxt->context, arg2);
11891                 XP_ERROR0(XPATH_INVALID_TYPE);
11892             }
11893             if ((ctxt->context->opLimit != 0) &&
11894                 (((arg1->nodesetval != NULL) &&
11895                   (xmlXPathCheckOpLimit(ctxt,
11896                                         arg1->nodesetval->nodeNr) < 0)) ||
11897                  ((arg2->nodesetval != NULL) &&
11898                   (xmlXPathCheckOpLimit(ctxt,
11899                                         arg2->nodesetval->nodeNr) < 0)))) {
11900 	        xmlXPathReleaseObject(ctxt->context, arg1);
11901 	        xmlXPathReleaseObject(ctxt->context, arg2);
11902                 break;
11903             }
11904 
11905 	    if (((arg2->nodesetval != NULL) &&
11906 		 (arg2->nodesetval->nodeNr != 0)))
11907 	    {
11908 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11909 							arg2->nodesetval);
11910                 if (arg1->nodesetval == NULL)
11911                     xmlXPathPErrMemory(ctxt);
11912 	    }
11913 
11914             valuePush(ctxt, arg1);
11915 	    xmlXPathReleaseObject(ctxt->context, arg2);
11916             break;
11917         case XPATH_OP_ROOT:
11918             xmlXPathRoot(ctxt);
11919             break;
11920         case XPATH_OP_NODE:
11921             if (op->ch1 != -1)
11922                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11923 	    CHECK_ERROR0;
11924             if (op->ch2 != -1)
11925                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11926 	    CHECK_ERROR0;
11927 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11928                                                     ctxt->context->node));
11929             break;
11930         case XPATH_OP_COLLECT:{
11931                 if (op->ch1 == -1)
11932                     break;
11933 
11934                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11935 		CHECK_ERROR0;
11936 
11937                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
11938                 break;
11939             }
11940         case XPATH_OP_VALUE:
11941             valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11942             break;
11943         case XPATH_OP_VARIABLE:{
11944 		xmlXPathObjectPtr val;
11945 
11946                 if (op->ch1 != -1)
11947                     total +=
11948                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11949                 if (op->value5 == NULL) {
11950 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
11951 		    if (val == NULL)
11952 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
11953                     valuePush(ctxt, val);
11954 		} else {
11955                     const xmlChar *URI;
11956 
11957                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
11958                     if (URI == NULL) {
11959                         XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11960                         break;
11961                     }
11962 		    val = xmlXPathVariableLookupNS(ctxt->context,
11963                                                        op->value4, URI);
11964 		    if (val == NULL)
11965 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
11966                     valuePush(ctxt, val);
11967                 }
11968                 break;
11969             }
11970         case XPATH_OP_FUNCTION:{
11971                 xmlXPathFunction func;
11972                 const xmlChar *oldFunc, *oldFuncURI;
11973 		int i;
11974                 int frame;
11975 
11976                 frame = ctxt->valueNr;
11977                 if (op->ch1 != -1) {
11978                     total +=
11979                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11980                     if (ctxt->error != XPATH_EXPRESSION_OK)
11981                         break;
11982                 }
11983 		if (ctxt->valueNr < frame + op->value)
11984 		    XP_ERROR0(XPATH_INVALID_OPERAND);
11985 		for (i = 0; i < op->value; i++) {
11986 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL)
11987 			XP_ERROR0(XPATH_INVALID_OPERAND);
11988                 }
11989                 if (op->cache != NULL)
11990                     func = op->cache;
11991                 else {
11992                     const xmlChar *URI = NULL;
11993 
11994                     if (op->value5 == NULL)
11995                         func =
11996                             xmlXPathFunctionLookup(ctxt->context,
11997                                                    op->value4);
11998                     else {
11999                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
12000                         if (URI == NULL)
12001                             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12002                         func = xmlXPathFunctionLookupNS(ctxt->context,
12003                                                         op->value4, URI);
12004                     }
12005                     if (func == NULL)
12006                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
12007                     op->cache = func;
12008                     op->cacheURI = (void *) URI;
12009                 }
12010                 oldFunc = ctxt->context->function;
12011                 oldFuncURI = ctxt->context->functionURI;
12012                 ctxt->context->function = op->value4;
12013                 ctxt->context->functionURI = op->cacheURI;
12014                 func(ctxt, op->value);
12015                 ctxt->context->function = oldFunc;
12016                 ctxt->context->functionURI = oldFuncURI;
12017                 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
12018                     (ctxt->valueNr != frame + 1))
12019                     XP_ERROR0(XPATH_STACK_ERROR);
12020                 break;
12021             }
12022         case XPATH_OP_ARG:
12023             if (op->ch1 != -1) {
12024                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12025 	        CHECK_ERROR0;
12026             }
12027             if (op->ch2 != -1) {
12028                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12029 	        CHECK_ERROR0;
12030 	    }
12031             break;
12032         case XPATH_OP_PREDICATE:
12033         case XPATH_OP_FILTER:{
12034                 xmlXPathObjectPtr obj;
12035                 xmlNodeSetPtr set;
12036 
12037                 /*
12038                  * Optimization for ()[1] selection i.e. the first elem
12039                  */
12040                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12041 #ifdef XP_OPTIMIZED_FILTER_FIRST
12042 		    /*
12043 		    * FILTER TODO: Can we assume that the inner processing
12044 		    *  will result in an ordered list if we have an
12045 		    *  XPATH_OP_FILTER?
12046 		    *  What about an additional field or flag on
12047 		    *  xmlXPathObject like @sorted ? This way we wouldn't need
12048 		    *  to assume anything, so it would be more robust and
12049 		    *  easier to optimize.
12050 		    */
12051                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
12052 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
12053 #else
12054 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12055 #endif
12056                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
12057                     xmlXPathObjectPtr val;
12058 
12059                     val = comp->steps[op->ch2].value4;
12060                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
12061                         (val->floatval == 1.0)) {
12062                         xmlNodePtr first = NULL;
12063 
12064                         total +=
12065                             xmlXPathCompOpEvalFirst(ctxt,
12066                                                     &comp->steps[op->ch1],
12067                                                     &first);
12068 			CHECK_ERROR0;
12069                         /*
12070                          * The nodeset should be in document order,
12071                          * Keep only the first value
12072                          */
12073                         if ((ctxt->value != NULL) &&
12074                             (ctxt->value->type == XPATH_NODESET) &&
12075                             (ctxt->value->nodesetval != NULL) &&
12076                             (ctxt->value->nodesetval->nodeNr > 1))
12077                             xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
12078                                                         1, 1);
12079                         break;
12080                     }
12081                 }
12082                 /*
12083                  * Optimization for ()[last()] selection i.e. the last elem
12084                  */
12085                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12086                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12087                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12088                     int f = comp->steps[op->ch2].ch1;
12089 
12090                     if ((f != -1) &&
12091                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12092                         (comp->steps[f].value5 == NULL) &&
12093                         (comp->steps[f].value == 0) &&
12094                         (comp->steps[f].value4 != NULL) &&
12095                         (xmlStrEqual
12096                          (comp->steps[f].value4, BAD_CAST "last"))) {
12097                         xmlNodePtr last = NULL;
12098 
12099                         total +=
12100                             xmlXPathCompOpEvalLast(ctxt,
12101                                                    &comp->steps[op->ch1],
12102                                                    &last);
12103 			CHECK_ERROR0;
12104                         /*
12105                          * The nodeset should be in document order,
12106                          * Keep only the last value
12107                          */
12108                         if ((ctxt->value != NULL) &&
12109                             (ctxt->value->type == XPATH_NODESET) &&
12110                             (ctxt->value->nodesetval != NULL) &&
12111                             (ctxt->value->nodesetval->nodeTab != NULL) &&
12112                             (ctxt->value->nodesetval->nodeNr > 1))
12113                             xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12114                         break;
12115                     }
12116                 }
12117 		/*
12118 		* Process inner predicates first.
12119 		* Example "index[parent::book][1]":
12120 		* ...
12121 		*   PREDICATE   <-- we are here "[1]"
12122 		*     PREDICATE <-- process "[parent::book]" first
12123 		*       SORT
12124 		*         COLLECT  'parent' 'name' 'node' book
12125 		*           NODE
12126 		*     ELEM Object is a number : 1
12127 		*/
12128                 if (op->ch1 != -1)
12129                     total +=
12130                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12131 		CHECK_ERROR0;
12132                 if (op->ch2 == -1)
12133                     break;
12134                 if (ctxt->value == NULL)
12135                     break;
12136 
12137 #ifdef LIBXML_XPTR_LOCS_ENABLED
12138                 /*
12139                  * Hum are we filtering the result of an XPointer expression
12140                  */
12141                 if (ctxt->value->type == XPATH_LOCATIONSET) {
12142                     xmlLocationSetPtr locset = ctxt->value->user;
12143                     xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
12144                                               1, locset->locNr);
12145                     break;
12146                 }
12147 #endif /* LIBXML_XPTR_LOCS_ENABLED */
12148 
12149                 /*
12150                  * In case of errors, xmlXPathNodeSetFilter can pop additional
12151                  * nodes from the stack. We have to temporarily remove the
12152                  * nodeset object from the stack to avoid freeing it
12153                  * prematurely.
12154                  */
12155                 CHECK_TYPE0(XPATH_NODESET);
12156                 obj = valuePop(ctxt);
12157                 set = obj->nodesetval;
12158                 if (set != NULL)
12159                     xmlXPathNodeSetFilter(ctxt, set, op->ch2,
12160                                           1, set->nodeNr, 1);
12161                 valuePush(ctxt, obj);
12162                 break;
12163             }
12164         case XPATH_OP_SORT:
12165             if (op->ch1 != -1)
12166                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12167 	    CHECK_ERROR0;
12168             if ((ctxt->value != NULL) &&
12169                 (ctxt->value->type == XPATH_NODESET) &&
12170                 (ctxt->value->nodesetval != NULL) &&
12171 		(ctxt->value->nodesetval->nodeNr > 1))
12172 	    {
12173                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12174 	    }
12175             break;
12176 #ifdef LIBXML_XPTR_LOCS_ENABLED
12177         case XPATH_OP_RANGETO:{
12178                 xmlXPathObjectPtr range;
12179                 xmlXPathObjectPtr res, obj;
12180                 xmlXPathObjectPtr tmp;
12181                 xmlLocationSetPtr newlocset = NULL;
12182 		    xmlLocationSetPtr oldlocset;
12183                 xmlNodeSetPtr oldset;
12184                 xmlNodePtr oldnode = ctxt->context->node;
12185                 int oldcs = ctxt->context->contextSize;
12186                 int oldpp = ctxt->context->proximityPosition;
12187                 int i, j;
12188 
12189                 if (op->ch1 != -1) {
12190                     total +=
12191                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12192                     CHECK_ERROR0;
12193                 }
12194                 if (ctxt->value == NULL) {
12195                     XP_ERROR0(XPATH_INVALID_OPERAND);
12196                 }
12197                 if (op->ch2 == -1)
12198                     break;
12199 
12200                 if (ctxt->value->type == XPATH_LOCATIONSET) {
12201                     /*
12202                      * Extract the old locset, and then evaluate the result of the
12203                      * expression for all the element in the locset. use it to grow
12204                      * up a new locset.
12205                      */
12206                     CHECK_TYPE0(XPATH_LOCATIONSET);
12207 
12208                     if ((ctxt->value->user == NULL) ||
12209                         (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
12210                         break;
12211 
12212                     obj = valuePop(ctxt);
12213                     oldlocset = obj->user;
12214 
12215                     newlocset = xmlXPtrLocationSetCreate(NULL);
12216 
12217                     for (i = 0; i < oldlocset->locNr; i++) {
12218                         /*
12219                          * Run the evaluation with a node list made of a
12220                          * single item in the nodelocset.
12221                          */
12222                         ctxt->context->node = oldlocset->locTab[i]->user;
12223                         ctxt->context->contextSize = oldlocset->locNr;
12224                         ctxt->context->proximityPosition = i + 1;
12225                         tmp = xmlXPathCacheNewNodeSet(ctxt,
12226                                                       ctxt->context->node);
12227                         valuePush(ctxt, tmp);
12228 
12229                         if (op->ch2 != -1)
12230                             total +=
12231                                 xmlXPathCompOpEval(ctxt,
12232                                                    &comp->steps[op->ch2]);
12233 			if (ctxt->error != XPATH_EXPRESSION_OK) {
12234                             xmlXPtrFreeLocationSet(newlocset);
12235                             goto rangeto_error;
12236 			}
12237 
12238                         res = valuePop(ctxt);
12239 			if (res->type == XPATH_LOCATIONSET) {
12240 			    xmlLocationSetPtr rloc =
12241 			        (xmlLocationSetPtr)res->user;
12242 			    for (j=0; j<rloc->locNr; j++) {
12243 			        range = xmlXPtrNewRange(
12244 				  oldlocset->locTab[i]->user,
12245 				  oldlocset->locTab[i]->index,
12246 				  rloc->locTab[j]->user2,
12247 				  rloc->locTab[j]->index2);
12248 				if (range != NULL) {
12249 				    xmlXPtrLocationSetAdd(newlocset, range);
12250 				}
12251 			    }
12252 			} else {
12253 			    range = xmlXPtrNewRangeNodeObject(
12254 				(xmlNodePtr)oldlocset->locTab[i]->user, res);
12255                             if (range != NULL) {
12256                                 xmlXPtrLocationSetAdd(newlocset,range);
12257 			    }
12258                         }
12259 
12260                         /*
12261                          * Cleanup
12262                          */
12263                         if (res != NULL) {
12264 			    xmlXPathReleaseObject(ctxt->context, res);
12265 			}
12266                         if (ctxt->value == tmp) {
12267                             res = valuePop(ctxt);
12268 			    xmlXPathReleaseObject(ctxt->context, res);
12269                         }
12270                     }
12271 		} else {	/* Not a location set */
12272                     CHECK_TYPE0(XPATH_NODESET);
12273                     obj = valuePop(ctxt);
12274                     oldset = obj->nodesetval;
12275 
12276                     newlocset = xmlXPtrLocationSetCreate(NULL);
12277 
12278                     if (oldset != NULL) {
12279                         for (i = 0; i < oldset->nodeNr; i++) {
12280                             /*
12281                              * Run the evaluation with a node list made of a single item
12282                              * in the nodeset.
12283                              */
12284                             ctxt->context->node = oldset->nodeTab[i];
12285 			    /*
12286 			    * OPTIMIZE TODO: Avoid recreation for every iteration.
12287 			    */
12288                             tmp = xmlXPathCacheNewNodeSet(ctxt,
12289                                                           ctxt->context->node);
12290                             valuePush(ctxt, tmp);
12291 
12292                             if (op->ch2 != -1)
12293                                 total +=
12294                                     xmlXPathCompOpEval(ctxt,
12295                                                    &comp->steps[op->ch2]);
12296 			    if (ctxt->error != XPATH_EXPRESSION_OK) {
12297                                 xmlXPtrFreeLocationSet(newlocset);
12298                                 goto rangeto_error;
12299 			    }
12300 
12301                             res = valuePop(ctxt);
12302                             range =
12303                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
12304                                                       res);
12305                             if (range != NULL) {
12306                                 xmlXPtrLocationSetAdd(newlocset, range);
12307                             }
12308 
12309                             /*
12310                              * Cleanup
12311                              */
12312                             if (res != NULL) {
12313 				xmlXPathReleaseObject(ctxt->context, res);
12314 			    }
12315                             if (ctxt->value == tmp) {
12316                                 res = valuePop(ctxt);
12317 				xmlXPathReleaseObject(ctxt->context, res);
12318                             }
12319                         }
12320                     }
12321                 }
12322 
12323                 /*
12324                  * The result is used as the new evaluation set.
12325                  */
12326                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12327 rangeto_error:
12328 		xmlXPathReleaseObject(ctxt->context, obj);
12329                 ctxt->context->node = oldnode;
12330                 ctxt->context->contextSize = oldcs;
12331                 ctxt->context->proximityPosition = oldpp;
12332                 break;
12333             }
12334 #endif /* LIBXML_XPTR_LOCS_ENABLED */
12335         default:
12336             XP_ERROR0(XPATH_INVALID_OPERAND);
12337             break;
12338     }
12339 
12340     ctxt->context->depth -= 1;
12341     return (total);
12342 }
12343 
12344 /**
12345  * xmlXPathCompOpEvalToBoolean:
12346  * @ctxt:  the XPath parser context
12347  *
12348  * Evaluates if the expression evaluates to true.
12349  *
12350  * Returns 1 if true, 0 if false and -1 on API or internal errors.
12351  */
12352 static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int isPredicate)12353 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
12354 			    xmlXPathStepOpPtr op,
12355 			    int isPredicate)
12356 {
12357     xmlXPathObjectPtr resObj = NULL;
12358 
12359 start:
12360     if (OP_LIMIT_EXCEEDED(ctxt, 1))
12361         return(0);
12362     /* comp = ctxt->comp; */
12363     switch (op->op) {
12364         case XPATH_OP_END:
12365             return (0);
12366 	case XPATH_OP_VALUE:
12367 	    resObj = (xmlXPathObjectPtr) op->value4;
12368 	    if (isPredicate)
12369 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
12370 	    return(xmlXPathCastToBoolean(resObj));
12371 	case XPATH_OP_SORT:
12372 	    /*
12373 	    * We don't need sorting for boolean results. Skip this one.
12374 	    */
12375             if (op->ch1 != -1) {
12376 		op = &ctxt->comp->steps[op->ch1];
12377 		goto start;
12378 	    }
12379 	    return(0);
12380 	case XPATH_OP_COLLECT:
12381 	    if (op->ch1 == -1)
12382 		return(0);
12383 
12384             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
12385 	    if (ctxt->error != XPATH_EXPRESSION_OK)
12386 		return(-1);
12387 
12388             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
12389 	    if (ctxt->error != XPATH_EXPRESSION_OK)
12390 		return(-1);
12391 
12392 	    resObj = valuePop(ctxt);
12393 	    if (resObj == NULL)
12394 		return(-1);
12395 	    break;
12396 	default:
12397 	    /*
12398 	    * Fallback to call xmlXPathCompOpEval().
12399 	    */
12400 	    xmlXPathCompOpEval(ctxt, op);
12401 	    if (ctxt->error != XPATH_EXPRESSION_OK)
12402 		return(-1);
12403 
12404 	    resObj = valuePop(ctxt);
12405 	    if (resObj == NULL)
12406 		return(-1);
12407 	    break;
12408     }
12409 
12410     if (resObj) {
12411 	int res;
12412 
12413 	if (resObj->type == XPATH_BOOLEAN) {
12414 	    res = resObj->boolval;
12415 	} else if (isPredicate) {
12416 	    /*
12417 	    * For predicates a result of type "number" is handled
12418 	    * differently:
12419 	    * SPEC XPath 1.0:
12420 	    * "If the result is a number, the result will be converted
12421 	    *  to true if the number is equal to the context position
12422 	    *  and will be converted to false otherwise;"
12423 	    */
12424 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
12425 	} else {
12426 	    res = xmlXPathCastToBoolean(resObj);
12427 	}
12428 	xmlXPathReleaseObject(ctxt->context, resObj);
12429 	return(res);
12430     }
12431 
12432     return(0);
12433 }
12434 
12435 #ifdef XPATH_STREAMING
12436 /**
12437  * xmlXPathRunStreamEval:
12438  * @pctxt:  the XPath parser context with the compiled expression
12439  *
12440  * Evaluate the Precompiled Streamable XPath expression in the given context.
12441  */
12442 static int
xmlXPathRunStreamEval(xmlXPathParserContextPtr pctxt,xmlPatternPtr comp,xmlXPathObjectPtr * resultSeq,int toBool)12443 xmlXPathRunStreamEval(xmlXPathParserContextPtr pctxt, xmlPatternPtr comp,
12444 		      xmlXPathObjectPtr *resultSeq, int toBool)
12445 {
12446     int max_depth, min_depth;
12447     int from_root;
12448     int ret, depth;
12449     int eval_all_nodes;
12450     xmlNodePtr cur = NULL, limit = NULL;
12451     xmlStreamCtxtPtr patstream = NULL;
12452     xmlXPathContextPtr ctxt = pctxt->context;
12453 
12454     if ((ctxt == NULL) || (comp == NULL))
12455         return(-1);
12456     max_depth = xmlPatternMaxDepth(comp);
12457     if (max_depth == -1)
12458         return(-1);
12459     if (max_depth == -2)
12460         max_depth = 10000;
12461     min_depth = xmlPatternMinDepth(comp);
12462     if (min_depth == -1)
12463         return(-1);
12464     from_root = xmlPatternFromRoot(comp);
12465     if (from_root < 0)
12466         return(-1);
12467 #if 0
12468     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
12469 #endif
12470 
12471     if (! toBool) {
12472 	if (resultSeq == NULL)
12473 	    return(-1);
12474 	*resultSeq = xmlXPathCacheNewNodeSet(pctxt, NULL);
12475 	if (*resultSeq == NULL)
12476 	    return(-1);
12477     }
12478 
12479     /*
12480      * handle the special cases of "/" amd "." being matched
12481      */
12482     if (min_depth == 0) {
12483         int res;
12484 
12485 	if (from_root) {
12486 	    /* Select "/" */
12487 	    if (toBool)
12488 		return(1);
12489             res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
12490                                            (xmlNodePtr) ctxt->doc);
12491 	} else {
12492 	    /* Select "self::node()" */
12493 	    if (toBool)
12494 		return(1);
12495             res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
12496                                            ctxt->node);
12497 	}
12498 
12499         if (res < 0)
12500             xmlXPathPErrMemory(pctxt);
12501     }
12502     if (max_depth == 0) {
12503 	return(0);
12504     }
12505 
12506     if (from_root) {
12507         cur = (xmlNodePtr)ctxt->doc;
12508     } else if (ctxt->node != NULL) {
12509         switch (ctxt->node->type) {
12510             case XML_ELEMENT_NODE:
12511             case XML_DOCUMENT_NODE:
12512             case XML_DOCUMENT_FRAG_NODE:
12513             case XML_HTML_DOCUMENT_NODE:
12514 	        cur = ctxt->node;
12515 		break;
12516             case XML_ATTRIBUTE_NODE:
12517             case XML_TEXT_NODE:
12518             case XML_CDATA_SECTION_NODE:
12519             case XML_ENTITY_REF_NODE:
12520             case XML_ENTITY_NODE:
12521             case XML_PI_NODE:
12522             case XML_COMMENT_NODE:
12523             case XML_NOTATION_NODE:
12524             case XML_DTD_NODE:
12525             case XML_DOCUMENT_TYPE_NODE:
12526             case XML_ELEMENT_DECL:
12527             case XML_ATTRIBUTE_DECL:
12528             case XML_ENTITY_DECL:
12529             case XML_NAMESPACE_DECL:
12530             case XML_XINCLUDE_START:
12531             case XML_XINCLUDE_END:
12532 		break;
12533 	}
12534 	limit = cur;
12535     }
12536     if (cur == NULL) {
12537         return(0);
12538     }
12539 
12540     patstream = xmlPatternGetStreamCtxt(comp);
12541     if (patstream == NULL) {
12542         xmlXPathPErrMemory(pctxt);
12543 	return(-1);
12544     }
12545 
12546     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
12547 
12548     if (from_root) {
12549 	ret = xmlStreamPush(patstream, NULL, NULL);
12550 	if (ret < 0) {
12551 	} else if (ret == 1) {
12552 	    if (toBool)
12553 		goto return_1;
12554 	    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) < 0)
12555                 xmlXPathPErrMemory(pctxt);
12556 	}
12557     }
12558     depth = 0;
12559     goto scan_children;
12560 next_node:
12561     do {
12562         if (ctxt->opLimit != 0) {
12563             if (ctxt->opCount >= ctxt->opLimit) {
12564                 xmlXPathErr(ctxt, XPATH_RECURSION_LIMIT_EXCEEDED);
12565                 xmlFreeStreamCtxt(patstream);
12566                 return(-1);
12567             }
12568             ctxt->opCount++;
12569         }
12570 
12571 	switch (cur->type) {
12572 	    case XML_ELEMENT_NODE:
12573 	    case XML_TEXT_NODE:
12574 	    case XML_CDATA_SECTION_NODE:
12575 	    case XML_COMMENT_NODE:
12576 	    case XML_PI_NODE:
12577 		if (cur->type == XML_ELEMENT_NODE) {
12578 		    ret = xmlStreamPush(patstream, cur->name,
12579 				(cur->ns ? cur->ns->href : NULL));
12580 		} else if (eval_all_nodes)
12581 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
12582 		else
12583 		    break;
12584 
12585 		if (ret < 0) {
12586 		    xmlXPathPErrMemory(pctxt);
12587 		} else if (ret == 1) {
12588 		    if (toBool)
12589 			goto return_1;
12590 		    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
12591                                                  cur) < 0)
12592                         xmlXPathPErrMemory(pctxt);
12593 		}
12594 		if ((cur->children == NULL) || (depth >= max_depth)) {
12595 		    ret = xmlStreamPop(patstream);
12596 		    while (cur->next != NULL) {
12597 			cur = cur->next;
12598 			if ((cur->type != XML_ENTITY_DECL) &&
12599 			    (cur->type != XML_DTD_NODE))
12600 			    goto next_node;
12601 		    }
12602 		}
12603 	    default:
12604 		break;
12605 	}
12606 
12607 scan_children:
12608 	if (cur->type == XML_NAMESPACE_DECL) break;
12609 	if ((cur->children != NULL) && (depth < max_depth)) {
12610 	    /*
12611 	     * Do not descend on entities declarations
12612 	     */
12613 	    if (cur->children->type != XML_ENTITY_DECL) {
12614 		cur = cur->children;
12615 		depth++;
12616 		/*
12617 		 * Skip DTDs
12618 		 */
12619 		if (cur->type != XML_DTD_NODE)
12620 		    continue;
12621 	    }
12622 	}
12623 
12624 	if (cur == limit)
12625 	    break;
12626 
12627 	while (cur->next != NULL) {
12628 	    cur = cur->next;
12629 	    if ((cur->type != XML_ENTITY_DECL) &&
12630 		(cur->type != XML_DTD_NODE))
12631 		goto next_node;
12632 	}
12633 
12634 	do {
12635 	    cur = cur->parent;
12636 	    depth--;
12637 	    if ((cur == NULL) || (cur == limit) ||
12638                 (cur->type == XML_DOCUMENT_NODE))
12639 	        goto done;
12640 	    if (cur->type == XML_ELEMENT_NODE) {
12641 		ret = xmlStreamPop(patstream);
12642 	    } else if ((eval_all_nodes) &&
12643 		((cur->type == XML_TEXT_NODE) ||
12644 		 (cur->type == XML_CDATA_SECTION_NODE) ||
12645 		 (cur->type == XML_COMMENT_NODE) ||
12646 		 (cur->type == XML_PI_NODE)))
12647 	    {
12648 		ret = xmlStreamPop(patstream);
12649 	    }
12650 	    if (cur->next != NULL) {
12651 		cur = cur->next;
12652 		break;
12653 	    }
12654 	} while (cur != NULL);
12655 
12656     } while ((cur != NULL) && (depth >= 0));
12657 
12658 done:
12659 
12660     if (patstream)
12661 	xmlFreeStreamCtxt(patstream);
12662     return(0);
12663 
12664 return_1:
12665     if (patstream)
12666 	xmlFreeStreamCtxt(patstream);
12667     return(1);
12668 }
12669 #endif /* XPATH_STREAMING */
12670 
12671 /**
12672  * xmlXPathRunEval:
12673  * @ctxt:  the XPath parser context with the compiled expression
12674  * @toBool:  evaluate to a boolean result
12675  *
12676  * Evaluate the Precompiled XPath expression in the given context.
12677  */
12678 static int
xmlXPathRunEval(xmlXPathParserContextPtr ctxt,int toBool)12679 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
12680 {
12681     xmlXPathCompExprPtr comp;
12682     int oldDepth;
12683 
12684     if ((ctxt == NULL) || (ctxt->comp == NULL))
12685 	return(-1);
12686 
12687     if (ctxt->valueTab == NULL) {
12688 	/* Allocate the value stack */
12689 	ctxt->valueTab = (xmlXPathObjectPtr *)
12690 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
12691 	if (ctxt->valueTab == NULL) {
12692 	    xmlXPathPErrMemory(ctxt);
12693 	    return(-1);
12694 	}
12695 	ctxt->valueNr = 0;
12696 	ctxt->valueMax = 10;
12697 	ctxt->value = NULL;
12698     }
12699 #ifdef XPATH_STREAMING
12700     if (ctxt->comp->stream) {
12701 	int res;
12702 
12703 	if (toBool) {
12704 	    /*
12705 	    * Evaluation to boolean result.
12706 	    */
12707 	    res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, NULL, 1);
12708 	    if (res != -1)
12709 		return(res);
12710 	} else {
12711 	    xmlXPathObjectPtr resObj = NULL;
12712 
12713 	    /*
12714 	    * Evaluation to a sequence.
12715 	    */
12716 	    res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, &resObj, 0);
12717 
12718 	    if ((res != -1) && (resObj != NULL)) {
12719 		valuePush(ctxt, resObj);
12720 		return(0);
12721 	    }
12722 	    if (resObj != NULL)
12723 		xmlXPathReleaseObject(ctxt->context, resObj);
12724 	}
12725 	/*
12726 	* QUESTION TODO: This falls back to normal XPath evaluation
12727 	* if res == -1. Is this intended?
12728 	*/
12729     }
12730 #endif
12731     comp = ctxt->comp;
12732     if (comp->last < 0) {
12733         xmlXPathErr(ctxt, XPATH_STACK_ERROR);
12734 	return(-1);
12735     }
12736     oldDepth = ctxt->context->depth;
12737     if (toBool)
12738 	return(xmlXPathCompOpEvalToBoolean(ctxt,
12739 	    &comp->steps[comp->last], 0));
12740     else
12741 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
12742     ctxt->context->depth = oldDepth;
12743 
12744     return(0);
12745 }
12746 
12747 /************************************************************************
12748  *									*
12749  *			Public interfaces				*
12750  *									*
12751  ************************************************************************/
12752 
12753 /**
12754  * xmlXPathEvalPredicate:
12755  * @ctxt:  the XPath context
12756  * @res:  the Predicate Expression evaluation result
12757  *
12758  * Evaluate a predicate result for the current node.
12759  * A PredicateExpr is evaluated by evaluating the Expr and converting
12760  * the result to a boolean. If the result is a number, the result will
12761  * be converted to true if the number is equal to the position of the
12762  * context node in the context node list (as returned by the position
12763  * function) and will be converted to false otherwise; if the result
12764  * is not a number, then the result will be converted as if by a call
12765  * to the boolean function.
12766  *
12767  * Returns 1 if predicate is true, 0 otherwise
12768  */
12769 int
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt,xmlXPathObjectPtr res)12770 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
12771     if ((ctxt == NULL) || (res == NULL)) return(0);
12772     switch (res->type) {
12773         case XPATH_BOOLEAN:
12774 	    return(res->boolval);
12775         case XPATH_NUMBER:
12776 	    return(res->floatval == ctxt->proximityPosition);
12777         case XPATH_NODESET:
12778         case XPATH_XSLT_TREE:
12779 	    if (res->nodesetval == NULL)
12780 		return(0);
12781 	    return(res->nodesetval->nodeNr != 0);
12782         case XPATH_STRING:
12783 	    return((res->stringval != NULL) &&
12784 	           (xmlStrlen(res->stringval) != 0));
12785         default:
12786 	    break;
12787     }
12788     return(0);
12789 }
12790 
12791 /**
12792  * xmlXPathEvaluatePredicateResult:
12793  * @ctxt:  the XPath Parser context
12794  * @res:  the Predicate Expression evaluation result
12795  *
12796  * Evaluate a predicate result for the current node.
12797  * A PredicateExpr is evaluated by evaluating the Expr and converting
12798  * the result to a boolean. If the result is a number, the result will
12799  * be converted to true if the number is equal to the position of the
12800  * context node in the context node list (as returned by the position
12801  * function) and will be converted to false otherwise; if the result
12802  * is not a number, then the result will be converted as if by a call
12803  * to the boolean function.
12804  *
12805  * Returns 1 if predicate is true, 0 otherwise
12806  */
12807 int
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr res)12808 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
12809                                 xmlXPathObjectPtr res) {
12810     if ((ctxt == NULL) || (res == NULL)) return(0);
12811     switch (res->type) {
12812         case XPATH_BOOLEAN:
12813 	    return(res->boolval);
12814         case XPATH_NUMBER:
12815 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
12816 	    return((res->floatval == ctxt->context->proximityPosition) &&
12817 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
12818 #else
12819 	    return(res->floatval == ctxt->context->proximityPosition);
12820 #endif
12821         case XPATH_NODESET:
12822         case XPATH_XSLT_TREE:
12823 	    if (res->nodesetval == NULL)
12824 		return(0);
12825 	    return(res->nodesetval->nodeNr != 0);
12826         case XPATH_STRING:
12827 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
12828 #ifdef LIBXML_XPTR_LOCS_ENABLED
12829 	case XPATH_LOCATIONSET:{
12830 	    xmlLocationSetPtr ptr = res->user;
12831 	    if (ptr == NULL)
12832 	        return(0);
12833 	    return (ptr->locNr != 0);
12834 	    }
12835 #endif
12836         default:
12837 	    break;
12838     }
12839     return(0);
12840 }
12841 
12842 #ifdef XPATH_STREAMING
12843 /**
12844  * xmlXPathTryStreamCompile:
12845  * @ctxt: an XPath context
12846  * @str:  the XPath expression
12847  *
12848  * Try to compile the XPath expression as a streamable subset.
12849  *
12850  * Returns the compiled expression or NULL if failed to compile.
12851  */
12852 static xmlXPathCompExprPtr
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt,const xmlChar * str)12853 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
12854     /*
12855      * Optimization: use streaming patterns when the XPath expression can
12856      * be compiled to a stream lookup
12857      */
12858     xmlPatternPtr stream;
12859     xmlXPathCompExprPtr comp;
12860     xmlDictPtr dict = NULL;
12861     const xmlChar **namespaces = NULL;
12862     xmlNsPtr ns;
12863     int i, j;
12864 
12865     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
12866         (!xmlStrchr(str, '@'))) {
12867 	const xmlChar *tmp;
12868         int res;
12869 
12870 	/*
12871 	 * We don't try to handle expressions using the verbose axis
12872 	 * specifiers ("::"), just the simplified form at this point.
12873 	 * Additionally, if there is no list of namespaces available and
12874 	 *  there's a ":" in the expression, indicating a prefixed QName,
12875 	 *  then we won't try to compile either. xmlPatterncompile() needs
12876 	 *  to have a list of namespaces at compilation time in order to
12877 	 *  compile prefixed name tests.
12878 	 */
12879 	tmp = xmlStrchr(str, ':');
12880 	if ((tmp != NULL) &&
12881 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
12882 	    return(NULL);
12883 
12884 	if (ctxt != NULL) {
12885 	    dict = ctxt->dict;
12886 	    if (ctxt->nsNr > 0) {
12887 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
12888 		if (namespaces == NULL) {
12889 		    xmlXPathErrMemory(ctxt);
12890 		    return(NULL);
12891 		}
12892 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
12893 		    ns = ctxt->namespaces[j];
12894 		    namespaces[i++] = ns->href;
12895 		    namespaces[i++] = ns->prefix;
12896 		}
12897 		namespaces[i++] = NULL;
12898 		namespaces[i] = NULL;
12899 	    }
12900 	}
12901 
12902 	res = xmlPatternCompileSafe(str, dict, XML_PATTERN_XPATH, namespaces,
12903                                     &stream);
12904 	if (namespaces != NULL) {
12905 	    xmlFree((xmlChar **)namespaces);
12906 	}
12907         if (res < 0) {
12908             xmlXPathErrMemory(ctxt);
12909             return(NULL);
12910         }
12911 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
12912 	    comp = xmlXPathNewCompExpr();
12913 	    if (comp == NULL) {
12914 		xmlXPathErrMemory(ctxt);
12915 	        xmlFreePattern(stream);
12916 		return(NULL);
12917 	    }
12918 	    comp->stream = stream;
12919 	    comp->dict = dict;
12920 	    if (comp->dict)
12921 		xmlDictReference(comp->dict);
12922 	    return(comp);
12923 	}
12924 	xmlFreePattern(stream);
12925     }
12926     return(NULL);
12927 }
12928 #endif /* XPATH_STREAMING */
12929 
12930 static void
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,xmlXPathStepOpPtr op)12931 xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
12932                            xmlXPathStepOpPtr op)
12933 {
12934     xmlXPathCompExprPtr comp = pctxt->comp;
12935     xmlXPathContextPtr ctxt;
12936 
12937     /*
12938     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
12939     * internal representation.
12940     */
12941 
12942     if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
12943         (op->ch1 != -1) &&
12944         (op->ch2 == -1 /* no predicate */))
12945     {
12946         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
12947 
12948         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
12949             ((xmlXPathAxisVal) prevop->value ==
12950                 AXIS_DESCENDANT_OR_SELF) &&
12951             (prevop->ch2 == -1) &&
12952             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
12953             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
12954         {
12955             /*
12956             * This is a "descendant-or-self::node()" without predicates.
12957             * Try to eliminate it.
12958             */
12959 
12960             switch ((xmlXPathAxisVal) op->value) {
12961                 case AXIS_CHILD:
12962                 case AXIS_DESCENDANT:
12963                     /*
12964                     * Convert "descendant-or-self::node()/child::" or
12965                     * "descendant-or-self::node()/descendant::" to
12966                     * "descendant::"
12967                     */
12968                     op->ch1   = prevop->ch1;
12969                     op->value = AXIS_DESCENDANT;
12970                     break;
12971                 case AXIS_SELF:
12972                 case AXIS_DESCENDANT_OR_SELF:
12973                     /*
12974                     * Convert "descendant-or-self::node()/self::" or
12975                     * "descendant-or-self::node()/descendant-or-self::" to
12976                     * to "descendant-or-self::"
12977                     */
12978                     op->ch1   = prevop->ch1;
12979                     op->value = AXIS_DESCENDANT_OR_SELF;
12980                     break;
12981                 default:
12982                     break;
12983             }
12984 	}
12985     }
12986 
12987     /* OP_VALUE has invalid ch1. */
12988     if (op->op == XPATH_OP_VALUE)
12989         return;
12990 
12991     /* Recurse */
12992     ctxt = pctxt->context;
12993     if (ctxt != NULL) {
12994         if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
12995             return;
12996         ctxt->depth += 1;
12997     }
12998     if (op->ch1 != -1)
12999         xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
13000     if (op->ch2 != -1)
13001 	xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
13002     if (ctxt != NULL)
13003         ctxt->depth -= 1;
13004 }
13005 
13006 /**
13007  * xmlXPathCtxtCompile:
13008  * @ctxt: an XPath context
13009  * @str:  the XPath expression
13010  *
13011  * Compile an XPath expression
13012  *
13013  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
13014  *         the caller has to free the object.
13015  */
13016 xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt,const xmlChar * str)13017 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
13018     xmlXPathParserContextPtr pctxt;
13019     xmlXPathCompExprPtr comp;
13020     int oldDepth = 0;
13021 
13022 #ifdef XPATH_STREAMING
13023     comp = xmlXPathTryStreamCompile(ctxt, str);
13024     if (comp != NULL)
13025         return(comp);
13026 #endif
13027 
13028     xmlInitParser();
13029 
13030     pctxt = xmlXPathNewParserContext(str, ctxt);
13031     if (pctxt == NULL)
13032         return NULL;
13033     if (ctxt != NULL)
13034         oldDepth = ctxt->depth;
13035     xmlXPathCompileExpr(pctxt, 1);
13036     if (ctxt != NULL)
13037         ctxt->depth = oldDepth;
13038 
13039     if( pctxt->error != XPATH_EXPRESSION_OK )
13040     {
13041         xmlXPathFreeParserContext(pctxt);
13042         return(NULL);
13043     }
13044 
13045     if (*pctxt->cur != 0) {
13046 	/*
13047 	 * aleksey: in some cases this line prints *second* error message
13048 	 * (see bug #78858) and probably this should be fixed.
13049 	 * However, we are not sure that all error messages are printed
13050 	 * out in other places. It's not critical so we leave it as-is for now
13051 	 */
13052 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
13053 	comp = NULL;
13054     } else {
13055 	comp = pctxt->comp;
13056 	if ((comp->nbStep > 1) && (comp->last >= 0)) {
13057             if (ctxt != NULL)
13058                 oldDepth = ctxt->depth;
13059 	    xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
13060             if (ctxt != NULL)
13061                 ctxt->depth = oldDepth;
13062 	}
13063 	pctxt->comp = NULL;
13064     }
13065     xmlXPathFreeParserContext(pctxt);
13066 
13067     if (comp != NULL) {
13068 	comp->expr = xmlStrdup(str);
13069     }
13070     return(comp);
13071 }
13072 
13073 /**
13074  * xmlXPathCompile:
13075  * @str:  the XPath expression
13076  *
13077  * Compile an XPath expression
13078  *
13079  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
13080  *         the caller has to free the object.
13081  */
13082 xmlXPathCompExprPtr
xmlXPathCompile(const xmlChar * str)13083 xmlXPathCompile(const xmlChar *str) {
13084     return(xmlXPathCtxtCompile(NULL, str));
13085 }
13086 
13087 /**
13088  * xmlXPathCompiledEvalInternal:
13089  * @comp:  the compiled XPath expression
13090  * @ctxt:  the XPath context
13091  * @resObj: the resulting XPath object or NULL
13092  * @toBool: 1 if only a boolean result is requested
13093  *
13094  * Evaluate the Precompiled XPath expression in the given context.
13095  * The caller has to free @resObj.
13096  *
13097  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13098  *         the caller has to free the object.
13099  */
13100 static int
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt,xmlXPathObjectPtr * resObjPtr,int toBool)13101 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
13102 			     xmlXPathContextPtr ctxt,
13103 			     xmlXPathObjectPtr *resObjPtr,
13104 			     int toBool)
13105 {
13106     xmlXPathParserContextPtr pctxt;
13107     xmlXPathObjectPtr resObj = NULL;
13108 #ifndef LIBXML_THREAD_ENABLED
13109     static int reentance = 0;
13110 #endif
13111     int res;
13112 
13113     if (comp == NULL)
13114 	return(-1);
13115     xmlInitParser();
13116 
13117     xmlResetError(&ctxt->lastError);
13118 
13119 #ifndef LIBXML_THREAD_ENABLED
13120     reentance++;
13121     if (reentance > 1)
13122 	xmlXPathDisableOptimizer = 1;
13123 #endif
13124 
13125     pctxt = xmlXPathCompParserContext(comp, ctxt);
13126     if (pctxt == NULL)
13127         return(-1);
13128     res = xmlXPathRunEval(pctxt, toBool);
13129 
13130     if (pctxt->error == XPATH_EXPRESSION_OK) {
13131         if (pctxt->valueNr != ((toBool) ? 0 : 1))
13132             xmlXPathErr(pctxt, XPATH_STACK_ERROR);
13133         else if (!toBool)
13134             resObj = valuePop(pctxt);
13135     }
13136 
13137     if (resObjPtr)
13138         *resObjPtr = resObj;
13139     else
13140         xmlXPathReleaseObject(ctxt, resObj);
13141 
13142     pctxt->comp = NULL;
13143     xmlXPathFreeParserContext(pctxt);
13144 #ifndef LIBXML_THREAD_ENABLED
13145     reentance--;
13146 #endif
13147 
13148     return(res);
13149 }
13150 
13151 /**
13152  * xmlXPathCompiledEval:
13153  * @comp:  the compiled XPath expression
13154  * @ctx:  the XPath context
13155  *
13156  * Evaluate the Precompiled XPath expression in the given context.
13157  *
13158  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13159  *         the caller has to free the object.
13160  */
13161 xmlXPathObjectPtr
xmlXPathCompiledEval(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctx)13162 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
13163 {
13164     xmlXPathObjectPtr res = NULL;
13165 
13166     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
13167     return(res);
13168 }
13169 
13170 /**
13171  * xmlXPathCompiledEvalToBoolean:
13172  * @comp:  the compiled XPath expression
13173  * @ctxt:  the XPath context
13174  *
13175  * Applies the XPath boolean() function on the result of the given
13176  * compiled expression.
13177  *
13178  * Returns 1 if the expression evaluated to true, 0 if to false and
13179  *         -1 in API and internal errors.
13180  */
13181 int
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)13182 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
13183 			      xmlXPathContextPtr ctxt)
13184 {
13185     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
13186 }
13187 
13188 /**
13189  * xmlXPathEvalExpr:
13190  * @ctxt:  the XPath Parser context
13191  *
13192  * Parse and evaluate an XPath expression in the given context,
13193  * then push the result on the context stack
13194  */
13195 void
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt)13196 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
13197 #ifdef XPATH_STREAMING
13198     xmlXPathCompExprPtr comp;
13199 #endif
13200     int oldDepth = 0;
13201 
13202     if (ctxt == NULL)
13203         return;
13204     if (ctxt->context->lastError.code != 0)
13205         return;
13206 
13207 #ifdef XPATH_STREAMING
13208     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
13209     if ((comp == NULL) &&
13210         (ctxt->context->lastError.code == XML_ERR_NO_MEMORY)) {
13211         xmlXPathPErrMemory(ctxt);
13212         return;
13213     }
13214     if (comp != NULL) {
13215         if (ctxt->comp != NULL)
13216 	    xmlXPathFreeCompExpr(ctxt->comp);
13217         ctxt->comp = comp;
13218     } else
13219 #endif
13220     {
13221         if (ctxt->context != NULL)
13222             oldDepth = ctxt->context->depth;
13223 	xmlXPathCompileExpr(ctxt, 1);
13224         if (ctxt->context != NULL)
13225             ctxt->context->depth = oldDepth;
13226         CHECK_ERROR;
13227 
13228         /* Check for trailing characters. */
13229         if (*ctxt->cur != 0)
13230             XP_ERROR(XPATH_EXPR_ERROR);
13231 
13232 	if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
13233             if (ctxt->context != NULL)
13234                 oldDepth = ctxt->context->depth;
13235 	    xmlXPathOptimizeExpression(ctxt,
13236 		&ctxt->comp->steps[ctxt->comp->last]);
13237             if (ctxt->context != NULL)
13238                 ctxt->context->depth = oldDepth;
13239         }
13240     }
13241 
13242     xmlXPathRunEval(ctxt, 0);
13243 }
13244 
13245 /**
13246  * xmlXPathEval:
13247  * @str:  the XPath expression
13248  * @ctx:  the XPath context
13249  *
13250  * Evaluate the XPath Location Path in the given context.
13251  *
13252  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13253  *         the caller has to free the object.
13254  */
13255 xmlXPathObjectPtr
xmlXPathEval(const xmlChar * str,xmlXPathContextPtr ctx)13256 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
13257     xmlXPathParserContextPtr ctxt;
13258     xmlXPathObjectPtr res;
13259 
13260     if (ctx == NULL)
13261         return(NULL);
13262 
13263     xmlInitParser();
13264 
13265     xmlResetError(&ctx->lastError);
13266 
13267     ctxt = xmlXPathNewParserContext(str, ctx);
13268     if (ctxt == NULL)
13269         return NULL;
13270     xmlXPathEvalExpr(ctxt);
13271 
13272     if (ctxt->error != XPATH_EXPRESSION_OK) {
13273 	res = NULL;
13274     } else if (ctxt->valueNr != 1) {
13275         xmlXPathErr(ctxt, XPATH_STACK_ERROR);
13276 	res = NULL;
13277     } else {
13278 	res = valuePop(ctxt);
13279     }
13280 
13281     xmlXPathFreeParserContext(ctxt);
13282     return(res);
13283 }
13284 
13285 /**
13286  * xmlXPathSetContextNode:
13287  * @node: the node to to use as the context node
13288  * @ctx:  the XPath context
13289  *
13290  * Sets 'node' as the context node. The node must be in the same
13291  * document as that associated with the context.
13292  *
13293  * Returns -1 in case of error or 0 if successful
13294  */
13295 int
xmlXPathSetContextNode(xmlNodePtr node,xmlXPathContextPtr ctx)13296 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
13297     if ((node == NULL) || (ctx == NULL))
13298         return(-1);
13299 
13300     if (node->doc == ctx->doc) {
13301         ctx->node = node;
13302 	return(0);
13303     }
13304     return(-1);
13305 }
13306 
13307 /**
13308  * xmlXPathNodeEval:
13309  * @node: the node to to use as the context node
13310  * @str:  the XPath expression
13311  * @ctx:  the XPath context
13312  *
13313  * Evaluate the XPath Location Path in the given context. The node 'node'
13314  * is set as the context node. The context node is not restored.
13315  *
13316  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13317  *         the caller has to free the object.
13318  */
13319 xmlXPathObjectPtr
xmlXPathNodeEval(xmlNodePtr node,const xmlChar * str,xmlXPathContextPtr ctx)13320 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
13321     if (str == NULL)
13322         return(NULL);
13323     if (xmlXPathSetContextNode(node, ctx) < 0)
13324         return(NULL);
13325     return(xmlXPathEval(str, ctx));
13326 }
13327 
13328 /**
13329  * xmlXPathEvalExpression:
13330  * @str:  the XPath expression
13331  * @ctxt:  the XPath context
13332  *
13333  * Alias for xmlXPathEval().
13334  *
13335  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13336  *         the caller has to free the object.
13337  */
13338 xmlXPathObjectPtr
xmlXPathEvalExpression(const xmlChar * str,xmlXPathContextPtr ctxt)13339 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
13340     return(xmlXPathEval(str, ctxt));
13341 }
13342 
13343 /************************************************************************
13344  *									*
13345  *	Extra functions not pertaining to the XPath spec		*
13346  *									*
13347  ************************************************************************/
13348 /**
13349  * xmlXPathEscapeUriFunction:
13350  * @ctxt:  the XPath Parser context
13351  * @nargs:  the number of arguments
13352  *
13353  * Implement the escape-uri() XPath function
13354  *    string escape-uri(string $str, bool $escape-reserved)
13355  *
13356  * This function applies the URI escaping rules defined in section 2 of [RFC
13357  * 2396] to the string supplied as $uri-part, which typically represents all
13358  * or part of a URI. The effect of the function is to replace any special
13359  * character in the string by an escape sequence of the form %xx%yy...,
13360  * where xxyy... is the hexadecimal representation of the octets used to
13361  * represent the character in UTF-8.
13362  *
13363  * The set of characters that are escaped depends on the setting of the
13364  * boolean argument $escape-reserved.
13365  *
13366  * If $escape-reserved is true, all characters are escaped other than lower
13367  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
13368  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
13369  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
13370  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
13371  * A-F).
13372  *
13373  * If $escape-reserved is false, the behavior differs in that characters
13374  * referred to in [RFC 2396] as reserved characters are not escaped. These
13375  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
13376  *
13377  * [RFC 2396] does not define whether escaped URIs should use lower case or
13378  * upper case for hexadecimal digits. To ensure that escaped URIs can be
13379  * compared using string comparison functions, this function must always use
13380  * the upper-case letters A-F.
13381  *
13382  * Generally, $escape-reserved should be set to true when escaping a string
13383  * that is to form a single part of a URI, and to false when escaping an
13384  * entire URI or URI reference.
13385  *
13386  * In the case of non-ascii characters, the string is encoded according to
13387  * utf-8 and then converted according to RFC 2396.
13388  *
13389  * Examples
13390  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
13391  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
13392  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
13393  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
13394  *
13395  */
13396 static void
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt,int nargs)13397 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
13398     xmlXPathObjectPtr str;
13399     int escape_reserved;
13400     xmlBufPtr target;
13401     xmlChar *cptr;
13402     xmlChar escape[4];
13403 
13404     CHECK_ARITY(2);
13405 
13406     escape_reserved = xmlXPathPopBoolean(ctxt);
13407 
13408     CAST_TO_STRING;
13409     str = valuePop(ctxt);
13410 
13411     target = xmlBufCreate();
13412 
13413     escape[0] = '%';
13414     escape[3] = 0;
13415 
13416     if (target) {
13417 	for (cptr = str->stringval; *cptr; cptr++) {
13418 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
13419 		(*cptr >= 'a' && *cptr <= 'z') ||
13420 		(*cptr >= '0' && *cptr <= '9') ||
13421 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
13422 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
13423 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
13424 		(*cptr == '%' &&
13425 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
13426 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
13427 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
13428 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
13429 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
13430 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
13431 		(!escape_reserved &&
13432 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
13433 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
13434 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
13435 		  *cptr == ','))) {
13436 		xmlBufAdd(target, cptr, 1);
13437 	    } else {
13438 		if ((*cptr >> 4) < 10)
13439 		    escape[1] = '0' + (*cptr >> 4);
13440 		else
13441 		    escape[1] = 'A' - 10 + (*cptr >> 4);
13442 		if ((*cptr & 0xF) < 10)
13443 		    escape[2] = '0' + (*cptr & 0xF);
13444 		else
13445 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
13446 
13447 		xmlBufAdd(target, &escape[0], 3);
13448 	    }
13449 	}
13450     }
13451     valuePush(ctxt, xmlXPathCacheNewString(ctxt, xmlBufContent(target)));
13452     xmlBufFree(target);
13453     xmlXPathReleaseObject(ctxt->context, str);
13454 }
13455 
13456 /**
13457  * xmlXPathRegisterAllFunctions:
13458  * @ctxt:  the XPath context
13459  *
13460  * Registers all default XPath functions in this context
13461  */
13462 void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)13463 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
13464 {
13465     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
13466                          xmlXPathBooleanFunction);
13467     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
13468                          xmlXPathCeilingFunction);
13469     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
13470                          xmlXPathCountFunction);
13471     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
13472                          xmlXPathConcatFunction);
13473     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
13474                          xmlXPathContainsFunction);
13475     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
13476                          xmlXPathIdFunction);
13477     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
13478                          xmlXPathFalseFunction);
13479     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
13480                          xmlXPathFloorFunction);
13481     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
13482                          xmlXPathLastFunction);
13483     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
13484                          xmlXPathLangFunction);
13485     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
13486                          xmlXPathLocalNameFunction);
13487     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
13488                          xmlXPathNotFunction);
13489     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
13490                          xmlXPathNameFunction);
13491     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
13492                          xmlXPathNamespaceURIFunction);
13493     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
13494                          xmlXPathNormalizeFunction);
13495     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
13496                          xmlXPathNumberFunction);
13497     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
13498                          xmlXPathPositionFunction);
13499     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
13500                          xmlXPathRoundFunction);
13501     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
13502                          xmlXPathStringFunction);
13503     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
13504                          xmlXPathStringLengthFunction);
13505     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
13506                          xmlXPathStartsWithFunction);
13507     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
13508                          xmlXPathSubstringFunction);
13509     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
13510                          xmlXPathSubstringBeforeFunction);
13511     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
13512                          xmlXPathSubstringAfterFunction);
13513     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
13514                          xmlXPathSumFunction);
13515     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
13516                          xmlXPathTrueFunction);
13517     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
13518                          xmlXPathTranslateFunction);
13519 
13520     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
13521 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
13522                          xmlXPathEscapeUriFunction);
13523 }
13524 
13525 #endif /* LIBXML_XPATH_ENABLED */
13526