• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * xpath.c: XML Path Language implementation
3  *          XPath is a language for addressing parts of an XML document,
4  *          designed to be used by both XSLT and XPointer
5  *
6  * Reference: W3C Recommendation 16 November 1999
7  *     http://www.w3.org/TR/1999/REC-xpath-19991116
8  * Public reference:
9  *     http://www.w3.org/TR/xpath
10  *
11  * See Copyright for the status of this software
12  *
13  * Author: daniel@veillard.com
14  *
15  */
16 
17 /* To avoid EBCDIC trouble when parsing on zOS */
18 #if defined(__MVS__)
19 #pragma convert("ISO8859-1")
20 #endif
21 
22 #define IN_LIBXML
23 #include "libxml.h"
24 
25 #include <limits.h>
26 #include <string.h>
27 #include <stddef.h>
28 #include <math.h>
29 #include <float.h>
30 #include <ctype.h>
31 
32 #include <libxml/xmlmemory.h>
33 #include <libxml/tree.h>
34 #include <libxml/xpath.h>
35 #include <libxml/xpathInternals.h>
36 #include <libxml/parserInternals.h>
37 #include <libxml/hash.h>
38 #ifdef LIBXML_DEBUG_ENABLED
39 #include <libxml/debugXML.h>
40 #endif
41 #include <libxml/xmlerror.h>
42 #include <libxml/threads.h>
43 #ifdef LIBXML_PATTERN_ENABLED
44 #include <libxml/pattern.h>
45 #endif
46 
47 #include "private/buf.h"
48 #include "private/error.h"
49 #include "private/xpath.h"
50 
51 /* Disabled for now */
52 #if 0
53 #ifdef LIBXML_PATTERN_ENABLED
54 #define XPATH_STREAMING
55 #endif
56 #endif
57 
58 /**
59  * WITH_TIM_SORT:
60  *
61  * Use the Timsort algorithm provided in timsort.h to sort
62  * nodeset as this is a great improvement over the old Shell sort
63  * used in xmlXPathNodeSetSort()
64  */
65 #define WITH_TIM_SORT
66 
67 /*
68 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
69 * If defined, this will use xmlXPathCmpNodesExt() instead of
70 * xmlXPathCmpNodes(). The new function is optimized comparison of
71 * non-element nodes; actually it will speed up comparison only if
72 * xmlXPathOrderDocElems() was called in order to index the elements of
73 * a tree in document order; Libxslt does such an indexing, thus it will
74 * benefit from this optimization.
75 */
76 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
77 
78 /*
79 * XP_OPTIMIZED_FILTER_FIRST:
80 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
81 * in a way, that it stop evaluation at the first node.
82 */
83 #define XP_OPTIMIZED_FILTER_FIRST
84 
85 /*
86  * XPATH_MAX_STEPS:
87  * when compiling an XPath expression we arbitrary limit the maximum
88  * number of step operation in the compiled expression. 1000000 is
89  * an insanely large value which should never be reached under normal
90  * circumstances
91  */
92 #define XPATH_MAX_STEPS 1000000
93 
94 /*
95  * XPATH_MAX_STACK_DEPTH:
96  * when evaluating an XPath expression we arbitrary limit the maximum
97  * number of object allowed to be pushed on the stack. 1000000 is
98  * an insanely large value which should never be reached under normal
99  * circumstances
100  */
101 #define XPATH_MAX_STACK_DEPTH 1000000
102 
103 /*
104  * XPATH_MAX_NODESET_LENGTH:
105  * when evaluating an XPath expression nodesets are created and we
106  * arbitrary limit the maximum length of those node set. 10000000 is
107  * an insanely large value which should never be reached under normal
108  * circumstances, one would first need to construct an in memory tree
109  * with more than 10 millions nodes.
110  */
111 #define XPATH_MAX_NODESET_LENGTH 10000000
112 
113 /*
114  * XPATH_MAX_RECRUSION_DEPTH:
115  * Maximum amount of nested functions calls when parsing or evaluating
116  * expressions
117  */
118 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
119 #define XPATH_MAX_RECURSION_DEPTH 500
120 #elif defined(_WIN32)
121 /* Windows typically limits stack size to 1MB. */
122 #define XPATH_MAX_RECURSION_DEPTH 1000
123 #else
124 #define XPATH_MAX_RECURSION_DEPTH 5000
125 #endif
126 
127 /*
128  * TODO:
129  * There are a few spots where some tests are done which depend upon ascii
130  * data.  These should be enhanced for full UTF8 support (see particularly
131  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
132  */
133 
134 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
135 
136 /************************************************************************
137  *									*
138  *			Floating point stuff				*
139  *									*
140  ************************************************************************/
141 
142 double xmlXPathNAN = 0.0;
143 double xmlXPathPINF = 0.0;
144 double xmlXPathNINF = 0.0;
145 
146 /**
147  * xmlXPathInit:
148  *
149  * DEPRECATED: Alias for xmlInitParser.
150  */
151 void
xmlXPathInit(void)152 xmlXPathInit(void) {
153     xmlInitParser();
154 }
155 
156 /**
157  * xmlInitXPathInternal:
158  *
159  * Initialize the XPath environment
160  */
161 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
162 void
xmlInitXPathInternal(void)163 xmlInitXPathInternal(void) {
164 #if defined(NAN) && defined(INFINITY)
165     xmlXPathNAN = NAN;
166     xmlXPathPINF = INFINITY;
167     xmlXPathNINF = -INFINITY;
168 #else
169     /* MSVC doesn't allow division by zero in constant expressions. */
170     double zero = 0.0;
171     xmlXPathNAN = 0.0 / zero;
172     xmlXPathPINF = 1.0 / zero;
173     xmlXPathNINF = -xmlXPathPINF;
174 #endif
175 }
176 
177 /**
178  * xmlXPathIsNaN:
179  * @val:  a double value
180  *
181  * Checks whether a double is a NaN.
182  *
183  * Returns 1 if the value is a NaN, 0 otherwise
184  */
185 int
xmlXPathIsNaN(double val)186 xmlXPathIsNaN(double val) {
187 #ifdef isnan
188     return isnan(val);
189 #else
190     return !(val == val);
191 #endif
192 }
193 
194 /**
195  * xmlXPathIsInf:
196  * @val:  a double value
197  *
198  * Checks whether a double is an infinity.
199  *
200  * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
201  */
202 int
xmlXPathIsInf(double val)203 xmlXPathIsInf(double val) {
204 #ifdef isinf
205     return isinf(val) ? (val > 0 ? 1 : -1) : 0;
206 #else
207     if (val >= xmlXPathPINF)
208         return 1;
209     if (val <= -xmlXPathPINF)
210         return -1;
211     return 0;
212 #endif
213 }
214 
215 #endif /* SCHEMAS or XPATH */
216 
217 #ifdef LIBXML_XPATH_ENABLED
218 
219 /*
220  * TODO: when compatibility allows remove all "fake node libxslt" strings
221  *       the test should just be name[0] = ' '
222  */
223 
224 static const xmlNs xmlXPathXMLNamespaceStruct = {
225     NULL,
226     XML_NAMESPACE_DECL,
227     XML_XML_NAMESPACE,
228     BAD_CAST "xml",
229     NULL,
230     NULL
231 };
232 static const xmlNs *const xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
233 #ifndef LIBXML_THREAD_ENABLED
234 /*
235  * Optimizer is disabled only when threaded apps are detected while
236  * the library ain't compiled for thread safety.
237  */
238 static int xmlXPathDisableOptimizer = 0;
239 #endif
240 
241 static void
242 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes);
243 
244 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
245 /**
246  * xmlXPathCmpNodesExt:
247  * @node1:  the first node
248  * @node2:  the second node
249  *
250  * Compare two nodes w.r.t document order.
251  * This one is optimized for handling of non-element nodes.
252  *
253  * Returns -2 in case of error 1 if first point < second point, 0 if
254  *         it's the same node, -1 otherwise
255  */
256 static int
xmlXPathCmpNodesExt(xmlNodePtr node1,xmlNodePtr node2)257 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
258     int depth1, depth2;
259     int misc = 0, precedence1 = 0, precedence2 = 0;
260     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
261     xmlNodePtr cur, root;
262     ptrdiff_t l1, l2;
263 
264     if ((node1 == NULL) || (node2 == NULL))
265 	return(-2);
266 
267     if (node1 == node2)
268 	return(0);
269 
270     /*
271      * a couple of optimizations which will avoid computations in most cases
272      */
273     switch (node1->type) {
274 	case XML_ELEMENT_NODE:
275 	    if (node2->type == XML_ELEMENT_NODE) {
276 		if ((0 > (ptrdiff_t) node1->content) &&
277 		    (0 > (ptrdiff_t) node2->content) &&
278 		    (node1->doc == node2->doc))
279 		{
280 		    l1 = -((ptrdiff_t) node1->content);
281 		    l2 = -((ptrdiff_t) node2->content);
282 		    if (l1 < l2)
283 			return(1);
284 		    if (l1 > l2)
285 			return(-1);
286 		} else
287 		    goto turtle_comparison;
288 	    }
289 	    break;
290 	case XML_ATTRIBUTE_NODE:
291 	    precedence1 = 1; /* element is owner */
292 	    miscNode1 = node1;
293 	    node1 = node1->parent;
294 	    misc = 1;
295 	    break;
296 	case XML_TEXT_NODE:
297 	case XML_CDATA_SECTION_NODE:
298 	case XML_COMMENT_NODE:
299 	case XML_PI_NODE: {
300 	    miscNode1 = node1;
301 	    /*
302 	    * Find nearest element node.
303 	    */
304 	    if (node1->prev != NULL) {
305 		do {
306 		    node1 = node1->prev;
307 		    if (node1->type == XML_ELEMENT_NODE) {
308 			precedence1 = 3; /* element in prev-sibl axis */
309 			break;
310 		    }
311 		    if (node1->prev == NULL) {
312 			precedence1 = 2; /* element is parent */
313 			/*
314 			* URGENT TODO: Are there any cases, where the
315 			* parent of such a node is not an element node?
316 			*/
317 			node1 = node1->parent;
318 			break;
319 		    }
320 		} while (1);
321 	    } else {
322 		precedence1 = 2; /* element is parent */
323 		node1 = node1->parent;
324 	    }
325 	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
326 		(0 <= (ptrdiff_t) node1->content)) {
327 		/*
328 		* Fallback for whatever case.
329 		*/
330 		node1 = miscNode1;
331 		precedence1 = 0;
332 	    } else
333 		misc = 1;
334 	}
335 	    break;
336 	case XML_NAMESPACE_DECL:
337 	    /*
338 	    * TODO: why do we return 1 for namespace nodes?
339 	    */
340 	    return(1);
341 	default:
342 	    break;
343     }
344     switch (node2->type) {
345 	case XML_ELEMENT_NODE:
346 	    break;
347 	case XML_ATTRIBUTE_NODE:
348 	    precedence2 = 1; /* element is owner */
349 	    miscNode2 = node2;
350 	    node2 = node2->parent;
351 	    misc = 1;
352 	    break;
353 	case XML_TEXT_NODE:
354 	case XML_CDATA_SECTION_NODE:
355 	case XML_COMMENT_NODE:
356 	case XML_PI_NODE: {
357 	    miscNode2 = node2;
358 	    if (node2->prev != NULL) {
359 		do {
360 		    node2 = node2->prev;
361 		    if (node2->type == XML_ELEMENT_NODE) {
362 			precedence2 = 3; /* element in prev-sibl axis */
363 			break;
364 		    }
365 		    if (node2->prev == NULL) {
366 			precedence2 = 2; /* element is parent */
367 			node2 = node2->parent;
368 			break;
369 		    }
370 		} while (1);
371 	    } else {
372 		precedence2 = 2; /* element is parent */
373 		node2 = node2->parent;
374 	    }
375 	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
376 		(0 <= (ptrdiff_t) node2->content))
377 	    {
378 		node2 = miscNode2;
379 		precedence2 = 0;
380 	    } else
381 		misc = 1;
382 	}
383 	    break;
384 	case XML_NAMESPACE_DECL:
385 	    return(1);
386 	default:
387 	    break;
388     }
389     if (misc) {
390 	if (node1 == node2) {
391 	    if (precedence1 == precedence2) {
392 		/*
393 		* The ugly case; but normally there aren't many
394 		* adjacent non-element nodes around.
395 		*/
396 		cur = miscNode2->prev;
397 		while (cur != NULL) {
398 		    if (cur == miscNode1)
399 			return(1);
400 		    if (cur->type == XML_ELEMENT_NODE)
401 			return(-1);
402 		    cur = cur->prev;
403 		}
404 		return (-1);
405 	    } else {
406 		/*
407 		* Evaluate based on higher precedence wrt to the element.
408 		* TODO: This assumes attributes are sorted before content.
409 		*   Is this 100% correct?
410 		*/
411 		if (precedence1 < precedence2)
412 		    return(1);
413 		else
414 		    return(-1);
415 	    }
416 	}
417 	/*
418 	* Special case: One of the helper-elements is contained by the other.
419 	* <foo>
420 	*   <node2>
421 	*     <node1>Text-1(precedence1 == 2)</node1>
422 	*   </node2>
423 	*   Text-6(precedence2 == 3)
424 	* </foo>
425 	*/
426 	if ((precedence2 == 3) && (precedence1 > 1)) {
427 	    cur = node1->parent;
428 	    while (cur) {
429 		if (cur == node2)
430 		    return(1);
431 		cur = cur->parent;
432 	    }
433 	}
434 	if ((precedence1 == 3) && (precedence2 > 1)) {
435 	    cur = node2->parent;
436 	    while (cur) {
437 		if (cur == node1)
438 		    return(-1);
439 		cur = cur->parent;
440 	    }
441 	}
442     }
443 
444     /*
445      * Speedup using document order if available.
446      */
447     if ((node1->type == XML_ELEMENT_NODE) &&
448 	(node2->type == XML_ELEMENT_NODE) &&
449 	(0 > (ptrdiff_t) node1->content) &&
450 	(0 > (ptrdiff_t) node2->content) &&
451 	(node1->doc == node2->doc)) {
452 
453 	l1 = -((ptrdiff_t) node1->content);
454 	l2 = -((ptrdiff_t) node2->content);
455 	if (l1 < l2)
456 	    return(1);
457 	if (l1 > l2)
458 	    return(-1);
459     }
460 
461 turtle_comparison:
462 
463     if (node1 == node2->prev)
464 	return(1);
465     if (node1 == node2->next)
466 	return(-1);
467     /*
468      * compute depth to root
469      */
470     for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
471 	if (cur->parent == node1)
472 	    return(1);
473 	depth2++;
474     }
475     root = cur;
476     for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
477 	if (cur->parent == node2)
478 	    return(-1);
479 	depth1++;
480     }
481     /*
482      * Distinct document (or distinct entities :-( ) case.
483      */
484     if (root != cur) {
485 	return(-2);
486     }
487     /*
488      * get the nearest common ancestor.
489      */
490     while (depth1 > depth2) {
491 	depth1--;
492 	node1 = node1->parent;
493     }
494     while (depth2 > depth1) {
495 	depth2--;
496 	node2 = node2->parent;
497     }
498     while (node1->parent != node2->parent) {
499 	node1 = node1->parent;
500 	node2 = node2->parent;
501 	/* should not happen but just in case ... */
502 	if ((node1 == NULL) || (node2 == NULL))
503 	    return(-2);
504     }
505     /*
506      * Find who's first.
507      */
508     if (node1 == node2->prev)
509 	return(1);
510     if (node1 == node2->next)
511 	return(-1);
512     /*
513      * Speedup using document order if available.
514      */
515     if ((node1->type == XML_ELEMENT_NODE) &&
516 	(node2->type == XML_ELEMENT_NODE) &&
517 	(0 > (ptrdiff_t) node1->content) &&
518 	(0 > (ptrdiff_t) node2->content) &&
519 	(node1->doc == node2->doc)) {
520 
521 	l1 = -((ptrdiff_t) node1->content);
522 	l2 = -((ptrdiff_t) node2->content);
523 	if (l1 < l2)
524 	    return(1);
525 	if (l1 > l2)
526 	    return(-1);
527     }
528 
529     for (cur = node1->next;cur != NULL;cur = cur->next)
530 	if (cur == node2)
531 	    return(1);
532     return(-1); /* assume there is no sibling list corruption */
533 }
534 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
535 
536 /*
537  * Wrapper for the Timsort algorithm from timsort.h
538  */
539 #ifdef WITH_TIM_SORT
540 #define SORT_NAME libxml_domnode
541 #define SORT_TYPE xmlNodePtr
542 /**
543  * wrap_cmp:
544  * @x: a node
545  * @y: another node
546  *
547  * Comparison function for the Timsort implementation
548  *
549  * Returns -2 in case of error -1 if first point < second point, 0 if
550  *         it's the same node, +1 otherwise
551  */
552 static
553 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
554 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
wrap_cmp(xmlNodePtr x,xmlNodePtr y)555     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
556     {
557         int res = xmlXPathCmpNodesExt(x, y);
558         return res == -2 ? res : -res;
559     }
560 #else
wrap_cmp(xmlNodePtr x,xmlNodePtr y)561     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
562     {
563         int res = xmlXPathCmpNodes(x, y);
564         return res == -2 ? res : -res;
565     }
566 #endif
567 #define SORT_CMP(x, y)  (wrap_cmp(x, y))
568 #include "timsort.h"
569 #endif /* WITH_TIM_SORT */
570 
571 /************************************************************************
572  *									*
573  *			Error handling routines				*
574  *									*
575  ************************************************************************/
576 
577 /**
578  * XP_ERRORNULL:
579  * @X:  the error code
580  *
581  * Macro to raise an XPath error and return NULL.
582  */
583 #define XP_ERRORNULL(X)							\
584     { xmlXPathErr(ctxt, X); return(NULL); }
585 
586 /*
587  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
588  */
589 static const char* const xmlXPathErrorMessages[] = {
590     "Ok\n",
591     "Number encoding\n",
592     "Unfinished literal\n",
593     "Start of literal\n",
594     "Expected $ for variable reference\n",
595     "Undefined variable\n",
596     "Invalid predicate\n",
597     "Invalid expression\n",
598     "Missing closing curly brace\n",
599     "Unregistered function\n",
600     "Invalid operand\n",
601     "Invalid type\n",
602     "Invalid number of arguments\n",
603     "Invalid context size\n",
604     "Invalid context position\n",
605     "Memory allocation error\n",
606     "Syntax error\n",
607     "Resource error\n",
608     "Sub resource error\n",
609     "Undefined namespace prefix\n",
610     "Encoding error\n",
611     "Char out of XML range\n",
612     "Invalid or incomplete context\n",
613     "Stack usage error\n",
614     "Forbidden variable\n",
615     "Operation limit exceeded\n",
616     "Recursion limit exceeded\n",
617     "?? Unknown error ??\n"	/* Must be last in the list! */
618 };
619 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
620 		   sizeof(xmlXPathErrorMessages[0])) - 1)
621 /**
622  * xmlXPathErrMemory:
623  * @ctxt:  an XPath context
624  *
625  * Handle a memory allocation failure.
626  */
627 void
xmlXPathErrMemory(xmlXPathContextPtr ctxt)628 xmlXPathErrMemory(xmlXPathContextPtr ctxt)
629 {
630     if (ctxt == NULL)
631         return;
632     xmlRaiseMemoryError(ctxt->error, NULL, ctxt->userData, XML_FROM_XPATH,
633                         &ctxt->lastError);
634 }
635 
636 /**
637  * xmlXPathPErrMemory:
638  * @ctxt:  an XPath parser context
639  *
640  * Handle a memory allocation failure.
641  */
642 void
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt)643 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt)
644 {
645     if (ctxt == NULL)
646         return;
647     ctxt->error = XPATH_MEMORY_ERROR;
648     xmlXPathErrMemory(ctxt->context);
649 }
650 
651 /**
652  * xmlXPathErr:
653  * @ctxt:  a XPath parser context
654  * @code:  the error code
655  *
656  * Handle an XPath error
657  */
658 void
xmlXPathErr(xmlXPathParserContextPtr ctxt,int code)659 xmlXPathErr(xmlXPathParserContextPtr ctxt, int code)
660 {
661     xmlStructuredErrorFunc schannel = NULL;
662     xmlGenericErrorFunc channel = NULL;
663     void *data = NULL;
664     xmlNodePtr node = NULL;
665     int res;
666 
667     if (ctxt == NULL)
668         return;
669     if ((code < 0) || (code > MAXERRNO))
670 	code = MAXERRNO;
671     /* Only report the first error */
672     if (ctxt->error != 0)
673         return;
674 
675     ctxt->error = code;
676 
677     if (ctxt->context != NULL) {
678         xmlErrorPtr err = &ctxt->context->lastError;
679 
680         /* Don't overwrite memory error. */
681         if (err->code == XML_ERR_NO_MEMORY)
682             return;
683 
684         /* cleanup current last error */
685         xmlResetError(err);
686 
687         err->domain = XML_FROM_XPATH;
688         err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK;
689         err->level = XML_ERR_ERROR;
690         if (ctxt->base != NULL) {
691             err->str1 = (char *) xmlStrdup(ctxt->base);
692             if (err->str1 == NULL) {
693                 xmlXPathPErrMemory(ctxt);
694                 return;
695             }
696         }
697         err->int1 = ctxt->cur - ctxt->base;
698         err->node = ctxt->context->debugNode;
699 
700         schannel = ctxt->context->error;
701         data = ctxt->context->userData;
702         node = ctxt->context->debugNode;
703     }
704 
705     if (schannel == NULL) {
706         channel = xmlGenericError;
707         data = xmlGenericErrorContext;
708     }
709 
710     res = __xmlRaiseError(schannel, channel, data, NULL, node, XML_FROM_XPATH,
711                           code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
712                           XML_ERR_ERROR, NULL, 0,
713                           (const char *) ctxt->base, NULL, NULL,
714                           ctxt->cur - ctxt->base, 0,
715                           "%s", xmlXPathErrorMessages[code]);
716     if (res < 0)
717         xmlXPathPErrMemory(ctxt);
718 }
719 
720 /**
721  * xmlXPatherror:
722  * @ctxt:  the XPath Parser context
723  * @file:  the file name
724  * @line:  the line number
725  * @no:  the error number
726  *
727  * Formats an error message.
728  */
729 void
xmlXPatherror(xmlXPathParserContextPtr ctxt,const char * file ATTRIBUTE_UNUSED,int line ATTRIBUTE_UNUSED,int no)730 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
731               int line ATTRIBUTE_UNUSED, int no) {
732     xmlXPathErr(ctxt, no);
733 }
734 
735 /**
736  * xmlXPathCheckOpLimit:
737  * @ctxt:  the XPath Parser context
738  * @opCount:  the number of operations to be added
739  *
740  * Adds opCount to the running total of operations and returns -1 if the
741  * operation limit is exceeded. Returns 0 otherwise.
742  */
743 static int
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt,unsigned long opCount)744 xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
745     xmlXPathContextPtr xpctxt = ctxt->context;
746 
747     if ((opCount > xpctxt->opLimit) ||
748         (xpctxt->opCount > xpctxt->opLimit - opCount)) {
749         xpctxt->opCount = xpctxt->opLimit;
750         xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
751         return(-1);
752     }
753 
754     xpctxt->opCount += opCount;
755     return(0);
756 }
757 
758 #define OP_LIMIT_EXCEEDED(ctxt, n) \
759     ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
760 
761 /************************************************************************
762  *									*
763  *			Parser Types					*
764  *									*
765  ************************************************************************/
766 
767 /*
768  * Types are private:
769  */
770 
771 typedef enum {
772     XPATH_OP_END=0,
773     XPATH_OP_AND,
774     XPATH_OP_OR,
775     XPATH_OP_EQUAL,
776     XPATH_OP_CMP,
777     XPATH_OP_PLUS,
778     XPATH_OP_MULT,
779     XPATH_OP_UNION,
780     XPATH_OP_ROOT,
781     XPATH_OP_NODE,
782     XPATH_OP_COLLECT,
783     XPATH_OP_VALUE, /* 11 */
784     XPATH_OP_VARIABLE,
785     XPATH_OP_FUNCTION,
786     XPATH_OP_ARG,
787     XPATH_OP_PREDICATE,
788     XPATH_OP_FILTER, /* 16 */
789     XPATH_OP_SORT /* 17 */
790 } xmlXPathOp;
791 
792 typedef enum {
793     AXIS_ANCESTOR = 1,
794     AXIS_ANCESTOR_OR_SELF,
795     AXIS_ATTRIBUTE,
796     AXIS_CHILD,
797     AXIS_DESCENDANT,
798     AXIS_DESCENDANT_OR_SELF,
799     AXIS_FOLLOWING,
800     AXIS_FOLLOWING_SIBLING,
801     AXIS_NAMESPACE,
802     AXIS_PARENT,
803     AXIS_PRECEDING,
804     AXIS_PRECEDING_SIBLING,
805     AXIS_SELF
806 } xmlXPathAxisVal;
807 
808 typedef enum {
809     NODE_TEST_NONE = 0,
810     NODE_TEST_TYPE = 1,
811     NODE_TEST_PI = 2,
812     NODE_TEST_ALL = 3,
813     NODE_TEST_NS = 4,
814     NODE_TEST_NAME = 5
815 } xmlXPathTestVal;
816 
817 typedef enum {
818     NODE_TYPE_NODE = 0,
819     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
820     NODE_TYPE_TEXT = XML_TEXT_NODE,
821     NODE_TYPE_PI = XML_PI_NODE
822 } xmlXPathTypeVal;
823 
824 typedef struct _xmlXPathStepOp xmlXPathStepOp;
825 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
826 struct _xmlXPathStepOp {
827     xmlXPathOp op;		/* The identifier of the operation */
828     int ch1;			/* First child */
829     int ch2;			/* Second child */
830     int value;
831     int value2;
832     int value3;
833     void *value4;
834     void *value5;
835     xmlXPathFunction cache;
836     void *cacheURI;
837 };
838 
839 struct _xmlXPathCompExpr {
840     int nbStep;			/* Number of steps in this expression */
841     int maxStep;		/* Maximum number of steps allocated */
842     xmlXPathStepOp *steps;	/* ops for computation of this expression */
843     int last;			/* index of last step in expression */
844     xmlChar *expr;		/* the expression being computed */
845     xmlDictPtr dict;		/* the dictionary to use if any */
846 #ifdef XPATH_STREAMING
847     xmlPatternPtr stream;
848 #endif
849 };
850 
851 /************************************************************************
852  *									*
853  *			Forward declarations				*
854  *									*
855  ************************************************************************/
856 
857 static void
858 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
859 static int
860 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
861                         xmlXPathStepOpPtr op, xmlNodePtr *first);
862 static int
863 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
864 			    xmlXPathStepOpPtr op,
865 			    int isPredicate);
866 static void
867 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
868 
869 /************************************************************************
870  *									*
871  *			Parser Type functions				*
872  *									*
873  ************************************************************************/
874 
875 /**
876  * xmlXPathNewCompExpr:
877  *
878  * Create a new Xpath component
879  *
880  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
881  */
882 static xmlXPathCompExprPtr
xmlXPathNewCompExpr(void)883 xmlXPathNewCompExpr(void) {
884     xmlXPathCompExprPtr cur;
885 
886     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
887     if (cur == NULL)
888 	return(NULL);
889     memset(cur, 0, sizeof(xmlXPathCompExpr));
890     cur->maxStep = 10;
891     cur->nbStep = 0;
892     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
893 	                                   sizeof(xmlXPathStepOp));
894     if (cur->steps == NULL) {
895 	xmlFree(cur);
896 	return(NULL);
897     }
898     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
899     cur->last = -1;
900     return(cur);
901 }
902 
903 /**
904  * xmlXPathFreeCompExpr:
905  * @comp:  an XPATH comp
906  *
907  * Free up the memory allocated by @comp
908  */
909 void
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)910 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
911 {
912     xmlXPathStepOpPtr op;
913     int i;
914 
915     if (comp == NULL)
916         return;
917     if (comp->dict == NULL) {
918 	for (i = 0; i < comp->nbStep; i++) {
919 	    op = &comp->steps[i];
920 	    if (op->value4 != NULL) {
921 		if (op->op == XPATH_OP_VALUE)
922 		    xmlXPathFreeObject(op->value4);
923 		else
924 		    xmlFree(op->value4);
925 	    }
926 	    if (op->value5 != NULL)
927 		xmlFree(op->value5);
928 	}
929     } else {
930 	for (i = 0; i < comp->nbStep; i++) {
931 	    op = &comp->steps[i];
932 	    if (op->value4 != NULL) {
933 		if (op->op == XPATH_OP_VALUE)
934 		    xmlXPathFreeObject(op->value4);
935 	    }
936 	}
937         xmlDictFree(comp->dict);
938     }
939     if (comp->steps != NULL) {
940         xmlFree(comp->steps);
941     }
942 #ifdef XPATH_STREAMING
943     if (comp->stream != NULL) {
944         xmlFreePatternList(comp->stream);
945     }
946 #endif
947     if (comp->expr != NULL) {
948         xmlFree(comp->expr);
949     }
950 
951     xmlFree(comp);
952 }
953 
954 /**
955  * xmlXPathCompExprAdd:
956  * @comp:  the compiled expression
957  * @ch1: first child index
958  * @ch2: second child index
959  * @op:  an op
960  * @value:  the first int value
961  * @value2:  the second int value
962  * @value3:  the third int value
963  * @value4:  the first string value
964  * @value5:  the second string value
965  *
966  * Add a step to an XPath Compiled Expression
967  *
968  * Returns -1 in case of failure, the index otherwise
969  */
970 static int
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt,int ch1,int ch2,xmlXPathOp op,int value,int value2,int value3,void * value4,void * value5)971 xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
972    xmlXPathOp op, int value,
973    int value2, int value3, void *value4, void *value5) {
974     xmlXPathCompExprPtr comp = ctxt->comp;
975     if (comp->nbStep >= comp->maxStep) {
976 	xmlXPathStepOp *real;
977 
978         if (comp->maxStep >= XPATH_MAX_STEPS) {
979 	    xmlXPathPErrMemory(ctxt);
980 	    return(-1);
981         }
982 	comp->maxStep *= 2;
983 	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
984 		                      comp->maxStep * sizeof(xmlXPathStepOp));
985 	if (real == NULL) {
986 	    comp->maxStep /= 2;
987 	    xmlXPathPErrMemory(ctxt);
988 	    return(-1);
989 	}
990 	comp->steps = real;
991     }
992     comp->last = comp->nbStep;
993     comp->steps[comp->nbStep].ch1 = ch1;
994     comp->steps[comp->nbStep].ch2 = ch2;
995     comp->steps[comp->nbStep].op = op;
996     comp->steps[comp->nbStep].value = value;
997     comp->steps[comp->nbStep].value2 = value2;
998     comp->steps[comp->nbStep].value3 = value3;
999     if ((comp->dict != NULL) &&
1000         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1001 	 (op == XPATH_OP_COLLECT))) {
1002         if (value4 != NULL) {
1003 	    comp->steps[comp->nbStep].value4 = (xmlChar *)
1004 	        (void *)xmlDictLookup(comp->dict, value4, -1);
1005 	    xmlFree(value4);
1006 	} else
1007 	    comp->steps[comp->nbStep].value4 = NULL;
1008         if (value5 != NULL) {
1009 	    comp->steps[comp->nbStep].value5 = (xmlChar *)
1010 	        (void *)xmlDictLookup(comp->dict, value5, -1);
1011 	    xmlFree(value5);
1012 	} else
1013 	    comp->steps[comp->nbStep].value5 = NULL;
1014     } else {
1015 	comp->steps[comp->nbStep].value4 = value4;
1016 	comp->steps[comp->nbStep].value5 = value5;
1017     }
1018     comp->steps[comp->nbStep].cache = NULL;
1019     return(comp->nbStep++);
1020 }
1021 
1022 /**
1023  * xmlXPathCompSwap:
1024  * @comp:  the compiled expression
1025  * @op: operation index
1026  *
1027  * Swaps 2 operations in the compiled expression
1028  */
1029 static void
xmlXPathCompSwap(xmlXPathStepOpPtr op)1030 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1031     int tmp;
1032 
1033 #ifndef LIBXML_THREAD_ENABLED
1034     /*
1035      * Since this manipulates possibly shared variables, this is
1036      * disabled if one detects that the library is used in a multithreaded
1037      * application
1038      */
1039     if (xmlXPathDisableOptimizer)
1040 	return;
1041 #endif
1042 
1043     tmp = op->ch1;
1044     op->ch1 = op->ch2;
1045     op->ch2 = tmp;
1046 }
1047 
1048 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
1049     xmlXPathCompExprAdd(ctxt, (op1), (op2),			\
1050 	                (op), (val), (val2), (val3), (val4), (val5))
1051 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
1052     xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,		\
1053 	                (op), (val), (val2), (val3), (val4), (val5))
1054 
1055 #define PUSH_LEAVE_EXPR(op, val, val2)					\
1056 xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1057 
1058 #define PUSH_UNARY_EXPR(op, ch, val, val2)				\
1059 xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1060 
1061 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
1062 xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),			\
1063 			(val), (val2), 0 ,NULL ,NULL)
1064 
1065 /************************************************************************
1066  *									*
1067  *		XPath object cache structures				*
1068  *									*
1069  ************************************************************************/
1070 
1071 /* #define XP_DEFAULT_CACHE_ON */
1072 
1073 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1074 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1075 struct _xmlXPathContextCache {
1076     xmlXPathObjectPtr nodesetObjs;  /* stringval points to next */
1077     xmlXPathObjectPtr miscObjs;     /* stringval points to next */
1078     int numNodeset;
1079     int maxNodeset;
1080     int numMisc;
1081     int maxMisc;
1082 };
1083 
1084 /************************************************************************
1085  *									*
1086  *		Debugging related functions				*
1087  *									*
1088  ************************************************************************/
1089 
1090 #ifdef LIBXML_DEBUG_ENABLED
1091 static void
xmlXPathDebugDumpNode(FILE * output,xmlNodePtr cur,int depth)1092 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1093     int i;
1094     char shift[100];
1095 
1096     for (i = 0;((i < depth) && (i < 25));i++)
1097         shift[2 * i] = shift[2 * i + 1] = ' ';
1098     shift[2 * i] = shift[2 * i + 1] = 0;
1099     if (cur == NULL) {
1100 	fprintf(output, "%s", shift);
1101 	fprintf(output, "Node is NULL !\n");
1102 	return;
1103 
1104     }
1105 
1106     if ((cur->type == XML_DOCUMENT_NODE) ||
1107 	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
1108 	fprintf(output, "%s", shift);
1109 	fprintf(output, " /\n");
1110     } else if (cur->type == XML_ATTRIBUTE_NODE)
1111 	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1112     else
1113 	xmlDebugDumpOneNode(output, cur, depth);
1114 }
1115 static void
xmlXPathDebugDumpNodeList(FILE * output,xmlNodePtr cur,int depth)1116 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1117     xmlNodePtr tmp;
1118     int i;
1119     char shift[100];
1120 
1121     for (i = 0;((i < depth) && (i < 25));i++)
1122         shift[2 * i] = shift[2 * i + 1] = ' ';
1123     shift[2 * i] = shift[2 * i + 1] = 0;
1124     if (cur == NULL) {
1125 	fprintf(output, "%s", shift);
1126 	fprintf(output, "Node is NULL !\n");
1127 	return;
1128 
1129     }
1130 
1131     while (cur != NULL) {
1132 	tmp = cur;
1133 	cur = cur->next;
1134 	xmlDebugDumpOneNode(output, tmp, depth);
1135     }
1136 }
1137 
1138 static void
xmlXPathDebugDumpNodeSet(FILE * output,xmlNodeSetPtr cur,int depth)1139 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1140     int i;
1141     char shift[100];
1142 
1143     for (i = 0;((i < depth) && (i < 25));i++)
1144         shift[2 * i] = shift[2 * i + 1] = ' ';
1145     shift[2 * i] = shift[2 * i + 1] = 0;
1146 
1147     if (cur == NULL) {
1148 	fprintf(output, "%s", shift);
1149 	fprintf(output, "NodeSet is NULL !\n");
1150 	return;
1151 
1152     }
1153 
1154     if (cur != NULL) {
1155 	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1156 	for (i = 0;i < cur->nodeNr;i++) {
1157 	    fprintf(output, "%s", shift);
1158 	    fprintf(output, "%d", i + 1);
1159 	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1160 	}
1161     }
1162 }
1163 
1164 static void
xmlXPathDebugDumpValueTree(FILE * output,xmlNodeSetPtr cur,int depth)1165 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1166     int i;
1167     char shift[100];
1168 
1169     for (i = 0;((i < depth) && (i < 25));i++)
1170         shift[2 * i] = shift[2 * i + 1] = ' ';
1171     shift[2 * i] = shift[2 * i + 1] = 0;
1172 
1173     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1174 	fprintf(output, "%s", shift);
1175 	fprintf(output, "Value Tree is NULL !\n");
1176 	return;
1177 
1178     }
1179 
1180     fprintf(output, "%s", shift);
1181     fprintf(output, "%d", i + 1);
1182     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1183 }
1184 
1185 /**
1186  * xmlXPathDebugDumpObject:
1187  * @output:  the FILE * to dump the output
1188  * @cur:  the object to inspect
1189  * @depth:  indentation level
1190  *
1191  * Dump the content of the object for debugging purposes
1192  */
1193 void
xmlXPathDebugDumpObject(FILE * output,xmlXPathObjectPtr cur,int depth)1194 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1195     int i;
1196     char shift[100];
1197 
1198     if (output == NULL) return;
1199 
1200     for (i = 0;((i < depth) && (i < 25));i++)
1201         shift[2 * i] = shift[2 * i + 1] = ' ';
1202     shift[2 * i] = shift[2 * i + 1] = 0;
1203 
1204 
1205     fprintf(output, "%s", shift);
1206 
1207     if (cur == NULL) {
1208         fprintf(output, "Object is empty (NULL)\n");
1209 	return;
1210     }
1211     switch(cur->type) {
1212         case XPATH_UNDEFINED:
1213 	    fprintf(output, "Object is uninitialized\n");
1214 	    break;
1215         case XPATH_NODESET:
1216 	    fprintf(output, "Object is a Node Set :\n");
1217 	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1218 	    break;
1219 	case XPATH_XSLT_TREE:
1220 	    fprintf(output, "Object is an XSLT value tree :\n");
1221 	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1222 	    break;
1223         case XPATH_BOOLEAN:
1224 	    fprintf(output, "Object is a Boolean : ");
1225 	    if (cur->boolval) fprintf(output, "true\n");
1226 	    else fprintf(output, "false\n");
1227 	    break;
1228         case XPATH_NUMBER:
1229 	    switch (xmlXPathIsInf(cur->floatval)) {
1230 	    case 1:
1231 		fprintf(output, "Object is a number : Infinity\n");
1232 		break;
1233 	    case -1:
1234 		fprintf(output, "Object is a number : -Infinity\n");
1235 		break;
1236 	    default:
1237 		if (xmlXPathIsNaN(cur->floatval)) {
1238 		    fprintf(output, "Object is a number : NaN\n");
1239 		} else if (cur->floatval == 0) {
1240                     /* Omit sign for negative zero. */
1241 		    fprintf(output, "Object is a number : 0\n");
1242 		} else {
1243 		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
1244 		}
1245 	    }
1246 	    break;
1247         case XPATH_STRING:
1248 	    fprintf(output, "Object is a string : ");
1249 	    xmlDebugDumpString(output, cur->stringval);
1250 	    fprintf(output, "\n");
1251 	    break;
1252 	case XPATH_USERS:
1253 	    fprintf(output, "Object is user defined\n");
1254 	    break;
1255     }
1256 }
1257 
1258 static void
xmlXPathDebugDumpStepOp(FILE * output,xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op,int depth)1259 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1260 	                     xmlXPathStepOpPtr op, int depth) {
1261     int i;
1262     char shift[100];
1263 
1264     for (i = 0;((i < depth) && (i < 25));i++)
1265         shift[2 * i] = shift[2 * i + 1] = ' ';
1266     shift[2 * i] = shift[2 * i + 1] = 0;
1267 
1268     fprintf(output, "%s", shift);
1269     if (op == NULL) {
1270 	fprintf(output, "Step is NULL\n");
1271 	return;
1272     }
1273     switch (op->op) {
1274         case XPATH_OP_END:
1275 	    fprintf(output, "END"); break;
1276         case XPATH_OP_AND:
1277 	    fprintf(output, "AND"); break;
1278         case XPATH_OP_OR:
1279 	    fprintf(output, "OR"); break;
1280         case XPATH_OP_EQUAL:
1281 	     if (op->value)
1282 		 fprintf(output, "EQUAL =");
1283 	     else
1284 		 fprintf(output, "EQUAL !=");
1285 	     break;
1286         case XPATH_OP_CMP:
1287 	     if (op->value)
1288 		 fprintf(output, "CMP <");
1289 	     else
1290 		 fprintf(output, "CMP >");
1291 	     if (!op->value2)
1292 		 fprintf(output, "=");
1293 	     break;
1294         case XPATH_OP_PLUS:
1295 	     if (op->value == 0)
1296 		 fprintf(output, "PLUS -");
1297 	     else if (op->value == 1)
1298 		 fprintf(output, "PLUS +");
1299 	     else if (op->value == 2)
1300 		 fprintf(output, "PLUS unary -");
1301 	     else if (op->value == 3)
1302 		 fprintf(output, "PLUS unary - -");
1303 	     break;
1304         case XPATH_OP_MULT:
1305 	     if (op->value == 0)
1306 		 fprintf(output, "MULT *");
1307 	     else if (op->value == 1)
1308 		 fprintf(output, "MULT div");
1309 	     else
1310 		 fprintf(output, "MULT mod");
1311 	     break;
1312         case XPATH_OP_UNION:
1313 	     fprintf(output, "UNION"); break;
1314         case XPATH_OP_ROOT:
1315 	     fprintf(output, "ROOT"); break;
1316         case XPATH_OP_NODE:
1317 	     fprintf(output, "NODE"); break;
1318         case XPATH_OP_SORT:
1319 	     fprintf(output, "SORT"); break;
1320         case XPATH_OP_COLLECT: {
1321 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1322 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1323 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1324 	    const xmlChar *prefix = op->value4;
1325 	    const xmlChar *name = op->value5;
1326 
1327 	    fprintf(output, "COLLECT ");
1328 	    switch (axis) {
1329 		case AXIS_ANCESTOR:
1330 		    fprintf(output, " 'ancestors' "); break;
1331 		case AXIS_ANCESTOR_OR_SELF:
1332 		    fprintf(output, " 'ancestors-or-self' "); break;
1333 		case AXIS_ATTRIBUTE:
1334 		    fprintf(output, " 'attributes' "); break;
1335 		case AXIS_CHILD:
1336 		    fprintf(output, " 'child' "); break;
1337 		case AXIS_DESCENDANT:
1338 		    fprintf(output, " 'descendant' "); break;
1339 		case AXIS_DESCENDANT_OR_SELF:
1340 		    fprintf(output, " 'descendant-or-self' "); break;
1341 		case AXIS_FOLLOWING:
1342 		    fprintf(output, " 'following' "); break;
1343 		case AXIS_FOLLOWING_SIBLING:
1344 		    fprintf(output, " 'following-siblings' "); break;
1345 		case AXIS_NAMESPACE:
1346 		    fprintf(output, " 'namespace' "); break;
1347 		case AXIS_PARENT:
1348 		    fprintf(output, " 'parent' "); break;
1349 		case AXIS_PRECEDING:
1350 		    fprintf(output, " 'preceding' "); break;
1351 		case AXIS_PRECEDING_SIBLING:
1352 		    fprintf(output, " 'preceding-sibling' "); break;
1353 		case AXIS_SELF:
1354 		    fprintf(output, " 'self' "); break;
1355 	    }
1356 	    switch (test) {
1357                 case NODE_TEST_NONE:
1358 		    fprintf(output, "'none' "); break;
1359                 case NODE_TEST_TYPE:
1360 		    fprintf(output, "'type' "); break;
1361                 case NODE_TEST_PI:
1362 		    fprintf(output, "'PI' "); break;
1363                 case NODE_TEST_ALL:
1364 		    fprintf(output, "'all' "); break;
1365                 case NODE_TEST_NS:
1366 		    fprintf(output, "'namespace' "); break;
1367                 case NODE_TEST_NAME:
1368 		    fprintf(output, "'name' "); break;
1369 	    }
1370 	    switch (type) {
1371                 case NODE_TYPE_NODE:
1372 		    fprintf(output, "'node' "); break;
1373                 case NODE_TYPE_COMMENT:
1374 		    fprintf(output, "'comment' "); break;
1375                 case NODE_TYPE_TEXT:
1376 		    fprintf(output, "'text' "); break;
1377                 case NODE_TYPE_PI:
1378 		    fprintf(output, "'PI' "); break;
1379 	    }
1380 	    if (prefix != NULL)
1381 		fprintf(output, "%s:", prefix);
1382 	    if (name != NULL)
1383 		fprintf(output, "%s", (const char *) name);
1384 	    break;
1385 
1386         }
1387 	case XPATH_OP_VALUE: {
1388 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1389 
1390 	    fprintf(output, "ELEM ");
1391 	    xmlXPathDebugDumpObject(output, object, 0);
1392 	    goto finish;
1393 	}
1394 	case XPATH_OP_VARIABLE: {
1395 	    const xmlChar *prefix = op->value5;
1396 	    const xmlChar *name = op->value4;
1397 
1398 	    if (prefix != NULL)
1399 		fprintf(output, "VARIABLE %s:%s", prefix, name);
1400 	    else
1401 		fprintf(output, "VARIABLE %s", name);
1402 	    break;
1403 	}
1404 	case XPATH_OP_FUNCTION: {
1405 	    int nbargs = op->value;
1406 	    const xmlChar *prefix = op->value5;
1407 	    const xmlChar *name = op->value4;
1408 
1409 	    if (prefix != NULL)
1410 		fprintf(output, "FUNCTION %s:%s(%d args)",
1411 			prefix, name, nbargs);
1412 	    else
1413 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1414 	    break;
1415 	}
1416         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1417         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1418         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1419 	default:
1420         fprintf(output, "UNKNOWN %d\n", op->op); return;
1421     }
1422     fprintf(output, "\n");
1423 finish:
1424     if (op->ch1 >= 0)
1425 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1426     if (op->ch2 >= 0)
1427 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1428 }
1429 
1430 /**
1431  * xmlXPathDebugDumpCompExpr:
1432  * @output:  the FILE * for the output
1433  * @comp:  the precompiled XPath expression
1434  * @depth:  the indentation level.
1435  *
1436  * Dumps the tree of the compiled XPath expression.
1437  */
1438 void
xmlXPathDebugDumpCompExpr(FILE * output,xmlXPathCompExprPtr comp,int depth)1439 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1440 	                  int depth) {
1441     int i;
1442     char shift[100];
1443 
1444     if ((output == NULL) || (comp == NULL)) return;
1445 
1446     for (i = 0;((i < depth) && (i < 25));i++)
1447         shift[2 * i] = shift[2 * i + 1] = ' ';
1448     shift[2 * i] = shift[2 * i + 1] = 0;
1449 
1450     fprintf(output, "%s", shift);
1451 
1452 #ifdef XPATH_STREAMING
1453     if (comp->stream) {
1454         fprintf(output, "Streaming Expression\n");
1455     } else
1456 #endif
1457     {
1458         fprintf(output, "Compiled Expression : %d elements\n",
1459                 comp->nbStep);
1460         i = comp->last;
1461         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1462     }
1463 }
1464 
1465 #endif /* LIBXML_DEBUG_ENABLED */
1466 
1467 /************************************************************************
1468  *									*
1469  *			XPath object caching				*
1470  *									*
1471  ************************************************************************/
1472 
1473 /**
1474  * xmlXPathNewCache:
1475  *
1476  * Create a new object cache
1477  *
1478  * Returns the xmlXPathCache just allocated.
1479  */
1480 static xmlXPathContextCachePtr
xmlXPathNewCache(void)1481 xmlXPathNewCache(void)
1482 {
1483     xmlXPathContextCachePtr ret;
1484 
1485     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1486     if (ret == NULL)
1487 	return(NULL);
1488     memset(ret, 0 , sizeof(xmlXPathContextCache));
1489     ret->maxNodeset = 100;
1490     ret->maxMisc = 100;
1491     return(ret);
1492 }
1493 
1494 static void
xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)1495 xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)
1496 {
1497     while (list != NULL) {
1498         xmlXPathObjectPtr next;
1499 
1500         next = (void *) list->stringval;
1501 
1502 	if (list->nodesetval != NULL) {
1503 	    if (list->nodesetval->nodeTab != NULL)
1504 		xmlFree(list->nodesetval->nodeTab);
1505 	    xmlFree(list->nodesetval);
1506 	}
1507 	xmlFree(list);
1508 
1509         list = next;
1510     }
1511 }
1512 
1513 static void
xmlXPathFreeCache(xmlXPathContextCachePtr cache)1514 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1515 {
1516     if (cache == NULL)
1517 	return;
1518     if (cache->nodesetObjs)
1519 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1520     if (cache->miscObjs)
1521 	xmlXPathCacheFreeObjectList(cache->miscObjs);
1522     xmlFree(cache);
1523 }
1524 
1525 /**
1526  * xmlXPathContextSetCache:
1527  *
1528  * @ctxt:  the XPath context
1529  * @active: enables/disables (creates/frees) the cache
1530  * @value: a value with semantics dependent on @options
1531  * @options: options (currently only the value 0 is used)
1532  *
1533  * Creates/frees an object cache on the XPath context.
1534  * If activates XPath objects (xmlXPathObject) will be cached internally
1535  * to be reused.
1536  * @options:
1537  *   0: This will set the XPath object caching:
1538  *      @value:
1539  *        This will set the maximum number of XPath objects
1540  *        to be cached per slot
1541  *        There are two slots for node-set and misc objects.
1542  *        Use <0 for the default number (100).
1543  *   Other values for @options have currently no effect.
1544  *
1545  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1546  */
1547 int
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,int active,int value,int options)1548 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1549 			int active,
1550 			int value,
1551 			int options)
1552 {
1553     if (ctxt == NULL)
1554 	return(-1);
1555     if (active) {
1556 	xmlXPathContextCachePtr cache;
1557 
1558 	if (ctxt->cache == NULL) {
1559 	    ctxt->cache = xmlXPathNewCache();
1560 	    if (ctxt->cache == NULL) {
1561                 xmlXPathErrMemory(ctxt);
1562 		return(-1);
1563             }
1564 	}
1565 	cache = (xmlXPathContextCachePtr) ctxt->cache;
1566 	if (options == 0) {
1567 	    if (value < 0)
1568 		value = 100;
1569 	    cache->maxNodeset = value;
1570 	    cache->maxMisc = value;
1571 	}
1572     } else if (ctxt->cache != NULL) {
1573 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1574 	ctxt->cache = NULL;
1575     }
1576     return(0);
1577 }
1578 
1579 /**
1580  * xmlXPathCacheWrapNodeSet:
1581  * @pctxt: the XPath context
1582  * @val:  the NodePtr value
1583  *
1584  * This is the cached version of xmlXPathWrapNodeSet().
1585  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1586  *
1587  * Returns the created or reused object.
1588  *
1589  * In case of error the node set is destroyed and NULL is returned.
1590  */
1591 static xmlXPathObjectPtr
xmlXPathCacheWrapNodeSet(xmlXPathParserContextPtr pctxt,xmlNodeSetPtr val)1592 xmlXPathCacheWrapNodeSet(xmlXPathParserContextPtr pctxt, xmlNodeSetPtr val)
1593 {
1594     xmlXPathObjectPtr ret;
1595     xmlXPathContextPtr ctxt = pctxt->context;
1596 
1597     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1598 	xmlXPathContextCachePtr cache =
1599 	    (xmlXPathContextCachePtr) ctxt->cache;
1600 
1601 	if (cache->miscObjs != NULL) {
1602 	    ret = cache->miscObjs;
1603             cache->miscObjs = (void *) ret->stringval;
1604             cache->numMisc -= 1;
1605             ret->stringval = NULL;
1606 	    ret->type = XPATH_NODESET;
1607 	    ret->nodesetval = val;
1608 	    return(ret);
1609 	}
1610     }
1611 
1612     ret = xmlXPathWrapNodeSet(val);
1613     if (ret == NULL)
1614         xmlXPathPErrMemory(pctxt);
1615     return(ret);
1616 }
1617 
1618 /**
1619  * xmlXPathCacheWrapString:
1620  * @pctxt the XPath context
1621  * @val:  the xmlChar * value
1622  *
1623  * This is the cached version of xmlXPathWrapString().
1624  * Wraps the @val string into an XPath object.
1625  *
1626  * Returns the created or reused object.
1627  */
1628 static xmlXPathObjectPtr
xmlXPathCacheWrapString(xmlXPathParserContextPtr pctxt,xmlChar * val)1629 xmlXPathCacheWrapString(xmlXPathParserContextPtr pctxt, xmlChar *val)
1630 {
1631     xmlXPathObjectPtr ret;
1632     xmlXPathContextPtr ctxt = pctxt->context;
1633 
1634     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1635 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1636 
1637 	if (cache->miscObjs != NULL) {
1638 	    ret = cache->miscObjs;
1639             cache->miscObjs = (void *) ret->stringval;
1640             cache->numMisc -= 1;
1641 	    ret->type = XPATH_STRING;
1642 	    ret->stringval = val;
1643 	    return(ret);
1644 	}
1645     }
1646 
1647     ret = xmlXPathWrapString(val);
1648     if (ret == NULL)
1649         xmlXPathPErrMemory(pctxt);
1650     return(ret);
1651 }
1652 
1653 /**
1654  * xmlXPathCacheNewNodeSet:
1655  * @pctxt the XPath context
1656  * @val:  the NodePtr value
1657  *
1658  * This is the cached version of xmlXPathNewNodeSet().
1659  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
1660  * it with the single Node @val
1661  *
1662  * Returns the created or reused object.
1663  */
1664 static xmlXPathObjectPtr
xmlXPathCacheNewNodeSet(xmlXPathParserContextPtr pctxt,xmlNodePtr val)1665 xmlXPathCacheNewNodeSet(xmlXPathParserContextPtr pctxt, xmlNodePtr val)
1666 {
1667     xmlXPathObjectPtr ret;
1668     xmlXPathContextPtr ctxt = pctxt->context;
1669 
1670     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1671 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1672 
1673 	if (cache->nodesetObjs != NULL) {
1674 	    /*
1675 	    * Use the nodeset-cache.
1676 	    */
1677 	    ret = cache->nodesetObjs;
1678             cache->nodesetObjs = (void *) ret->stringval;
1679             cache->numNodeset -= 1;
1680             ret->stringval = NULL;
1681 	    ret->type = XPATH_NODESET;
1682 	    ret->boolval = 0;
1683 	    if (val) {
1684 		if ((ret->nodesetval->nodeMax == 0) ||
1685 		    (val->type == XML_NAMESPACE_DECL))
1686 		{
1687 		    if (xmlXPathNodeSetAddUnique(ret->nodesetval, val) < 0)
1688                         xmlXPathPErrMemory(pctxt);
1689 		} else {
1690 		    ret->nodesetval->nodeTab[0] = val;
1691 		    ret->nodesetval->nodeNr = 1;
1692 		}
1693 	    }
1694 	    return(ret);
1695 	} else if (cache->miscObjs != NULL) {
1696             xmlNodeSetPtr set;
1697 	    /*
1698 	    * Fallback to misc-cache.
1699 	    */
1700 
1701 	    set = xmlXPathNodeSetCreate(val);
1702 	    if (set == NULL) {
1703                 xmlXPathPErrMemory(pctxt);
1704 		return(NULL);
1705 	    }
1706 
1707 	    ret = cache->miscObjs;
1708             cache->miscObjs = (void *) ret->stringval;
1709             cache->numMisc -= 1;
1710             ret->stringval = NULL;
1711 	    ret->type = XPATH_NODESET;
1712 	    ret->boolval = 0;
1713 	    ret->nodesetval = set;
1714 	    return(ret);
1715 	}
1716     }
1717     ret = xmlXPathNewNodeSet(val);
1718     if (ret == NULL)
1719         xmlXPathPErrMemory(pctxt);
1720     return(ret);
1721 }
1722 
1723 /**
1724  * xmlXPathCacheNewString:
1725  * @pctxt the XPath context
1726  * @val:  the xmlChar * value
1727  *
1728  * This is the cached version of xmlXPathNewString().
1729  * Acquire an xmlXPathObjectPtr of type string and of value @val
1730  *
1731  * Returns the created or reused object.
1732  */
1733 static xmlXPathObjectPtr
xmlXPathCacheNewString(xmlXPathParserContextPtr pctxt,const xmlChar * val)1734 xmlXPathCacheNewString(xmlXPathParserContextPtr pctxt, const xmlChar *val)
1735 {
1736     xmlXPathObjectPtr ret;
1737     xmlXPathContextPtr ctxt = pctxt->context;
1738 
1739     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1740 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1741 
1742 	if (cache->miscObjs != NULL) {
1743             xmlChar *copy;
1744 
1745             if (val == NULL)
1746                 val = BAD_CAST "";
1747             copy = xmlStrdup(val);
1748             if (copy == NULL) {
1749                 xmlXPathPErrMemory(pctxt);
1750                 return(NULL);
1751             }
1752 
1753 	    ret = cache->miscObjs;
1754             cache->miscObjs = (void *) ret->stringval;
1755             cache->numMisc -= 1;
1756 	    ret->type = XPATH_STRING;
1757             ret->stringval = copy;
1758 	    return(ret);
1759 	}
1760     }
1761 
1762     ret = xmlXPathNewString(val);
1763     if (ret == NULL)
1764         xmlXPathPErrMemory(pctxt);
1765     return(ret);
1766 }
1767 
1768 /**
1769  * xmlXPathCacheNewCString:
1770  * @pctxt the XPath context
1771  * @val:  the char * value
1772  *
1773  * This is the cached version of xmlXPathNewCString().
1774  * Acquire an xmlXPathObjectPtr of type string and of value @val
1775  *
1776  * Returns the created or reused object.
1777  */
1778 static xmlXPathObjectPtr
xmlXPathCacheNewCString(xmlXPathParserContextPtr pctxt,const char * val)1779 xmlXPathCacheNewCString(xmlXPathParserContextPtr pctxt, const char *val)
1780 {
1781     return xmlXPathCacheNewString(pctxt, BAD_CAST val);
1782 }
1783 
1784 /**
1785  * xmlXPathCacheNewBoolean:
1786  * @pctxt the XPath context
1787  * @val:  the boolean value
1788  *
1789  * This is the cached version of xmlXPathNewBoolean().
1790  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
1791  *
1792  * Returns the created or reused object.
1793  */
1794 static xmlXPathObjectPtr
xmlXPathCacheNewBoolean(xmlXPathParserContextPtr pctxt,int val)1795 xmlXPathCacheNewBoolean(xmlXPathParserContextPtr pctxt, int val)
1796 {
1797     xmlXPathObjectPtr ret;
1798     xmlXPathContextPtr ctxt = pctxt->context;
1799 
1800     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1801 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1802 
1803 	if (cache->miscObjs != NULL) {
1804 	    ret = cache->miscObjs;
1805             cache->miscObjs = (void *) ret->stringval;
1806             cache->numMisc -= 1;
1807             ret->stringval = NULL;
1808 	    ret->type = XPATH_BOOLEAN;
1809 	    ret->boolval = (val != 0);
1810 	    return(ret);
1811 	}
1812     }
1813 
1814     ret = xmlXPathNewBoolean(val);
1815     if (ret == NULL)
1816         xmlXPathPErrMemory(pctxt);
1817     return(ret);
1818 }
1819 
1820 /**
1821  * xmlXPathCacheNewFloat:
1822  * @pctxt the XPath context
1823  * @val:  the double value
1824  *
1825  * This is the cached version of xmlXPathNewFloat().
1826  * Acquires an xmlXPathObjectPtr of type double and of value @val
1827  *
1828  * Returns the created or reused object.
1829  */
1830 static xmlXPathObjectPtr
xmlXPathCacheNewFloat(xmlXPathParserContextPtr pctxt,double val)1831 xmlXPathCacheNewFloat(xmlXPathParserContextPtr pctxt, double val)
1832 {
1833     xmlXPathObjectPtr ret;
1834     xmlXPathContextPtr ctxt = pctxt->context;
1835 
1836     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1837 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1838 
1839 	if (cache->miscObjs != NULL) {
1840 	    ret = cache->miscObjs;
1841             cache->miscObjs = (void *) ret->stringval;
1842             cache->numMisc -= 1;
1843             ret->stringval = NULL;
1844 	    ret->type = XPATH_NUMBER;
1845 	    ret->floatval = val;
1846 	    return(ret);
1847 	}
1848     }
1849 
1850     ret = xmlXPathNewFloat(val);
1851     if (ret == NULL)
1852         xmlXPathPErrMemory(pctxt);
1853     return(ret);
1854 }
1855 
1856 /**
1857  * xmlXPathCacheObjectCopy:
1858  * @pctxt the XPath context
1859  * @val:  the original object
1860  *
1861  * This is the cached version of xmlXPathObjectCopy().
1862  * Acquire a copy of a given object
1863  *
1864  * Returns a created or reused created object.
1865  */
1866 static xmlXPathObjectPtr
xmlXPathCacheObjectCopy(xmlXPathParserContextPtr pctxt,xmlXPathObjectPtr val)1867 xmlXPathCacheObjectCopy(xmlXPathParserContextPtr pctxt, xmlXPathObjectPtr val)
1868 {
1869     xmlXPathObjectPtr ret;
1870     xmlXPathContextPtr ctxt = pctxt->context;
1871 
1872     if (val == NULL)
1873 	return(NULL);
1874 
1875     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1876 	switch (val->type) {
1877             case XPATH_NODESET: {
1878                 xmlNodeSetPtr set;
1879 
1880                 set = xmlXPathNodeSetMerge(NULL, val->nodesetval);
1881                 if (set == NULL) {
1882                     xmlXPathPErrMemory(pctxt);
1883                     return(NULL);
1884                 }
1885                 return(xmlXPathCacheWrapNodeSet(pctxt, set));
1886             }
1887 	    case XPATH_STRING:
1888 		return(xmlXPathCacheNewString(pctxt, val->stringval));
1889 	    case XPATH_BOOLEAN:
1890 		return(xmlXPathCacheNewBoolean(pctxt, val->boolval));
1891 	    case XPATH_NUMBER:
1892 		return(xmlXPathCacheNewFloat(pctxt, val->floatval));
1893 	    default:
1894 		break;
1895 	}
1896     }
1897     ret = xmlXPathObjectCopy(val);
1898     if (ret == NULL)
1899         xmlXPathPErrMemory(pctxt);
1900     return(ret);
1901 }
1902 
1903 /************************************************************************
1904  *									*
1905  *		Parser stacks related functions and macros		*
1906  *									*
1907  ************************************************************************/
1908 
1909 /**
1910  * xmlXPathCastToNumberInternal:
1911  * @ctxt:  parser context
1912  * @val:  an XPath object
1913  *
1914  * Converts an XPath object to its number value
1915  *
1916  * Returns the number value
1917  */
1918 static double
xmlXPathCastToNumberInternal(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr val)1919 xmlXPathCastToNumberInternal(xmlXPathParserContextPtr ctxt,
1920                              xmlXPathObjectPtr val) {
1921     double ret = 0.0;
1922 
1923     if (val == NULL)
1924 	return(xmlXPathNAN);
1925     switch (val->type) {
1926     case XPATH_UNDEFINED:
1927 	ret = xmlXPathNAN;
1928 	break;
1929     case XPATH_NODESET:
1930     case XPATH_XSLT_TREE: {
1931         xmlChar *str;
1932 
1933 	str = xmlXPathCastNodeSetToString(val->nodesetval);
1934         if (str == NULL) {
1935             xmlXPathPErrMemory(ctxt);
1936             ret = xmlXPathNAN;
1937         } else {
1938 	    ret = xmlXPathCastStringToNumber(str);
1939             xmlFree(str);
1940         }
1941 	break;
1942     }
1943     case XPATH_STRING:
1944 	ret = xmlXPathCastStringToNumber(val->stringval);
1945 	break;
1946     case XPATH_NUMBER:
1947 	ret = val->floatval;
1948 	break;
1949     case XPATH_BOOLEAN:
1950 	ret = xmlXPathCastBooleanToNumber(val->boolval);
1951 	break;
1952     case XPATH_USERS:
1953 	/* TODO */
1954 	ret = xmlXPathNAN;
1955 	break;
1956     }
1957     return(ret);
1958 }
1959 
1960 /**
1961  * valuePop:
1962  * @ctxt: an XPath evaluation context
1963  *
1964  * Pops the top XPath object from the value stack
1965  *
1966  * Returns the XPath object just removed
1967  */
1968 xmlXPathObjectPtr
valuePop(xmlXPathParserContextPtr ctxt)1969 valuePop(xmlXPathParserContextPtr ctxt)
1970 {
1971     xmlXPathObjectPtr ret;
1972 
1973     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
1974         return (NULL);
1975 
1976     ctxt->valueNr--;
1977     if (ctxt->valueNr > 0)
1978         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1979     else
1980         ctxt->value = NULL;
1981     ret = ctxt->valueTab[ctxt->valueNr];
1982     ctxt->valueTab[ctxt->valueNr] = NULL;
1983     return (ret);
1984 }
1985 /**
1986  * valuePush:
1987  * @ctxt:  an XPath evaluation context
1988  * @value:  the XPath object
1989  *
1990  * Pushes a new XPath object on top of the value stack. If value is NULL,
1991  * a memory error is recorded in the parser context.
1992  *
1993  * Returns the number of items on the value stack, or -1 in case of error.
1994  *
1995  * The object is destroyed in case of error.
1996  */
1997 int
valuePush(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr value)1998 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1999 {
2000     if (ctxt == NULL) return(-1);
2001     if (value == NULL) {
2002         /*
2003          * A NULL value typically indicates that a memory allocation failed.
2004          */
2005         xmlXPathPErrMemory(ctxt);
2006         return(-1);
2007     }
2008     if (ctxt->valueNr >= ctxt->valueMax) {
2009         xmlXPathObjectPtr *tmp;
2010 
2011         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2012             xmlXPathPErrMemory(ctxt);
2013             xmlXPathFreeObject(value);
2014             return (-1);
2015         }
2016         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2017                                              2 * ctxt->valueMax *
2018                                              sizeof(ctxt->valueTab[0]));
2019         if (tmp == NULL) {
2020             xmlXPathPErrMemory(ctxt);
2021             xmlXPathFreeObject(value);
2022             return (-1);
2023         }
2024         ctxt->valueMax *= 2;
2025 	ctxt->valueTab = tmp;
2026     }
2027     ctxt->valueTab[ctxt->valueNr] = value;
2028     ctxt->value = value;
2029     return (ctxt->valueNr++);
2030 }
2031 
2032 /**
2033  * xmlXPathPopBoolean:
2034  * @ctxt:  an XPath parser context
2035  *
2036  * Pops a boolean from the stack, handling conversion if needed.
2037  * Check error with #xmlXPathCheckError.
2038  *
2039  * Returns the boolean
2040  */
2041 int
xmlXPathPopBoolean(xmlXPathParserContextPtr ctxt)2042 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2043     xmlXPathObjectPtr obj;
2044     int ret;
2045 
2046     obj = valuePop(ctxt);
2047     if (obj == NULL) {
2048 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2049 	return(0);
2050     }
2051     if (obj->type != XPATH_BOOLEAN)
2052 	ret = xmlXPathCastToBoolean(obj);
2053     else
2054         ret = obj->boolval;
2055     xmlXPathReleaseObject(ctxt->context, obj);
2056     return(ret);
2057 }
2058 
2059 /**
2060  * xmlXPathPopNumber:
2061  * @ctxt:  an XPath parser context
2062  *
2063  * Pops a number from the stack, handling conversion if needed.
2064  * Check error with #xmlXPathCheckError.
2065  *
2066  * Returns the number
2067  */
2068 double
xmlXPathPopNumber(xmlXPathParserContextPtr ctxt)2069 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2070     xmlXPathObjectPtr obj;
2071     double ret;
2072 
2073     obj = valuePop(ctxt);
2074     if (obj == NULL) {
2075 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2076 	return(0);
2077     }
2078     if (obj->type != XPATH_NUMBER)
2079 	ret = xmlXPathCastToNumberInternal(ctxt, obj);
2080     else
2081         ret = obj->floatval;
2082     xmlXPathReleaseObject(ctxt->context, obj);
2083     return(ret);
2084 }
2085 
2086 /**
2087  * xmlXPathPopString:
2088  * @ctxt:  an XPath parser context
2089  *
2090  * Pops a string from the stack, handling conversion if needed.
2091  * Check error with #xmlXPathCheckError.
2092  *
2093  * Returns the string
2094  */
2095 xmlChar *
xmlXPathPopString(xmlXPathParserContextPtr ctxt)2096 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2097     xmlXPathObjectPtr obj;
2098     xmlChar * ret;
2099 
2100     obj = valuePop(ctxt);
2101     if (obj == NULL) {
2102 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2103 	return(NULL);
2104     }
2105     ret = xmlXPathCastToString(obj);
2106     if (ret == NULL)
2107         xmlXPathPErrMemory(ctxt);
2108     xmlXPathReleaseObject(ctxt->context, obj);
2109     return(ret);
2110 }
2111 
2112 /**
2113  * xmlXPathPopNodeSet:
2114  * @ctxt:  an XPath parser context
2115  *
2116  * Pops a node-set from the stack, handling conversion if needed.
2117  * Check error with #xmlXPathCheckError.
2118  *
2119  * Returns the node-set
2120  */
2121 xmlNodeSetPtr
xmlXPathPopNodeSet(xmlXPathParserContextPtr ctxt)2122 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2123     xmlXPathObjectPtr obj;
2124     xmlNodeSetPtr ret;
2125 
2126     if (ctxt == NULL) return(NULL);
2127     if (ctxt->value == NULL) {
2128 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2129 	return(NULL);
2130     }
2131     if (!xmlXPathStackIsNodeSet(ctxt)) {
2132 	xmlXPathSetTypeError(ctxt);
2133 	return(NULL);
2134     }
2135     obj = valuePop(ctxt);
2136     ret = obj->nodesetval;
2137 #if 0
2138     /* to fix memory leak of not clearing obj->user */
2139     if (obj->boolval && obj->user != NULL)
2140         xmlFreeNodeList((xmlNodePtr) obj->user);
2141 #endif
2142     obj->nodesetval = NULL;
2143     xmlXPathReleaseObject(ctxt->context, obj);
2144     return(ret);
2145 }
2146 
2147 /**
2148  * xmlXPathPopExternal:
2149  * @ctxt:  an XPath parser context
2150  *
2151  * Pops an external object from the stack, handling conversion if needed.
2152  * Check error with #xmlXPathCheckError.
2153  *
2154  * Returns the object
2155  */
2156 void *
xmlXPathPopExternal(xmlXPathParserContextPtr ctxt)2157 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2158     xmlXPathObjectPtr obj;
2159     void * ret;
2160 
2161     if ((ctxt == NULL) || (ctxt->value == NULL)) {
2162 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2163 	return(NULL);
2164     }
2165     if (ctxt->value->type != XPATH_USERS) {
2166 	xmlXPathSetTypeError(ctxt);
2167 	return(NULL);
2168     }
2169     obj = valuePop(ctxt);
2170     ret = obj->user;
2171     obj->user = NULL;
2172     xmlXPathReleaseObject(ctxt->context, obj);
2173     return(ret);
2174 }
2175 
2176 /*
2177  * Macros for accessing the content. Those should be used only by the parser,
2178  * and not exported.
2179  *
2180  * Dirty macros, i.e. one need to make assumption on the context to use them
2181  *
2182  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2183  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2184  *           in ISO-Latin or UTF-8.
2185  *           This should be used internally by the parser
2186  *           only to compare to ASCII values otherwise it would break when
2187  *           running with UTF-8 encoding.
2188  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2189  *           to compare on ASCII based substring.
2190  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2191  *           strings within the parser.
2192  *   CURRENT Returns the current char value, with the full decoding of
2193  *           UTF-8 if we are using this mode. It returns an int.
2194  *   NEXT    Skip to the next character, this does the proper decoding
2195  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2196  *           It returns the pointer to the current xmlChar.
2197  */
2198 
2199 #define CUR (*ctxt->cur)
2200 #define SKIP(val) ctxt->cur += (val)
2201 #define NXT(val) ctxt->cur[(val)]
2202 #define CUR_PTR ctxt->cur
2203 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2204 
2205 #define COPY_BUF(l,b,i,v)                                              \
2206     if (l == 1) b[i++] = v;                                            \
2207     else i += xmlCopyChar(l,&b[i],v)
2208 
2209 #define NEXTL(l)  ctxt->cur += l
2210 
2211 #define SKIP_BLANKS							\
2212     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2213 
2214 #define CURRENT (*ctxt->cur)
2215 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
2216 
2217 
2218 #ifndef DBL_DIG
2219 #define DBL_DIG 16
2220 #endif
2221 #ifndef DBL_EPSILON
2222 #define DBL_EPSILON 1E-9
2223 #endif
2224 
2225 #define UPPER_DOUBLE 1E9
2226 #define LOWER_DOUBLE 1E-5
2227 #define	LOWER_DOUBLE_EXP 5
2228 
2229 #define INTEGER_DIGITS DBL_DIG
2230 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2231 #define EXPONENT_DIGITS (3 + 2)
2232 
2233 /**
2234  * xmlXPathFormatNumber:
2235  * @number:     number to format
2236  * @buffer:     output buffer
2237  * @buffersize: size of output buffer
2238  *
2239  * Convert the number into a string representation.
2240  */
2241 static void
xmlXPathFormatNumber(double number,char buffer[],int buffersize)2242 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2243 {
2244     switch (xmlXPathIsInf(number)) {
2245     case 1:
2246 	if (buffersize > (int)sizeof("Infinity"))
2247 	    snprintf(buffer, buffersize, "Infinity");
2248 	break;
2249     case -1:
2250 	if (buffersize > (int)sizeof("-Infinity"))
2251 	    snprintf(buffer, buffersize, "-Infinity");
2252 	break;
2253     default:
2254 	if (xmlXPathIsNaN(number)) {
2255 	    if (buffersize > (int)sizeof("NaN"))
2256 		snprintf(buffer, buffersize, "NaN");
2257 	} else if (number == 0) {
2258             /* Omit sign for negative zero. */
2259 	    snprintf(buffer, buffersize, "0");
2260 	} else if ((number > INT_MIN) && (number < INT_MAX) &&
2261                    (number == (int) number)) {
2262 	    char work[30];
2263 	    char *ptr, *cur;
2264 	    int value = (int) number;
2265 
2266             ptr = &buffer[0];
2267 	    if (value == 0) {
2268 		*ptr++ = '0';
2269 	    } else {
2270 		snprintf(work, 29, "%d", value);
2271 		cur = &work[0];
2272 		while ((*cur) && (ptr - buffer < buffersize)) {
2273 		    *ptr++ = *cur++;
2274 		}
2275 	    }
2276 	    if (ptr - buffer < buffersize) {
2277 		*ptr = 0;
2278 	    } else if (buffersize > 0) {
2279 		ptr--;
2280 		*ptr = 0;
2281 	    }
2282 	} else {
2283 	    /*
2284 	      For the dimension of work,
2285 	          DBL_DIG is number of significant digits
2286 		  EXPONENT is only needed for "scientific notation"
2287 	          3 is sign, decimal point, and terminating zero
2288 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2289 	      Note that this dimension is slightly (a few characters)
2290 	      larger than actually necessary.
2291 	    */
2292 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2293 	    int integer_place, fraction_place;
2294 	    char *ptr;
2295 	    char *after_fraction;
2296 	    double absolute_value;
2297 	    int size;
2298 
2299 	    absolute_value = fabs(number);
2300 
2301 	    /*
2302 	     * First choose format - scientific or regular floating point.
2303 	     * In either case, result is in work, and after_fraction points
2304 	     * just past the fractional part.
2305 	    */
2306 	    if ( ((absolute_value > UPPER_DOUBLE) ||
2307 		  (absolute_value < LOWER_DOUBLE)) &&
2308 		 (absolute_value != 0.0) ) {
2309 		/* Use scientific notation */
2310 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2311 		fraction_place = DBL_DIG - 1;
2312 		size = snprintf(work, sizeof(work),"%*.*e",
2313 			 integer_place, fraction_place, number);
2314 		while ((size > 0) && (work[size] != 'e')) size--;
2315 
2316 	    }
2317 	    else {
2318 		/* Use regular notation */
2319 		if (absolute_value > 0.0) {
2320 		    integer_place = (int)log10(absolute_value);
2321 		    if (integer_place > 0)
2322 		        fraction_place = DBL_DIG - integer_place - 1;
2323 		    else
2324 		        fraction_place = DBL_DIG - integer_place;
2325 		} else {
2326 		    fraction_place = 1;
2327 		}
2328 		size = snprintf(work, sizeof(work), "%0.*f",
2329 				fraction_place, number);
2330 	    }
2331 
2332 	    /* Remove leading spaces sometimes inserted by snprintf */
2333 	    while (work[0] == ' ') {
2334 	        for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2335 		size--;
2336 	    }
2337 
2338 	    /* Remove fractional trailing zeroes */
2339 	    after_fraction = work + size;
2340 	    ptr = after_fraction;
2341 	    while (*(--ptr) == '0')
2342 		;
2343 	    if (*ptr != '.')
2344 	        ptr++;
2345 	    while ((*ptr++ = *after_fraction++) != 0);
2346 
2347 	    /* Finally copy result back to caller */
2348 	    size = strlen(work) + 1;
2349 	    if (size > buffersize) {
2350 		work[buffersize - 1] = 0;
2351 		size = buffersize;
2352 	    }
2353 	    memmove(buffer, work, size);
2354 	}
2355 	break;
2356     }
2357 }
2358 
2359 
2360 /************************************************************************
2361  *									*
2362  *			Routines to handle NodeSets			*
2363  *									*
2364  ************************************************************************/
2365 
2366 /**
2367  * xmlXPathOrderDocElems:
2368  * @doc:  an input document
2369  *
2370  * Call this routine to speed up XPath computation on static documents.
2371  * This stamps all the element nodes with the document order
2372  * Like for line information, the order is kept in the element->content
2373  * field, the value stored is actually - the node number (starting at -1)
2374  * to be able to differentiate from line numbers.
2375  *
2376  * Returns the number of elements found in the document or -1 in case
2377  *    of error.
2378  */
2379 long
xmlXPathOrderDocElems(xmlDocPtr doc)2380 xmlXPathOrderDocElems(xmlDocPtr doc) {
2381     ptrdiff_t count = 0;
2382     xmlNodePtr cur;
2383 
2384     if (doc == NULL)
2385 	return(-1);
2386     cur = doc->children;
2387     while (cur != NULL) {
2388 	if (cur->type == XML_ELEMENT_NODE) {
2389 	    cur->content = (void *) (-(++count));
2390 	    if (cur->children != NULL) {
2391 		cur = cur->children;
2392 		continue;
2393 	    }
2394 	}
2395 	if (cur->next != NULL) {
2396 	    cur = cur->next;
2397 	    continue;
2398 	}
2399 	do {
2400 	    cur = cur->parent;
2401 	    if (cur == NULL)
2402 		break;
2403 	    if (cur == (xmlNodePtr) doc) {
2404 		cur = NULL;
2405 		break;
2406 	    }
2407 	    if (cur->next != NULL) {
2408 		cur = cur->next;
2409 		break;
2410 	    }
2411 	} while (cur != NULL);
2412     }
2413     return(count);
2414 }
2415 
2416 /**
2417  * xmlXPathCmpNodes:
2418  * @node1:  the first node
2419  * @node2:  the second node
2420  *
2421  * Compare two nodes w.r.t document order
2422  *
2423  * Returns -2 in case of error 1 if first point < second point, 0 if
2424  *         it's the same node, -1 otherwise
2425  */
2426 int
xmlXPathCmpNodes(xmlNodePtr node1,xmlNodePtr node2)2427 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2428     int depth1, depth2;
2429     int attr1 = 0, attr2 = 0;
2430     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2431     xmlNodePtr cur, root;
2432 
2433     if ((node1 == NULL) || (node2 == NULL))
2434 	return(-2);
2435     /*
2436      * a couple of optimizations which will avoid computations in most cases
2437      */
2438     if (node1 == node2)		/* trivial case */
2439 	return(0);
2440     if (node1->type == XML_ATTRIBUTE_NODE) {
2441 	attr1 = 1;
2442 	attrNode1 = node1;
2443 	node1 = node1->parent;
2444     }
2445     if (node2->type == XML_ATTRIBUTE_NODE) {
2446 	attr2 = 1;
2447 	attrNode2 = node2;
2448 	node2 = node2->parent;
2449     }
2450     if (node1 == node2) {
2451 	if (attr1 == attr2) {
2452 	    /* not required, but we keep attributes in order */
2453 	    if (attr1 != 0) {
2454 	        cur = attrNode2->prev;
2455 		while (cur != NULL) {
2456 		    if (cur == attrNode1)
2457 		        return (1);
2458 		    cur = cur->prev;
2459 		}
2460 		return (-1);
2461 	    }
2462 	    return(0);
2463 	}
2464 	if (attr2 == 1)
2465 	    return(1);
2466 	return(-1);
2467     }
2468     if ((node1->type == XML_NAMESPACE_DECL) ||
2469         (node2->type == XML_NAMESPACE_DECL))
2470 	return(1);
2471     if (node1 == node2->prev)
2472 	return(1);
2473     if (node1 == node2->next)
2474 	return(-1);
2475 
2476     /*
2477      * Speedup using document order if available.
2478      */
2479     if ((node1->type == XML_ELEMENT_NODE) &&
2480 	(node2->type == XML_ELEMENT_NODE) &&
2481 	(0 > (ptrdiff_t) node1->content) &&
2482 	(0 > (ptrdiff_t) node2->content) &&
2483 	(node1->doc == node2->doc)) {
2484 	ptrdiff_t l1, l2;
2485 
2486 	l1 = -((ptrdiff_t) node1->content);
2487 	l2 = -((ptrdiff_t) node2->content);
2488 	if (l1 < l2)
2489 	    return(1);
2490 	if (l1 > l2)
2491 	    return(-1);
2492     }
2493 
2494     /*
2495      * compute depth to root
2496      */
2497     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2498 	if (cur->parent == node1)
2499 	    return(1);
2500 	depth2++;
2501     }
2502     root = cur;
2503     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2504 	if (cur->parent == node2)
2505 	    return(-1);
2506 	depth1++;
2507     }
2508     /*
2509      * Distinct document (or distinct entities :-( ) case.
2510      */
2511     if (root != cur) {
2512 	return(-2);
2513     }
2514     /*
2515      * get the nearest common ancestor.
2516      */
2517     while (depth1 > depth2) {
2518 	depth1--;
2519 	node1 = node1->parent;
2520     }
2521     while (depth2 > depth1) {
2522 	depth2--;
2523 	node2 = node2->parent;
2524     }
2525     while (node1->parent != node2->parent) {
2526 	node1 = node1->parent;
2527 	node2 = node2->parent;
2528 	/* should not happen but just in case ... */
2529 	if ((node1 == NULL) || (node2 == NULL))
2530 	    return(-2);
2531     }
2532     /*
2533      * Find who's first.
2534      */
2535     if (node1 == node2->prev)
2536 	return(1);
2537     if (node1 == node2->next)
2538 	return(-1);
2539     /*
2540      * Speedup using document order if available.
2541      */
2542     if ((node1->type == XML_ELEMENT_NODE) &&
2543 	(node2->type == XML_ELEMENT_NODE) &&
2544 	(0 > (ptrdiff_t) node1->content) &&
2545 	(0 > (ptrdiff_t) node2->content) &&
2546 	(node1->doc == node2->doc)) {
2547 	ptrdiff_t l1, l2;
2548 
2549 	l1 = -((ptrdiff_t) node1->content);
2550 	l2 = -((ptrdiff_t) node2->content);
2551 	if (l1 < l2)
2552 	    return(1);
2553 	if (l1 > l2)
2554 	    return(-1);
2555     }
2556 
2557     for (cur = node1->next;cur != NULL;cur = cur->next)
2558 	if (cur == node2)
2559 	    return(1);
2560     return(-1); /* assume there is no sibling list corruption */
2561 }
2562 
2563 /**
2564  * xmlXPathNodeSetSort:
2565  * @set:  the node set
2566  *
2567  * Sort the node set in document order
2568  */
2569 void
xmlXPathNodeSetSort(xmlNodeSetPtr set)2570 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
2571 #ifndef WITH_TIM_SORT
2572     int i, j, incr, len;
2573     xmlNodePtr tmp;
2574 #endif
2575 
2576     if (set == NULL)
2577 	return;
2578 
2579 #ifndef WITH_TIM_SORT
2580     /*
2581      * Use the old Shell's sort implementation to sort the node-set
2582      * Timsort ought to be quite faster
2583      */
2584     len = set->nodeNr;
2585     for (incr = len / 2; incr > 0; incr /= 2) {
2586 	for (i = incr; i < len; i++) {
2587 	    j = i - incr;
2588 	    while (j >= 0) {
2589 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2590 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
2591 			set->nodeTab[j + incr]) == -1)
2592 #else
2593 		if (xmlXPathCmpNodes(set->nodeTab[j],
2594 			set->nodeTab[j + incr]) == -1)
2595 #endif
2596 		{
2597 		    tmp = set->nodeTab[j];
2598 		    set->nodeTab[j] = set->nodeTab[j + incr];
2599 		    set->nodeTab[j + incr] = tmp;
2600 		    j -= incr;
2601 		} else
2602 		    break;
2603 	    }
2604 	}
2605     }
2606 #else /* WITH_TIM_SORT */
2607     libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2608 #endif /* WITH_TIM_SORT */
2609 }
2610 
2611 #define XML_NODESET_DEFAULT	10
2612 /**
2613  * xmlXPathNodeSetDupNs:
2614  * @node:  the parent node of the namespace XPath node
2615  * @ns:  the libxml namespace declaration node.
2616  *
2617  * Namespace node in libxml don't match the XPath semantic. In a node set
2618  * the namespace nodes are duplicated and the next pointer is set to the
2619  * parent node in the XPath semantic.
2620  *
2621  * Returns the newly created object.
2622  */
2623 static xmlNodePtr
xmlXPathNodeSetDupNs(xmlNodePtr node,xmlNsPtr ns)2624 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2625     xmlNsPtr cur;
2626 
2627     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2628 	return(NULL);
2629     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
2630 	return((xmlNodePtr) ns);
2631 
2632     /*
2633      * Allocate a new Namespace and fill the fields.
2634      */
2635     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2636     if (cur == NULL)
2637 	return(NULL);
2638     memset(cur, 0, sizeof(xmlNs));
2639     cur->type = XML_NAMESPACE_DECL;
2640     if (ns->href != NULL) {
2641 	cur->href = xmlStrdup(ns->href);
2642         if (cur->href == NULL) {
2643             xmlFree(cur);
2644             return(NULL);
2645         }
2646     }
2647     if (ns->prefix != NULL) {
2648 	cur->prefix = xmlStrdup(ns->prefix);
2649         if (cur->prefix == NULL) {
2650             xmlFree((xmlChar *) cur->href);
2651             xmlFree(cur);
2652             return(NULL);
2653         }
2654     }
2655     cur->next = (xmlNsPtr) node;
2656     return((xmlNodePtr) cur);
2657 }
2658 
2659 /**
2660  * xmlXPathNodeSetFreeNs:
2661  * @ns:  the XPath namespace node found in a nodeset.
2662  *
2663  * Namespace nodes in libxml don't match the XPath semantic. In a node set
2664  * the namespace nodes are duplicated and the next pointer is set to the
2665  * parent node in the XPath semantic. Check if such a node needs to be freed
2666  */
2667 void
xmlXPathNodeSetFreeNs(xmlNsPtr ns)2668 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
2669     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2670 	return;
2671 
2672     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2673 	if (ns->href != NULL)
2674 	    xmlFree((xmlChar *)ns->href);
2675 	if (ns->prefix != NULL)
2676 	    xmlFree((xmlChar *)ns->prefix);
2677 	xmlFree(ns);
2678     }
2679 }
2680 
2681 /**
2682  * xmlXPathNodeSetCreate:
2683  * @val:  an initial xmlNodePtr, or NULL
2684  *
2685  * Create a new xmlNodeSetPtr of type double and of value @val
2686  *
2687  * Returns the newly created object.
2688  */
2689 xmlNodeSetPtr
xmlXPathNodeSetCreate(xmlNodePtr val)2690 xmlXPathNodeSetCreate(xmlNodePtr val) {
2691     xmlNodeSetPtr ret;
2692 
2693     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2694     if (ret == NULL)
2695 	return(NULL);
2696     memset(ret, 0 , sizeof(xmlNodeSet));
2697     if (val != NULL) {
2698         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2699 					     sizeof(xmlNodePtr));
2700 	if (ret->nodeTab == NULL) {
2701 	    xmlFree(ret);
2702 	    return(NULL);
2703 	}
2704 	memset(ret->nodeTab, 0 ,
2705 	       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2706         ret->nodeMax = XML_NODESET_DEFAULT;
2707 	if (val->type == XML_NAMESPACE_DECL) {
2708 	    xmlNsPtr ns = (xmlNsPtr) val;
2709             xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2710 
2711             if (nsNode == NULL) {
2712                 xmlXPathFreeNodeSet(ret);
2713                 return(NULL);
2714             }
2715 	    ret->nodeTab[ret->nodeNr++] = nsNode;
2716 	} else
2717 	    ret->nodeTab[ret->nodeNr++] = val;
2718     }
2719     return(ret);
2720 }
2721 
2722 /**
2723  * xmlXPathNodeSetContains:
2724  * @cur:  the node-set
2725  * @val:  the node
2726  *
2727  * checks whether @cur contains @val
2728  *
2729  * Returns true (1) if @cur contains @val, false (0) otherwise
2730  */
2731 int
xmlXPathNodeSetContains(xmlNodeSetPtr cur,xmlNodePtr val)2732 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
2733     int i;
2734 
2735     if ((cur == NULL) || (val == NULL)) return(0);
2736     if (val->type == XML_NAMESPACE_DECL) {
2737 	for (i = 0; i < cur->nodeNr; i++) {
2738 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2739 		xmlNsPtr ns1, ns2;
2740 
2741 		ns1 = (xmlNsPtr) val;
2742 		ns2 = (xmlNsPtr) cur->nodeTab[i];
2743 		if (ns1 == ns2)
2744 		    return(1);
2745 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
2746 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
2747 		    return(1);
2748 	    }
2749 	}
2750     } else {
2751 	for (i = 0; i < cur->nodeNr; i++) {
2752 	    if (cur->nodeTab[i] == val)
2753 		return(1);
2754 	}
2755     }
2756     return(0);
2757 }
2758 
2759 /**
2760  * xmlXPathNodeSetAddNs:
2761  * @cur:  the initial node set
2762  * @node:  the hosting node
2763  * @ns:  a the namespace node
2764  *
2765  * add a new namespace node to an existing NodeSet
2766  *
2767  * Returns 0 in case of success and -1 in case of error
2768  */
2769 int
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur,xmlNodePtr node,xmlNsPtr ns)2770 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
2771     int i;
2772     xmlNodePtr nsNode;
2773 
2774     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
2775         (ns->type != XML_NAMESPACE_DECL) ||
2776 	(node->type != XML_ELEMENT_NODE))
2777 	return(-1);
2778 
2779     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2780     /*
2781      * prevent duplicates
2782      */
2783     for (i = 0;i < cur->nodeNr;i++) {
2784         if ((cur->nodeTab[i] != NULL) &&
2785 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
2786 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
2787 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
2788 	    return(0);
2789     }
2790 
2791     /*
2792      * grow the nodeTab if needed
2793      */
2794     if (cur->nodeMax == 0) {
2795         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2796 					     sizeof(xmlNodePtr));
2797 	if (cur->nodeTab == NULL)
2798 	    return(-1);
2799 	memset(cur->nodeTab, 0 ,
2800 	       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2801         cur->nodeMax = XML_NODESET_DEFAULT;
2802     } else if (cur->nodeNr == cur->nodeMax) {
2803         xmlNodePtr *temp;
2804 
2805         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2806             return(-1);
2807 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2808 				      sizeof(xmlNodePtr));
2809 	if (temp == NULL)
2810 	    return(-1);
2811         cur->nodeMax *= 2;
2812 	cur->nodeTab = temp;
2813     }
2814     nsNode = xmlXPathNodeSetDupNs(node, ns);
2815     if(nsNode == NULL)
2816         return(-1);
2817     cur->nodeTab[cur->nodeNr++] = nsNode;
2818     return(0);
2819 }
2820 
2821 /**
2822  * xmlXPathNodeSetAdd:
2823  * @cur:  the initial node set
2824  * @val:  a new xmlNodePtr
2825  *
2826  * add a new xmlNodePtr to an existing NodeSet
2827  *
2828  * Returns 0 in case of success, and -1 in case of error
2829  */
2830 int
xmlXPathNodeSetAdd(xmlNodeSetPtr cur,xmlNodePtr val)2831 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
2832     int i;
2833 
2834     if ((cur == NULL) || (val == NULL)) return(-1);
2835 
2836     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2837     /*
2838      * prevent duplicates
2839      */
2840     for (i = 0;i < cur->nodeNr;i++)
2841         if (cur->nodeTab[i] == val) return(0);
2842 
2843     /*
2844      * grow the nodeTab if needed
2845      */
2846     if (cur->nodeMax == 0) {
2847         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2848 					     sizeof(xmlNodePtr));
2849 	if (cur->nodeTab == NULL)
2850 	    return(-1);
2851 	memset(cur->nodeTab, 0 ,
2852 	       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2853         cur->nodeMax = XML_NODESET_DEFAULT;
2854     } else if (cur->nodeNr == cur->nodeMax) {
2855         xmlNodePtr *temp;
2856 
2857         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2858             return(-1);
2859 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2860 				      sizeof(xmlNodePtr));
2861 	if (temp == NULL)
2862 	    return(-1);
2863         cur->nodeMax *= 2;
2864 	cur->nodeTab = temp;
2865     }
2866     if (val->type == XML_NAMESPACE_DECL) {
2867 	xmlNsPtr ns = (xmlNsPtr) val;
2868         xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2869 
2870         if (nsNode == NULL)
2871             return(-1);
2872 	cur->nodeTab[cur->nodeNr++] = nsNode;
2873     } else
2874 	cur->nodeTab[cur->nodeNr++] = val;
2875     return(0);
2876 }
2877 
2878 /**
2879  * xmlXPathNodeSetAddUnique:
2880  * @cur:  the initial node set
2881  * @val:  a new xmlNodePtr
2882  *
2883  * add a new xmlNodePtr to an existing NodeSet, optimized version
2884  * when we are sure the node is not already in the set.
2885  *
2886  * Returns 0 in case of success and -1 in case of failure
2887  */
2888 int
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur,xmlNodePtr val)2889 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
2890     if ((cur == NULL) || (val == NULL)) return(-1);
2891 
2892     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2893     /*
2894      * grow the nodeTab if needed
2895      */
2896     if (cur->nodeMax == 0) {
2897         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2898 					     sizeof(xmlNodePtr));
2899 	if (cur->nodeTab == NULL)
2900 	    return(-1);
2901 	memset(cur->nodeTab, 0 ,
2902 	       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2903         cur->nodeMax = XML_NODESET_DEFAULT;
2904     } else if (cur->nodeNr == cur->nodeMax) {
2905         xmlNodePtr *temp;
2906 
2907         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2908             return(-1);
2909 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2910 				      sizeof(xmlNodePtr));
2911 	if (temp == NULL)
2912 	    return(-1);
2913 	cur->nodeTab = temp;
2914         cur->nodeMax *= 2;
2915     }
2916     if (val->type == XML_NAMESPACE_DECL) {
2917 	xmlNsPtr ns = (xmlNsPtr) val;
2918         xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2919 
2920         if (nsNode == NULL)
2921             return(-1);
2922 	cur->nodeTab[cur->nodeNr++] = nsNode;
2923     } else
2924 	cur->nodeTab[cur->nodeNr++] = val;
2925     return(0);
2926 }
2927 
2928 /**
2929  * xmlXPathNodeSetMerge:
2930  * @val1:  the first NodeSet or NULL
2931  * @val2:  the second NodeSet
2932  *
2933  * Merges two nodesets, all nodes from @val2 are added to @val1
2934  * if @val1 is NULL, a new set is created and copied from @val2
2935  *
2936  * Returns @val1 once extended or NULL in case of error.
2937  *
2938  * Frees @val1 in case of error.
2939  */
2940 xmlNodeSetPtr
xmlXPathNodeSetMerge(xmlNodeSetPtr val1,xmlNodeSetPtr val2)2941 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
2942     int i, j, initNr, skip;
2943     xmlNodePtr n1, n2;
2944 
2945     if (val1 == NULL) {
2946 	val1 = xmlXPathNodeSetCreate(NULL);
2947         if (val1 == NULL)
2948             return (NULL);
2949     }
2950     if (val2 == NULL)
2951         return(val1);
2952 
2953     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2954     initNr = val1->nodeNr;
2955 
2956     for (i = 0;i < val2->nodeNr;i++) {
2957 	n2 = val2->nodeTab[i];
2958 	/*
2959 	 * check against duplicates
2960 	 */
2961 	skip = 0;
2962 	for (j = 0; j < initNr; j++) {
2963 	    n1 = val1->nodeTab[j];
2964 	    if (n1 == n2) {
2965 		skip = 1;
2966 		break;
2967 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
2968 		       (n2->type == XML_NAMESPACE_DECL)) {
2969 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2970 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2971 			((xmlNsPtr) n2)->prefix)))
2972 		{
2973 		    skip = 1;
2974 		    break;
2975 		}
2976 	    }
2977 	}
2978 	if (skip)
2979 	    continue;
2980 
2981 	/*
2982 	 * grow the nodeTab if needed
2983 	 */
2984 	if (val1->nodeMax == 0) {
2985 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2986 						    sizeof(xmlNodePtr));
2987 	    if (val1->nodeTab == NULL)
2988 		goto error;
2989 	    memset(val1->nodeTab, 0 ,
2990 		   XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2991 	    val1->nodeMax = XML_NODESET_DEFAULT;
2992 	} else if (val1->nodeNr == val1->nodeMax) {
2993 	    xmlNodePtr *temp;
2994 
2995             if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2996                 goto error;
2997 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
2998 					     sizeof(xmlNodePtr));
2999 	    if (temp == NULL)
3000 		goto error;
3001 	    val1->nodeTab = temp;
3002 	    val1->nodeMax *= 2;
3003 	}
3004 	if (n2->type == XML_NAMESPACE_DECL) {
3005 	    xmlNsPtr ns = (xmlNsPtr) n2;
3006             xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3007 
3008             if (nsNode == NULL)
3009                 goto error;
3010 	    val1->nodeTab[val1->nodeNr++] = nsNode;
3011 	} else
3012 	    val1->nodeTab[val1->nodeNr++] = n2;
3013     }
3014 
3015     return(val1);
3016 
3017 error:
3018     xmlXPathFreeNodeSet(val1);
3019     return(NULL);
3020 }
3021 
3022 
3023 /**
3024  * xmlXPathNodeSetMergeAndClear:
3025  * @set1:  the first NodeSet or NULL
3026  * @set2:  the second NodeSet
3027  *
3028  * Merges two nodesets, all nodes from @set2 are added to @set1.
3029  * Checks for duplicate nodes. Clears set2.
3030  *
3031  * Returns @set1 once extended or NULL in case of error.
3032  *
3033  * Frees @set1 in case of error.
3034  */
3035 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1,xmlNodeSetPtr set2)3036 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3037 {
3038     {
3039 	int i, j, initNbSet1;
3040 	xmlNodePtr n1, n2;
3041 
3042 	initNbSet1 = set1->nodeNr;
3043 	for (i = 0;i < set2->nodeNr;i++) {
3044 	    n2 = set2->nodeTab[i];
3045 	    /*
3046 	    * Skip duplicates.
3047 	    */
3048 	    for (j = 0; j < initNbSet1; j++) {
3049 		n1 = set1->nodeTab[j];
3050 		if (n1 == n2) {
3051 		    goto skip_node;
3052 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
3053 		    (n2->type == XML_NAMESPACE_DECL))
3054 		{
3055 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3056 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
3057 			((xmlNsPtr) n2)->prefix)))
3058 		    {
3059 			/*
3060 			* Free the namespace node.
3061 			*/
3062 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3063 			goto skip_node;
3064 		    }
3065 		}
3066 	    }
3067 	    /*
3068 	    * grow the nodeTab if needed
3069 	    */
3070 	    if (set1->nodeMax == 0) {
3071 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3072 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3073 		if (set1->nodeTab == NULL)
3074 		    goto error;
3075 		memset(set1->nodeTab, 0,
3076 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3077 		set1->nodeMax = XML_NODESET_DEFAULT;
3078 	    } else if (set1->nodeNr >= set1->nodeMax) {
3079 		xmlNodePtr *temp;
3080 
3081                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
3082                     goto error;
3083 		temp = (xmlNodePtr *) xmlRealloc(
3084 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3085 		if (temp == NULL)
3086 		    goto error;
3087 		set1->nodeTab = temp;
3088 		set1->nodeMax *= 2;
3089 	    }
3090 	    set1->nodeTab[set1->nodeNr++] = n2;
3091 skip_node:
3092             set2->nodeTab[i] = NULL;
3093 	}
3094     }
3095     set2->nodeNr = 0;
3096     return(set1);
3097 
3098 error:
3099     xmlXPathFreeNodeSet(set1);
3100     xmlXPathNodeSetClear(set2, 1);
3101     return(NULL);
3102 }
3103 
3104 /**
3105  * xmlXPathNodeSetMergeAndClearNoDupls:
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  * Doesn't check 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
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1,xmlNodeSetPtr set2)3117 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3118 {
3119     {
3120 	int i;
3121 	xmlNodePtr n2;
3122 
3123 	for (i = 0;i < set2->nodeNr;i++) {
3124 	    n2 = set2->nodeTab[i];
3125 	    if (set1->nodeMax == 0) {
3126 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3127 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3128 		if (set1->nodeTab == NULL)
3129 		    goto error;
3130 		memset(set1->nodeTab, 0,
3131 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3132 		set1->nodeMax = XML_NODESET_DEFAULT;
3133 	    } else if (set1->nodeNr >= set1->nodeMax) {
3134 		xmlNodePtr *temp;
3135 
3136                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
3137                     goto error;
3138 		temp = (xmlNodePtr *) xmlRealloc(
3139 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3140 		if (temp == NULL)
3141 		    goto error;
3142 		set1->nodeTab = temp;
3143 		set1->nodeMax *= 2;
3144 	    }
3145 	    set1->nodeTab[set1->nodeNr++] = n2;
3146             set2->nodeTab[i] = NULL;
3147 	}
3148     }
3149     set2->nodeNr = 0;
3150     return(set1);
3151 
3152 error:
3153     xmlXPathFreeNodeSet(set1);
3154     xmlXPathNodeSetClear(set2, 1);
3155     return(NULL);
3156 }
3157 
3158 /**
3159  * xmlXPathNodeSetDel:
3160  * @cur:  the initial node set
3161  * @val:  an xmlNodePtr
3162  *
3163  * Removes an xmlNodePtr from an existing NodeSet
3164  */
3165 void
xmlXPathNodeSetDel(xmlNodeSetPtr cur,xmlNodePtr val)3166 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3167     int i;
3168 
3169     if (cur == NULL) return;
3170     if (val == NULL) return;
3171 
3172     /*
3173      * find node in nodeTab
3174      */
3175     for (i = 0;i < cur->nodeNr;i++)
3176         if (cur->nodeTab[i] == val) break;
3177 
3178     if (i >= cur->nodeNr) {	/* not found */
3179         return;
3180     }
3181     if ((cur->nodeTab[i] != NULL) &&
3182 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
3183 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
3184     cur->nodeNr--;
3185     for (;i < cur->nodeNr;i++)
3186         cur->nodeTab[i] = cur->nodeTab[i + 1];
3187     cur->nodeTab[cur->nodeNr] = NULL;
3188 }
3189 
3190 /**
3191  * xmlXPathNodeSetRemove:
3192  * @cur:  the initial node set
3193  * @val:  the index to remove
3194  *
3195  * Removes an entry from an existing NodeSet list.
3196  */
3197 void
xmlXPathNodeSetRemove(xmlNodeSetPtr cur,int val)3198 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
3199     if (cur == NULL) return;
3200     if (val >= cur->nodeNr) return;
3201     if ((cur->nodeTab[val] != NULL) &&
3202 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
3203 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
3204     cur->nodeNr--;
3205     for (;val < cur->nodeNr;val++)
3206         cur->nodeTab[val] = cur->nodeTab[val + 1];
3207     cur->nodeTab[cur->nodeNr] = NULL;
3208 }
3209 
3210 /**
3211  * xmlXPathFreeNodeSet:
3212  * @obj:  the xmlNodeSetPtr to free
3213  *
3214  * Free the NodeSet compound (not the actual nodes !).
3215  */
3216 void
xmlXPathFreeNodeSet(xmlNodeSetPtr obj)3217 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
3218     if (obj == NULL) return;
3219     if (obj->nodeTab != NULL) {
3220 	int i;
3221 
3222 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
3223 	for (i = 0;i < obj->nodeNr;i++)
3224 	    if ((obj->nodeTab[i] != NULL) &&
3225 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3226 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3227 	xmlFree(obj->nodeTab);
3228     }
3229     xmlFree(obj);
3230 }
3231 
3232 /**
3233  * xmlXPathNodeSetClearFromPos:
3234  * @set: the node set to be cleared
3235  * @pos: the start position to clear from
3236  *
3237  * Clears the list from temporary XPath objects (e.g. namespace nodes
3238  * are feed) starting with the entry at @pos, but does *not* free the list
3239  * itself. Sets the length of the list to @pos.
3240  */
3241 static void
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set,int pos,int hasNsNodes)3242 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
3243 {
3244     if ((set == NULL) || (pos >= set->nodeNr))
3245 	return;
3246     else if ((hasNsNodes)) {
3247 	int i;
3248 	xmlNodePtr node;
3249 
3250 	for (i = pos; i < set->nodeNr; i++) {
3251 	    node = set->nodeTab[i];
3252 	    if ((node != NULL) &&
3253 		(node->type == XML_NAMESPACE_DECL))
3254 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3255 	}
3256     }
3257     set->nodeNr = pos;
3258 }
3259 
3260 /**
3261  * xmlXPathNodeSetClear:
3262  * @set:  the node set to clear
3263  *
3264  * Clears the list from all temporary XPath objects (e.g. namespace nodes
3265  * are feed), but does *not* free the list itself. Sets the length of the
3266  * list to 0.
3267  */
3268 static void
xmlXPathNodeSetClear(xmlNodeSetPtr set,int hasNsNodes)3269 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
3270 {
3271     xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3272 }
3273 
3274 /**
3275  * xmlXPathNodeSetKeepLast:
3276  * @set: the node set to be cleared
3277  *
3278  * Move the last node to the first position and clear temporary XPath objects
3279  * (e.g. namespace nodes) from all other nodes. Sets the length of the list
3280  * to 1.
3281  */
3282 static void
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)3283 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
3284 {
3285     int i;
3286     xmlNodePtr node;
3287 
3288     if ((set == NULL) || (set->nodeNr <= 1))
3289 	return;
3290     for (i = 0; i < set->nodeNr - 1; i++) {
3291         node = set->nodeTab[i];
3292         if ((node != NULL) &&
3293             (node->type == XML_NAMESPACE_DECL))
3294             xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3295     }
3296     set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
3297     set->nodeNr = 1;
3298 }
3299 
3300 /**
3301  * xmlXPathNewNodeSet:
3302  * @val:  the NodePtr value
3303  *
3304  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3305  * it with the single Node @val
3306  *
3307  * Returns the newly created object.
3308  */
3309 xmlXPathObjectPtr
xmlXPathNewNodeSet(xmlNodePtr val)3310 xmlXPathNewNodeSet(xmlNodePtr val) {
3311     xmlXPathObjectPtr ret;
3312 
3313     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3314     if (ret == NULL)
3315 	return(NULL);
3316     memset(ret, 0 , sizeof(xmlXPathObject));
3317     ret->type = XPATH_NODESET;
3318     ret->boolval = 0;
3319     ret->nodesetval = xmlXPathNodeSetCreate(val);
3320     if (ret->nodesetval == NULL) {
3321         xmlFree(ret);
3322         return(NULL);
3323     }
3324     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3325     return(ret);
3326 }
3327 
3328 /**
3329  * xmlXPathNewValueTree:
3330  * @val:  the NodePtr value
3331  *
3332  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
3333  * it with the tree root @val
3334  *
3335  * Returns the newly created object.
3336  */
3337 xmlXPathObjectPtr
xmlXPathNewValueTree(xmlNodePtr val)3338 xmlXPathNewValueTree(xmlNodePtr val) {
3339     xmlXPathObjectPtr ret;
3340 
3341     ret = xmlXPathNewNodeSet(val);
3342     if (ret == NULL)
3343 	return(NULL);
3344     ret->type = XPATH_XSLT_TREE;
3345 
3346     return(ret);
3347 }
3348 
3349 /**
3350  * xmlXPathNewNodeSetList:
3351  * @val:  an existing NodeSet
3352  *
3353  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3354  * it with the Nodeset @val
3355  *
3356  * Returns the newly created object.
3357  */
3358 xmlXPathObjectPtr
xmlXPathNewNodeSetList(xmlNodeSetPtr val)3359 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
3360 {
3361     xmlXPathObjectPtr ret;
3362 
3363     if (val == NULL)
3364         ret = NULL;
3365     else if (val->nodeTab == NULL)
3366         ret = xmlXPathNewNodeSet(NULL);
3367     else {
3368         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
3369         if (ret) {
3370             ret->nodesetval = xmlXPathNodeSetMerge(NULL, val);
3371             if (ret->nodesetval == NULL) {
3372                 xmlFree(ret);
3373                 return(NULL);
3374             }
3375         }
3376     }
3377 
3378     return (ret);
3379 }
3380 
3381 /**
3382  * xmlXPathWrapNodeSet:
3383  * @val:  the NodePtr value
3384  *
3385  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
3386  *
3387  * Returns the newly created object.
3388  *
3389  * In case of error the node set is destroyed and NULL is returned.
3390  */
3391 xmlXPathObjectPtr
xmlXPathWrapNodeSet(xmlNodeSetPtr val)3392 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
3393     xmlXPathObjectPtr ret;
3394 
3395     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3396     if (ret == NULL) {
3397         xmlXPathFreeNodeSet(val);
3398 	return(NULL);
3399     }
3400     memset(ret, 0 , sizeof(xmlXPathObject));
3401     ret->type = XPATH_NODESET;
3402     ret->nodesetval = val;
3403     return(ret);
3404 }
3405 
3406 /**
3407  * xmlXPathFreeNodeSetList:
3408  * @obj:  an existing NodeSetList object
3409  *
3410  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
3411  * the list contrary to xmlXPathFreeObject().
3412  */
3413 void
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj)3414 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
3415     if (obj == NULL) return;
3416     xmlFree(obj);
3417 }
3418 
3419 /**
3420  * xmlXPathDifference:
3421  * @nodes1:  a node-set
3422  * @nodes2:  a node-set
3423  *
3424  * Implements the EXSLT - Sets difference() function:
3425  *    node-set set:difference (node-set, node-set)
3426  *
3427  * Returns the difference between the two node sets, or nodes1 if
3428  *         nodes2 is empty
3429  */
3430 xmlNodeSetPtr
xmlXPathDifference(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3431 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3432     xmlNodeSetPtr ret;
3433     int i, l1;
3434     xmlNodePtr cur;
3435 
3436     if (xmlXPathNodeSetIsEmpty(nodes2))
3437 	return(nodes1);
3438 
3439     ret = xmlXPathNodeSetCreate(NULL);
3440     if (ret == NULL)
3441         return(NULL);
3442     if (xmlXPathNodeSetIsEmpty(nodes1))
3443 	return(ret);
3444 
3445     l1 = xmlXPathNodeSetGetLength(nodes1);
3446 
3447     for (i = 0; i < l1; i++) {
3448 	cur = xmlXPathNodeSetItem(nodes1, i);
3449 	if (!xmlXPathNodeSetContains(nodes2, cur)) {
3450 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3451                 xmlXPathFreeNodeSet(ret);
3452 	        return(NULL);
3453             }
3454 	}
3455     }
3456     return(ret);
3457 }
3458 
3459 /**
3460  * xmlXPathIntersection:
3461  * @nodes1:  a node-set
3462  * @nodes2:  a node-set
3463  *
3464  * Implements the EXSLT - Sets intersection() function:
3465  *    node-set set:intersection (node-set, node-set)
3466  *
3467  * Returns a node set comprising the nodes that are within both the
3468  *         node sets passed as arguments
3469  */
3470 xmlNodeSetPtr
xmlXPathIntersection(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3471 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3472     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
3473     int i, l1;
3474     xmlNodePtr cur;
3475 
3476     if (ret == NULL)
3477         return(ret);
3478     if (xmlXPathNodeSetIsEmpty(nodes1))
3479 	return(ret);
3480     if (xmlXPathNodeSetIsEmpty(nodes2))
3481 	return(ret);
3482 
3483     l1 = xmlXPathNodeSetGetLength(nodes1);
3484 
3485     for (i = 0; i < l1; i++) {
3486 	cur = xmlXPathNodeSetItem(nodes1, i);
3487 	if (xmlXPathNodeSetContains(nodes2, cur)) {
3488 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3489                 xmlXPathFreeNodeSet(ret);
3490 	        return(NULL);
3491             }
3492 	}
3493     }
3494     return(ret);
3495 }
3496 
3497 /**
3498  * xmlXPathDistinctSorted:
3499  * @nodes:  a node-set, sorted by document order
3500  *
3501  * Implements the EXSLT - Sets distinct() function:
3502  *    node-set set:distinct (node-set)
3503  *
3504  * Returns a subset of the nodes contained in @nodes, or @nodes if
3505  *         it is empty
3506  */
3507 xmlNodeSetPtr
xmlXPathDistinctSorted(xmlNodeSetPtr nodes)3508 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
3509     xmlNodeSetPtr ret;
3510     xmlHashTablePtr hash;
3511     int i, l;
3512     xmlChar * strval;
3513     xmlNodePtr cur;
3514 
3515     if (xmlXPathNodeSetIsEmpty(nodes))
3516 	return(nodes);
3517 
3518     ret = xmlXPathNodeSetCreate(NULL);
3519     if (ret == NULL)
3520         return(ret);
3521     l = xmlXPathNodeSetGetLength(nodes);
3522     hash = xmlHashCreate (l);
3523     for (i = 0; i < l; i++) {
3524 	cur = xmlXPathNodeSetItem(nodes, i);
3525 	strval = xmlXPathCastNodeToString(cur);
3526 	if (xmlHashLookup(hash, strval) == NULL) {
3527 	    if (xmlHashAddEntry(hash, strval, strval) < 0) {
3528                 xmlFree(strval);
3529                 goto error;
3530             }
3531 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3532 	        goto error;
3533 	} else {
3534 	    xmlFree(strval);
3535 	}
3536     }
3537     xmlHashFree(hash, xmlHashDefaultDeallocator);
3538     return(ret);
3539 
3540 error:
3541     xmlHashFree(hash, xmlHashDefaultDeallocator);
3542     xmlXPathFreeNodeSet(ret);
3543     return(NULL);
3544 }
3545 
3546 /**
3547  * xmlXPathDistinct:
3548  * @nodes:  a node-set
3549  *
3550  * Implements the EXSLT - Sets distinct() function:
3551  *    node-set set:distinct (node-set)
3552  * @nodes is sorted by document order, then #exslSetsDistinctSorted
3553  * is called with the sorted node-set
3554  *
3555  * Returns a subset of the nodes contained in @nodes, or @nodes if
3556  *         it is empty
3557  */
3558 xmlNodeSetPtr
xmlXPathDistinct(xmlNodeSetPtr nodes)3559 xmlXPathDistinct (xmlNodeSetPtr nodes) {
3560     if (xmlXPathNodeSetIsEmpty(nodes))
3561 	return(nodes);
3562 
3563     xmlXPathNodeSetSort(nodes);
3564     return(xmlXPathDistinctSorted(nodes));
3565 }
3566 
3567 /**
3568  * xmlXPathHasSameNodes:
3569  * @nodes1:  a node-set
3570  * @nodes2:  a node-set
3571  *
3572  * Implements the EXSLT - Sets has-same-nodes function:
3573  *    boolean set:has-same-node(node-set, node-set)
3574  *
3575  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
3576  *         otherwise
3577  */
3578 int
xmlXPathHasSameNodes(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3579 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3580     int i, l;
3581     xmlNodePtr cur;
3582 
3583     if (xmlXPathNodeSetIsEmpty(nodes1) ||
3584 	xmlXPathNodeSetIsEmpty(nodes2))
3585 	return(0);
3586 
3587     l = xmlXPathNodeSetGetLength(nodes1);
3588     for (i = 0; i < l; i++) {
3589 	cur = xmlXPathNodeSetItem(nodes1, i);
3590 	if (xmlXPathNodeSetContains(nodes2, cur))
3591 	    return(1);
3592     }
3593     return(0);
3594 }
3595 
3596 /**
3597  * xmlXPathNodeLeadingSorted:
3598  * @nodes: a node-set, sorted by document order
3599  * @node: a node
3600  *
3601  * Implements the EXSLT - Sets leading() function:
3602  *    node-set set:leading (node-set, node-set)
3603  *
3604  * Returns the nodes in @nodes that precede @node in document order,
3605  *         @nodes if @node is NULL or an empty node-set if @nodes
3606  *         doesn't contain @node
3607  */
3608 xmlNodeSetPtr
xmlXPathNodeLeadingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)3609 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3610     int i, l;
3611     xmlNodePtr cur;
3612     xmlNodeSetPtr ret;
3613 
3614     if (node == NULL)
3615 	return(nodes);
3616 
3617     ret = xmlXPathNodeSetCreate(NULL);
3618     if (ret == NULL)
3619         return(ret);
3620     if (xmlXPathNodeSetIsEmpty(nodes) ||
3621 	(!xmlXPathNodeSetContains(nodes, node)))
3622 	return(ret);
3623 
3624     l = xmlXPathNodeSetGetLength(nodes);
3625     for (i = 0; i < l; i++) {
3626 	cur = xmlXPathNodeSetItem(nodes, i);
3627 	if (cur == node)
3628 	    break;
3629 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3630             xmlXPathFreeNodeSet(ret);
3631 	    return(NULL);
3632         }
3633     }
3634     return(ret);
3635 }
3636 
3637 /**
3638  * xmlXPathNodeLeading:
3639  * @nodes:  a node-set
3640  * @node:  a node
3641  *
3642  * Implements the EXSLT - Sets leading() function:
3643  *    node-set set:leading (node-set, node-set)
3644  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
3645  * is called.
3646  *
3647  * Returns the nodes in @nodes that precede @node in document order,
3648  *         @nodes if @node is NULL or an empty node-set if @nodes
3649  *         doesn't contain @node
3650  */
3651 xmlNodeSetPtr
xmlXPathNodeLeading(xmlNodeSetPtr nodes,xmlNodePtr node)3652 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
3653     xmlXPathNodeSetSort(nodes);
3654     return(xmlXPathNodeLeadingSorted(nodes, node));
3655 }
3656 
3657 /**
3658  * xmlXPathLeadingSorted:
3659  * @nodes1:  a node-set, sorted by document order
3660  * @nodes2:  a node-set, sorted by document order
3661  *
3662  * Implements the EXSLT - Sets leading() function:
3663  *    node-set set:leading (node-set, node-set)
3664  *
3665  * Returns the nodes in @nodes1 that precede the first node in @nodes2
3666  *         in document order, @nodes1 if @nodes2 is NULL or empty or
3667  *         an empty node-set if @nodes1 doesn't contain @nodes2
3668  */
3669 xmlNodeSetPtr
xmlXPathLeadingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3670 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3671     if (xmlXPathNodeSetIsEmpty(nodes2))
3672 	return(nodes1);
3673     return(xmlXPathNodeLeadingSorted(nodes1,
3674 				     xmlXPathNodeSetItem(nodes2, 1)));
3675 }
3676 
3677 /**
3678  * xmlXPathLeading:
3679  * @nodes1:  a node-set
3680  * @nodes2:  a node-set
3681  *
3682  * Implements the EXSLT - Sets leading() function:
3683  *    node-set set:leading (node-set, node-set)
3684  * @nodes1 and @nodes2 are sorted by document order, then
3685  * #exslSetsLeadingSorted is called.
3686  *
3687  * Returns the nodes in @nodes1 that precede the first node in @nodes2
3688  *         in document order, @nodes1 if @nodes2 is NULL or empty or
3689  *         an empty node-set if @nodes1 doesn't contain @nodes2
3690  */
3691 xmlNodeSetPtr
xmlXPathLeading(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3692 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3693     if (xmlXPathNodeSetIsEmpty(nodes2))
3694 	return(nodes1);
3695     if (xmlXPathNodeSetIsEmpty(nodes1))
3696 	return(xmlXPathNodeSetCreate(NULL));
3697     xmlXPathNodeSetSort(nodes1);
3698     xmlXPathNodeSetSort(nodes2);
3699     return(xmlXPathNodeLeadingSorted(nodes1,
3700 				     xmlXPathNodeSetItem(nodes2, 1)));
3701 }
3702 
3703 /**
3704  * xmlXPathNodeTrailingSorted:
3705  * @nodes: a node-set, sorted by document order
3706  * @node: a node
3707  *
3708  * Implements the EXSLT - Sets trailing() function:
3709  *    node-set set:trailing (node-set, node-set)
3710  *
3711  * Returns the nodes in @nodes that follow @node in document order,
3712  *         @nodes if @node is NULL or an empty node-set if @nodes
3713  *         doesn't contain @node
3714  */
3715 xmlNodeSetPtr
xmlXPathNodeTrailingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)3716 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3717     int i, l;
3718     xmlNodePtr cur;
3719     xmlNodeSetPtr ret;
3720 
3721     if (node == NULL)
3722 	return(nodes);
3723 
3724     ret = xmlXPathNodeSetCreate(NULL);
3725     if (ret == NULL)
3726         return(ret);
3727     if (xmlXPathNodeSetIsEmpty(nodes) ||
3728 	(!xmlXPathNodeSetContains(nodes, node)))
3729 	return(ret);
3730 
3731     l = xmlXPathNodeSetGetLength(nodes);
3732     for (i = l - 1; i >= 0; i--) {
3733 	cur = xmlXPathNodeSetItem(nodes, i);
3734 	if (cur == node)
3735 	    break;
3736 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3737             xmlXPathFreeNodeSet(ret);
3738 	    return(NULL);
3739         }
3740     }
3741     xmlXPathNodeSetSort(ret);	/* bug 413451 */
3742     return(ret);
3743 }
3744 
3745 /**
3746  * xmlXPathNodeTrailing:
3747  * @nodes:  a node-set
3748  * @node:  a node
3749  *
3750  * Implements the EXSLT - Sets trailing() function:
3751  *    node-set set:trailing (node-set, node-set)
3752  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
3753  * is called.
3754  *
3755  * Returns the nodes in @nodes that follow @node in document order,
3756  *         @nodes if @node is NULL or an empty node-set if @nodes
3757  *         doesn't contain @node
3758  */
3759 xmlNodeSetPtr
xmlXPathNodeTrailing(xmlNodeSetPtr nodes,xmlNodePtr node)3760 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
3761     xmlXPathNodeSetSort(nodes);
3762     return(xmlXPathNodeTrailingSorted(nodes, node));
3763 }
3764 
3765 /**
3766  * xmlXPathTrailingSorted:
3767  * @nodes1:  a node-set, sorted by document order
3768  * @nodes2:  a node-set, sorted by document order
3769  *
3770  * Implements the EXSLT - Sets trailing() function:
3771  *    node-set set:trailing (node-set, node-set)
3772  *
3773  * Returns the nodes in @nodes1 that follow the first node in @nodes2
3774  *         in document order, @nodes1 if @nodes2 is NULL or empty or
3775  *         an empty node-set if @nodes1 doesn't contain @nodes2
3776  */
3777 xmlNodeSetPtr
xmlXPathTrailingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3778 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3779     if (xmlXPathNodeSetIsEmpty(nodes2))
3780 	return(nodes1);
3781     return(xmlXPathNodeTrailingSorted(nodes1,
3782 				      xmlXPathNodeSetItem(nodes2, 0)));
3783 }
3784 
3785 /**
3786  * xmlXPathTrailing:
3787  * @nodes1:  a node-set
3788  * @nodes2:  a node-set
3789  *
3790  * Implements the EXSLT - Sets trailing() function:
3791  *    node-set set:trailing (node-set, node-set)
3792  * @nodes1 and @nodes2 are sorted by document order, then
3793  * #xmlXPathTrailingSorted is called.
3794  *
3795  * Returns the nodes in @nodes1 that follow the first node in @nodes2
3796  *         in document order, @nodes1 if @nodes2 is NULL or empty or
3797  *         an empty node-set if @nodes1 doesn't contain @nodes2
3798  */
3799 xmlNodeSetPtr
xmlXPathTrailing(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3800 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3801     if (xmlXPathNodeSetIsEmpty(nodes2))
3802 	return(nodes1);
3803     if (xmlXPathNodeSetIsEmpty(nodes1))
3804 	return(xmlXPathNodeSetCreate(NULL));
3805     xmlXPathNodeSetSort(nodes1);
3806     xmlXPathNodeSetSort(nodes2);
3807     return(xmlXPathNodeTrailingSorted(nodes1,
3808 				      xmlXPathNodeSetItem(nodes2, 0)));
3809 }
3810 
3811 /************************************************************************
3812  *									*
3813  *		Routines to handle extra functions			*
3814  *									*
3815  ************************************************************************/
3816 
3817 /**
3818  * xmlXPathRegisterFunc:
3819  * @ctxt:  the XPath context
3820  * @name:  the function name
3821  * @f:  the function implementation or NULL
3822  *
3823  * Register a new function. If @f is NULL it unregisters the function
3824  *
3825  * Returns 0 in case of success, -1 in case of error
3826  */
3827 int
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathFunction f)3828 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
3829 		     xmlXPathFunction f) {
3830     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
3831 }
3832 
3833 /**
3834  * xmlXPathRegisterFuncNS:
3835  * @ctxt:  the XPath context
3836  * @name:  the function name
3837  * @ns_uri:  the function namespace URI
3838  * @f:  the function implementation or NULL
3839  *
3840  * Register a new function. If @f is NULL it unregisters the function
3841  *
3842  * Returns 0 in case of success, -1 in case of error
3843  */
3844 int
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathFunction f)3845 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3846 		       const xmlChar *ns_uri, xmlXPathFunction f) {
3847     int ret;
3848 
3849     if (ctxt == NULL)
3850 	return(-1);
3851     if (name == NULL)
3852 	return(-1);
3853 
3854     if (ctxt->funcHash == NULL)
3855 	ctxt->funcHash = xmlHashCreate(0);
3856     if (ctxt->funcHash == NULL) {
3857         xmlXPathErrMemory(ctxt);
3858 	return(-1);
3859     }
3860     if (f == NULL)
3861         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
3862 XML_IGNORE_FPTR_CAST_WARNINGS
3863     ret = xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f);
3864 XML_POP_WARNINGS
3865     if (ret < 0) {
3866         xmlXPathErrMemory(ctxt);
3867         return(-1);
3868     }
3869 
3870     return(0);
3871 }
3872 
3873 /**
3874  * xmlXPathRegisterFuncLookup:
3875  * @ctxt:  the XPath context
3876  * @f:  the lookup function
3877  * @funcCtxt:  the lookup data
3878  *
3879  * Registers an external mechanism to do function lookup.
3880  */
3881 void
xmlXPathRegisterFuncLookup(xmlXPathContextPtr ctxt,xmlXPathFuncLookupFunc f,void * funcCtxt)3882 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
3883 			    xmlXPathFuncLookupFunc f,
3884 			    void *funcCtxt) {
3885     if (ctxt == NULL)
3886 	return;
3887     ctxt->funcLookupFunc = f;
3888     ctxt->funcLookupData = funcCtxt;
3889 }
3890 
3891 /**
3892  * xmlXPathFunctionLookup:
3893  * @ctxt:  the XPath context
3894  * @name:  the function name
3895  *
3896  * Search in the Function array of the context for the given
3897  * function.
3898  *
3899  * Returns the xmlXPathFunction or NULL if not found
3900  */
3901 xmlXPathFunction
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt,const xmlChar * name)3902 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
3903     if (ctxt == NULL)
3904 	return (NULL);
3905 
3906     if (ctxt->funcLookupFunc != NULL) {
3907 	xmlXPathFunction ret;
3908 	xmlXPathFuncLookupFunc f;
3909 
3910 	f = ctxt->funcLookupFunc;
3911 	ret = f(ctxt->funcLookupData, name, NULL);
3912 	if (ret != NULL)
3913 	    return(ret);
3914     }
3915     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
3916 }
3917 
3918 /**
3919  * xmlXPathFunctionLookupNS:
3920  * @ctxt:  the XPath context
3921  * @name:  the function name
3922  * @ns_uri:  the function namespace URI
3923  *
3924  * Search in the Function array of the context for the given
3925  * function.
3926  *
3927  * Returns the xmlXPathFunction or NULL if not found
3928  */
3929 xmlXPathFunction
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)3930 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3931 			 const xmlChar *ns_uri) {
3932     xmlXPathFunction ret;
3933 
3934     if (ctxt == NULL)
3935 	return(NULL);
3936     if (name == NULL)
3937 	return(NULL);
3938 
3939     if (ctxt->funcLookupFunc != NULL) {
3940 	xmlXPathFuncLookupFunc f;
3941 
3942 	f = ctxt->funcLookupFunc;
3943 	ret = f(ctxt->funcLookupData, name, ns_uri);
3944 	if (ret != NULL)
3945 	    return(ret);
3946     }
3947 
3948     if (ctxt->funcHash == NULL)
3949 	return(NULL);
3950 
3951 XML_IGNORE_FPTR_CAST_WARNINGS
3952     ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
3953 XML_POP_WARNINGS
3954     return(ret);
3955 }
3956 
3957 /**
3958  * xmlXPathRegisteredFuncsCleanup:
3959  * @ctxt:  the XPath context
3960  *
3961  * Cleanup the XPath context data associated to registered functions
3962  */
3963 void
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt)3964 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
3965     if (ctxt == NULL)
3966 	return;
3967 
3968     xmlHashFree(ctxt->funcHash, NULL);
3969     ctxt->funcHash = NULL;
3970 }
3971 
3972 /************************************************************************
3973  *									*
3974  *			Routines to handle Variables			*
3975  *									*
3976  ************************************************************************/
3977 
3978 /**
3979  * xmlXPathRegisterVariable:
3980  * @ctxt:  the XPath context
3981  * @name:  the variable name
3982  * @value:  the variable value or NULL
3983  *
3984  * Register a new variable value. If @value is NULL it unregisters
3985  * the variable
3986  *
3987  * Returns 0 in case of success, -1 in case of error
3988  */
3989 int
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathObjectPtr value)3990 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
3991 			 xmlXPathObjectPtr value) {
3992     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
3993 }
3994 
3995 /**
3996  * xmlXPathRegisterVariableNS:
3997  * @ctxt:  the XPath context
3998  * @name:  the variable name
3999  * @ns_uri:  the variable namespace URI
4000  * @value:  the variable value or NULL
4001  *
4002  * Register a new variable value. If @value is NULL it unregisters
4003  * the variable
4004  *
4005  * Returns 0 in case of success, -1 in case of error
4006  */
4007 int
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathObjectPtr value)4008 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4009 			   const xmlChar *ns_uri,
4010 			   xmlXPathObjectPtr value) {
4011     if (ctxt == NULL)
4012 	return(-1);
4013     if (name == NULL)
4014 	return(-1);
4015 
4016     if (ctxt->varHash == NULL)
4017 	ctxt->varHash = xmlHashCreate(0);
4018     if (ctxt->varHash == NULL)
4019 	return(-1);
4020     if (value == NULL)
4021         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4022 	                           xmlXPathFreeObjectEntry));
4023     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4024 			       (void *) value, xmlXPathFreeObjectEntry));
4025 }
4026 
4027 /**
4028  * xmlXPathRegisterVariableLookup:
4029  * @ctxt:  the XPath context
4030  * @f:  the lookup function
4031  * @data:  the lookup data
4032  *
4033  * register an external mechanism to do variable lookup
4034  */
4035 void
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,xmlXPathVariableLookupFunc f,void * data)4036 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4037 	 xmlXPathVariableLookupFunc f, void *data) {
4038     if (ctxt == NULL)
4039 	return;
4040     ctxt->varLookupFunc = f;
4041     ctxt->varLookupData = data;
4042 }
4043 
4044 /**
4045  * xmlXPathVariableLookup:
4046  * @ctxt:  the XPath context
4047  * @name:  the variable name
4048  *
4049  * Search in the Variable array of the context for the given
4050  * variable value.
4051  *
4052  * Returns a copy of the value or NULL if not found
4053  */
4054 xmlXPathObjectPtr
xmlXPathVariableLookup(xmlXPathContextPtr ctxt,const xmlChar * name)4055 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4056     if (ctxt == NULL)
4057 	return(NULL);
4058 
4059     if (ctxt->varLookupFunc != NULL) {
4060 	xmlXPathObjectPtr ret;
4061 
4062 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4063 	        (ctxt->varLookupData, name, NULL);
4064 	return(ret);
4065     }
4066     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4067 }
4068 
4069 /**
4070  * xmlXPathVariableLookupNS:
4071  * @ctxt:  the XPath context
4072  * @name:  the variable name
4073  * @ns_uri:  the variable namespace URI
4074  *
4075  * Search in the Variable array of the context for the given
4076  * variable value.
4077  *
4078  * Returns the a copy of the value or NULL if not found
4079  */
4080 xmlXPathObjectPtr
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4081 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4082 			 const xmlChar *ns_uri) {
4083     if (ctxt == NULL)
4084 	return(NULL);
4085 
4086     if (ctxt->varLookupFunc != NULL) {
4087 	xmlXPathObjectPtr ret;
4088 
4089 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4090 	        (ctxt->varLookupData, name, ns_uri);
4091 	if (ret != NULL) return(ret);
4092     }
4093 
4094     if (ctxt->varHash == NULL)
4095 	return(NULL);
4096     if (name == NULL)
4097 	return(NULL);
4098 
4099     return(xmlXPathObjectCopy(xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4100 }
4101 
4102 /**
4103  * xmlXPathRegisteredVariablesCleanup:
4104  * @ctxt:  the XPath context
4105  *
4106  * Cleanup the XPath context data associated to registered variables
4107  */
4108 void
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt)4109 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4110     if (ctxt == NULL)
4111 	return;
4112 
4113     xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
4114     ctxt->varHash = NULL;
4115 }
4116 
4117 /**
4118  * xmlXPathRegisterNs:
4119  * @ctxt:  the XPath context
4120  * @prefix:  the namespace prefix cannot be NULL or empty string
4121  * @ns_uri:  the namespace name
4122  *
4123  * Register a new namespace. If @ns_uri is NULL it unregisters
4124  * the namespace
4125  *
4126  * Returns 0 in case of success, -1 in case of error
4127  */
4128 int
xmlXPathRegisterNs(xmlXPathContextPtr ctxt,const xmlChar * prefix,const xmlChar * ns_uri)4129 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4130 			   const xmlChar *ns_uri) {
4131     xmlChar *copy;
4132 
4133     if (ctxt == NULL)
4134 	return(-1);
4135     if (prefix == NULL)
4136 	return(-1);
4137     if (prefix[0] == 0)
4138 	return(-1);
4139 
4140     if (ctxt->nsHash == NULL)
4141 	ctxt->nsHash = xmlHashCreate(10);
4142     if (ctxt->nsHash == NULL) {
4143         xmlXPathErrMemory(ctxt);
4144 	return(-1);
4145     }
4146     if (ns_uri == NULL)
4147         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
4148 	                          xmlHashDefaultDeallocator));
4149 
4150     copy = xmlStrdup(ns_uri);
4151     if (copy == NULL) {
4152         xmlXPathErrMemory(ctxt);
4153         return(-1);
4154     }
4155     if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
4156                            xmlHashDefaultDeallocator) < 0) {
4157         xmlXPathErrMemory(ctxt);
4158         xmlFree(copy);
4159         return(-1);
4160     }
4161 
4162     return(0);
4163 }
4164 
4165 /**
4166  * xmlXPathNsLookup:
4167  * @ctxt:  the XPath context
4168  * @prefix:  the namespace prefix value
4169  *
4170  * Search in the namespace declaration array of the context for the given
4171  * namespace name associated to the given prefix
4172  *
4173  * Returns the value or NULL if not found
4174  */
4175 const xmlChar *
xmlXPathNsLookup(xmlXPathContextPtr ctxt,const xmlChar * prefix)4176 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
4177     if (ctxt == NULL)
4178 	return(NULL);
4179     if (prefix == NULL)
4180 	return(NULL);
4181 
4182     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4183 	return(XML_XML_NAMESPACE);
4184 
4185     if (ctxt->namespaces != NULL) {
4186 	int i;
4187 
4188 	for (i = 0;i < ctxt->nsNr;i++) {
4189 	    if ((ctxt->namespaces[i] != NULL) &&
4190 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4191 		return(ctxt->namespaces[i]->href);
4192 	}
4193     }
4194 
4195     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4196 }
4197 
4198 /**
4199  * xmlXPathRegisteredNsCleanup:
4200  * @ctxt:  the XPath context
4201  *
4202  * Cleanup the XPath context data associated to registered variables
4203  */
4204 void
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt)4205 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
4206     if (ctxt == NULL)
4207 	return;
4208 
4209     xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4210     ctxt->nsHash = NULL;
4211 }
4212 
4213 /************************************************************************
4214  *									*
4215  *			Routines to handle Values			*
4216  *									*
4217  ************************************************************************/
4218 
4219 /* Allocations are terrible, one needs to optimize all this !!! */
4220 
4221 /**
4222  * xmlXPathNewFloat:
4223  * @val:  the double value
4224  *
4225  * Create a new xmlXPathObjectPtr of type double and of value @val
4226  *
4227  * Returns the newly created object.
4228  */
4229 xmlXPathObjectPtr
xmlXPathNewFloat(double val)4230 xmlXPathNewFloat(double val) {
4231     xmlXPathObjectPtr ret;
4232 
4233     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4234     if (ret == NULL)
4235 	return(NULL);
4236     memset(ret, 0 , sizeof(xmlXPathObject));
4237     ret->type = XPATH_NUMBER;
4238     ret->floatval = val;
4239     return(ret);
4240 }
4241 
4242 /**
4243  * xmlXPathNewBoolean:
4244  * @val:  the boolean value
4245  *
4246  * Create a new xmlXPathObjectPtr of type boolean and of value @val
4247  *
4248  * Returns the newly created object.
4249  */
4250 xmlXPathObjectPtr
xmlXPathNewBoolean(int val)4251 xmlXPathNewBoolean(int val) {
4252     xmlXPathObjectPtr ret;
4253 
4254     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4255     if (ret == NULL)
4256 	return(NULL);
4257     memset(ret, 0 , sizeof(xmlXPathObject));
4258     ret->type = XPATH_BOOLEAN;
4259     ret->boolval = (val != 0);
4260     return(ret);
4261 }
4262 
4263 /**
4264  * xmlXPathNewString:
4265  * @val:  the xmlChar * value
4266  *
4267  * Create a new xmlXPathObjectPtr of type string and of value @val
4268  *
4269  * Returns the newly created object.
4270  */
4271 xmlXPathObjectPtr
xmlXPathNewString(const xmlChar * val)4272 xmlXPathNewString(const xmlChar *val) {
4273     xmlXPathObjectPtr ret;
4274 
4275     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4276     if (ret == NULL)
4277 	return(NULL);
4278     memset(ret, 0 , sizeof(xmlXPathObject));
4279     ret->type = XPATH_STRING;
4280     if (val == NULL)
4281         val = BAD_CAST "";
4282     ret->stringval = xmlStrdup(val);
4283     if (ret->stringval == NULL) {
4284         xmlFree(ret);
4285         return(NULL);
4286     }
4287     return(ret);
4288 }
4289 
4290 /**
4291  * xmlXPathWrapString:
4292  * @val:  the xmlChar * value
4293  *
4294  * Wraps the @val string into an XPath object.
4295  *
4296  * Returns the newly created object.
4297  *
4298  * Frees @val in case of error.
4299  */
4300 xmlXPathObjectPtr
xmlXPathWrapString(xmlChar * val)4301 xmlXPathWrapString (xmlChar *val) {
4302     xmlXPathObjectPtr ret;
4303 
4304     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4305     if (ret == NULL) {
4306         xmlFree(val);
4307 	return(NULL);
4308     }
4309     memset(ret, 0 , sizeof(xmlXPathObject));
4310     ret->type = XPATH_STRING;
4311     ret->stringval = val;
4312     return(ret);
4313 }
4314 
4315 /**
4316  * xmlXPathNewCString:
4317  * @val:  the char * value
4318  *
4319  * Create a new xmlXPathObjectPtr of type string and of value @val
4320  *
4321  * Returns the newly created object.
4322  */
4323 xmlXPathObjectPtr
xmlXPathNewCString(const char * val)4324 xmlXPathNewCString(const char *val) {
4325     return(xmlXPathNewString(BAD_CAST val));
4326 }
4327 
4328 /**
4329  * xmlXPathWrapCString:
4330  * @val:  the char * value
4331  *
4332  * Wraps a string into an XPath object.
4333  *
4334  * Returns the newly created object.
4335  */
4336 xmlXPathObjectPtr
xmlXPathWrapCString(char * val)4337 xmlXPathWrapCString (char * val) {
4338     return(xmlXPathWrapString((xmlChar *)(val)));
4339 }
4340 
4341 /**
4342  * xmlXPathWrapExternal:
4343  * @val:  the user data
4344  *
4345  * Wraps the @val data into an XPath object.
4346  *
4347  * Returns the newly created object.
4348  */
4349 xmlXPathObjectPtr
xmlXPathWrapExternal(void * val)4350 xmlXPathWrapExternal (void *val) {
4351     xmlXPathObjectPtr ret;
4352 
4353     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4354     if (ret == NULL)
4355 	return(NULL);
4356     memset(ret, 0 , sizeof(xmlXPathObject));
4357     ret->type = XPATH_USERS;
4358     ret->user = val;
4359     return(ret);
4360 }
4361 
4362 /**
4363  * xmlXPathObjectCopy:
4364  * @val:  the original object
4365  *
4366  * allocate a new copy of a given object
4367  *
4368  * Returns the newly created object.
4369  */
4370 xmlXPathObjectPtr
xmlXPathObjectCopy(xmlXPathObjectPtr val)4371 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
4372     xmlXPathObjectPtr ret;
4373 
4374     if (val == NULL)
4375 	return(NULL);
4376 
4377     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4378     if (ret == NULL)
4379 	return(NULL);
4380     memcpy(ret, val , sizeof(xmlXPathObject));
4381     switch (val->type) {
4382 	case XPATH_BOOLEAN:
4383 	case XPATH_NUMBER:
4384 	    break;
4385 	case XPATH_STRING:
4386 	    ret->stringval = xmlStrdup(val->stringval);
4387             if (ret->stringval == NULL) {
4388                 xmlFree(ret);
4389                 return(NULL);
4390             }
4391 	    break;
4392 	case XPATH_XSLT_TREE:
4393 #if 0
4394 /*
4395   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
4396   this previous handling is no longer correct, and can cause some serious
4397   problems (ref. bug 145547)
4398 */
4399 	    if ((val->nodesetval != NULL) &&
4400 		(val->nodesetval->nodeTab != NULL)) {
4401 		xmlNodePtr cur, tmp;
4402 		xmlDocPtr top;
4403 
4404 		ret->boolval = 1;
4405 		top =  xmlNewDoc(NULL);
4406 		top->name = (char *)
4407 		    xmlStrdup(val->nodesetval->nodeTab[0]->name);
4408 		ret->user = top;
4409 		if (top != NULL) {
4410 		    top->doc = top;
4411 		    cur = val->nodesetval->nodeTab[0]->children;
4412 		    while (cur != NULL) {
4413 			tmp = xmlDocCopyNode(cur, top, 1);
4414 			xmlAddChild((xmlNodePtr) top, tmp);
4415 			cur = cur->next;
4416 		    }
4417 		}
4418 
4419 		ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
4420 	    } else
4421 		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
4422 	    /* Deallocate the copied tree value */
4423 	    break;
4424 #endif
4425 	case XPATH_NODESET:
4426 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
4427             if (ret->nodesetval == NULL) {
4428                 xmlFree(ret);
4429                 return(NULL);
4430             }
4431 	    /* Do not deallocate the copied tree value */
4432 	    ret->boolval = 0;
4433 	    break;
4434         case XPATH_USERS:
4435 	    ret->user = val->user;
4436 	    break;
4437         default:
4438             xmlFree(ret);
4439             ret = NULL;
4440 	    break;
4441     }
4442     return(ret);
4443 }
4444 
4445 /**
4446  * xmlXPathFreeObject:
4447  * @obj:  the object to free
4448  *
4449  * Free up an xmlXPathObjectPtr object.
4450  */
4451 void
xmlXPathFreeObject(xmlXPathObjectPtr obj)4452 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
4453     if (obj == NULL) return;
4454     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4455         if (obj->nodesetval != NULL)
4456             xmlXPathFreeNodeSet(obj->nodesetval);
4457     } else if (obj->type == XPATH_STRING) {
4458 	if (obj->stringval != NULL)
4459 	    xmlFree(obj->stringval);
4460     }
4461     xmlFree(obj);
4462 }
4463 
4464 static void
xmlXPathFreeObjectEntry(void * obj,const xmlChar * name ATTRIBUTE_UNUSED)4465 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
4466     xmlXPathFreeObject((xmlXPathObjectPtr) obj);
4467 }
4468 
4469 /**
4470  * xmlXPathReleaseObject:
4471  * @obj:  the xmlXPathObjectPtr to free or to cache
4472  *
4473  * Depending on the state of the cache this frees the given
4474  * XPath object or stores it in the cache.
4475  */
4476 static void
xmlXPathReleaseObject(xmlXPathContextPtr ctxt,xmlXPathObjectPtr obj)4477 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
4478 {
4479     if (obj == NULL)
4480 	return;
4481     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4482 	 xmlXPathFreeObject(obj);
4483     } else {
4484 	xmlXPathContextCachePtr cache =
4485 	    (xmlXPathContextCachePtr) ctxt->cache;
4486 
4487 	switch (obj->type) {
4488 	    case XPATH_NODESET:
4489 	    case XPATH_XSLT_TREE:
4490 		if (obj->nodesetval != NULL) {
4491 		    if ((obj->nodesetval->nodeMax <= 40) &&
4492 			(cache->numNodeset < cache->maxNodeset)) {
4493                         obj->stringval = (void *) cache->nodesetObjs;
4494                         cache->nodesetObjs = obj;
4495                         cache->numNodeset += 1;
4496 			goto obj_cached;
4497 		    } else {
4498 			xmlXPathFreeNodeSet(obj->nodesetval);
4499 			obj->nodesetval = NULL;
4500 		    }
4501 		}
4502 		break;
4503 	    case XPATH_STRING:
4504 		if (obj->stringval != NULL)
4505 		    xmlFree(obj->stringval);
4506                 obj->stringval = NULL;
4507 		break;
4508 	    case XPATH_BOOLEAN:
4509 	    case XPATH_NUMBER:
4510 		break;
4511 	    default:
4512 		goto free_obj;
4513 	}
4514 
4515 	/*
4516 	* Fallback to adding to the misc-objects slot.
4517 	*/
4518         if (cache->numMisc >= cache->maxMisc)
4519 	    goto free_obj;
4520         obj->stringval = (void *) cache->miscObjs;
4521         cache->miscObjs = obj;
4522         cache->numMisc += 1;
4523 
4524 obj_cached:
4525         obj->boolval = 0;
4526 	if (obj->nodesetval != NULL) {
4527 	    xmlNodeSetPtr tmpset = obj->nodesetval;
4528 
4529 	    /*
4530 	    * Due to those nasty ns-nodes, we need to traverse
4531 	    * the list and free the ns-nodes.
4532 	    */
4533 	    if (tmpset->nodeNr > 0) {
4534 		int i;
4535 		xmlNodePtr node;
4536 
4537 		for (i = 0; i < tmpset->nodeNr; i++) {
4538 		    node = tmpset->nodeTab[i];
4539 		    if ((node != NULL) &&
4540 			(node->type == XML_NAMESPACE_DECL))
4541 		    {
4542 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4543 		    }
4544 		}
4545 	    }
4546 	    tmpset->nodeNr = 0;
4547         }
4548 
4549 	return;
4550 
4551 free_obj:
4552 	/*
4553 	* Cache is full; free the object.
4554 	*/
4555 	if (obj->nodesetval != NULL)
4556 	    xmlXPathFreeNodeSet(obj->nodesetval);
4557 	xmlFree(obj);
4558     }
4559     return;
4560 }
4561 
4562 
4563 /************************************************************************
4564  *									*
4565  *			Type Casting Routines				*
4566  *									*
4567  ************************************************************************/
4568 
4569 /**
4570  * xmlXPathCastBooleanToString:
4571  * @val:  a boolean
4572  *
4573  * Converts a boolean to its string value.
4574  *
4575  * Returns a newly allocated string.
4576  */
4577 xmlChar *
xmlXPathCastBooleanToString(int val)4578 xmlXPathCastBooleanToString (int val) {
4579     xmlChar *ret;
4580     if (val)
4581 	ret = xmlStrdup((const xmlChar *) "true");
4582     else
4583 	ret = xmlStrdup((const xmlChar *) "false");
4584     return(ret);
4585 }
4586 
4587 /**
4588  * xmlXPathCastNumberToString:
4589  * @val:  a number
4590  *
4591  * Converts a number to its string value.
4592  *
4593  * Returns a newly allocated string.
4594  */
4595 xmlChar *
xmlXPathCastNumberToString(double val)4596 xmlXPathCastNumberToString (double val) {
4597     xmlChar *ret;
4598     switch (xmlXPathIsInf(val)) {
4599     case 1:
4600 	ret = xmlStrdup((const xmlChar *) "Infinity");
4601 	break;
4602     case -1:
4603 	ret = xmlStrdup((const xmlChar *) "-Infinity");
4604 	break;
4605     default:
4606 	if (xmlXPathIsNaN(val)) {
4607 	    ret = xmlStrdup((const xmlChar *) "NaN");
4608 	} else if (val == 0) {
4609             /* Omit sign for negative zero. */
4610 	    ret = xmlStrdup((const xmlChar *) "0");
4611 	} else {
4612 	    /* could be improved */
4613 	    char buf[100];
4614 	    xmlXPathFormatNumber(val, buf, 99);
4615 	    buf[99] = 0;
4616 	    ret = xmlStrdup((const xmlChar *) buf);
4617 	}
4618     }
4619     return(ret);
4620 }
4621 
4622 /**
4623  * xmlXPathCastNodeToString:
4624  * @node:  a node
4625  *
4626  * Converts a node to its string value.
4627  *
4628  * Returns a newly allocated string.
4629  */
4630 xmlChar *
xmlXPathCastNodeToString(xmlNodePtr node)4631 xmlXPathCastNodeToString (xmlNodePtr node) {
4632     return(xmlNodeGetContent(node));
4633 }
4634 
4635 /**
4636  * xmlXPathCastNodeSetToString:
4637  * @ns:  a node-set
4638  *
4639  * Converts a node-set to its string value.
4640  *
4641  * Returns a newly allocated string.
4642  */
4643 xmlChar *
xmlXPathCastNodeSetToString(xmlNodeSetPtr ns)4644 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
4645     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
4646 	return(xmlStrdup((const xmlChar *) ""));
4647 
4648     if (ns->nodeNr > 1)
4649 	xmlXPathNodeSetSort(ns);
4650     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
4651 }
4652 
4653 /**
4654  * xmlXPathCastToString:
4655  * @val:  an XPath object
4656  *
4657  * Converts an existing object to its string() equivalent
4658  *
4659  * Returns the allocated string value of the object, NULL in case of error.
4660  *         It's up to the caller to free the string memory with xmlFree().
4661  */
4662 xmlChar *
xmlXPathCastToString(xmlXPathObjectPtr val)4663 xmlXPathCastToString(xmlXPathObjectPtr val) {
4664     xmlChar *ret = NULL;
4665 
4666     if (val == NULL)
4667 	return(xmlStrdup((const xmlChar *) ""));
4668     switch (val->type) {
4669 	case XPATH_UNDEFINED:
4670 	    ret = xmlStrdup((const xmlChar *) "");
4671 	    break;
4672         case XPATH_NODESET:
4673         case XPATH_XSLT_TREE:
4674 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
4675 	    break;
4676 	case XPATH_STRING:
4677 	    return(xmlStrdup(val->stringval));
4678         case XPATH_BOOLEAN:
4679 	    ret = xmlXPathCastBooleanToString(val->boolval);
4680 	    break;
4681 	case XPATH_NUMBER: {
4682 	    ret = xmlXPathCastNumberToString(val->floatval);
4683 	    break;
4684 	}
4685 	case XPATH_USERS:
4686 	    /* TODO */
4687 	    ret = xmlStrdup((const xmlChar *) "");
4688 	    break;
4689     }
4690     return(ret);
4691 }
4692 
4693 /**
4694  * xmlXPathConvertString:
4695  * @val:  an XPath object
4696  *
4697  * Converts an existing object to its string() equivalent
4698  *
4699  * Returns the new object, the old one is freed (or the operation
4700  *         is done directly on @val)
4701  */
4702 xmlXPathObjectPtr
xmlXPathConvertString(xmlXPathObjectPtr val)4703 xmlXPathConvertString(xmlXPathObjectPtr val) {
4704     xmlChar *res = NULL;
4705 
4706     if (val == NULL)
4707 	return(xmlXPathNewCString(""));
4708 
4709     switch (val->type) {
4710     case XPATH_UNDEFINED:
4711 	break;
4712     case XPATH_NODESET:
4713     case XPATH_XSLT_TREE:
4714 	res = xmlXPathCastNodeSetToString(val->nodesetval);
4715 	break;
4716     case XPATH_STRING:
4717 	return(val);
4718     case XPATH_BOOLEAN:
4719 	res = xmlXPathCastBooleanToString(val->boolval);
4720 	break;
4721     case XPATH_NUMBER:
4722 	res = xmlXPathCastNumberToString(val->floatval);
4723 	break;
4724     case XPATH_USERS:
4725 	/* TODO */
4726 	break;
4727     }
4728     xmlXPathFreeObject(val);
4729     if (res == NULL)
4730 	return(xmlXPathNewCString(""));
4731     return(xmlXPathWrapString(res));
4732 }
4733 
4734 /**
4735  * xmlXPathCastBooleanToNumber:
4736  * @val:  a boolean
4737  *
4738  * Converts a boolean to its number value
4739  *
4740  * Returns the number value
4741  */
4742 double
xmlXPathCastBooleanToNumber(int val)4743 xmlXPathCastBooleanToNumber(int val) {
4744     if (val)
4745 	return(1.0);
4746     return(0.0);
4747 }
4748 
4749 /**
4750  * xmlXPathCastStringToNumber:
4751  * @val:  a string
4752  *
4753  * Converts a string to its number value
4754  *
4755  * Returns the number value
4756  */
4757 double
xmlXPathCastStringToNumber(const xmlChar * val)4758 xmlXPathCastStringToNumber(const xmlChar * val) {
4759     return(xmlXPathStringEvalNumber(val));
4760 }
4761 
4762 /**
4763  * xmlXPathNodeToNumberInternal:
4764  * @node:  a node
4765  *
4766  * Converts a node to its number value
4767  *
4768  * Returns the number value
4769  */
4770 static double
xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr node)4771 xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt, xmlNodePtr node) {
4772     xmlChar *strval;
4773     double ret;
4774 
4775     if (node == NULL)
4776 	return(xmlXPathNAN);
4777     strval = xmlXPathCastNodeToString(node);
4778     if (strval == NULL) {
4779         xmlXPathPErrMemory(ctxt);
4780 	return(xmlXPathNAN);
4781     }
4782     ret = xmlXPathCastStringToNumber(strval);
4783     xmlFree(strval);
4784 
4785     return(ret);
4786 }
4787 
4788 /**
4789  * xmlXPathCastNodeToNumber:
4790  * @node:  a node
4791  *
4792  * Converts a node to its number value
4793  *
4794  * Returns the number value
4795  */
4796 double
xmlXPathCastNodeToNumber(xmlNodePtr node)4797 xmlXPathCastNodeToNumber (xmlNodePtr node) {
4798     return(xmlXPathNodeToNumberInternal(NULL, node));
4799 }
4800 
4801 /**
4802  * xmlXPathCastNodeSetToNumber:
4803  * @ns:  a node-set
4804  *
4805  * Converts a node-set to its number value
4806  *
4807  * Returns the number value
4808  */
4809 double
xmlXPathCastNodeSetToNumber(xmlNodeSetPtr ns)4810 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
4811     xmlChar *str;
4812     double ret;
4813 
4814     if (ns == NULL)
4815 	return(xmlXPathNAN);
4816     str = xmlXPathCastNodeSetToString(ns);
4817     ret = xmlXPathCastStringToNumber(str);
4818     xmlFree(str);
4819     return(ret);
4820 }
4821 
4822 /**
4823  * xmlXPathCastToNumber:
4824  * @val:  an XPath object
4825  *
4826  * Converts an XPath object to its number value
4827  *
4828  * Returns the number value
4829  */
4830 double
xmlXPathCastToNumber(xmlXPathObjectPtr val)4831 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
4832     return(xmlXPathCastToNumberInternal(NULL, val));
4833 }
4834 
4835 /**
4836  * xmlXPathConvertNumber:
4837  * @val:  an XPath object
4838  *
4839  * Converts an existing object to its number() equivalent
4840  *
4841  * Returns the new object, the old one is freed (or the operation
4842  *         is done directly on @val)
4843  */
4844 xmlXPathObjectPtr
xmlXPathConvertNumber(xmlXPathObjectPtr val)4845 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
4846     xmlXPathObjectPtr ret;
4847 
4848     if (val == NULL)
4849 	return(xmlXPathNewFloat(0.0));
4850     if (val->type == XPATH_NUMBER)
4851 	return(val);
4852     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
4853     xmlXPathFreeObject(val);
4854     return(ret);
4855 }
4856 
4857 /**
4858  * xmlXPathCastNumberToBoolean:
4859  * @val:  a number
4860  *
4861  * Converts a number to its boolean value
4862  *
4863  * Returns the boolean value
4864  */
4865 int
xmlXPathCastNumberToBoolean(double val)4866 xmlXPathCastNumberToBoolean (double val) {
4867      if (xmlXPathIsNaN(val) || (val == 0.0))
4868 	 return(0);
4869      return(1);
4870 }
4871 
4872 /**
4873  * xmlXPathCastStringToBoolean:
4874  * @val:  a string
4875  *
4876  * Converts a string to its boolean value
4877  *
4878  * Returns the boolean value
4879  */
4880 int
xmlXPathCastStringToBoolean(const xmlChar * val)4881 xmlXPathCastStringToBoolean (const xmlChar *val) {
4882     if ((val == NULL) || (xmlStrlen(val) == 0))
4883 	return(0);
4884     return(1);
4885 }
4886 
4887 /**
4888  * xmlXPathCastNodeSetToBoolean:
4889  * @ns:  a node-set
4890  *
4891  * Converts a node-set to its boolean value
4892  *
4893  * Returns the boolean value
4894  */
4895 int
xmlXPathCastNodeSetToBoolean(xmlNodeSetPtr ns)4896 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
4897     if ((ns == NULL) || (ns->nodeNr == 0))
4898 	return(0);
4899     return(1);
4900 }
4901 
4902 /**
4903  * xmlXPathCastToBoolean:
4904  * @val:  an XPath object
4905  *
4906  * Converts an XPath object to its boolean value
4907  *
4908  * Returns the boolean value
4909  */
4910 int
xmlXPathCastToBoolean(xmlXPathObjectPtr val)4911 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
4912     int ret = 0;
4913 
4914     if (val == NULL)
4915 	return(0);
4916     switch (val->type) {
4917     case XPATH_UNDEFINED:
4918 	ret = 0;
4919 	break;
4920     case XPATH_NODESET:
4921     case XPATH_XSLT_TREE:
4922 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
4923 	break;
4924     case XPATH_STRING:
4925 	ret = xmlXPathCastStringToBoolean(val->stringval);
4926 	break;
4927     case XPATH_NUMBER:
4928 	ret = xmlXPathCastNumberToBoolean(val->floatval);
4929 	break;
4930     case XPATH_BOOLEAN:
4931 	ret = val->boolval;
4932 	break;
4933     case XPATH_USERS:
4934 	/* TODO */
4935 	ret = 0;
4936 	break;
4937     }
4938     return(ret);
4939 }
4940 
4941 
4942 /**
4943  * xmlXPathConvertBoolean:
4944  * @val:  an XPath object
4945  *
4946  * Converts an existing object to its boolean() equivalent
4947  *
4948  * Returns the new object, the old one is freed (or the operation
4949  *         is done directly on @val)
4950  */
4951 xmlXPathObjectPtr
xmlXPathConvertBoolean(xmlXPathObjectPtr val)4952 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
4953     xmlXPathObjectPtr ret;
4954 
4955     if (val == NULL)
4956 	return(xmlXPathNewBoolean(0));
4957     if (val->type == XPATH_BOOLEAN)
4958 	return(val);
4959     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
4960     xmlXPathFreeObject(val);
4961     return(ret);
4962 }
4963 
4964 /************************************************************************
4965  *									*
4966  *		Routines to handle XPath contexts			*
4967  *									*
4968  ************************************************************************/
4969 
4970 /**
4971  * xmlXPathNewContext:
4972  * @doc:  the XML document
4973  *
4974  * Create a new xmlXPathContext
4975  *
4976  * Returns the xmlXPathContext just allocated. The caller will need to free it.
4977  */
4978 xmlXPathContextPtr
xmlXPathNewContext(xmlDocPtr doc)4979 xmlXPathNewContext(xmlDocPtr doc) {
4980     xmlXPathContextPtr ret;
4981 
4982     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
4983     if (ret == NULL)
4984 	return(NULL);
4985     memset(ret, 0 , sizeof(xmlXPathContext));
4986     ret->doc = doc;
4987     ret->node = NULL;
4988 
4989     ret->varHash = NULL;
4990 
4991     ret->nb_types = 0;
4992     ret->max_types = 0;
4993     ret->types = NULL;
4994 
4995     ret->nb_axis = 0;
4996     ret->max_axis = 0;
4997     ret->axis = NULL;
4998 
4999     ret->nsHash = NULL;
5000     ret->user = NULL;
5001 
5002     ret->contextSize = -1;
5003     ret->proximityPosition = -1;
5004 
5005 #ifdef XP_DEFAULT_CACHE_ON
5006     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
5007 	xmlXPathFreeContext(ret);
5008 	return(NULL);
5009     }
5010 #endif
5011 
5012     xmlXPathRegisterAllFunctions(ret);
5013 
5014     if (ret->lastError.code != XML_ERR_OK) {
5015 	xmlXPathFreeContext(ret);
5016 	return(NULL);
5017     }
5018 
5019     return(ret);
5020 }
5021 
5022 /**
5023  * xmlXPathFreeContext:
5024  * @ctxt:  the context to free
5025  *
5026  * Free up an xmlXPathContext
5027  */
5028 void
xmlXPathFreeContext(xmlXPathContextPtr ctxt)5029 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
5030     if (ctxt == NULL) return;
5031 
5032     if (ctxt->cache != NULL)
5033 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
5034     xmlXPathRegisteredNsCleanup(ctxt);
5035     xmlXPathRegisteredFuncsCleanup(ctxt);
5036     xmlXPathRegisteredVariablesCleanup(ctxt);
5037     xmlResetError(&ctxt->lastError);
5038     xmlFree(ctxt);
5039 }
5040 
5041 /**
5042  * xmlXPathSetErrorHandler:
5043  * @ctxt:  the XPath context
5044  * @handler:  error handler
5045  * @data:  user data which will be passed to the handler
5046  *
5047  * Register a callback function that will be called on errors and
5048  * warnings. If handler is NULL, the error handler will be deactivated.
5049  *
5050  * Available since 2.13.0.
5051  */
5052 void
xmlXPathSetErrorHandler(xmlXPathContextPtr ctxt,xmlStructuredErrorFunc handler,void * data)5053 xmlXPathSetErrorHandler(xmlXPathContextPtr ctxt,
5054                         xmlStructuredErrorFunc handler, void *data) {
5055     if (ctxt == NULL)
5056         return;
5057 
5058     ctxt->error = handler;
5059     ctxt->userData = data;
5060 }
5061 
5062 /************************************************************************
5063  *									*
5064  *		Routines to handle XPath parser contexts		*
5065  *									*
5066  ************************************************************************/
5067 
5068 /**
5069  * xmlXPathNewParserContext:
5070  * @str:  the XPath expression
5071  * @ctxt:  the XPath context
5072  *
5073  * Create a new xmlXPathParserContext
5074  *
5075  * Returns the xmlXPathParserContext just allocated.
5076  */
5077 xmlXPathParserContextPtr
xmlXPathNewParserContext(const xmlChar * str,xmlXPathContextPtr ctxt)5078 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
5079     xmlXPathParserContextPtr ret;
5080 
5081     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5082     if (ret == NULL) {
5083         xmlXPathErrMemory(ctxt);
5084 	return(NULL);
5085     }
5086     memset(ret, 0 , sizeof(xmlXPathParserContext));
5087     ret->cur = ret->base = str;
5088     ret->context = ctxt;
5089 
5090     ret->comp = xmlXPathNewCompExpr();
5091     if (ret->comp == NULL) {
5092         xmlXPathErrMemory(ctxt);
5093 	xmlFree(ret->valueTab);
5094 	xmlFree(ret);
5095 	return(NULL);
5096     }
5097     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
5098         ret->comp->dict = ctxt->dict;
5099 	xmlDictReference(ret->comp->dict);
5100     }
5101 
5102     return(ret);
5103 }
5104 
5105 /**
5106  * xmlXPathCompParserContext:
5107  * @comp:  the XPath compiled expression
5108  * @ctxt:  the XPath context
5109  *
5110  * Create a new xmlXPathParserContext when processing a compiled expression
5111  *
5112  * Returns the xmlXPathParserContext just allocated.
5113  */
5114 static xmlXPathParserContextPtr
xmlXPathCompParserContext(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)5115 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
5116     xmlXPathParserContextPtr ret;
5117 
5118     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5119     if (ret == NULL) {
5120         xmlXPathErrMemory(ctxt);
5121 	return(NULL);
5122     }
5123     memset(ret, 0 , sizeof(xmlXPathParserContext));
5124 
5125     /* Allocate the value stack */
5126     ret->valueTab = (xmlXPathObjectPtr *)
5127                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
5128     if (ret->valueTab == NULL) {
5129 	xmlFree(ret);
5130 	xmlXPathErrMemory(ctxt);
5131 	return(NULL);
5132     }
5133     ret->valueNr = 0;
5134     ret->valueMax = 10;
5135     ret->value = NULL;
5136 
5137     ret->context = ctxt;
5138     ret->comp = comp;
5139 
5140     return(ret);
5141 }
5142 
5143 /**
5144  * xmlXPathFreeParserContext:
5145  * @ctxt:  the context to free
5146  *
5147  * Free up an xmlXPathParserContext
5148  */
5149 void
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt)5150 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
5151     int i;
5152 
5153     if (ctxt->valueTab != NULL) {
5154         for (i = 0; i < ctxt->valueNr; i++) {
5155             if (ctxt->context)
5156                 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
5157             else
5158                 xmlXPathFreeObject(ctxt->valueTab[i]);
5159         }
5160         xmlFree(ctxt->valueTab);
5161     }
5162     if (ctxt->comp != NULL) {
5163 #ifdef XPATH_STREAMING
5164 	if (ctxt->comp->stream != NULL) {
5165 	    xmlFreePatternList(ctxt->comp->stream);
5166 	    ctxt->comp->stream = NULL;
5167 	}
5168 #endif
5169 	xmlXPathFreeCompExpr(ctxt->comp);
5170     }
5171     xmlFree(ctxt);
5172 }
5173 
5174 /************************************************************************
5175  *									*
5176  *		The implicit core function library			*
5177  *									*
5178  ************************************************************************/
5179 
5180 /**
5181  * xmlXPathNodeValHash:
5182  * @node:  a node pointer
5183  *
5184  * Function computing the beginning of the string value of the node,
5185  * used to speed up comparisons
5186  *
5187  * Returns an int usable as a hash
5188  */
5189 static unsigned int
xmlXPathNodeValHash(xmlNodePtr node)5190 xmlXPathNodeValHash(xmlNodePtr node) {
5191     int len = 2;
5192     const xmlChar * string = NULL;
5193     xmlNodePtr tmp = NULL;
5194     unsigned int ret = 0;
5195 
5196     if (node == NULL)
5197 	return(0);
5198 
5199     if (node->type == XML_DOCUMENT_NODE) {
5200 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
5201 	if (tmp == NULL)
5202 	    node = node->children;
5203 	else
5204 	    node = tmp;
5205 
5206 	if (node == NULL)
5207 	    return(0);
5208     }
5209 
5210     switch (node->type) {
5211 	case XML_COMMENT_NODE:
5212 	case XML_PI_NODE:
5213 	case XML_CDATA_SECTION_NODE:
5214 	case XML_TEXT_NODE:
5215 	    string = node->content;
5216 	    if (string == NULL)
5217 		return(0);
5218 	    if (string[0] == 0)
5219 		return(0);
5220 	    return(string[0] + (string[1] << 8));
5221 	case XML_NAMESPACE_DECL:
5222 	    string = ((xmlNsPtr)node)->href;
5223 	    if (string == NULL)
5224 		return(0);
5225 	    if (string[0] == 0)
5226 		return(0);
5227 	    return(string[0] + (string[1] << 8));
5228 	case XML_ATTRIBUTE_NODE:
5229 	    tmp = ((xmlAttrPtr) node)->children;
5230 	    break;
5231 	case XML_ELEMENT_NODE:
5232 	    tmp = node->children;
5233 	    break;
5234 	default:
5235 	    return(0);
5236     }
5237     while (tmp != NULL) {
5238 	switch (tmp->type) {
5239 	    case XML_CDATA_SECTION_NODE:
5240 	    case XML_TEXT_NODE:
5241 		string = tmp->content;
5242 		break;
5243 	    default:
5244                 string = NULL;
5245 		break;
5246 	}
5247 	if ((string != NULL) && (string[0] != 0)) {
5248 	    if (len == 1) {
5249 		return(ret + (string[0] << 8));
5250 	    }
5251 	    if (string[1] == 0) {
5252 		len = 1;
5253 		ret = string[0];
5254 	    } else {
5255 		return(string[0] + (string[1] << 8));
5256 	    }
5257 	}
5258 	/*
5259 	 * Skip to next node
5260 	 */
5261         if ((tmp->children != NULL) &&
5262             (tmp->type != XML_DTD_NODE) &&
5263             (tmp->type != XML_ENTITY_REF_NODE) &&
5264             (tmp->children->type != XML_ENTITY_DECL)) {
5265             tmp = tmp->children;
5266             continue;
5267 	}
5268 	if (tmp == node)
5269 	    break;
5270 
5271 	if (tmp->next != NULL) {
5272 	    tmp = tmp->next;
5273 	    continue;
5274 	}
5275 
5276 	do {
5277 	    tmp = tmp->parent;
5278 	    if (tmp == NULL)
5279 		break;
5280 	    if (tmp == node) {
5281 		tmp = NULL;
5282 		break;
5283 	    }
5284 	    if (tmp->next != NULL) {
5285 		tmp = tmp->next;
5286 		break;
5287 	    }
5288 	} while (tmp != NULL);
5289     }
5290     return(ret);
5291 }
5292 
5293 /**
5294  * xmlXPathStringHash:
5295  * @string:  a string
5296  *
5297  * Function computing the beginning of the string value of the node,
5298  * used to speed up comparisons
5299  *
5300  * Returns an int usable as a hash
5301  */
5302 static unsigned int
xmlXPathStringHash(const xmlChar * string)5303 xmlXPathStringHash(const xmlChar * string) {
5304     if (string == NULL)
5305 	return(0);
5306     if (string[0] == 0)
5307 	return(0);
5308     return(string[0] + (string[1] << 8));
5309 }
5310 
5311 /**
5312  * xmlXPathCompareNodeSetFloat:
5313  * @ctxt:  the XPath Parser context
5314  * @inf:  less than (1) or greater than (0)
5315  * @strict:  is the comparison strict
5316  * @arg:  the node set
5317  * @f:  the value
5318  *
5319  * Implement the compare operation between a nodeset and a number
5320  *     @ns < @val    (1, 1, ...
5321  *     @ns <= @val   (1, 0, ...
5322  *     @ns > @val    (0, 1, ...
5323  *     @ns >= @val   (0, 0, ...
5324  *
5325  * If one object to be compared is a node-set and the other is a number,
5326  * then the comparison will be true if and only if there is a node in the
5327  * node-set such that the result of performing the comparison on the number
5328  * to be compared and on the result of converting the string-value of that
5329  * node to a number using the number function is true.
5330  *
5331  * Returns 0 or 1 depending on the results of the test.
5332  */
5333 static int
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr f)5334 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
5335 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5336     int i, ret = 0;
5337     xmlNodeSetPtr ns;
5338     xmlChar *str2;
5339 
5340     if ((f == NULL) || (arg == NULL) ||
5341 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5342 	xmlXPathReleaseObject(ctxt->context, arg);
5343 	xmlXPathReleaseObject(ctxt->context, f);
5344         return(0);
5345     }
5346     ns = arg->nodesetval;
5347     if (ns != NULL) {
5348 	for (i = 0;i < ns->nodeNr;i++) {
5349 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5350 	     if (str2 != NULL) {
5351 		 valuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5352 		 xmlFree(str2);
5353 		 xmlXPathNumberFunction(ctxt, 1);
5354 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, f));
5355 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
5356 		 if (ret)
5357 		     break;
5358 	     } else {
5359                  xmlXPathPErrMemory(ctxt);
5360              }
5361 	}
5362     }
5363     xmlXPathReleaseObject(ctxt->context, arg);
5364     xmlXPathReleaseObject(ctxt->context, f);
5365     return(ret);
5366 }
5367 
5368 /**
5369  * xmlXPathCompareNodeSetString:
5370  * @ctxt:  the XPath Parser context
5371  * @inf:  less than (1) or greater than (0)
5372  * @strict:  is the comparison strict
5373  * @arg:  the node set
5374  * @s:  the value
5375  *
5376  * Implement the compare operation between a nodeset and a string
5377  *     @ns < @val    (1, 1, ...
5378  *     @ns <= @val   (1, 0, ...
5379  *     @ns > @val    (0, 1, ...
5380  *     @ns >= @val   (0, 0, ...
5381  *
5382  * If one object to be compared is a node-set and the other is a string,
5383  * then the comparison will be true if and only if there is a node in
5384  * the node-set such that the result of performing the comparison on the
5385  * string-value of the node and the other string is true.
5386  *
5387  * Returns 0 or 1 depending on the results of the test.
5388  */
5389 static int
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr s)5390 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
5391 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5392     int i, ret = 0;
5393     xmlNodeSetPtr ns;
5394     xmlChar *str2;
5395 
5396     if ((s == NULL) || (arg == NULL) ||
5397 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5398 	xmlXPathReleaseObject(ctxt->context, arg);
5399 	xmlXPathReleaseObject(ctxt->context, s);
5400         return(0);
5401     }
5402     ns = arg->nodesetval;
5403     if (ns != NULL) {
5404 	for (i = 0;i < ns->nodeNr;i++) {
5405 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5406 	     if (str2 != NULL) {
5407 		 valuePush(ctxt,
5408 			   xmlXPathCacheNewString(ctxt, str2));
5409 		 xmlFree(str2);
5410 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, s));
5411 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
5412 		 if (ret)
5413 		     break;
5414 	     } else {
5415                  xmlXPathPErrMemory(ctxt);
5416              }
5417 	}
5418     }
5419     xmlXPathReleaseObject(ctxt->context, arg);
5420     xmlXPathReleaseObject(ctxt->context, s);
5421     return(ret);
5422 }
5423 
5424 /**
5425  * xmlXPathCompareNodeSets:
5426  * @inf:  less than (1) or greater than (0)
5427  * @strict:  is the comparison strict
5428  * @arg1:  the first node set object
5429  * @arg2:  the second node set object
5430  *
5431  * Implement the compare operation on nodesets:
5432  *
5433  * If both objects to be compared are node-sets, then the comparison
5434  * will be true if and only if there is a node in the first node-set
5435  * and a node in the second node-set such that the result of performing
5436  * the comparison on the string-values of the two nodes is true.
5437  * ....
5438  * When neither object to be compared is a node-set and the operator
5439  * is <=, <, >= or >, then the objects are compared by converting both
5440  * objects to numbers and comparing the numbers according to IEEE 754.
5441  * ....
5442  * The number function converts its argument to a number as follows:
5443  *  - a string that consists of optional whitespace followed by an
5444  *    optional minus sign followed by a Number followed by whitespace
5445  *    is converted to the IEEE 754 number that is nearest (according
5446  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
5447  *    represented by the string; any other string is converted to NaN
5448  *
5449  * Conclusion all nodes need to be converted first to their string value
5450  * and then the comparison must be done when possible
5451  */
5452 static int
xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)5453 xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt, int inf, int strict,
5454 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5455     int i, j, init = 0;
5456     double val1;
5457     double *values2;
5458     int ret = 0;
5459     xmlNodeSetPtr ns1;
5460     xmlNodeSetPtr ns2;
5461 
5462     if ((arg1 == NULL) ||
5463 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5464 	xmlXPathFreeObject(arg2);
5465         return(0);
5466     }
5467     if ((arg2 == NULL) ||
5468 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
5469 	xmlXPathFreeObject(arg1);
5470 	xmlXPathFreeObject(arg2);
5471         return(0);
5472     }
5473 
5474     ns1 = arg1->nodesetval;
5475     ns2 = arg2->nodesetval;
5476 
5477     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5478 	xmlXPathFreeObject(arg1);
5479 	xmlXPathFreeObject(arg2);
5480 	return(0);
5481     }
5482     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5483 	xmlXPathFreeObject(arg1);
5484 	xmlXPathFreeObject(arg2);
5485 	return(0);
5486     }
5487 
5488     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5489     if (values2 == NULL) {
5490         xmlXPathPErrMemory(ctxt);
5491 	xmlXPathFreeObject(arg1);
5492 	xmlXPathFreeObject(arg2);
5493 	return(0);
5494     }
5495     for (i = 0;i < ns1->nodeNr;i++) {
5496 	val1 = xmlXPathNodeToNumberInternal(ctxt, ns1->nodeTab[i]);
5497 	if (xmlXPathIsNaN(val1))
5498 	    continue;
5499 	for (j = 0;j < ns2->nodeNr;j++) {
5500 	    if (init == 0) {
5501 		values2[j] = xmlXPathNodeToNumberInternal(ctxt,
5502                                                           ns2->nodeTab[j]);
5503 	    }
5504 	    if (xmlXPathIsNaN(values2[j]))
5505 		continue;
5506 	    if (inf && strict)
5507 		ret = (val1 < values2[j]);
5508 	    else if (inf && !strict)
5509 		ret = (val1 <= values2[j]);
5510 	    else if (!inf && strict)
5511 		ret = (val1 > values2[j]);
5512 	    else if (!inf && !strict)
5513 		ret = (val1 >= values2[j]);
5514 	    if (ret)
5515 		break;
5516 	}
5517 	if (ret)
5518 	    break;
5519 	init = 1;
5520     }
5521     xmlFree(values2);
5522     xmlXPathFreeObject(arg1);
5523     xmlXPathFreeObject(arg2);
5524     return(ret);
5525 }
5526 
5527 /**
5528  * xmlXPathCompareNodeSetValue:
5529  * @ctxt:  the XPath Parser context
5530  * @inf:  less than (1) or greater than (0)
5531  * @strict:  is the comparison strict
5532  * @arg:  the node set
5533  * @val:  the value
5534  *
5535  * Implement the compare operation between a nodeset and a value
5536  *     @ns < @val    (1, 1, ...
5537  *     @ns <= @val   (1, 0, ...
5538  *     @ns > @val    (0, 1, ...
5539  *     @ns >= @val   (0, 0, ...
5540  *
5541  * If one object to be compared is a node-set and the other is a boolean,
5542  * then the comparison will be true if and only if the result of performing
5543  * the comparison on the boolean and on the result of converting
5544  * the node-set to a boolean using the boolean function is true.
5545  *
5546  * Returns 0 or 1 depending on the results of the test.
5547  */
5548 static int
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr val)5549 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
5550 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
5551     if ((val == NULL) || (arg == NULL) ||
5552 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5553         return(0);
5554 
5555     switch(val->type) {
5556         case XPATH_NUMBER:
5557 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
5558         case XPATH_NODESET:
5559         case XPATH_XSLT_TREE:
5560 	    return(xmlXPathCompareNodeSets(ctxt, inf, strict, arg, val));
5561         case XPATH_STRING:
5562 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
5563         case XPATH_BOOLEAN:
5564 	    valuePush(ctxt, arg);
5565 	    xmlXPathBooleanFunction(ctxt, 1);
5566 	    valuePush(ctxt, val);
5567 	    return(xmlXPathCompareValues(ctxt, inf, strict));
5568 	default:
5569             xmlXPathReleaseObject(ctxt->context, arg);
5570             xmlXPathReleaseObject(ctxt->context, val);
5571             XP_ERROR0(XPATH_INVALID_TYPE);
5572     }
5573     return(0);
5574 }
5575 
5576 /**
5577  * xmlXPathEqualNodeSetString:
5578  * @arg:  the nodeset object argument
5579  * @str:  the string to compare to.
5580  * @neq:  flag to show whether for '=' (0) or '!=' (1)
5581  *
5582  * Implement the equal operation on XPath objects content: @arg1 == @arg2
5583  * If one object to be compared is a node-set and the other is a string,
5584  * then the comparison will be true if and only if there is a node in
5585  * the node-set such that the result of performing the comparison on the
5586  * string-value of the node and the other string is true.
5587  *
5588  * Returns 0 or 1 depending on the results of the test.
5589  */
5590 static int
xmlXPathEqualNodeSetString(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,const xmlChar * str,int neq)5591 xmlXPathEqualNodeSetString(xmlXPathParserContextPtr ctxt,
5592                            xmlXPathObjectPtr arg, const xmlChar * str, int neq)
5593 {
5594     int i;
5595     xmlNodeSetPtr ns;
5596     xmlChar *str2;
5597     unsigned int hash;
5598 
5599     if ((str == NULL) || (arg == NULL) ||
5600         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5601         return (0);
5602     ns = arg->nodesetval;
5603     /*
5604      * A NULL nodeset compared with a string is always false
5605      * (since there is no node equal, and no node not equal)
5606      */
5607     if ((ns == NULL) || (ns->nodeNr <= 0) )
5608         return (0);
5609     hash = xmlXPathStringHash(str);
5610     for (i = 0; i < ns->nodeNr; i++) {
5611         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
5612             str2 = xmlNodeGetContent(ns->nodeTab[i]);
5613             if (str2 == NULL) {
5614                 xmlXPathPErrMemory(ctxt);
5615                 return(0);
5616             }
5617             if (xmlStrEqual(str, str2)) {
5618                 xmlFree(str2);
5619 		if (neq)
5620 		    continue;
5621                 return (1);
5622             } else if (neq) {
5623 		xmlFree(str2);
5624 		return (1);
5625 	    }
5626             xmlFree(str2);
5627         } else if (neq)
5628 	    return (1);
5629     }
5630     return (0);
5631 }
5632 
5633 /**
5634  * xmlXPathEqualNodeSetFloat:
5635  * @arg:  the nodeset object argument
5636  * @f:  the float to compare to
5637  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
5638  *
5639  * Implement the equal operation on XPath objects content: @arg1 == @arg2
5640  * If one object to be compared is a node-set and the other is a number,
5641  * then the comparison will be true if and only if there is a node in
5642  * the node-set such that the result of performing the comparison on the
5643  * number to be compared and on the result of converting the string-value
5644  * of that node to a number using the number function is true.
5645  *
5646  * Returns 0 or 1 depending on the results of the test.
5647  */
5648 static int
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,double f,int neq)5649 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
5650     xmlXPathObjectPtr arg, double f, int neq) {
5651   int i, ret=0;
5652   xmlNodeSetPtr ns;
5653   xmlChar *str2;
5654   xmlXPathObjectPtr val;
5655   double v;
5656 
5657     if ((arg == NULL) ||
5658 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5659         return(0);
5660 
5661     ns = arg->nodesetval;
5662     if (ns != NULL) {
5663 	for (i=0;i<ns->nodeNr;i++) {
5664 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5665 	    if (str2 != NULL) {
5666 		valuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5667 		xmlFree(str2);
5668 		xmlXPathNumberFunction(ctxt, 1);
5669                 CHECK_ERROR0;
5670 		val = valuePop(ctxt);
5671 		v = val->floatval;
5672 		xmlXPathReleaseObject(ctxt->context, val);
5673 		if (!xmlXPathIsNaN(v)) {
5674 		    if ((!neq) && (v==f)) {
5675 			ret = 1;
5676 			break;
5677 		    } else if ((neq) && (v!=f)) {
5678 			ret = 1;
5679 			break;
5680 		    }
5681 		} else {	/* NaN is unequal to any value */
5682 		    if (neq)
5683 			ret = 1;
5684 		}
5685 	    } else {
5686                 xmlXPathPErrMemory(ctxt);
5687             }
5688 	}
5689     }
5690 
5691     return(ret);
5692 }
5693 
5694 
5695 /**
5696  * xmlXPathEqualNodeSets:
5697  * @arg1:  first nodeset object argument
5698  * @arg2:  second nodeset object argument
5699  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
5700  *
5701  * Implement the equal / not equal operation on XPath nodesets:
5702  * @arg1 == @arg2  or  @arg1 != @arg2
5703  * If both objects to be compared are node-sets, then the comparison
5704  * will be true if and only if there is a node in the first node-set and
5705  * a node in the second node-set such that the result of performing the
5706  * comparison on the string-values of the two nodes is true.
5707  *
5708  * (needless to say, this is a costly operation)
5709  *
5710  * Returns 0 or 1 depending on the results of the test.
5711  */
5712 static int
xmlXPathEqualNodeSets(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2,int neq)5713 xmlXPathEqualNodeSets(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr arg1,
5714                       xmlXPathObjectPtr arg2, int neq) {
5715     int i, j;
5716     unsigned int *hashs1;
5717     unsigned int *hashs2;
5718     xmlChar **values1;
5719     xmlChar **values2;
5720     int ret = 0;
5721     xmlNodeSetPtr ns1;
5722     xmlNodeSetPtr ns2;
5723 
5724     if ((arg1 == NULL) ||
5725 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
5726         return(0);
5727     if ((arg2 == NULL) ||
5728 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
5729         return(0);
5730 
5731     ns1 = arg1->nodesetval;
5732     ns2 = arg2->nodesetval;
5733 
5734     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
5735 	return(0);
5736     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
5737 	return(0);
5738 
5739     /*
5740      * for equal, check if there is a node pertaining to both sets
5741      */
5742     if (neq == 0)
5743 	for (i = 0;i < ns1->nodeNr;i++)
5744 	    for (j = 0;j < ns2->nodeNr;j++)
5745 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
5746 		    return(1);
5747 
5748     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
5749     if (values1 == NULL) {
5750         xmlXPathPErrMemory(ctxt);
5751 	return(0);
5752     }
5753     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
5754     if (hashs1 == NULL) {
5755         xmlXPathPErrMemory(ctxt);
5756 	xmlFree(values1);
5757 	return(0);
5758     }
5759     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
5760     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
5761     if (values2 == NULL) {
5762         xmlXPathPErrMemory(ctxt);
5763 	xmlFree(hashs1);
5764 	xmlFree(values1);
5765 	return(0);
5766     }
5767     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
5768     if (hashs2 == NULL) {
5769         xmlXPathPErrMemory(ctxt);
5770 	xmlFree(hashs1);
5771 	xmlFree(values1);
5772 	xmlFree(values2);
5773 	return(0);
5774     }
5775     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
5776     for (i = 0;i < ns1->nodeNr;i++) {
5777 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
5778 	for (j = 0;j < ns2->nodeNr;j++) {
5779 	    if (i == 0)
5780 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
5781 	    if (hashs1[i] != hashs2[j]) {
5782 		if (neq) {
5783 		    ret = 1;
5784 		    break;
5785 		}
5786 	    }
5787 	    else {
5788 		if (values1[i] == NULL) {
5789 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
5790                     if (values1[i] == NULL)
5791                         xmlXPathPErrMemory(ctxt);
5792                 }
5793 		if (values2[j] == NULL) {
5794 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
5795                     if (values2[j] == NULL)
5796                         xmlXPathPErrMemory(ctxt);
5797                 }
5798 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
5799 		if (ret)
5800 		    break;
5801 	    }
5802 	}
5803 	if (ret)
5804 	    break;
5805     }
5806     for (i = 0;i < ns1->nodeNr;i++)
5807 	if (values1[i] != NULL)
5808 	    xmlFree(values1[i]);
5809     for (j = 0;j < ns2->nodeNr;j++)
5810 	if (values2[j] != NULL)
5811 	    xmlFree(values2[j]);
5812     xmlFree(values1);
5813     xmlFree(values2);
5814     xmlFree(hashs1);
5815     xmlFree(hashs2);
5816     return(ret);
5817 }
5818 
5819 static int
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)5820 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
5821   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5822     int ret = 0;
5823     /*
5824      *At this point we are assured neither arg1 nor arg2
5825      *is a nodeset, so we can just pick the appropriate routine.
5826      */
5827     switch (arg1->type) {
5828         case XPATH_UNDEFINED:
5829 	    break;
5830         case XPATH_BOOLEAN:
5831 	    switch (arg2->type) {
5832 	        case XPATH_UNDEFINED:
5833 		    break;
5834 		case XPATH_BOOLEAN:
5835 		    ret = (arg1->boolval == arg2->boolval);
5836 		    break;
5837 		case XPATH_NUMBER:
5838 		    ret = (arg1->boolval ==
5839 			   xmlXPathCastNumberToBoolean(arg2->floatval));
5840 		    break;
5841 		case XPATH_STRING:
5842 		    if ((arg2->stringval == NULL) ||
5843 			(arg2->stringval[0] == 0)) ret = 0;
5844 		    else
5845 			ret = 1;
5846 		    ret = (arg1->boolval == ret);
5847 		    break;
5848 		case XPATH_USERS:
5849 		    /* TODO */
5850 		    break;
5851 		case XPATH_NODESET:
5852 		case XPATH_XSLT_TREE:
5853 		    break;
5854 	    }
5855 	    break;
5856         case XPATH_NUMBER:
5857 	    switch (arg2->type) {
5858 	        case XPATH_UNDEFINED:
5859 		    break;
5860 		case XPATH_BOOLEAN:
5861 		    ret = (arg2->boolval==
5862 			   xmlXPathCastNumberToBoolean(arg1->floatval));
5863 		    break;
5864 		case XPATH_STRING:
5865 		    valuePush(ctxt, arg2);
5866 		    xmlXPathNumberFunction(ctxt, 1);
5867 		    arg2 = valuePop(ctxt);
5868                     if (ctxt->error)
5869                         break;
5870                     /* Falls through. */
5871 		case XPATH_NUMBER:
5872 		    /* Hand check NaN and Infinity equalities */
5873 		    if (xmlXPathIsNaN(arg1->floatval) ||
5874 			    xmlXPathIsNaN(arg2->floatval)) {
5875 		        ret = 0;
5876 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5877 		        if (xmlXPathIsInf(arg2->floatval) == 1)
5878 			    ret = 1;
5879 			else
5880 			    ret = 0;
5881 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5882 			if (xmlXPathIsInf(arg2->floatval) == -1)
5883 			    ret = 1;
5884 			else
5885 			    ret = 0;
5886 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5887 			if (xmlXPathIsInf(arg1->floatval) == 1)
5888 			    ret = 1;
5889 			else
5890 			    ret = 0;
5891 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5892 			if (xmlXPathIsInf(arg1->floatval) == -1)
5893 			    ret = 1;
5894 			else
5895 			    ret = 0;
5896 		    } else {
5897 		        ret = (arg1->floatval == arg2->floatval);
5898 		    }
5899 		    break;
5900 		case XPATH_USERS:
5901 		    /* TODO */
5902 		    break;
5903 		case XPATH_NODESET:
5904 		case XPATH_XSLT_TREE:
5905 		    break;
5906 	    }
5907 	    break;
5908         case XPATH_STRING:
5909 	    switch (arg2->type) {
5910 	        case XPATH_UNDEFINED:
5911 		    break;
5912 		case XPATH_BOOLEAN:
5913 		    if ((arg1->stringval == NULL) ||
5914 			(arg1->stringval[0] == 0)) ret = 0;
5915 		    else
5916 			ret = 1;
5917 		    ret = (arg2->boolval == ret);
5918 		    break;
5919 		case XPATH_STRING:
5920 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
5921 		    break;
5922 		case XPATH_NUMBER:
5923 		    valuePush(ctxt, arg1);
5924 		    xmlXPathNumberFunction(ctxt, 1);
5925 		    arg1 = valuePop(ctxt);
5926                     if (ctxt->error)
5927                         break;
5928 		    /* Hand check NaN and Infinity equalities */
5929 		    if (xmlXPathIsNaN(arg1->floatval) ||
5930 			    xmlXPathIsNaN(arg2->floatval)) {
5931 		        ret = 0;
5932 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5933 			if (xmlXPathIsInf(arg2->floatval) == 1)
5934 			    ret = 1;
5935 			else
5936 			    ret = 0;
5937 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5938 			if (xmlXPathIsInf(arg2->floatval) == -1)
5939 			    ret = 1;
5940 			else
5941 			    ret = 0;
5942 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5943 			if (xmlXPathIsInf(arg1->floatval) == 1)
5944 			    ret = 1;
5945 			else
5946 			    ret = 0;
5947 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5948 			if (xmlXPathIsInf(arg1->floatval) == -1)
5949 			    ret = 1;
5950 			else
5951 			    ret = 0;
5952 		    } else {
5953 		        ret = (arg1->floatval == arg2->floatval);
5954 		    }
5955 		    break;
5956 		case XPATH_USERS:
5957 		    /* TODO */
5958 		    break;
5959 		case XPATH_NODESET:
5960 		case XPATH_XSLT_TREE:
5961 		    break;
5962 	    }
5963 	    break;
5964         case XPATH_USERS:
5965 	    /* TODO */
5966 	    break;
5967 	case XPATH_NODESET:
5968 	case XPATH_XSLT_TREE:
5969 	    break;
5970     }
5971     xmlXPathReleaseObject(ctxt->context, arg1);
5972     xmlXPathReleaseObject(ctxt->context, arg2);
5973     return(ret);
5974 }
5975 
5976 /**
5977  * xmlXPathEqualValues:
5978  * @ctxt:  the XPath Parser context
5979  *
5980  * Implement the equal operation on XPath objects content: @arg1 == @arg2
5981  *
5982  * Returns 0 or 1 depending on the results of the test.
5983  */
5984 int
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt)5985 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
5986     xmlXPathObjectPtr arg1, arg2, argtmp;
5987     int ret = 0;
5988 
5989     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5990     arg2 = valuePop(ctxt);
5991     arg1 = valuePop(ctxt);
5992     if ((arg1 == NULL) || (arg2 == NULL)) {
5993 	if (arg1 != NULL)
5994 	    xmlXPathReleaseObject(ctxt->context, arg1);
5995 	else
5996 	    xmlXPathReleaseObject(ctxt->context, arg2);
5997 	XP_ERROR0(XPATH_INVALID_OPERAND);
5998     }
5999 
6000     if (arg1 == arg2) {
6001 	xmlXPathFreeObject(arg1);
6002         return(1);
6003     }
6004 
6005     /*
6006      *If either argument is a nodeset, it's a 'special case'
6007      */
6008     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6009       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6010 	/*
6011 	 *Hack it to assure arg1 is the nodeset
6012 	 */
6013 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6014 		argtmp = arg2;
6015 		arg2 = arg1;
6016 		arg1 = argtmp;
6017 	}
6018 	switch (arg2->type) {
6019 	    case XPATH_UNDEFINED:
6020 		break;
6021 	    case XPATH_NODESET:
6022 	    case XPATH_XSLT_TREE:
6023 		ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 0);
6024 		break;
6025 	    case XPATH_BOOLEAN:
6026 		if ((arg1->nodesetval == NULL) ||
6027 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
6028 		else
6029 		    ret = 1;
6030 		ret = (ret == arg2->boolval);
6031 		break;
6032 	    case XPATH_NUMBER:
6033 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
6034 		break;
6035 	    case XPATH_STRING:
6036 		ret = xmlXPathEqualNodeSetString(ctxt, arg1,
6037                                                  arg2->stringval, 0);
6038 		break;
6039 	    case XPATH_USERS:
6040 		/* TODO */
6041 		break;
6042 	}
6043 	xmlXPathReleaseObject(ctxt->context, arg1);
6044 	xmlXPathReleaseObject(ctxt->context, arg2);
6045 	return(ret);
6046     }
6047 
6048     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6049 }
6050 
6051 /**
6052  * xmlXPathNotEqualValues:
6053  * @ctxt:  the XPath Parser context
6054  *
6055  * Implement the equal operation on XPath objects content: @arg1 == @arg2
6056  *
6057  * Returns 0 or 1 depending on the results of the test.
6058  */
6059 int
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt)6060 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
6061     xmlXPathObjectPtr arg1, arg2, argtmp;
6062     int ret = 0;
6063 
6064     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6065     arg2 = valuePop(ctxt);
6066     arg1 = valuePop(ctxt);
6067     if ((arg1 == NULL) || (arg2 == NULL)) {
6068 	if (arg1 != NULL)
6069 	    xmlXPathReleaseObject(ctxt->context, arg1);
6070 	else
6071 	    xmlXPathReleaseObject(ctxt->context, arg2);
6072 	XP_ERROR0(XPATH_INVALID_OPERAND);
6073     }
6074 
6075     if (arg1 == arg2) {
6076 	xmlXPathReleaseObject(ctxt->context, arg1);
6077         return(0);
6078     }
6079 
6080     /*
6081      *If either argument is a nodeset, it's a 'special case'
6082      */
6083     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6084       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6085 	/*
6086 	 *Hack it to assure arg1 is the nodeset
6087 	 */
6088 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6089 		argtmp = arg2;
6090 		arg2 = arg1;
6091 		arg1 = argtmp;
6092 	}
6093 	switch (arg2->type) {
6094 	    case XPATH_UNDEFINED:
6095 		break;
6096 	    case XPATH_NODESET:
6097 	    case XPATH_XSLT_TREE:
6098 		ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 1);
6099 		break;
6100 	    case XPATH_BOOLEAN:
6101 		if ((arg1->nodesetval == NULL) ||
6102 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
6103 		else
6104 		    ret = 1;
6105 		ret = (ret != arg2->boolval);
6106 		break;
6107 	    case XPATH_NUMBER:
6108 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
6109 		break;
6110 	    case XPATH_STRING:
6111 		ret = xmlXPathEqualNodeSetString(ctxt, arg1,
6112                                                  arg2->stringval, 1);
6113 		break;
6114 	    case XPATH_USERS:
6115 		/* TODO */
6116 		break;
6117 	}
6118 	xmlXPathReleaseObject(ctxt->context, arg1);
6119 	xmlXPathReleaseObject(ctxt->context, arg2);
6120 	return(ret);
6121     }
6122 
6123     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6124 }
6125 
6126 /**
6127  * xmlXPathCompareValues:
6128  * @ctxt:  the XPath Parser context
6129  * @inf:  less than (1) or greater than (0)
6130  * @strict:  is the comparison strict
6131  *
6132  * Implement the compare operation on XPath objects:
6133  *     @arg1 < @arg2    (1, 1, ...
6134  *     @arg1 <= @arg2   (1, 0, ...
6135  *     @arg1 > @arg2    (0, 1, ...
6136  *     @arg1 >= @arg2   (0, 0, ...
6137  *
6138  * When neither object to be compared is a node-set and the operator is
6139  * <=, <, >=, >, then the objects are compared by converted both objects
6140  * to numbers and comparing the numbers according to IEEE 754. The <
6141  * comparison will be true if and only if the first number is less than the
6142  * second number. The <= comparison will be true if and only if the first
6143  * number is less than or equal to the second number. The > comparison
6144  * will be true if and only if the first number is greater than the second
6145  * number. The >= comparison will be true if and only if the first number
6146  * is greater than or equal to the second number.
6147  *
6148  * Returns 1 if the comparison succeeded, 0 if it failed
6149  */
6150 int
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt,int inf,int strict)6151 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
6152     int ret = 0, arg1i = 0, arg2i = 0;
6153     xmlXPathObjectPtr arg1, arg2;
6154 
6155     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6156     arg2 = valuePop(ctxt);
6157     arg1 = valuePop(ctxt);
6158     if ((arg1 == NULL) || (arg2 == NULL)) {
6159 	if (arg1 != NULL)
6160 	    xmlXPathReleaseObject(ctxt->context, arg1);
6161 	else
6162 	    xmlXPathReleaseObject(ctxt->context, arg2);
6163 	XP_ERROR0(XPATH_INVALID_OPERAND);
6164     }
6165 
6166     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6167       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6168 	/*
6169 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
6170 	 * are not freed from within this routine; they will be freed from the
6171 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
6172 	 */
6173 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
6174 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
6175 	    ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
6176 	} else {
6177 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6178 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
6179 			                          arg1, arg2);
6180 	    } else {
6181 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
6182 			                          arg2, arg1);
6183 	    }
6184 	}
6185 	return(ret);
6186     }
6187 
6188     if (arg1->type != XPATH_NUMBER) {
6189 	valuePush(ctxt, arg1);
6190 	xmlXPathNumberFunction(ctxt, 1);
6191 	arg1 = valuePop(ctxt);
6192     }
6193     if (arg2->type != XPATH_NUMBER) {
6194 	valuePush(ctxt, arg2);
6195 	xmlXPathNumberFunction(ctxt, 1);
6196 	arg2 = valuePop(ctxt);
6197     }
6198     if (ctxt->error)
6199         goto error;
6200     /*
6201      * Add tests for infinity and nan
6202      * => feedback on 3.4 for Inf and NaN
6203      */
6204     /* Hand check NaN and Infinity comparisons */
6205     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
6206 	ret=0;
6207     } else {
6208 	arg1i=xmlXPathIsInf(arg1->floatval);
6209 	arg2i=xmlXPathIsInf(arg2->floatval);
6210 	if (inf && strict) {
6211 	    if ((arg1i == -1 && arg2i != -1) ||
6212 		(arg2i == 1 && arg1i != 1)) {
6213 		ret = 1;
6214 	    } else if (arg1i == 0 && arg2i == 0) {
6215 		ret = (arg1->floatval < arg2->floatval);
6216 	    } else {
6217 		ret = 0;
6218 	    }
6219 	}
6220 	else if (inf && !strict) {
6221 	    if (arg1i == -1 || arg2i == 1) {
6222 		ret = 1;
6223 	    } else if (arg1i == 0 && arg2i == 0) {
6224 		ret = (arg1->floatval <= arg2->floatval);
6225 	    } else {
6226 		ret = 0;
6227 	    }
6228 	}
6229 	else if (!inf && strict) {
6230 	    if ((arg1i == 1 && arg2i != 1) ||
6231 		(arg2i == -1 && arg1i != -1)) {
6232 		ret = 1;
6233 	    } else if (arg1i == 0 && arg2i == 0) {
6234 		ret = (arg1->floatval > arg2->floatval);
6235 	    } else {
6236 		ret = 0;
6237 	    }
6238 	}
6239 	else if (!inf && !strict) {
6240 	    if (arg1i == 1 || arg2i == -1) {
6241 		ret = 1;
6242 	    } else if (arg1i == 0 && arg2i == 0) {
6243 		ret = (arg1->floatval >= arg2->floatval);
6244 	    } else {
6245 		ret = 0;
6246 	    }
6247 	}
6248     }
6249 error:
6250     xmlXPathReleaseObject(ctxt->context, arg1);
6251     xmlXPathReleaseObject(ctxt->context, arg2);
6252     return(ret);
6253 }
6254 
6255 /**
6256  * xmlXPathValueFlipSign:
6257  * @ctxt:  the XPath Parser context
6258  *
6259  * Implement the unary - operation on an XPath object
6260  * The numeric operators convert their operands to numbers as if
6261  * by calling the number function.
6262  */
6263 void
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt)6264 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
6265     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
6266     CAST_TO_NUMBER;
6267     CHECK_TYPE(XPATH_NUMBER);
6268     ctxt->value->floatval = -ctxt->value->floatval;
6269 }
6270 
6271 /**
6272  * xmlXPathAddValues:
6273  * @ctxt:  the XPath Parser context
6274  *
6275  * Implement the add operation on XPath objects:
6276  * The numeric operators convert their operands to numbers as if
6277  * by calling the number function.
6278  */
6279 void
xmlXPathAddValues(xmlXPathParserContextPtr ctxt)6280 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
6281     xmlXPathObjectPtr arg;
6282     double val;
6283 
6284     arg = valuePop(ctxt);
6285     if (arg == NULL)
6286 	XP_ERROR(XPATH_INVALID_OPERAND);
6287     val = xmlXPathCastToNumberInternal(ctxt, arg);
6288     xmlXPathReleaseObject(ctxt->context, arg);
6289     CAST_TO_NUMBER;
6290     CHECK_TYPE(XPATH_NUMBER);
6291     ctxt->value->floatval += val;
6292 }
6293 
6294 /**
6295  * xmlXPathSubValues:
6296  * @ctxt:  the XPath Parser context
6297  *
6298  * Implement the subtraction operation on XPath objects:
6299  * The numeric operators convert their operands to numbers as if
6300  * by calling the number function.
6301  */
6302 void
xmlXPathSubValues(xmlXPathParserContextPtr ctxt)6303 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
6304     xmlXPathObjectPtr arg;
6305     double val;
6306 
6307     arg = valuePop(ctxt);
6308     if (arg == NULL)
6309 	XP_ERROR(XPATH_INVALID_OPERAND);
6310     val = xmlXPathCastToNumberInternal(ctxt, arg);
6311     xmlXPathReleaseObject(ctxt->context, arg);
6312     CAST_TO_NUMBER;
6313     CHECK_TYPE(XPATH_NUMBER);
6314     ctxt->value->floatval -= val;
6315 }
6316 
6317 /**
6318  * xmlXPathMultValues:
6319  * @ctxt:  the XPath Parser context
6320  *
6321  * Implement the multiply operation on XPath objects:
6322  * The numeric operators convert their operands to numbers as if
6323  * by calling the number function.
6324  */
6325 void
xmlXPathMultValues(xmlXPathParserContextPtr ctxt)6326 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
6327     xmlXPathObjectPtr arg;
6328     double val;
6329 
6330     arg = valuePop(ctxt);
6331     if (arg == NULL)
6332 	XP_ERROR(XPATH_INVALID_OPERAND);
6333     val = xmlXPathCastToNumberInternal(ctxt, arg);
6334     xmlXPathReleaseObject(ctxt->context, arg);
6335     CAST_TO_NUMBER;
6336     CHECK_TYPE(XPATH_NUMBER);
6337     ctxt->value->floatval *= val;
6338 }
6339 
6340 /**
6341  * xmlXPathDivValues:
6342  * @ctxt:  the XPath Parser context
6343  *
6344  * Implement the div operation on XPath objects @arg1 / @arg2:
6345  * The numeric operators convert their operands to numbers as if
6346  * by calling the number function.
6347  */
6348 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
6349 void
xmlXPathDivValues(xmlXPathParserContextPtr ctxt)6350 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
6351     xmlXPathObjectPtr arg;
6352     double val;
6353 
6354     arg = valuePop(ctxt);
6355     if (arg == NULL)
6356 	XP_ERROR(XPATH_INVALID_OPERAND);
6357     val = xmlXPathCastToNumberInternal(ctxt, arg);
6358     xmlXPathReleaseObject(ctxt->context, arg);
6359     CAST_TO_NUMBER;
6360     CHECK_TYPE(XPATH_NUMBER);
6361     ctxt->value->floatval /= val;
6362 }
6363 
6364 /**
6365  * xmlXPathModValues:
6366  * @ctxt:  the XPath Parser context
6367  *
6368  * Implement the mod operation on XPath objects: @arg1 / @arg2
6369  * The numeric operators convert their operands to numbers as if
6370  * by calling the number function.
6371  */
6372 void
xmlXPathModValues(xmlXPathParserContextPtr ctxt)6373 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
6374     xmlXPathObjectPtr arg;
6375     double arg1, arg2;
6376 
6377     arg = valuePop(ctxt);
6378     if (arg == NULL)
6379 	XP_ERROR(XPATH_INVALID_OPERAND);
6380     arg2 = xmlXPathCastToNumberInternal(ctxt, arg);
6381     xmlXPathReleaseObject(ctxt->context, arg);
6382     CAST_TO_NUMBER;
6383     CHECK_TYPE(XPATH_NUMBER);
6384     arg1 = ctxt->value->floatval;
6385     if (arg2 == 0)
6386 	ctxt->value->floatval = xmlXPathNAN;
6387     else {
6388 	ctxt->value->floatval = fmod(arg1, arg2);
6389     }
6390 }
6391 
6392 /************************************************************************
6393  *									*
6394  *		The traversal functions					*
6395  *									*
6396  ************************************************************************/
6397 
6398 /*
6399  * A traversal function enumerates nodes along an axis.
6400  * Initially it must be called with NULL, and it indicates
6401  * termination on the axis by returning NULL.
6402  */
6403 typedef xmlNodePtr (*xmlXPathTraversalFunction)
6404                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
6405 
6406 /*
6407  * xmlXPathTraversalFunctionExt:
6408  * A traversal function enumerates nodes along an axis.
6409  * Initially it must be called with NULL, and it indicates
6410  * termination on the axis by returning NULL.
6411  * The context node of the traversal is specified via @contextNode.
6412  */
6413 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
6414                     (xmlNodePtr cur, xmlNodePtr contextNode);
6415 
6416 /*
6417  * xmlXPathNodeSetMergeFunction:
6418  * Used for merging node sets in xmlXPathCollectAndTest().
6419  */
6420 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
6421 		    (xmlNodeSetPtr, xmlNodeSetPtr);
6422 
6423 
6424 /**
6425  * xmlXPathNextSelf:
6426  * @ctxt:  the XPath Parser context
6427  * @cur:  the current node in the traversal
6428  *
6429  * Traversal function for the "self" direction
6430  * The self axis contains just the context node itself
6431  *
6432  * Returns the next element following that axis
6433  */
6434 xmlNodePtr
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6435 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6436     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6437     if (cur == NULL)
6438         return(ctxt->context->node);
6439     return(NULL);
6440 }
6441 
6442 /**
6443  * xmlXPathNextChild:
6444  * @ctxt:  the XPath Parser context
6445  * @cur:  the current node in the traversal
6446  *
6447  * Traversal function for the "child" direction
6448  * The child axis contains the children of the context node in document order.
6449  *
6450  * Returns the next element following that axis
6451  */
6452 xmlNodePtr
xmlXPathNextChild(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6453 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6454     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6455     if (cur == NULL) {
6456 	if (ctxt->context->node == NULL) return(NULL);
6457 	switch (ctxt->context->node->type) {
6458             case XML_ELEMENT_NODE:
6459             case XML_TEXT_NODE:
6460             case XML_CDATA_SECTION_NODE:
6461             case XML_ENTITY_REF_NODE:
6462             case XML_ENTITY_NODE:
6463             case XML_PI_NODE:
6464             case XML_COMMENT_NODE:
6465             case XML_NOTATION_NODE:
6466             case XML_DTD_NODE:
6467 		return(ctxt->context->node->children);
6468             case XML_DOCUMENT_NODE:
6469             case XML_DOCUMENT_TYPE_NODE:
6470             case XML_DOCUMENT_FRAG_NODE:
6471             case XML_HTML_DOCUMENT_NODE:
6472 		return(((xmlDocPtr) ctxt->context->node)->children);
6473 	    case XML_ELEMENT_DECL:
6474 	    case XML_ATTRIBUTE_DECL:
6475 	    case XML_ENTITY_DECL:
6476             case XML_ATTRIBUTE_NODE:
6477 	    case XML_NAMESPACE_DECL:
6478 	    case XML_XINCLUDE_START:
6479 	    case XML_XINCLUDE_END:
6480 		return(NULL);
6481 	}
6482 	return(NULL);
6483     }
6484     if ((cur->type == XML_DOCUMENT_NODE) ||
6485         (cur->type == XML_HTML_DOCUMENT_NODE))
6486 	return(NULL);
6487     return(cur->next);
6488 }
6489 
6490 /**
6491  * xmlXPathNextChildElement:
6492  * @ctxt:  the XPath Parser context
6493  * @cur:  the current node in the traversal
6494  *
6495  * Traversal function for the "child" direction and nodes of type element.
6496  * The child axis contains the children of the context node in document order.
6497  *
6498  * Returns the next element following that axis
6499  */
6500 static xmlNodePtr
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6501 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6502     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6503     if (cur == NULL) {
6504 	cur = ctxt->context->node;
6505 	if (cur == NULL) return(NULL);
6506 	/*
6507 	* Get the first element child.
6508 	*/
6509 	switch (cur->type) {
6510             case XML_ELEMENT_NODE:
6511 	    case XML_DOCUMENT_FRAG_NODE:
6512 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
6513             case XML_ENTITY_NODE:
6514 		cur = cur->children;
6515 		if (cur != NULL) {
6516 		    if (cur->type == XML_ELEMENT_NODE)
6517 			return(cur);
6518 		    do {
6519 			cur = cur->next;
6520 		    } while ((cur != NULL) &&
6521 			(cur->type != XML_ELEMENT_NODE));
6522 		    return(cur);
6523 		}
6524 		return(NULL);
6525             case XML_DOCUMENT_NODE:
6526             case XML_HTML_DOCUMENT_NODE:
6527 		return(xmlDocGetRootElement((xmlDocPtr) cur));
6528 	    default:
6529 		return(NULL);
6530 	}
6531 	return(NULL);
6532     }
6533     /*
6534     * Get the next sibling element node.
6535     */
6536     switch (cur->type) {
6537 	case XML_ELEMENT_NODE:
6538 	case XML_TEXT_NODE:
6539 	case XML_ENTITY_REF_NODE:
6540 	case XML_ENTITY_NODE:
6541 	case XML_CDATA_SECTION_NODE:
6542 	case XML_PI_NODE:
6543 	case XML_COMMENT_NODE:
6544 	case XML_XINCLUDE_END:
6545 	    break;
6546 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
6547 	default:
6548 	    return(NULL);
6549     }
6550     if (cur->next != NULL) {
6551 	if (cur->next->type == XML_ELEMENT_NODE)
6552 	    return(cur->next);
6553 	cur = cur->next;
6554 	do {
6555 	    cur = cur->next;
6556 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
6557 	return(cur);
6558     }
6559     return(NULL);
6560 }
6561 
6562 #if 0
6563 /**
6564  * xmlXPathNextDescendantOrSelfElemParent:
6565  * @ctxt:  the XPath Parser context
6566  * @cur:  the current node in the traversal
6567  *
6568  * Traversal function for the "descendant-or-self" axis.
6569  * Additionally it returns only nodes which can be parents of
6570  * element nodes.
6571  *
6572  *
6573  * Returns the next element following that axis
6574  */
6575 static xmlNodePtr
6576 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
6577 				       xmlNodePtr contextNode)
6578 {
6579     if (cur == NULL) {
6580 	if (contextNode == NULL)
6581 	    return(NULL);
6582 	switch (contextNode->type) {
6583 	    case XML_ELEMENT_NODE:
6584 	    case XML_XINCLUDE_START:
6585 	    case XML_DOCUMENT_FRAG_NODE:
6586 	    case XML_DOCUMENT_NODE:
6587 	    case XML_HTML_DOCUMENT_NODE:
6588 		return(contextNode);
6589 	    default:
6590 		return(NULL);
6591 	}
6592 	return(NULL);
6593     } else {
6594 	xmlNodePtr start = cur;
6595 
6596 	while (cur != NULL) {
6597 	    switch (cur->type) {
6598 		case XML_ELEMENT_NODE:
6599 		/* TODO: OK to have XInclude here? */
6600 		case XML_XINCLUDE_START:
6601 		case XML_DOCUMENT_FRAG_NODE:
6602 		    if (cur != start)
6603 			return(cur);
6604 		    if (cur->children != NULL) {
6605 			cur = cur->children;
6606 			continue;
6607 		    }
6608 		    break;
6609 		/* Not sure if we need those here. */
6610 		case XML_DOCUMENT_NODE:
6611 		case XML_HTML_DOCUMENT_NODE:
6612 		    if (cur != start)
6613 			return(cur);
6614 		    return(xmlDocGetRootElement((xmlDocPtr) cur));
6615 		default:
6616 		    break;
6617 	    }
6618 
6619 next_sibling:
6620 	    if ((cur == NULL) || (cur == contextNode))
6621 		return(NULL);
6622 	    if (cur->next != NULL) {
6623 		cur = cur->next;
6624 	    } else {
6625 		cur = cur->parent;
6626 		goto next_sibling;
6627 	    }
6628 	}
6629     }
6630     return(NULL);
6631 }
6632 #endif
6633 
6634 /**
6635  * xmlXPathNextDescendant:
6636  * @ctxt:  the XPath Parser context
6637  * @cur:  the current node in the traversal
6638  *
6639  * Traversal function for the "descendant" direction
6640  * the descendant axis contains the descendants of the context node in document
6641  * order; a descendant is a child or a child of a child and so on.
6642  *
6643  * Returns the next element following that axis
6644  */
6645 xmlNodePtr
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6646 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6647     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6648     if (cur == NULL) {
6649 	if (ctxt->context->node == NULL)
6650 	    return(NULL);
6651 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6652 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
6653 	    return(NULL);
6654 
6655         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6656 	    return(ctxt->context->doc->children);
6657         return(ctxt->context->node->children);
6658     }
6659 
6660     if (cur->type == XML_NAMESPACE_DECL)
6661         return(NULL);
6662     if (cur->children != NULL) {
6663 	/*
6664 	 * Do not descend on entities declarations
6665 	 */
6666 	if (cur->children->type != XML_ENTITY_DECL) {
6667 	    cur = cur->children;
6668 	    /*
6669 	     * Skip DTDs
6670 	     */
6671 	    if (cur->type != XML_DTD_NODE)
6672 		return(cur);
6673 	}
6674     }
6675 
6676     if (cur == ctxt->context->node) return(NULL);
6677 
6678     while (cur->next != NULL) {
6679 	cur = cur->next;
6680 	if ((cur->type != XML_ENTITY_DECL) &&
6681 	    (cur->type != XML_DTD_NODE))
6682 	    return(cur);
6683     }
6684 
6685     do {
6686         cur = cur->parent;
6687 	if (cur == NULL) break;
6688 	if (cur == ctxt->context->node) return(NULL);
6689 	if (cur->next != NULL) {
6690 	    cur = cur->next;
6691 	    return(cur);
6692 	}
6693     } while (cur != NULL);
6694     return(cur);
6695 }
6696 
6697 /**
6698  * xmlXPathNextDescendantOrSelf:
6699  * @ctxt:  the XPath Parser context
6700  * @cur:  the current node in the traversal
6701  *
6702  * Traversal function for the "descendant-or-self" direction
6703  * the descendant-or-self axis contains the context node and the descendants
6704  * of the context node in document order; thus the context node is the first
6705  * node on the axis, and the first child of the context node is the second node
6706  * on the axis
6707  *
6708  * Returns the next element following that axis
6709  */
6710 xmlNodePtr
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6711 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6712     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6713     if (cur == NULL)
6714         return(ctxt->context->node);
6715 
6716     if (ctxt->context->node == NULL)
6717         return(NULL);
6718     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6719         (ctxt->context->node->type == XML_NAMESPACE_DECL))
6720         return(NULL);
6721 
6722     return(xmlXPathNextDescendant(ctxt, cur));
6723 }
6724 
6725 /**
6726  * xmlXPathNextParent:
6727  * @ctxt:  the XPath Parser context
6728  * @cur:  the current node in the traversal
6729  *
6730  * Traversal function for the "parent" direction
6731  * The parent axis contains the parent of the context node, if there is one.
6732  *
6733  * Returns the next element following that axis
6734  */
6735 xmlNodePtr
xmlXPathNextParent(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6736 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6737     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6738     /*
6739      * the parent of an attribute or namespace node is the element
6740      * to which the attribute or namespace node is attached
6741      * Namespace handling !!!
6742      */
6743     if (cur == NULL) {
6744 	if (ctxt->context->node == NULL) return(NULL);
6745 	switch (ctxt->context->node->type) {
6746             case XML_ELEMENT_NODE:
6747             case XML_TEXT_NODE:
6748             case XML_CDATA_SECTION_NODE:
6749             case XML_ENTITY_REF_NODE:
6750             case XML_ENTITY_NODE:
6751             case XML_PI_NODE:
6752             case XML_COMMENT_NODE:
6753             case XML_NOTATION_NODE:
6754             case XML_DTD_NODE:
6755 	    case XML_ELEMENT_DECL:
6756 	    case XML_ATTRIBUTE_DECL:
6757 	    case XML_XINCLUDE_START:
6758 	    case XML_XINCLUDE_END:
6759 	    case XML_ENTITY_DECL:
6760 		if (ctxt->context->node->parent == NULL)
6761 		    return((xmlNodePtr) ctxt->context->doc);
6762 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6763 		    ((ctxt->context->node->parent->name[0] == ' ') ||
6764 		     (xmlStrEqual(ctxt->context->node->parent->name,
6765 				 BAD_CAST "fake node libxslt"))))
6766 		    return(NULL);
6767 		return(ctxt->context->node->parent);
6768             case XML_ATTRIBUTE_NODE: {
6769 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
6770 
6771 		return(att->parent);
6772 	    }
6773             case XML_DOCUMENT_NODE:
6774             case XML_DOCUMENT_TYPE_NODE:
6775             case XML_DOCUMENT_FRAG_NODE:
6776             case XML_HTML_DOCUMENT_NODE:
6777                 return(NULL);
6778 	    case XML_NAMESPACE_DECL: {
6779 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6780 
6781 		if ((ns->next != NULL) &&
6782 		    (ns->next->type != XML_NAMESPACE_DECL))
6783 		    return((xmlNodePtr) ns->next);
6784                 return(NULL);
6785 	    }
6786 	}
6787     }
6788     return(NULL);
6789 }
6790 
6791 /**
6792  * xmlXPathNextAncestor:
6793  * @ctxt:  the XPath Parser context
6794  * @cur:  the current node in the traversal
6795  *
6796  * Traversal function for the "ancestor" direction
6797  * the ancestor axis contains the ancestors of the context node; the ancestors
6798  * of the context node consist of the parent of context node and the parent's
6799  * parent and so on; the nodes are ordered in reverse document order; thus the
6800  * parent is the first node on the axis, and the parent's parent is the second
6801  * node on the axis
6802  *
6803  * Returns the next element following that axis
6804  */
6805 xmlNodePtr
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6806 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6807     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6808     /*
6809      * the parent of an attribute or namespace node is the element
6810      * to which the attribute or namespace node is attached
6811      * !!!!!!!!!!!!!
6812      */
6813     if (cur == NULL) {
6814 	if (ctxt->context->node == NULL) return(NULL);
6815 	switch (ctxt->context->node->type) {
6816             case XML_ELEMENT_NODE:
6817             case XML_TEXT_NODE:
6818             case XML_CDATA_SECTION_NODE:
6819             case XML_ENTITY_REF_NODE:
6820             case XML_ENTITY_NODE:
6821             case XML_PI_NODE:
6822             case XML_COMMENT_NODE:
6823 	    case XML_DTD_NODE:
6824 	    case XML_ELEMENT_DECL:
6825 	    case XML_ATTRIBUTE_DECL:
6826 	    case XML_ENTITY_DECL:
6827             case XML_NOTATION_NODE:
6828 	    case XML_XINCLUDE_START:
6829 	    case XML_XINCLUDE_END:
6830 		if (ctxt->context->node->parent == NULL)
6831 		    return((xmlNodePtr) ctxt->context->doc);
6832 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6833 		    ((ctxt->context->node->parent->name[0] == ' ') ||
6834 		     (xmlStrEqual(ctxt->context->node->parent->name,
6835 				 BAD_CAST "fake node libxslt"))))
6836 		    return(NULL);
6837 		return(ctxt->context->node->parent);
6838             case XML_ATTRIBUTE_NODE: {
6839 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
6840 
6841 		return(tmp->parent);
6842 	    }
6843             case XML_DOCUMENT_NODE:
6844             case XML_DOCUMENT_TYPE_NODE:
6845             case XML_DOCUMENT_FRAG_NODE:
6846             case XML_HTML_DOCUMENT_NODE:
6847                 return(NULL);
6848 	    case XML_NAMESPACE_DECL: {
6849 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6850 
6851 		if ((ns->next != NULL) &&
6852 		    (ns->next->type != XML_NAMESPACE_DECL))
6853 		    return((xmlNodePtr) ns->next);
6854 		/* Bad, how did that namespace end up here ? */
6855                 return(NULL);
6856 	    }
6857 	}
6858 	return(NULL);
6859     }
6860     if (cur == ctxt->context->doc->children)
6861 	return((xmlNodePtr) ctxt->context->doc);
6862     if (cur == (xmlNodePtr) ctxt->context->doc)
6863 	return(NULL);
6864     switch (cur->type) {
6865 	case XML_ELEMENT_NODE:
6866 	case XML_TEXT_NODE:
6867 	case XML_CDATA_SECTION_NODE:
6868 	case XML_ENTITY_REF_NODE:
6869 	case XML_ENTITY_NODE:
6870 	case XML_PI_NODE:
6871 	case XML_COMMENT_NODE:
6872 	case XML_NOTATION_NODE:
6873 	case XML_DTD_NODE:
6874         case XML_ELEMENT_DECL:
6875         case XML_ATTRIBUTE_DECL:
6876         case XML_ENTITY_DECL:
6877 	case XML_XINCLUDE_START:
6878 	case XML_XINCLUDE_END:
6879 	    if (cur->parent == NULL)
6880 		return(NULL);
6881 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
6882 		((cur->parent->name[0] == ' ') ||
6883 		 (xmlStrEqual(cur->parent->name,
6884 			      BAD_CAST "fake node libxslt"))))
6885 		return(NULL);
6886 	    return(cur->parent);
6887 	case XML_ATTRIBUTE_NODE: {
6888 	    xmlAttrPtr att = (xmlAttrPtr) cur;
6889 
6890 	    return(att->parent);
6891 	}
6892 	case XML_NAMESPACE_DECL: {
6893 	    xmlNsPtr ns = (xmlNsPtr) cur;
6894 
6895 	    if ((ns->next != NULL) &&
6896 	        (ns->next->type != XML_NAMESPACE_DECL))
6897 	        return((xmlNodePtr) ns->next);
6898 	    /* Bad, how did that namespace end up here ? */
6899             return(NULL);
6900 	}
6901 	case XML_DOCUMENT_NODE:
6902 	case XML_DOCUMENT_TYPE_NODE:
6903 	case XML_DOCUMENT_FRAG_NODE:
6904 	case XML_HTML_DOCUMENT_NODE:
6905 	    return(NULL);
6906     }
6907     return(NULL);
6908 }
6909 
6910 /**
6911  * xmlXPathNextAncestorOrSelf:
6912  * @ctxt:  the XPath Parser context
6913  * @cur:  the current node in the traversal
6914  *
6915  * Traversal function for the "ancestor-or-self" direction
6916  * he ancestor-or-self axis contains the context node and ancestors of
6917  * the context node in reverse document order; thus the context node is
6918  * the first node on the axis, and the context node's parent the second;
6919  * parent here is defined the same as with the parent axis.
6920  *
6921  * Returns the next element following that axis
6922  */
6923 xmlNodePtr
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6924 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6925     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6926     if (cur == NULL)
6927         return(ctxt->context->node);
6928     return(xmlXPathNextAncestor(ctxt, cur));
6929 }
6930 
6931 /**
6932  * xmlXPathNextFollowingSibling:
6933  * @ctxt:  the XPath Parser context
6934  * @cur:  the current node in the traversal
6935  *
6936  * Traversal function for the "following-sibling" direction
6937  * The following-sibling axis contains the following siblings of the context
6938  * node in document order.
6939  *
6940  * Returns the next element following that axis
6941  */
6942 xmlNodePtr
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6943 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6944     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6945     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6946 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
6947 	return(NULL);
6948     if (cur == (xmlNodePtr) ctxt->context->doc)
6949         return(NULL);
6950     if (cur == NULL)
6951         return(ctxt->context->node->next);
6952     return(cur->next);
6953 }
6954 
6955 /**
6956  * xmlXPathNextPrecedingSibling:
6957  * @ctxt:  the XPath Parser context
6958  * @cur:  the current node in the traversal
6959  *
6960  * Traversal function for the "preceding-sibling" direction
6961  * The preceding-sibling axis contains the preceding siblings of the context
6962  * node in reverse document order; the first preceding sibling is first on the
6963  * axis; the sibling preceding that node is the second on the axis and so on.
6964  *
6965  * Returns the next element following that axis
6966  */
6967 xmlNodePtr
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6968 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6969     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6970     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6971 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
6972 	return(NULL);
6973     if (cur == (xmlNodePtr) ctxt->context->doc)
6974         return(NULL);
6975     if (cur == NULL)
6976         return(ctxt->context->node->prev);
6977     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
6978 	cur = cur->prev;
6979 	if (cur == NULL)
6980 	    return(ctxt->context->node->prev);
6981     }
6982     return(cur->prev);
6983 }
6984 
6985 /**
6986  * xmlXPathNextFollowing:
6987  * @ctxt:  the XPath Parser context
6988  * @cur:  the current node in the traversal
6989  *
6990  * Traversal function for the "following" direction
6991  * The following axis contains all nodes in the same document as the context
6992  * node that are after the context node in document order, excluding any
6993  * descendants and excluding attribute nodes and namespace nodes; the nodes
6994  * are ordered in document order
6995  *
6996  * Returns the next element following that axis
6997  */
6998 xmlNodePtr
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6999 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7000     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7001     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
7002         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
7003         return(cur->children);
7004 
7005     if (cur == NULL) {
7006         cur = ctxt->context->node;
7007         if (cur->type == XML_ATTRIBUTE_NODE) {
7008             cur = cur->parent;
7009         } else if (cur->type == XML_NAMESPACE_DECL) {
7010             xmlNsPtr ns = (xmlNsPtr) cur;
7011 
7012             if ((ns->next == NULL) ||
7013                 (ns->next->type == XML_NAMESPACE_DECL))
7014                 return (NULL);
7015             cur = (xmlNodePtr) ns->next;
7016         }
7017     }
7018     if (cur == NULL) return(NULL) ; /* ERROR */
7019     if (cur->next != NULL) return(cur->next) ;
7020     do {
7021         cur = cur->parent;
7022         if (cur == NULL) break;
7023         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
7024         if (cur->next != NULL) return(cur->next);
7025     } while (cur != NULL);
7026     return(cur);
7027 }
7028 
7029 /*
7030  * xmlXPathIsAncestor:
7031  * @ancestor:  the ancestor node
7032  * @node:  the current node
7033  *
7034  * Check that @ancestor is a @node's ancestor
7035  *
7036  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
7037  */
7038 static int
xmlXPathIsAncestor(xmlNodePtr ancestor,xmlNodePtr node)7039 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
7040     if ((ancestor == NULL) || (node == NULL)) return(0);
7041     if (node->type == XML_NAMESPACE_DECL)
7042         return(0);
7043     if (ancestor->type == XML_NAMESPACE_DECL)
7044         return(0);
7045     /* nodes need to be in the same document */
7046     if (ancestor->doc != node->doc) return(0);
7047     /* avoid searching if ancestor or node is the root node */
7048     if (ancestor == (xmlNodePtr) node->doc) return(1);
7049     if (node == (xmlNodePtr) ancestor->doc) return(0);
7050     while (node->parent != NULL) {
7051         if (node->parent == ancestor)
7052             return(1);
7053 	node = node->parent;
7054     }
7055     return(0);
7056 }
7057 
7058 /**
7059  * xmlXPathNextPreceding:
7060  * @ctxt:  the XPath Parser context
7061  * @cur:  the current node in the traversal
7062  *
7063  * Traversal function for the "preceding" direction
7064  * the preceding axis contains all nodes in the same document as the context
7065  * node that are before the context node in document order, excluding any
7066  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7067  * ordered in reverse document order
7068  *
7069  * Returns the next element following that axis
7070  */
7071 xmlNodePtr
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7072 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
7073 {
7074     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7075     if (cur == NULL) {
7076         cur = ctxt->context->node;
7077         if (cur->type == XML_ATTRIBUTE_NODE) {
7078             cur = cur->parent;
7079         } else if (cur->type == XML_NAMESPACE_DECL) {
7080             xmlNsPtr ns = (xmlNsPtr) cur;
7081 
7082             if ((ns->next == NULL) ||
7083                 (ns->next->type == XML_NAMESPACE_DECL))
7084                 return (NULL);
7085             cur = (xmlNodePtr) ns->next;
7086         }
7087     }
7088     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
7089 	return (NULL);
7090     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7091 	cur = cur->prev;
7092     do {
7093         if (cur->prev != NULL) {
7094             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
7095             return (cur);
7096         }
7097 
7098         cur = cur->parent;
7099         if (cur == NULL)
7100             return (NULL);
7101         if (cur == ctxt->context->doc->children)
7102             return (NULL);
7103     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
7104     return (cur);
7105 }
7106 
7107 /**
7108  * xmlXPathNextPrecedingInternal:
7109  * @ctxt:  the XPath Parser context
7110  * @cur:  the current node in the traversal
7111  *
7112  * Traversal function for the "preceding" direction
7113  * the preceding axis contains all nodes in the same document as the context
7114  * node that are before the context node in document order, excluding any
7115  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7116  * ordered in reverse document order
7117  * This is a faster implementation but internal only since it requires a
7118  * state kept in the parser context: ctxt->ancestor.
7119  *
7120  * Returns the next element following that axis
7121  */
7122 static xmlNodePtr
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7123 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
7124                               xmlNodePtr cur)
7125 {
7126     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7127     if (cur == NULL) {
7128         cur = ctxt->context->node;
7129         if (cur == NULL)
7130             return (NULL);
7131         if (cur->type == XML_ATTRIBUTE_NODE) {
7132             cur = cur->parent;
7133         } else if (cur->type == XML_NAMESPACE_DECL) {
7134             xmlNsPtr ns = (xmlNsPtr) cur;
7135 
7136             if ((ns->next == NULL) ||
7137                 (ns->next->type == XML_NAMESPACE_DECL))
7138                 return (NULL);
7139             cur = (xmlNodePtr) ns->next;
7140         }
7141         ctxt->ancestor = cur->parent;
7142     }
7143     if (cur->type == XML_NAMESPACE_DECL)
7144         return(NULL);
7145     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7146 	cur = cur->prev;
7147     while (cur->prev == NULL) {
7148         cur = cur->parent;
7149         if (cur == NULL)
7150             return (NULL);
7151         if (cur == ctxt->context->doc->children)
7152             return (NULL);
7153         if (cur != ctxt->ancestor)
7154             return (cur);
7155         ctxt->ancestor = cur->parent;
7156     }
7157     cur = cur->prev;
7158     while (cur->last != NULL)
7159         cur = cur->last;
7160     return (cur);
7161 }
7162 
7163 /**
7164  * xmlXPathNextNamespace:
7165  * @ctxt:  the XPath Parser context
7166  * @cur:  the current attribute in the traversal
7167  *
7168  * Traversal function for the "namespace" direction
7169  * the namespace axis contains the namespace nodes of the context node;
7170  * the order of nodes on this axis is implementation-defined; the axis will
7171  * be empty unless the context node is an element
7172  *
7173  * We keep the XML namespace node at the end of the list.
7174  *
7175  * Returns the next element following that axis
7176  */
7177 xmlNodePtr
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7178 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7179     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7180     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
7181     if (cur == NULL) {
7182         if (ctxt->context->tmpNsList != NULL)
7183 	    xmlFree(ctxt->context->tmpNsList);
7184 	ctxt->context->tmpNsNr = 0;
7185         if (xmlGetNsListSafe(ctxt->context->doc, ctxt->context->node,
7186                              &ctxt->context->tmpNsList) < 0) {
7187             xmlXPathPErrMemory(ctxt);
7188             return(NULL);
7189         }
7190         if (ctxt->context->tmpNsList != NULL) {
7191             while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
7192                 ctxt->context->tmpNsNr++;
7193             }
7194         }
7195 	return((xmlNodePtr) xmlXPathXMLNamespace);
7196     }
7197     if (ctxt->context->tmpNsNr > 0) {
7198 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
7199     } else {
7200 	if (ctxt->context->tmpNsList != NULL)
7201 	    xmlFree(ctxt->context->tmpNsList);
7202 	ctxt->context->tmpNsList = NULL;
7203 	return(NULL);
7204     }
7205 }
7206 
7207 /**
7208  * xmlXPathNextAttribute:
7209  * @ctxt:  the XPath Parser context
7210  * @cur:  the current attribute in the traversal
7211  *
7212  * Traversal function for the "attribute" direction
7213  * TODO: support DTD inherited default attributes
7214  *
7215  * Returns the next element following that axis
7216  */
7217 xmlNodePtr
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7218 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7219     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7220     if (ctxt->context->node == NULL)
7221 	return(NULL);
7222     if (ctxt->context->node->type != XML_ELEMENT_NODE)
7223 	return(NULL);
7224     if (cur == NULL) {
7225         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7226 	    return(NULL);
7227         return((xmlNodePtr)ctxt->context->node->properties);
7228     }
7229     return((xmlNodePtr)cur->next);
7230 }
7231 
7232 /************************************************************************
7233  *									*
7234  *		NodeTest Functions					*
7235  *									*
7236  ************************************************************************/
7237 
7238 #define IS_FUNCTION			200
7239 
7240 
7241 /************************************************************************
7242  *									*
7243  *		Implicit tree core function library			*
7244  *									*
7245  ************************************************************************/
7246 
7247 /**
7248  * xmlXPathRoot:
7249  * @ctxt:  the XPath Parser context
7250  *
7251  * Initialize the context to the root of the document
7252  */
7253 void
xmlXPathRoot(xmlXPathParserContextPtr ctxt)7254 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
7255     if ((ctxt == NULL) || (ctxt->context == NULL))
7256 	return;
7257     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7258                                             (xmlNodePtr) ctxt->context->doc));
7259 }
7260 
7261 /************************************************************************
7262  *									*
7263  *		The explicit core function library			*
7264  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
7265  *									*
7266  ************************************************************************/
7267 
7268 
7269 /**
7270  * xmlXPathLastFunction:
7271  * @ctxt:  the XPath Parser context
7272  * @nargs:  the number of arguments
7273  *
7274  * Implement the last() XPath function
7275  *    number last()
7276  * The last function returns the number of nodes in the context node list.
7277  */
7278 void
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt,int nargs)7279 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7280     CHECK_ARITY(0);
7281     if (ctxt->context->contextSize >= 0) {
7282 	valuePush(ctxt,
7283 	    xmlXPathCacheNewFloat(ctxt, (double) ctxt->context->contextSize));
7284     } else {
7285 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
7286     }
7287 }
7288 
7289 /**
7290  * xmlXPathPositionFunction:
7291  * @ctxt:  the XPath Parser context
7292  * @nargs:  the number of arguments
7293  *
7294  * Implement the position() XPath function
7295  *    number position()
7296  * The position function returns the position of the context node in the
7297  * context node list. The first position is 1, and so the last position
7298  * will be equal to last().
7299  */
7300 void
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt,int nargs)7301 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7302     CHECK_ARITY(0);
7303     if (ctxt->context->proximityPosition >= 0) {
7304 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7305             (double) ctxt->context->proximityPosition));
7306     } else {
7307 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
7308     }
7309 }
7310 
7311 /**
7312  * xmlXPathCountFunction:
7313  * @ctxt:  the XPath Parser context
7314  * @nargs:  the number of arguments
7315  *
7316  * Implement the count() XPath function
7317  *    number count(node-set)
7318  */
7319 void
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt,int nargs)7320 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7321     xmlXPathObjectPtr cur;
7322 
7323     CHECK_ARITY(1);
7324     if ((ctxt->value == NULL) ||
7325 	((ctxt->value->type != XPATH_NODESET) &&
7326 	 (ctxt->value->type != XPATH_XSLT_TREE)))
7327 	XP_ERROR(XPATH_INVALID_TYPE);
7328     cur = valuePop(ctxt);
7329 
7330     if ((cur == NULL) || (cur->nodesetval == NULL))
7331 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
7332     else
7333 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7334 	    (double) cur->nodesetval->nodeNr));
7335     xmlXPathReleaseObject(ctxt->context, cur);
7336 }
7337 
7338 /**
7339  * xmlXPathGetElementsByIds:
7340  * @doc:  the document
7341  * @ids:  a whitespace separated list of IDs
7342  *
7343  * Selects elements by their unique ID.
7344  *
7345  * Returns a node-set of selected elements.
7346  */
7347 static xmlNodeSetPtr
xmlXPathGetElementsByIds(xmlDocPtr doc,const xmlChar * ids)7348 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
7349     xmlNodeSetPtr ret;
7350     const xmlChar *cur = ids;
7351     xmlChar *ID;
7352     xmlAttrPtr attr;
7353     xmlNodePtr elem = NULL;
7354 
7355     if (ids == NULL) return(NULL);
7356 
7357     ret = xmlXPathNodeSetCreate(NULL);
7358     if (ret == NULL)
7359         return(ret);
7360 
7361     while (IS_BLANK_CH(*cur)) cur++;
7362     while (*cur != 0) {
7363 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
7364 	    cur++;
7365 
7366         ID = xmlStrndup(ids, cur - ids);
7367 	if (ID == NULL) {
7368             xmlXPathFreeNodeSet(ret);
7369             return(NULL);
7370         }
7371         /*
7372          * We used to check the fact that the value passed
7373          * was an NCName, but this generated much troubles for
7374          * me and Aleksey Sanin, people blatantly violated that
7375          * constraint, like Visa3D spec.
7376          * if (xmlValidateNCName(ID, 1) == 0)
7377          */
7378         attr = xmlGetID(doc, ID);
7379         xmlFree(ID);
7380         if (attr != NULL) {
7381             if (attr->type == XML_ATTRIBUTE_NODE)
7382                 elem = attr->parent;
7383             else if (attr->type == XML_ELEMENT_NODE)
7384                 elem = (xmlNodePtr) attr;
7385             else
7386                 elem = NULL;
7387             if (elem != NULL) {
7388                 if (xmlXPathNodeSetAdd(ret, elem) < 0) {
7389                     xmlXPathFreeNodeSet(ret);
7390                     return(NULL);
7391                 }
7392             }
7393         }
7394 
7395 	while (IS_BLANK_CH(*cur)) cur++;
7396 	ids = cur;
7397     }
7398     return(ret);
7399 }
7400 
7401 /**
7402  * xmlXPathIdFunction:
7403  * @ctxt:  the XPath Parser context
7404  * @nargs:  the number of arguments
7405  *
7406  * Implement the id() XPath function
7407  *    node-set id(object)
7408  * The id function selects elements by their unique ID
7409  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
7410  * then the result is the union of the result of applying id to the
7411  * string value of each of the nodes in the argument node-set. When the
7412  * argument to id is of any other type, the argument is converted to a
7413  * string as if by a call to the string function; the string is split
7414  * into a whitespace-separated list of tokens (whitespace is any sequence
7415  * of characters matching the production S); the result is a node-set
7416  * containing the elements in the same document as the context node that
7417  * have a unique ID equal to any of the tokens in the list.
7418  */
7419 void
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt,int nargs)7420 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7421     xmlChar *tokens;
7422     xmlNodeSetPtr ret;
7423     xmlXPathObjectPtr obj;
7424 
7425     CHECK_ARITY(1);
7426     obj = valuePop(ctxt);
7427     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7428     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7429 	xmlNodeSetPtr ns;
7430 	int i;
7431 
7432 	ret = xmlXPathNodeSetCreate(NULL);
7433         if (ret == NULL)
7434             xmlXPathPErrMemory(ctxt);
7435 
7436 	if (obj->nodesetval != NULL) {
7437 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7438 		tokens =
7439 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7440                 if (tokens == NULL)
7441                     xmlXPathPErrMemory(ctxt);
7442 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7443                 if (ns == NULL)
7444                     xmlXPathPErrMemory(ctxt);
7445 		ret = xmlXPathNodeSetMerge(ret, ns);
7446                 if (ret == NULL)
7447                     xmlXPathPErrMemory(ctxt);
7448 		xmlXPathFreeNodeSet(ns);
7449 		if (tokens != NULL)
7450 		    xmlFree(tokens);
7451 	    }
7452 	}
7453 	xmlXPathReleaseObject(ctxt->context, obj);
7454 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7455 	return;
7456     }
7457     tokens = xmlXPathCastToString(obj);
7458     if (tokens == NULL)
7459         xmlXPathPErrMemory(ctxt);
7460     xmlXPathReleaseObject(ctxt->context, obj);
7461     ret = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7462     if (ret == NULL)
7463         xmlXPathPErrMemory(ctxt);
7464     xmlFree(tokens);
7465     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7466     return;
7467 }
7468 
7469 /**
7470  * xmlXPathLocalNameFunction:
7471  * @ctxt:  the XPath Parser context
7472  * @nargs:  the number of arguments
7473  *
7474  * Implement the local-name() XPath function
7475  *    string local-name(node-set?)
7476  * The local-name function returns a string containing the local part
7477  * of the name of the node in the argument node-set that is first in
7478  * document order. If the node-set is empty or the first node has no
7479  * name, an empty string is returned. If the argument is omitted it
7480  * defaults to the context node.
7481  */
7482 void
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt,int nargs)7483 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7484     xmlXPathObjectPtr cur;
7485 
7486     if (ctxt == NULL) return;
7487 
7488     if (nargs == 0) {
7489 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7490 	nargs = 1;
7491     }
7492 
7493     CHECK_ARITY(1);
7494     if ((ctxt->value == NULL) ||
7495 	((ctxt->value->type != XPATH_NODESET) &&
7496 	 (ctxt->value->type != XPATH_XSLT_TREE)))
7497 	XP_ERROR(XPATH_INVALID_TYPE);
7498     cur = valuePop(ctxt);
7499 
7500     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7501 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7502     } else {
7503 	int i = 0; /* Should be first in document order !!!!! */
7504 	switch (cur->nodesetval->nodeTab[i]->type) {
7505 	case XML_ELEMENT_NODE:
7506 	case XML_ATTRIBUTE_NODE:
7507 	case XML_PI_NODE:
7508 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7509 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7510 	    else
7511 		valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7512 			cur->nodesetval->nodeTab[i]->name));
7513 	    break;
7514 	case XML_NAMESPACE_DECL:
7515 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7516 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
7517 	    break;
7518 	default:
7519 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7520 	}
7521     }
7522     xmlXPathReleaseObject(ctxt->context, cur);
7523 }
7524 
7525 /**
7526  * xmlXPathNamespaceURIFunction:
7527  * @ctxt:  the XPath Parser context
7528  * @nargs:  the number of arguments
7529  *
7530  * Implement the namespace-uri() XPath function
7531  *    string namespace-uri(node-set?)
7532  * The namespace-uri function returns a string containing the
7533  * namespace URI of the expanded name of the node in the argument
7534  * node-set that is first in document order. If the node-set is empty,
7535  * the first node has no name, or the expanded name has no namespace
7536  * URI, an empty string is returned. If the argument is omitted it
7537  * defaults to the context node.
7538  */
7539 void
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt,int nargs)7540 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7541     xmlXPathObjectPtr cur;
7542 
7543     if (ctxt == NULL) return;
7544 
7545     if (nargs == 0) {
7546 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7547 	nargs = 1;
7548     }
7549     CHECK_ARITY(1);
7550     if ((ctxt->value == NULL) ||
7551 	((ctxt->value->type != XPATH_NODESET) &&
7552 	 (ctxt->value->type != XPATH_XSLT_TREE)))
7553 	XP_ERROR(XPATH_INVALID_TYPE);
7554     cur = valuePop(ctxt);
7555 
7556     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7557 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7558     } else {
7559 	int i = 0; /* Should be first in document order !!!!! */
7560 	switch (cur->nodesetval->nodeTab[i]->type) {
7561 	case XML_ELEMENT_NODE:
7562 	case XML_ATTRIBUTE_NODE:
7563 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
7564 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7565 	    else
7566 		valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7567 			  cur->nodesetval->nodeTab[i]->ns->href));
7568 	    break;
7569 	default:
7570 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7571 	}
7572     }
7573     xmlXPathReleaseObject(ctxt->context, cur);
7574 }
7575 
7576 /**
7577  * xmlXPathNameFunction:
7578  * @ctxt:  the XPath Parser context
7579  * @nargs:  the number of arguments
7580  *
7581  * Implement the name() XPath function
7582  *    string name(node-set?)
7583  * The name function returns a string containing a QName representing
7584  * the name of the node in the argument node-set that is first in document
7585  * order. The QName must represent the name with respect to the namespace
7586  * declarations in effect on the node whose name is being represented.
7587  * Typically, this will be the form in which the name occurred in the XML
7588  * source. This need not be the case if there are namespace declarations
7589  * in effect on the node that associate multiple prefixes with the same
7590  * namespace. However, an implementation may include information about
7591  * the original prefix in its representation of nodes; in this case, an
7592  * implementation can ensure that the returned string is always the same
7593  * as the QName used in the XML source. If the argument it omitted it
7594  * defaults to the context node.
7595  * Libxml keep the original prefix so the "real qualified name" used is
7596  * returned.
7597  */
7598 static void
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt,int nargs)7599 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
7600 {
7601     xmlXPathObjectPtr cur;
7602 
7603     if (nargs == 0) {
7604 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7605         nargs = 1;
7606     }
7607 
7608     CHECK_ARITY(1);
7609     if ((ctxt->value == NULL) ||
7610         ((ctxt->value->type != XPATH_NODESET) &&
7611          (ctxt->value->type != XPATH_XSLT_TREE)))
7612         XP_ERROR(XPATH_INVALID_TYPE);
7613     cur = valuePop(ctxt);
7614 
7615     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7616         valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7617     } else {
7618         int i = 0;              /* Should be first in document order !!!!! */
7619 
7620         switch (cur->nodesetval->nodeTab[i]->type) {
7621             case XML_ELEMENT_NODE:
7622             case XML_ATTRIBUTE_NODE:
7623 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7624 		    valuePush(ctxt,
7625 			xmlXPathCacheNewCString(ctxt, ""));
7626 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
7627                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
7628 		    valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7629 			    cur->nodesetval->nodeTab[i]->name));
7630 		} else {
7631 		    xmlChar *fullname;
7632 
7633 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
7634 				     cur->nodesetval->nodeTab[i]->ns->prefix,
7635 				     NULL, 0);
7636 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
7637 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
7638 		    if (fullname == NULL)
7639                         xmlXPathPErrMemory(ctxt);
7640 		    valuePush(ctxt, xmlXPathCacheWrapString(ctxt, fullname));
7641                 }
7642                 break;
7643             default:
7644 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7645 		    cur->nodesetval->nodeTab[i]));
7646                 xmlXPathLocalNameFunction(ctxt, 1);
7647         }
7648     }
7649     xmlXPathReleaseObject(ctxt->context, cur);
7650 }
7651 
7652 
7653 /**
7654  * xmlXPathStringFunction:
7655  * @ctxt:  the XPath Parser context
7656  * @nargs:  the number of arguments
7657  *
7658  * Implement the string() XPath function
7659  *    string string(object?)
7660  * The string function converts an object to a string as follows:
7661  *    - A node-set is converted to a string by returning the value of
7662  *      the node in the node-set that is first in document order.
7663  *      If the node-set is empty, an empty string is returned.
7664  *    - A number is converted to a string as follows
7665  *      + NaN is converted to the string NaN
7666  *      + positive zero is converted to the string 0
7667  *      + negative zero is converted to the string 0
7668  *      + positive infinity is converted to the string Infinity
7669  *      + negative infinity is converted to the string -Infinity
7670  *      + if the number is an integer, the number is represented in
7671  *        decimal form as a Number with no decimal point and no leading
7672  *        zeros, preceded by a minus sign (-) if the number is negative
7673  *      + otherwise, the number is represented in decimal form as a
7674  *        Number including a decimal point with at least one digit
7675  *        before the decimal point and at least one digit after the
7676  *        decimal point, preceded by a minus sign (-) if the number
7677  *        is negative; there must be no leading zeros before the decimal
7678  *        point apart possibly from the one required digit immediately
7679  *        before the decimal point; beyond the one required digit
7680  *        after the decimal point there must be as many, but only as
7681  *        many, more digits as are needed to uniquely distinguish the
7682  *        number from all other IEEE 754 numeric values.
7683  *    - The boolean false value is converted to the string false.
7684  *      The boolean true value is converted to the string true.
7685  *
7686  * If the argument is omitted, it defaults to a node-set with the
7687  * context node as its only member.
7688  */
7689 void
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt,int nargs)7690 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7691     xmlXPathObjectPtr cur;
7692     xmlChar *stringval;
7693 
7694     if (ctxt == NULL) return;
7695     if (nargs == 0) {
7696         stringval = xmlXPathCastNodeToString(ctxt->context->node);
7697         if (stringval == NULL)
7698             xmlXPathPErrMemory(ctxt);
7699         valuePush(ctxt, xmlXPathCacheWrapString(ctxt, stringval));
7700 	return;
7701     }
7702 
7703     CHECK_ARITY(1);
7704     cur = valuePop(ctxt);
7705     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7706     if (cur->type != XPATH_STRING) {
7707         stringval = xmlXPathCastToString(cur);
7708         if (stringval == NULL)
7709             xmlXPathPErrMemory(ctxt);
7710         xmlXPathReleaseObject(ctxt->context, cur);
7711         cur = xmlXPathCacheWrapString(ctxt, stringval);
7712     }
7713     valuePush(ctxt, cur);
7714 }
7715 
7716 /**
7717  * xmlXPathStringLengthFunction:
7718  * @ctxt:  the XPath Parser context
7719  * @nargs:  the number of arguments
7720  *
7721  * Implement the string-length() XPath function
7722  *    number string-length(string?)
7723  * The string-length returns the number of characters in the string
7724  * (see [3.6 Strings]). If the argument is omitted, it defaults to
7725  * the context node converted to a string, in other words the value
7726  * of the context node.
7727  */
7728 void
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt,int nargs)7729 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7730     xmlXPathObjectPtr cur;
7731 
7732     if (nargs == 0) {
7733         if ((ctxt == NULL) || (ctxt->context == NULL))
7734 	    return;
7735 	if (ctxt->context->node == NULL) {
7736 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0));
7737 	} else {
7738 	    xmlChar *content;
7739 
7740 	    content = xmlXPathCastNodeToString(ctxt->context->node);
7741             if (content == NULL)
7742                 xmlXPathPErrMemory(ctxt);
7743 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7744 		xmlUTF8Strlen(content)));
7745 	    xmlFree(content);
7746 	}
7747 	return;
7748     }
7749     CHECK_ARITY(1);
7750     CAST_TO_STRING;
7751     CHECK_TYPE(XPATH_STRING);
7752     cur = valuePop(ctxt);
7753     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7754 	xmlUTF8Strlen(cur->stringval)));
7755     xmlXPathReleaseObject(ctxt->context, cur);
7756 }
7757 
7758 /**
7759  * xmlXPathConcatFunction:
7760  * @ctxt:  the XPath Parser context
7761  * @nargs:  the number of arguments
7762  *
7763  * Implement the concat() XPath function
7764  *    string concat(string, string, string*)
7765  * The concat function returns the concatenation of its arguments.
7766  */
7767 void
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt,int nargs)7768 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7769     xmlXPathObjectPtr cur, newobj;
7770     xmlChar *tmp;
7771 
7772     if (ctxt == NULL) return;
7773     if (nargs < 2) {
7774 	CHECK_ARITY(2);
7775     }
7776 
7777     CAST_TO_STRING;
7778     cur = valuePop(ctxt);
7779     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
7780 	xmlXPathReleaseObject(ctxt->context, cur);
7781 	return;
7782     }
7783     nargs--;
7784 
7785     while (nargs > 0) {
7786 	CAST_TO_STRING;
7787 	newobj = valuePop(ctxt);
7788 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
7789 	    xmlXPathReleaseObject(ctxt->context, newobj);
7790 	    xmlXPathReleaseObject(ctxt->context, cur);
7791 	    XP_ERROR(XPATH_INVALID_TYPE);
7792 	}
7793 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
7794         if (tmp == NULL)
7795             xmlXPathPErrMemory(ctxt);
7796 	newobj->stringval = cur->stringval;
7797 	cur->stringval = tmp;
7798 	xmlXPathReleaseObject(ctxt->context, newobj);
7799 	nargs--;
7800     }
7801     valuePush(ctxt, cur);
7802 }
7803 
7804 /**
7805  * xmlXPathContainsFunction:
7806  * @ctxt:  the XPath Parser context
7807  * @nargs:  the number of arguments
7808  *
7809  * Implement the contains() XPath function
7810  *    boolean contains(string, string)
7811  * The contains function returns true if the first argument string
7812  * contains the second argument string, and otherwise returns false.
7813  */
7814 void
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt,int nargs)7815 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7816     xmlXPathObjectPtr hay, needle;
7817 
7818     CHECK_ARITY(2);
7819     CAST_TO_STRING;
7820     CHECK_TYPE(XPATH_STRING);
7821     needle = valuePop(ctxt);
7822     CAST_TO_STRING;
7823     hay = valuePop(ctxt);
7824 
7825     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7826 	xmlXPathReleaseObject(ctxt->context, hay);
7827 	xmlXPathReleaseObject(ctxt->context, needle);
7828 	XP_ERROR(XPATH_INVALID_TYPE);
7829     }
7830     if (xmlStrstr(hay->stringval, needle->stringval))
7831 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7832     else
7833 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7834     xmlXPathReleaseObject(ctxt->context, hay);
7835     xmlXPathReleaseObject(ctxt->context, needle);
7836 }
7837 
7838 /**
7839  * xmlXPathStartsWithFunction:
7840  * @ctxt:  the XPath Parser context
7841  * @nargs:  the number of arguments
7842  *
7843  * Implement the starts-with() XPath function
7844  *    boolean starts-with(string, string)
7845  * The starts-with function returns true if the first argument string
7846  * starts with the second argument string, and otherwise returns false.
7847  */
7848 void
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt,int nargs)7849 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7850     xmlXPathObjectPtr hay, needle;
7851     int n;
7852 
7853     CHECK_ARITY(2);
7854     CAST_TO_STRING;
7855     CHECK_TYPE(XPATH_STRING);
7856     needle = valuePop(ctxt);
7857     CAST_TO_STRING;
7858     hay = valuePop(ctxt);
7859 
7860     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7861 	xmlXPathReleaseObject(ctxt->context, hay);
7862 	xmlXPathReleaseObject(ctxt->context, needle);
7863 	XP_ERROR(XPATH_INVALID_TYPE);
7864     }
7865     n = xmlStrlen(needle->stringval);
7866     if (xmlStrncmp(hay->stringval, needle->stringval, n))
7867         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7868     else
7869         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7870     xmlXPathReleaseObject(ctxt->context, hay);
7871     xmlXPathReleaseObject(ctxt->context, needle);
7872 }
7873 
7874 /**
7875  * xmlXPathSubstringFunction:
7876  * @ctxt:  the XPath Parser context
7877  * @nargs:  the number of arguments
7878  *
7879  * Implement the substring() XPath function
7880  *    string substring(string, number, number?)
7881  * The substring function returns the substring of the first argument
7882  * starting at the position specified in the second argument with
7883  * length specified in the third argument. For example,
7884  * substring("12345",2,3) returns "234". If the third argument is not
7885  * specified, it returns the substring starting at the position specified
7886  * in the second argument and continuing to the end of the string. For
7887  * example, substring("12345",2) returns "2345".  More precisely, each
7888  * character in the string (see [3.6 Strings]) is considered to have a
7889  * numeric position: the position of the first character is 1, the position
7890  * of the second character is 2 and so on. The returned substring contains
7891  * those characters for which the position of the character is greater than
7892  * or equal to the second argument and, if the third argument is specified,
7893  * less than the sum of the second and third arguments; the comparisons
7894  * and addition used for the above follow the standard IEEE 754 rules. Thus:
7895  *  - substring("12345", 1.5, 2.6) returns "234"
7896  *  - substring("12345", 0, 3) returns "12"
7897  *  - substring("12345", 0 div 0, 3) returns ""
7898  *  - substring("12345", 1, 0 div 0) returns ""
7899  *  - substring("12345", -42, 1 div 0) returns "12345"
7900  *  - substring("12345", -1 div 0, 1 div 0) returns ""
7901  */
7902 void
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt,int nargs)7903 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7904     xmlXPathObjectPtr str, start, len;
7905     double le=0, in;
7906     int i = 1, j = INT_MAX;
7907 
7908     if (nargs < 2) {
7909 	CHECK_ARITY(2);
7910     }
7911     if (nargs > 3) {
7912 	CHECK_ARITY(3);
7913     }
7914     /*
7915      * take care of possible last (position) argument
7916     */
7917     if (nargs == 3) {
7918 	CAST_TO_NUMBER;
7919 	CHECK_TYPE(XPATH_NUMBER);
7920 	len = valuePop(ctxt);
7921 	le = len->floatval;
7922 	xmlXPathReleaseObject(ctxt->context, len);
7923     }
7924 
7925     CAST_TO_NUMBER;
7926     CHECK_TYPE(XPATH_NUMBER);
7927     start = valuePop(ctxt);
7928     in = start->floatval;
7929     xmlXPathReleaseObject(ctxt->context, start);
7930     CAST_TO_STRING;
7931     CHECK_TYPE(XPATH_STRING);
7932     str = valuePop(ctxt);
7933 
7934     if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
7935         i = INT_MAX;
7936     } else if (in >= 1.0) {
7937         i = (int)in;
7938         if (in - floor(in) >= 0.5)
7939             i += 1;
7940     }
7941 
7942     if (nargs == 3) {
7943         double rin, rle, end;
7944 
7945         rin = floor(in);
7946         if (in - rin >= 0.5)
7947             rin += 1.0;
7948 
7949         rle = floor(le);
7950         if (le - rle >= 0.5)
7951             rle += 1.0;
7952 
7953         end = rin + rle;
7954         if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
7955             j = 1;
7956         } else if (end < INT_MAX) {
7957             j = (int)end;
7958         }
7959     }
7960 
7961     i -= 1;
7962     j -= 1;
7963 
7964     if ((i < j) && (i < xmlUTF8Strlen(str->stringval))) {
7965         xmlChar *ret = xmlUTF8Strsub(str->stringval, i, j - i);
7966         if (ret == NULL)
7967             xmlXPathPErrMemory(ctxt);
7968 	valuePush(ctxt, xmlXPathCacheNewString(ctxt, ret));
7969 	xmlFree(ret);
7970     } else {
7971 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7972     }
7973 
7974     xmlXPathReleaseObject(ctxt->context, str);
7975 }
7976 
7977 /**
7978  * xmlXPathSubstringBeforeFunction:
7979  * @ctxt:  the XPath Parser context
7980  * @nargs:  the number of arguments
7981  *
7982  * Implement the substring-before() XPath function
7983  *    string substring-before(string, string)
7984  * The substring-before function returns the substring of the first
7985  * argument string that precedes the first occurrence of the second
7986  * argument string in the first argument string, or the empty string
7987  * if the first argument string does not contain the second argument
7988  * string. For example, substring-before("1999/04/01","/") returns 1999.
7989  */
7990 void
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt,int nargs)7991 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7992     xmlXPathObjectPtr str = NULL;
7993     xmlXPathObjectPtr find = NULL;
7994     const xmlChar *point;
7995     xmlChar *result;
7996 
7997     CHECK_ARITY(2);
7998     CAST_TO_STRING;
7999     find = valuePop(ctxt);
8000     CAST_TO_STRING;
8001     str = valuePop(ctxt);
8002     if (ctxt->error != 0)
8003         goto error;
8004 
8005     point = xmlStrstr(str->stringval, find->stringval);
8006     if (point == NULL) {
8007         result = xmlStrdup(BAD_CAST "");
8008     } else {
8009         result = xmlStrndup(str->stringval, point - str->stringval);
8010     }
8011     if (result == NULL) {
8012         xmlXPathPErrMemory(ctxt);
8013         goto error;
8014     }
8015     valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
8016 
8017 error:
8018     xmlXPathReleaseObject(ctxt->context, str);
8019     xmlXPathReleaseObject(ctxt->context, find);
8020 }
8021 
8022 /**
8023  * xmlXPathSubstringAfterFunction:
8024  * @ctxt:  the XPath Parser context
8025  * @nargs:  the number of arguments
8026  *
8027  * Implement the substring-after() XPath function
8028  *    string substring-after(string, string)
8029  * The substring-after function returns the substring of the first
8030  * argument string that follows the first occurrence of the second
8031  * argument string in the first argument string, or the empty string
8032  * if the first argument string does not contain the second argument
8033  * string. For example, substring-after("1999/04/01","/") returns 04/01,
8034  * and substring-after("1999/04/01","19") returns 99/04/01.
8035  */
8036 void
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt,int nargs)8037 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8038     xmlXPathObjectPtr str = NULL;
8039     xmlXPathObjectPtr find = NULL;
8040     const xmlChar *point;
8041     xmlChar *result;
8042 
8043     CHECK_ARITY(2);
8044     CAST_TO_STRING;
8045     find = valuePop(ctxt);
8046     CAST_TO_STRING;
8047     str = valuePop(ctxt);
8048     if (ctxt->error != 0)
8049         goto error;
8050 
8051     point = xmlStrstr(str->stringval, find->stringval);
8052     if (point == NULL) {
8053         result = xmlStrdup(BAD_CAST "");
8054     } else {
8055         result = xmlStrdup(point + xmlStrlen(find->stringval));
8056     }
8057     if (result == NULL) {
8058         xmlXPathPErrMemory(ctxt);
8059         goto error;
8060     }
8061     valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
8062 
8063 error:
8064     xmlXPathReleaseObject(ctxt->context, str);
8065     xmlXPathReleaseObject(ctxt->context, find);
8066 }
8067 
8068 /**
8069  * xmlXPathNormalizeFunction:
8070  * @ctxt:  the XPath Parser context
8071  * @nargs:  the number of arguments
8072  *
8073  * Implement the normalize-space() XPath function
8074  *    string normalize-space(string?)
8075  * The normalize-space function returns the argument string with white
8076  * space normalized by stripping leading and trailing whitespace
8077  * and replacing sequences of whitespace characters by a single
8078  * space. Whitespace characters are the same allowed by the S production
8079  * in XML. If the argument is omitted, it defaults to the context
8080  * node converted to a string, in other words the value of the context node.
8081  */
8082 void
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt,int nargs)8083 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8084     xmlChar *source, *target;
8085     int blank;
8086 
8087     if (ctxt == NULL) return;
8088     if (nargs == 0) {
8089         /* Use current context node */
8090         source = xmlXPathCastNodeToString(ctxt->context->node);
8091         if (source == NULL)
8092             xmlXPathPErrMemory(ctxt);
8093         valuePush(ctxt, xmlXPathCacheWrapString(ctxt, source));
8094         nargs = 1;
8095     }
8096 
8097     CHECK_ARITY(1);
8098     CAST_TO_STRING;
8099     CHECK_TYPE(XPATH_STRING);
8100     source = ctxt->value->stringval;
8101     if (source == NULL)
8102         return;
8103     target = source;
8104 
8105     /* Skip leading whitespaces */
8106     while (IS_BLANK_CH(*source))
8107         source++;
8108 
8109     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
8110     blank = 0;
8111     while (*source) {
8112         if (IS_BLANK_CH(*source)) {
8113 	    blank = 1;
8114         } else {
8115             if (blank) {
8116                 *target++ = 0x20;
8117                 blank = 0;
8118             }
8119             *target++ = *source;
8120         }
8121         source++;
8122     }
8123     *target = 0;
8124 }
8125 
8126 /**
8127  * xmlXPathTranslateFunction:
8128  * @ctxt:  the XPath Parser context
8129  * @nargs:  the number of arguments
8130  *
8131  * Implement the translate() XPath function
8132  *    string translate(string, string, string)
8133  * The translate function returns the first argument string with
8134  * occurrences of characters in the second argument string replaced
8135  * by the character at the corresponding position in the third argument
8136  * string. For example, translate("bar","abc","ABC") returns the string
8137  * BAr. If there is a character in the second argument string with no
8138  * character at a corresponding position in the third argument string
8139  * (because the second argument string is longer than the third argument
8140  * string), then occurrences of that character in the first argument
8141  * string are removed. For example, translate("--aaa--","abc-","ABC")
8142  * returns "AAA". If a character occurs more than once in second
8143  * argument string, then the first occurrence determines the replacement
8144  * character. If the third argument string is longer than the second
8145  * argument string, then excess characters are ignored.
8146  */
8147 void
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt,int nargs)8148 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8149     xmlXPathObjectPtr str = NULL;
8150     xmlXPathObjectPtr from = NULL;
8151     xmlXPathObjectPtr to = NULL;
8152     xmlBufPtr target;
8153     int offset, max;
8154     int ch;
8155     const xmlChar *point;
8156     xmlChar *cptr, *content;
8157 
8158     CHECK_ARITY(3);
8159 
8160     CAST_TO_STRING;
8161     to = valuePop(ctxt);
8162     CAST_TO_STRING;
8163     from = valuePop(ctxt);
8164     CAST_TO_STRING;
8165     str = valuePop(ctxt);
8166     if (ctxt->error != 0)
8167         goto error;
8168 
8169     /*
8170      * Account for quadratic runtime
8171      */
8172     if (ctxt->context->opLimit != 0) {
8173         unsigned long f1 = xmlStrlen(from->stringval);
8174         unsigned long f2 = xmlStrlen(str->stringval);
8175 
8176         if ((f1 > 0) && (f2 > 0)) {
8177             unsigned long p;
8178 
8179             f1 = f1 / 10 + 1;
8180             f2 = f2 / 10 + 1;
8181             p = f1 > ULONG_MAX / f2 ? ULONG_MAX : f1 * f2;
8182             if (xmlXPathCheckOpLimit(ctxt, p) < 0)
8183                 goto error;
8184         }
8185     }
8186 
8187     target = xmlBufCreateSize(64);
8188     if (target == NULL) {
8189         xmlXPathPErrMemory(ctxt);
8190         goto error;
8191     }
8192 
8193     max = xmlUTF8Strlen(to->stringval);
8194     for (cptr = str->stringval; (ch=*cptr); ) {
8195         offset = xmlUTF8Strloc(from->stringval, cptr);
8196         if (offset >= 0) {
8197             if (offset < max) {
8198                 point = xmlUTF8Strpos(to->stringval, offset);
8199                 if (point)
8200                     xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
8201             }
8202         } else
8203             xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
8204 
8205         /* Step to next character in input */
8206         cptr++;
8207         if ( ch & 0x80 ) {
8208             /* if not simple ascii, verify proper format */
8209             if ( (ch & 0xc0) != 0xc0 ) {
8210                 xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
8211                 break;
8212             }
8213             /* then skip over remaining bytes for this char */
8214             while ( (ch <<= 1) & 0x80 )
8215                 if ( (*cptr++ & 0xc0) != 0x80 ) {
8216                     xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
8217                     break;
8218                 }
8219             if (ch & 0x80) /* must have had error encountered */
8220                 break;
8221         }
8222     }
8223 
8224     content = xmlBufDetach(target);
8225     if (content == NULL)
8226         xmlXPathPErrMemory(ctxt);
8227     else
8228         valuePush(ctxt, xmlXPathCacheWrapString(ctxt, content));
8229     xmlBufFree(target);
8230 error:
8231     xmlXPathReleaseObject(ctxt->context, str);
8232     xmlXPathReleaseObject(ctxt->context, from);
8233     xmlXPathReleaseObject(ctxt->context, to);
8234 }
8235 
8236 /**
8237  * xmlXPathBooleanFunction:
8238  * @ctxt:  the XPath Parser context
8239  * @nargs:  the number of arguments
8240  *
8241  * Implement the boolean() XPath function
8242  *    boolean boolean(object)
8243  * The boolean function converts its argument to a boolean as follows:
8244  *    - a number is true if and only if it is neither positive or
8245  *      negative zero nor NaN
8246  *    - a node-set is true if and only if it is non-empty
8247  *    - a string is true if and only if its length is non-zero
8248  */
8249 void
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt,int nargs)8250 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8251     xmlXPathObjectPtr cur;
8252 
8253     CHECK_ARITY(1);
8254     cur = valuePop(ctxt);
8255     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8256     if (cur->type != XPATH_BOOLEAN) {
8257         int boolval = xmlXPathCastToBoolean(cur);
8258 
8259         xmlXPathReleaseObject(ctxt->context, cur);
8260         cur = xmlXPathCacheNewBoolean(ctxt, boolval);
8261     }
8262     valuePush(ctxt, cur);
8263 }
8264 
8265 /**
8266  * xmlXPathNotFunction:
8267  * @ctxt:  the XPath Parser context
8268  * @nargs:  the number of arguments
8269  *
8270  * Implement the not() XPath function
8271  *    boolean not(boolean)
8272  * The not function returns true if its argument is false,
8273  * and false otherwise.
8274  */
8275 void
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt,int nargs)8276 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8277     CHECK_ARITY(1);
8278     CAST_TO_BOOLEAN;
8279     CHECK_TYPE(XPATH_BOOLEAN);
8280     ctxt->value->boolval = ! ctxt->value->boolval;
8281 }
8282 
8283 /**
8284  * xmlXPathTrueFunction:
8285  * @ctxt:  the XPath Parser context
8286  * @nargs:  the number of arguments
8287  *
8288  * Implement the true() XPath function
8289  *    boolean true()
8290  */
8291 void
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt,int nargs)8292 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8293     CHECK_ARITY(0);
8294     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
8295 }
8296 
8297 /**
8298  * xmlXPathFalseFunction:
8299  * @ctxt:  the XPath Parser context
8300  * @nargs:  the number of arguments
8301  *
8302  * Implement the false() XPath function
8303  *    boolean false()
8304  */
8305 void
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt,int nargs)8306 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8307     CHECK_ARITY(0);
8308     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
8309 }
8310 
8311 /**
8312  * xmlXPathLangFunction:
8313  * @ctxt:  the XPath Parser context
8314  * @nargs:  the number of arguments
8315  *
8316  * Implement the lang() XPath function
8317  *    boolean lang(string)
8318  * The lang function returns true or false depending on whether the
8319  * language of the context node as specified by xml:lang attributes
8320  * is the same as or is a sublanguage of the language specified by
8321  * the argument string. The language of the context node is determined
8322  * by the value of the xml:lang attribute on the context node, or, if
8323  * the context node has no xml:lang attribute, by the value of the
8324  * xml:lang attribute on the nearest ancestor of the context node that
8325  * has an xml:lang attribute. If there is no such attribute, then lang
8326  * returns false. If there is such an attribute, then lang returns
8327  * true if the attribute value is equal to the argument ignoring case,
8328  * or if there is some suffix starting with - such that the attribute
8329  * value is equal to the argument ignoring that suffix of the attribute
8330  * value and ignoring case.
8331  */
8332 void
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt,int nargs)8333 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8334     xmlXPathObjectPtr val;
8335     xmlNodePtr cur;
8336     xmlChar *theLang;
8337     const xmlChar *lang;
8338     int ret = 0;
8339     int i;
8340 
8341     CHECK_ARITY(1);
8342     CAST_TO_STRING;
8343     CHECK_TYPE(XPATH_STRING);
8344     val = valuePop(ctxt);
8345     lang = val->stringval;
8346     cur = ctxt->context->node;
8347     while (cur != NULL) {
8348         if (xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE,
8349                                 &theLang) < 0)
8350             xmlXPathPErrMemory(ctxt);
8351         if (theLang != NULL)
8352             break;
8353         cur = cur->parent;
8354     }
8355     if ((theLang != NULL) && (lang != NULL)) {
8356         for (i = 0;lang[i] != 0;i++)
8357             if (toupper(lang[i]) != toupper(theLang[i]))
8358                 goto not_equal;
8359         if ((theLang[i] == 0) || (theLang[i] == '-'))
8360             ret = 1;
8361     }
8362 not_equal:
8363     if (theLang != NULL)
8364 	xmlFree((void *)theLang);
8365 
8366     xmlXPathReleaseObject(ctxt->context, val);
8367     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
8368 }
8369 
8370 /**
8371  * xmlXPathNumberFunction:
8372  * @ctxt:  the XPath Parser context
8373  * @nargs:  the number of arguments
8374  *
8375  * Implement the number() XPath function
8376  *    number number(object?)
8377  */
8378 void
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt,int nargs)8379 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8380     xmlXPathObjectPtr cur;
8381     double res;
8382 
8383     if (ctxt == NULL) return;
8384     if (nargs == 0) {
8385 	if (ctxt->context->node == NULL) {
8386 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
8387 	} else {
8388 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
8389             if (content == NULL)
8390                 xmlXPathPErrMemory(ctxt);
8391 
8392 	    res = xmlXPathStringEvalNumber(content);
8393 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8394 	    xmlFree(content);
8395 	}
8396 	return;
8397     }
8398 
8399     CHECK_ARITY(1);
8400     cur = valuePop(ctxt);
8401     if (cur->type != XPATH_NUMBER) {
8402         double floatval;
8403 
8404         floatval = xmlXPathCastToNumberInternal(ctxt, cur);
8405         xmlXPathReleaseObject(ctxt->context, cur);
8406         cur = xmlXPathCacheNewFloat(ctxt, floatval);
8407     }
8408     valuePush(ctxt, cur);
8409 }
8410 
8411 /**
8412  * xmlXPathSumFunction:
8413  * @ctxt:  the XPath Parser context
8414  * @nargs:  the number of arguments
8415  *
8416  * Implement the sum() XPath function
8417  *    number sum(node-set)
8418  * The sum function returns the sum of the values of the nodes in
8419  * the argument node-set.
8420  */
8421 void
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt,int nargs)8422 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8423     xmlXPathObjectPtr cur;
8424     int i;
8425     double res = 0.0;
8426 
8427     CHECK_ARITY(1);
8428     if ((ctxt->value == NULL) ||
8429 	((ctxt->value->type != XPATH_NODESET) &&
8430 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8431 	XP_ERROR(XPATH_INVALID_TYPE);
8432     cur = valuePop(ctxt);
8433 
8434     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
8435 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
8436 	    res += xmlXPathNodeToNumberInternal(ctxt,
8437                                                 cur->nodesetval->nodeTab[i]);
8438 	}
8439     }
8440     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8441     xmlXPathReleaseObject(ctxt->context, cur);
8442 }
8443 
8444 /**
8445  * xmlXPathFloorFunction:
8446  * @ctxt:  the XPath Parser context
8447  * @nargs:  the number of arguments
8448  *
8449  * Implement the floor() XPath function
8450  *    number floor(number)
8451  * The floor function returns the largest (closest to positive infinity)
8452  * number that is not greater than the argument and that is an integer.
8453  */
8454 void
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt,int nargs)8455 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8456     CHECK_ARITY(1);
8457     CAST_TO_NUMBER;
8458     CHECK_TYPE(XPATH_NUMBER);
8459 
8460     ctxt->value->floatval = floor(ctxt->value->floatval);
8461 }
8462 
8463 /**
8464  * xmlXPathCeilingFunction:
8465  * @ctxt:  the XPath Parser context
8466  * @nargs:  the number of arguments
8467  *
8468  * Implement the ceiling() XPath function
8469  *    number ceiling(number)
8470  * The ceiling function returns the smallest (closest to negative infinity)
8471  * number that is not less than the argument and that is an integer.
8472  */
8473 void
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt,int nargs)8474 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8475     CHECK_ARITY(1);
8476     CAST_TO_NUMBER;
8477     CHECK_TYPE(XPATH_NUMBER);
8478 
8479 #ifdef _AIX
8480     /* Work around buggy ceil() function on AIX */
8481     ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
8482 #else
8483     ctxt->value->floatval = ceil(ctxt->value->floatval);
8484 #endif
8485 }
8486 
8487 /**
8488  * xmlXPathRoundFunction:
8489  * @ctxt:  the XPath Parser context
8490  * @nargs:  the number of arguments
8491  *
8492  * Implement the round() XPath function
8493  *    number round(number)
8494  * The round function returns the number that is closest to the
8495  * argument and that is an integer. If there are two such numbers,
8496  * then the one that is closest to positive infinity is returned.
8497  */
8498 void
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt,int nargs)8499 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8500     double f;
8501 
8502     CHECK_ARITY(1);
8503     CAST_TO_NUMBER;
8504     CHECK_TYPE(XPATH_NUMBER);
8505 
8506     f = ctxt->value->floatval;
8507 
8508     if ((f >= -0.5) && (f < 0.5)) {
8509         /* Handles negative zero. */
8510         ctxt->value->floatval *= 0.0;
8511     }
8512     else {
8513         double rounded = floor(f);
8514         if (f - rounded >= 0.5)
8515             rounded += 1.0;
8516         ctxt->value->floatval = rounded;
8517     }
8518 }
8519 
8520 /************************************************************************
8521  *									*
8522  *			The Parser					*
8523  *									*
8524  ************************************************************************/
8525 
8526 /*
8527  * a few forward declarations since we use a recursive call based
8528  * implementation.
8529  */
8530 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
8531 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
8532 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
8533 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
8534 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
8535 	                                  int qualified);
8536 
8537 /**
8538  * xmlXPathCurrentChar:
8539  * @ctxt:  the XPath parser context
8540  * @cur:  pointer to the beginning of the char
8541  * @len:  pointer to the length of the char read
8542  *
8543  * The current char value, if using UTF-8 this may actually span multiple
8544  * bytes in the input buffer.
8545  *
8546  * Returns the current char value and its length
8547  */
8548 
8549 static int
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt,int * len)8550 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
8551     unsigned char c;
8552     unsigned int val;
8553     const xmlChar *cur;
8554 
8555     if (ctxt == NULL)
8556 	return(0);
8557     cur = ctxt->cur;
8558 
8559     /*
8560      * We are supposed to handle UTF8, check it's valid
8561      * From rfc2044: encoding of the Unicode values on UTF-8:
8562      *
8563      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
8564      * 0000 0000-0000 007F   0xxxxxxx
8565      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
8566      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
8567      *
8568      * Check for the 0x110000 limit too
8569      */
8570     c = *cur;
8571     if (c & 0x80) {
8572 	if ((cur[1] & 0xc0) != 0x80)
8573 	    goto encoding_error;
8574 	if ((c & 0xe0) == 0xe0) {
8575 
8576 	    if ((cur[2] & 0xc0) != 0x80)
8577 		goto encoding_error;
8578 	    if ((c & 0xf0) == 0xf0) {
8579 		if (((c & 0xf8) != 0xf0) ||
8580 		    ((cur[3] & 0xc0) != 0x80))
8581 		    goto encoding_error;
8582 		/* 4-byte code */
8583 		*len = 4;
8584 		val = (cur[0] & 0x7) << 18;
8585 		val |= (cur[1] & 0x3f) << 12;
8586 		val |= (cur[2] & 0x3f) << 6;
8587 		val |= cur[3] & 0x3f;
8588 	    } else {
8589 	      /* 3-byte code */
8590 		*len = 3;
8591 		val = (cur[0] & 0xf) << 12;
8592 		val |= (cur[1] & 0x3f) << 6;
8593 		val |= cur[2] & 0x3f;
8594 	    }
8595 	} else {
8596 	  /* 2-byte code */
8597 	    *len = 2;
8598 	    val = (cur[0] & 0x1f) << 6;
8599 	    val |= cur[1] & 0x3f;
8600 	}
8601 	if (!IS_CHAR(val)) {
8602 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
8603 	}
8604 	return(val);
8605     } else {
8606 	/* 1-byte code */
8607 	*len = 1;
8608 	return(*cur);
8609     }
8610 encoding_error:
8611     /*
8612      * If we detect an UTF8 error that probably means that the
8613      * input encoding didn't get properly advertised in the
8614      * declaration header. Report the error and switch the encoding
8615      * to ISO-Latin-1 (if you don't like this policy, just declare the
8616      * encoding !)
8617      */
8618     *len = 0;
8619     XP_ERROR0(XPATH_ENCODING_ERROR);
8620 }
8621 
8622 /**
8623  * xmlXPathParseNCName:
8624  * @ctxt:  the XPath Parser context
8625  *
8626  * parse an XML namespace non qualified name.
8627  *
8628  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
8629  *
8630  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
8631  *                       CombiningChar | Extender
8632  *
8633  * Returns the namespace name or NULL
8634  */
8635 
8636 xmlChar *
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt)8637 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
8638     const xmlChar *in;
8639     xmlChar *ret;
8640     int count = 0;
8641 
8642     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8643     /*
8644      * Accelerator for simple ASCII names
8645      */
8646     in = ctxt->cur;
8647     if (((*in >= 0x61) && (*in <= 0x7A)) ||
8648 	((*in >= 0x41) && (*in <= 0x5A)) ||
8649 	(*in == '_')) {
8650 	in++;
8651 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
8652 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
8653 	       ((*in >= 0x30) && (*in <= 0x39)) ||
8654 	       (*in == '_') || (*in == '.') ||
8655 	       (*in == '-'))
8656 	    in++;
8657 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
8658             (*in == '[') || (*in == ']') || (*in == ':') ||
8659             (*in == '@') || (*in == '*')) {
8660 	    count = in - ctxt->cur;
8661 	    if (count == 0)
8662 		return(NULL);
8663 	    ret = xmlStrndup(ctxt->cur, count);
8664             if (ret == NULL)
8665                 xmlXPathPErrMemory(ctxt);
8666 	    ctxt->cur = in;
8667 	    return(ret);
8668 	}
8669     }
8670     return(xmlXPathParseNameComplex(ctxt, 0));
8671 }
8672 
8673 
8674 /**
8675  * xmlXPathParseQName:
8676  * @ctxt:  the XPath Parser context
8677  * @prefix:  a xmlChar **
8678  *
8679  * parse an XML qualified name
8680  *
8681  * [NS 5] QName ::= (Prefix ':')? LocalPart
8682  *
8683  * [NS 6] Prefix ::= NCName
8684  *
8685  * [NS 7] LocalPart ::= NCName
8686  *
8687  * Returns the function returns the local part, and prefix is updated
8688  *   to get the Prefix if any.
8689  */
8690 
8691 static xmlChar *
xmlXPathParseQName(xmlXPathParserContextPtr ctxt,xmlChar ** prefix)8692 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
8693     xmlChar *ret = NULL;
8694 
8695     *prefix = NULL;
8696     ret = xmlXPathParseNCName(ctxt);
8697     if (ret && CUR == ':') {
8698         *prefix = ret;
8699 	NEXT;
8700 	ret = xmlXPathParseNCName(ctxt);
8701     }
8702     return(ret);
8703 }
8704 
8705 /**
8706  * xmlXPathParseName:
8707  * @ctxt:  the XPath Parser context
8708  *
8709  * parse an XML name
8710  *
8711  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8712  *                  CombiningChar | Extender
8713  *
8714  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8715  *
8716  * Returns the namespace name or NULL
8717  */
8718 
8719 xmlChar *
xmlXPathParseName(xmlXPathParserContextPtr ctxt)8720 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
8721     const xmlChar *in;
8722     xmlChar *ret;
8723     size_t count = 0;
8724 
8725     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8726     /*
8727      * Accelerator for simple ASCII names
8728      */
8729     in = ctxt->cur;
8730     if (((*in >= 0x61) && (*in <= 0x7A)) ||
8731 	((*in >= 0x41) && (*in <= 0x5A)) ||
8732 	(*in == '_') || (*in == ':')) {
8733 	in++;
8734 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
8735 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
8736 	       ((*in >= 0x30) && (*in <= 0x39)) ||
8737 	       (*in == '_') || (*in == '-') ||
8738 	       (*in == ':') || (*in == '.'))
8739 	    in++;
8740 	if ((*in > 0) && (*in < 0x80)) {
8741 	    count = in - ctxt->cur;
8742             if (count > XML_MAX_NAME_LENGTH) {
8743                 ctxt->cur = in;
8744                 XP_ERRORNULL(XPATH_EXPR_ERROR);
8745             }
8746 	    ret = xmlStrndup(ctxt->cur, count);
8747             if (ret == NULL)
8748                 xmlXPathPErrMemory(ctxt);
8749 	    ctxt->cur = in;
8750 	    return(ret);
8751 	}
8752     }
8753     return(xmlXPathParseNameComplex(ctxt, 1));
8754 }
8755 
8756 static xmlChar *
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,int qualified)8757 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
8758     xmlChar *ret;
8759     xmlChar buf[XML_MAX_NAMELEN + 5];
8760     int len = 0, l;
8761     int c;
8762 
8763     /*
8764      * Handler for more complex cases
8765      */
8766     c = CUR_CHAR(l);
8767     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8768         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
8769         (c == '*') || /* accelerators */
8770 	(!IS_LETTER(c) && (c != '_') &&
8771          ((!qualified) || (c != ':')))) {
8772 	return(NULL);
8773     }
8774 
8775     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8776 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8777             (c == '.') || (c == '-') ||
8778 	    (c == '_') || ((qualified) && (c == ':')) ||
8779 	    (IS_COMBINING(c)) ||
8780 	    (IS_EXTENDER(c)))) {
8781 	COPY_BUF(l,buf,len,c);
8782 	NEXTL(l);
8783 	c = CUR_CHAR(l);
8784 	if (len >= XML_MAX_NAMELEN) {
8785 	    /*
8786 	     * Okay someone managed to make a huge name, so he's ready to pay
8787 	     * for the processing speed.
8788 	     */
8789 	    xmlChar *buffer;
8790 	    int max = len * 2;
8791 
8792             if (len > XML_MAX_NAME_LENGTH) {
8793                 XP_ERRORNULL(XPATH_EXPR_ERROR);
8794             }
8795 	    buffer = (xmlChar *) xmlMallocAtomic(max);
8796 	    if (buffer == NULL) {
8797                 xmlXPathPErrMemory(ctxt);
8798                 return(NULL);
8799 	    }
8800 	    memcpy(buffer, buf, len);
8801 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
8802 		   (c == '.') || (c == '-') ||
8803 		   (c == '_') || ((qualified) && (c == ':')) ||
8804 		   (IS_COMBINING(c)) ||
8805 		   (IS_EXTENDER(c))) {
8806 		if (len + 10 > max) {
8807                     xmlChar *tmp;
8808                     if (max > XML_MAX_NAME_LENGTH) {
8809                         xmlFree(buffer);
8810                         XP_ERRORNULL(XPATH_EXPR_ERROR);
8811                     }
8812 		    max *= 2;
8813 		    tmp = (xmlChar *) xmlRealloc(buffer, max);
8814 		    if (tmp == NULL) {
8815                         xmlFree(buffer);
8816                         xmlXPathPErrMemory(ctxt);
8817                         return(NULL);
8818 		    }
8819                     buffer = tmp;
8820 		}
8821 		COPY_BUF(l,buffer,len,c);
8822 		NEXTL(l);
8823 		c = CUR_CHAR(l);
8824 	    }
8825 	    buffer[len] = 0;
8826 	    return(buffer);
8827 	}
8828     }
8829     if (len == 0)
8830 	return(NULL);
8831     ret = xmlStrndup(buf, len);
8832     if (ret == NULL)
8833         xmlXPathPErrMemory(ctxt);
8834     return(ret);
8835 }
8836 
8837 #define MAX_FRAC 20
8838 
8839 /**
8840  * xmlXPathStringEvalNumber:
8841  * @str:  A string to scan
8842  *
8843  *  [30a]  Float  ::= Number ('e' Digits?)?
8844  *
8845  *  [30]   Number ::=   Digits ('.' Digits?)?
8846  *                    | '.' Digits
8847  *  [31]   Digits ::=   [0-9]+
8848  *
8849  * Compile a Number in the string
8850  * In complement of the Number expression, this function also handles
8851  * negative values : '-' Number.
8852  *
8853  * Returns the double value.
8854  */
8855 double
xmlXPathStringEvalNumber(const xmlChar * str)8856 xmlXPathStringEvalNumber(const xmlChar *str) {
8857     const xmlChar *cur = str;
8858     double ret;
8859     int ok = 0;
8860     int isneg = 0;
8861     int exponent = 0;
8862     int is_exponent_negative = 0;
8863 #ifdef __GNUC__
8864     unsigned long tmp = 0;
8865     double temp;
8866 #endif
8867     if (cur == NULL) return(0);
8868     while (IS_BLANK_CH(*cur)) cur++;
8869     if (*cur == '-') {
8870 	isneg = 1;
8871 	cur++;
8872     }
8873     if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
8874         return(xmlXPathNAN);
8875     }
8876 
8877 #ifdef __GNUC__
8878     /*
8879      * tmp/temp is a workaround against a gcc compiler bug
8880      * http://veillard.com/gcc.bug
8881      */
8882     ret = 0;
8883     while ((*cur >= '0') && (*cur <= '9')) {
8884 	ret = ret * 10;
8885 	tmp = (*cur - '0');
8886 	ok = 1;
8887 	cur++;
8888 	temp = (double) tmp;
8889 	ret = ret + temp;
8890     }
8891 #else
8892     ret = 0;
8893     while ((*cur >= '0') && (*cur <= '9')) {
8894 	ret = ret * 10 + (*cur - '0');
8895 	ok = 1;
8896 	cur++;
8897     }
8898 #endif
8899 
8900     if (*cur == '.') {
8901 	int v, frac = 0, max;
8902 	double fraction = 0;
8903 
8904         cur++;
8905 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
8906 	    return(xmlXPathNAN);
8907 	}
8908         while (*cur == '0') {
8909 	    frac = frac + 1;
8910 	    cur++;
8911         }
8912         max = frac + MAX_FRAC;
8913 	while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
8914 	    v = (*cur - '0');
8915 	    fraction = fraction * 10 + v;
8916 	    frac = frac + 1;
8917 	    cur++;
8918 	}
8919 	fraction /= pow(10.0, frac);
8920 	ret = ret + fraction;
8921 	while ((*cur >= '0') && (*cur <= '9'))
8922 	    cur++;
8923     }
8924     if ((*cur == 'e') || (*cur == 'E')) {
8925       cur++;
8926       if (*cur == '-') {
8927 	is_exponent_negative = 1;
8928 	cur++;
8929       } else if (*cur == '+') {
8930         cur++;
8931       }
8932       while ((*cur >= '0') && (*cur <= '9')) {
8933         if (exponent < 1000000)
8934 	  exponent = exponent * 10 + (*cur - '0');
8935 	cur++;
8936       }
8937     }
8938     while (IS_BLANK_CH(*cur)) cur++;
8939     if (*cur != 0) return(xmlXPathNAN);
8940     if (isneg) ret = -ret;
8941     if (is_exponent_negative) exponent = -exponent;
8942     ret *= pow(10.0, (double)exponent);
8943     return(ret);
8944 }
8945 
8946 /**
8947  * xmlXPathCompNumber:
8948  * @ctxt:  the XPath Parser context
8949  *
8950  *  [30]   Number ::=   Digits ('.' Digits?)?
8951  *                    | '.' Digits
8952  *  [31]   Digits ::=   [0-9]+
8953  *
8954  * Compile a Number, then push it on the stack
8955  *
8956  */
8957 static void
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)8958 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
8959 {
8960     double ret = 0.0;
8961     int ok = 0;
8962     int exponent = 0;
8963     int is_exponent_negative = 0;
8964     xmlXPathObjectPtr num;
8965 #ifdef __GNUC__
8966     unsigned long tmp = 0;
8967     double temp;
8968 #endif
8969 
8970     CHECK_ERROR;
8971     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
8972         XP_ERROR(XPATH_NUMBER_ERROR);
8973     }
8974 #ifdef __GNUC__
8975     /*
8976      * tmp/temp is a workaround against a gcc compiler bug
8977      * http://veillard.com/gcc.bug
8978      */
8979     ret = 0;
8980     while ((CUR >= '0') && (CUR <= '9')) {
8981 	ret = ret * 10;
8982 	tmp = (CUR - '0');
8983         ok = 1;
8984         NEXT;
8985 	temp = (double) tmp;
8986 	ret = ret + temp;
8987     }
8988 #else
8989     ret = 0;
8990     while ((CUR >= '0') && (CUR <= '9')) {
8991 	ret = ret * 10 + (CUR - '0');
8992 	ok = 1;
8993 	NEXT;
8994     }
8995 #endif
8996     if (CUR == '.') {
8997 	int v, frac = 0, max;
8998 	double fraction = 0;
8999 
9000         NEXT;
9001         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
9002             XP_ERROR(XPATH_NUMBER_ERROR);
9003         }
9004         while (CUR == '0') {
9005             frac = frac + 1;
9006             NEXT;
9007         }
9008         max = frac + MAX_FRAC;
9009         while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
9010 	    v = (CUR - '0');
9011 	    fraction = fraction * 10 + v;
9012 	    frac = frac + 1;
9013             NEXT;
9014         }
9015         fraction /= pow(10.0, frac);
9016         ret = ret + fraction;
9017         while ((CUR >= '0') && (CUR <= '9'))
9018             NEXT;
9019     }
9020     if ((CUR == 'e') || (CUR == 'E')) {
9021         NEXT;
9022         if (CUR == '-') {
9023             is_exponent_negative = 1;
9024             NEXT;
9025         } else if (CUR == '+') {
9026 	    NEXT;
9027 	}
9028         while ((CUR >= '0') && (CUR <= '9')) {
9029             if (exponent < 1000000)
9030                 exponent = exponent * 10 + (CUR - '0');
9031             NEXT;
9032         }
9033         if (is_exponent_negative)
9034             exponent = -exponent;
9035         ret *= pow(10.0, (double) exponent);
9036     }
9037     num = xmlXPathCacheNewFloat(ctxt, ret);
9038     if (num == NULL) {
9039 	ctxt->error = XPATH_MEMORY_ERROR;
9040     } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
9041                               NULL) == -1) {
9042         xmlXPathReleaseObject(ctxt->context, num);
9043     }
9044 }
9045 
9046 /**
9047  * xmlXPathParseLiteral:
9048  * @ctxt:  the XPath Parser context
9049  *
9050  * Parse a Literal
9051  *
9052  *  [29]   Literal ::=   '"' [^"]* '"'
9053  *                    | "'" [^']* "'"
9054  *
9055  * Returns the value found or NULL in case of error
9056  */
9057 static xmlChar *
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt)9058 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
9059     const xmlChar *q;
9060     xmlChar *ret = NULL;
9061     int quote;
9062 
9063     if (CUR == '"') {
9064         quote = '"';
9065     } else if (CUR == '\'') {
9066         quote = '\'';
9067     } else {
9068 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
9069     }
9070 
9071     NEXT;
9072     q = CUR_PTR;
9073     while (CUR != quote) {
9074         int ch;
9075         int len = 4;
9076 
9077         if (CUR == 0)
9078             XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
9079         ch = xmlGetUTF8Char(CUR_PTR, &len);
9080         if ((ch < 0) || (IS_CHAR(ch) == 0))
9081             XP_ERRORNULL(XPATH_INVALID_CHAR_ERROR);
9082         CUR_PTR += len;
9083     }
9084     ret = xmlStrndup(q, CUR_PTR - q);
9085     if (ret == NULL)
9086         xmlXPathPErrMemory(ctxt);
9087     NEXT;
9088     return(ret);
9089 }
9090 
9091 /**
9092  * xmlXPathCompLiteral:
9093  * @ctxt:  the XPath Parser context
9094  *
9095  * Parse a Literal and push it on the stack.
9096  *
9097  *  [29]   Literal ::=   '"' [^"]* '"'
9098  *                    | "'" [^']* "'"
9099  *
9100  * TODO: xmlXPathCompLiteral memory allocation could be improved.
9101  */
9102 static void
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt)9103 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
9104     xmlChar *ret = NULL;
9105     xmlXPathObjectPtr lit;
9106 
9107     ret = xmlXPathParseLiteral(ctxt);
9108     if (ret == NULL)
9109         return;
9110     lit = xmlXPathCacheNewString(ctxt, ret);
9111     if (lit == NULL) {
9112         ctxt->error = XPATH_MEMORY_ERROR;
9113     } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
9114                               NULL) == -1) {
9115         xmlXPathReleaseObject(ctxt->context, lit);
9116     }
9117     xmlFree(ret);
9118 }
9119 
9120 /**
9121  * xmlXPathCompVariableReference:
9122  * @ctxt:  the XPath Parser context
9123  *
9124  * Parse a VariableReference, evaluate it and push it on the stack.
9125  *
9126  * The variable bindings consist of a mapping from variable names
9127  * to variable values. The value of a variable is an object, which can be
9128  * of any of the types that are possible for the value of an expression,
9129  * and may also be of additional types not specified here.
9130  *
9131  * Early evaluation is possible since:
9132  * The variable bindings [...] used to evaluate a subexpression are
9133  * always the same as those used to evaluate the containing expression.
9134  *
9135  *  [36]   VariableReference ::=   '$' QName
9136  */
9137 static void
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt)9138 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
9139     xmlChar *name;
9140     xmlChar *prefix;
9141 
9142     SKIP_BLANKS;
9143     if (CUR != '$') {
9144 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9145     }
9146     NEXT;
9147     name = xmlXPathParseQName(ctxt, &prefix);
9148     if (name == NULL) {
9149         xmlFree(prefix);
9150 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9151     }
9152     ctxt->comp->last = -1;
9153     if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
9154         xmlFree(prefix);
9155         xmlFree(name);
9156     }
9157     SKIP_BLANKS;
9158     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
9159 	XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
9160     }
9161 }
9162 
9163 /**
9164  * xmlXPathIsNodeType:
9165  * @name:  a name string
9166  *
9167  * Is the name given a NodeType one.
9168  *
9169  *  [38]   NodeType ::=   'comment'
9170  *                    | 'text'
9171  *                    | 'processing-instruction'
9172  *                    | 'node'
9173  *
9174  * Returns 1 if true 0 otherwise
9175  */
9176 int
xmlXPathIsNodeType(const xmlChar * name)9177 xmlXPathIsNodeType(const xmlChar *name) {
9178     if (name == NULL)
9179 	return(0);
9180 
9181     if (xmlStrEqual(name, BAD_CAST "node"))
9182 	return(1);
9183     if (xmlStrEqual(name, BAD_CAST "text"))
9184 	return(1);
9185     if (xmlStrEqual(name, BAD_CAST "comment"))
9186 	return(1);
9187     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9188 	return(1);
9189     return(0);
9190 }
9191 
9192 /**
9193  * xmlXPathCompFunctionCall:
9194  * @ctxt:  the XPath Parser context
9195  *
9196  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
9197  *  [17]   Argument ::=   Expr
9198  *
9199  * Compile a function call, the evaluation of all arguments are
9200  * pushed on the stack
9201  */
9202 static void
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt)9203 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
9204     xmlChar *name;
9205     xmlChar *prefix;
9206     int nbargs = 0;
9207     int sort = 1;
9208 
9209     name = xmlXPathParseQName(ctxt, &prefix);
9210     if (name == NULL) {
9211 	xmlFree(prefix);
9212 	XP_ERROR(XPATH_EXPR_ERROR);
9213     }
9214     SKIP_BLANKS;
9215 
9216     if (CUR != '(') {
9217 	xmlFree(name);
9218 	xmlFree(prefix);
9219 	XP_ERROR(XPATH_EXPR_ERROR);
9220     }
9221     NEXT;
9222     SKIP_BLANKS;
9223 
9224     /*
9225     * Optimization for count(): we don't need the node-set to be sorted.
9226     */
9227     if ((prefix == NULL) && (name[0] == 'c') &&
9228 	xmlStrEqual(name, BAD_CAST "count"))
9229     {
9230 	sort = 0;
9231     }
9232     ctxt->comp->last = -1;
9233     if (CUR != ')') {
9234 	while (CUR != 0) {
9235 	    int op1 = ctxt->comp->last;
9236 	    ctxt->comp->last = -1;
9237 	    xmlXPathCompileExpr(ctxt, sort);
9238 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
9239 		xmlFree(name);
9240 		xmlFree(prefix);
9241 		return;
9242 	    }
9243 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
9244 	    nbargs++;
9245 	    if (CUR == ')') break;
9246 	    if (CUR != ',') {
9247 		xmlFree(name);
9248 		xmlFree(prefix);
9249 		XP_ERROR(XPATH_EXPR_ERROR);
9250 	    }
9251 	    NEXT;
9252 	    SKIP_BLANKS;
9253 	}
9254     }
9255     if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
9256         xmlFree(prefix);
9257         xmlFree(name);
9258     }
9259     NEXT;
9260     SKIP_BLANKS;
9261 }
9262 
9263 /**
9264  * xmlXPathCompPrimaryExpr:
9265  * @ctxt:  the XPath Parser context
9266  *
9267  *  [15]   PrimaryExpr ::=   VariableReference
9268  *                | '(' Expr ')'
9269  *                | Literal
9270  *                | Number
9271  *                | FunctionCall
9272  *
9273  * Compile a primary expression.
9274  */
9275 static void
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt)9276 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
9277     SKIP_BLANKS;
9278     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
9279     else if (CUR == '(') {
9280 	NEXT;
9281 	SKIP_BLANKS;
9282 	xmlXPathCompileExpr(ctxt, 1);
9283 	CHECK_ERROR;
9284 	if (CUR != ')') {
9285 	    XP_ERROR(XPATH_EXPR_ERROR);
9286 	}
9287 	NEXT;
9288 	SKIP_BLANKS;
9289     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9290 	xmlXPathCompNumber(ctxt);
9291     } else if ((CUR == '\'') || (CUR == '"')) {
9292 	xmlXPathCompLiteral(ctxt);
9293     } else {
9294 	xmlXPathCompFunctionCall(ctxt);
9295     }
9296     SKIP_BLANKS;
9297 }
9298 
9299 /**
9300  * xmlXPathCompFilterExpr:
9301  * @ctxt:  the XPath Parser context
9302  *
9303  *  [20]   FilterExpr ::=   PrimaryExpr
9304  *               | FilterExpr Predicate
9305  *
9306  * Compile a filter expression.
9307  * Square brackets are used to filter expressions in the same way that
9308  * they are used in location paths. It is an error if the expression to
9309  * be filtered does not evaluate to a node-set. The context node list
9310  * used for evaluating the expression in square brackets is the node-set
9311  * to be filtered listed in document order.
9312  */
9313 
9314 static void
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt)9315 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
9316     xmlXPathCompPrimaryExpr(ctxt);
9317     CHECK_ERROR;
9318     SKIP_BLANKS;
9319 
9320     while (CUR == '[') {
9321 	xmlXPathCompPredicate(ctxt, 1);
9322 	SKIP_BLANKS;
9323     }
9324 
9325 
9326 }
9327 
9328 /**
9329  * xmlXPathScanName:
9330  * @ctxt:  the XPath Parser context
9331  *
9332  * Trickery: parse an XML name but without consuming the input flow
9333  * Needed to avoid insanity in the parser state.
9334  *
9335  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9336  *                  CombiningChar | Extender
9337  *
9338  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9339  *
9340  * [6] Names ::= Name (S Name)*
9341  *
9342  * Returns the Name parsed or NULL
9343  */
9344 
9345 static xmlChar *
xmlXPathScanName(xmlXPathParserContextPtr ctxt)9346 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
9347     int l;
9348     int c;
9349     const xmlChar *cur;
9350     xmlChar *ret;
9351 
9352     cur = ctxt->cur;
9353 
9354     c = CUR_CHAR(l);
9355     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9356 	(!IS_LETTER(c) && (c != '_') &&
9357          (c != ':'))) {
9358 	return(NULL);
9359     }
9360 
9361     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9362 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9363             (c == '.') || (c == '-') ||
9364 	    (c == '_') || (c == ':') ||
9365 	    (IS_COMBINING(c)) ||
9366 	    (IS_EXTENDER(c)))) {
9367 	NEXTL(l);
9368 	c = CUR_CHAR(l);
9369     }
9370     ret = xmlStrndup(cur, ctxt->cur - cur);
9371     if (ret == NULL)
9372         xmlXPathPErrMemory(ctxt);
9373     ctxt->cur = cur;
9374     return(ret);
9375 }
9376 
9377 /**
9378  * xmlXPathCompPathExpr:
9379  * @ctxt:  the XPath Parser context
9380  *
9381  *  [19]   PathExpr ::=   LocationPath
9382  *               | FilterExpr
9383  *               | FilterExpr '/' RelativeLocationPath
9384  *               | FilterExpr '//' RelativeLocationPath
9385  *
9386  * Compile a path expression.
9387  * The / operator and // operators combine an arbitrary expression
9388  * and a relative location path. It is an error if the expression
9389  * does not evaluate to a node-set.
9390  * The / operator does composition in the same way as when / is
9391  * used in a location path. As in location paths, // is short for
9392  * /descendant-or-self::node()/.
9393  */
9394 
9395 static void
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt)9396 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
9397     int lc = 1;           /* Should we branch to LocationPath ?         */
9398     xmlChar *name = NULL; /* we may have to preparse a name to find out */
9399 
9400     SKIP_BLANKS;
9401     if ((CUR == '$') || (CUR == '(') ||
9402 	(IS_ASCII_DIGIT(CUR)) ||
9403         (CUR == '\'') || (CUR == '"') ||
9404 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9405 	lc = 0;
9406     } else if (CUR == '*') {
9407 	/* relative or absolute location path */
9408 	lc = 1;
9409     } else if (CUR == '/') {
9410 	/* relative or absolute location path */
9411 	lc = 1;
9412     } else if (CUR == '@') {
9413 	/* relative abbreviated attribute location path */
9414 	lc = 1;
9415     } else if (CUR == '.') {
9416 	/* relative abbreviated attribute location path */
9417 	lc = 1;
9418     } else {
9419 	/*
9420 	 * Problem is finding if we have a name here whether it's:
9421 	 *   - a nodetype
9422 	 *   - a function call in which case it's followed by '('
9423 	 *   - an axis in which case it's followed by ':'
9424 	 *   - a element name
9425 	 * We do an a priori analysis here rather than having to
9426 	 * maintain parsed token content through the recursive function
9427 	 * calls. This looks uglier but makes the code easier to
9428 	 * read/write/debug.
9429 	 */
9430 	SKIP_BLANKS;
9431 	name = xmlXPathScanName(ctxt);
9432 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
9433 	    lc = 1;
9434 	    xmlFree(name);
9435 	} else if (name != NULL) {
9436 	    int len =xmlStrlen(name);
9437 
9438 
9439 	    while (NXT(len) != 0) {
9440 		if (NXT(len) == '/') {
9441 		    /* element name */
9442 		    lc = 1;
9443 		    break;
9444 		} else if (IS_BLANK_CH(NXT(len))) {
9445 		    /* ignore blanks */
9446 		    ;
9447 		} else if (NXT(len) == ':') {
9448 		    lc = 1;
9449 		    break;
9450 		} else if ((NXT(len) == '(')) {
9451 		    /* Node Type or Function */
9452 		    if (xmlXPathIsNodeType(name)) {
9453 			lc = 1;
9454 		    } else {
9455 			lc = 0;
9456 		    }
9457                     break;
9458 		} else if ((NXT(len) == '[')) {
9459 		    /* element name */
9460 		    lc = 1;
9461 		    break;
9462 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
9463 			   (NXT(len) == '=')) {
9464 		    lc = 1;
9465 		    break;
9466 		} else {
9467 		    lc = 1;
9468 		    break;
9469 		}
9470 		len++;
9471 	    }
9472 	    if (NXT(len) == 0) {
9473 		/* element name */
9474 		lc = 1;
9475 	    }
9476 	    xmlFree(name);
9477 	} else {
9478 	    /* make sure all cases are covered explicitly */
9479 	    XP_ERROR(XPATH_EXPR_ERROR);
9480 	}
9481     }
9482 
9483     if (lc) {
9484 	if (CUR == '/') {
9485 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
9486 	} else {
9487 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9488 	}
9489 	xmlXPathCompLocationPath(ctxt);
9490     } else {
9491 	xmlXPathCompFilterExpr(ctxt);
9492 	CHECK_ERROR;
9493 	if ((CUR == '/') && (NXT(1) == '/')) {
9494 	    SKIP(2);
9495 	    SKIP_BLANKS;
9496 
9497 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9498 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9499 
9500 	    xmlXPathCompRelativeLocationPath(ctxt);
9501 	} else if (CUR == '/') {
9502 	    xmlXPathCompRelativeLocationPath(ctxt);
9503 	}
9504     }
9505     SKIP_BLANKS;
9506 }
9507 
9508 /**
9509  * xmlXPathCompUnionExpr:
9510  * @ctxt:  the XPath Parser context
9511  *
9512  *  [18]   UnionExpr ::=   PathExpr
9513  *               | UnionExpr '|' PathExpr
9514  *
9515  * Compile an union expression.
9516  */
9517 
9518 static void
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt)9519 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
9520     xmlXPathCompPathExpr(ctxt);
9521     CHECK_ERROR;
9522     SKIP_BLANKS;
9523     while (CUR == '|') {
9524 	int op1 = ctxt->comp->last;
9525 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9526 
9527 	NEXT;
9528 	SKIP_BLANKS;
9529 	xmlXPathCompPathExpr(ctxt);
9530 
9531 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
9532 
9533 	SKIP_BLANKS;
9534     }
9535 }
9536 
9537 /**
9538  * xmlXPathCompUnaryExpr:
9539  * @ctxt:  the XPath Parser context
9540  *
9541  *  [27]   UnaryExpr ::=   UnionExpr
9542  *                   | '-' UnaryExpr
9543  *
9544  * Compile an unary expression.
9545  */
9546 
9547 static void
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt)9548 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
9549     int minus = 0;
9550     int found = 0;
9551 
9552     SKIP_BLANKS;
9553     while (CUR == '-') {
9554         minus = 1 - minus;
9555 	found = 1;
9556 	NEXT;
9557 	SKIP_BLANKS;
9558     }
9559 
9560     xmlXPathCompUnionExpr(ctxt);
9561     CHECK_ERROR;
9562     if (found) {
9563 	if (minus)
9564 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
9565 	else
9566 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
9567     }
9568 }
9569 
9570 /**
9571  * xmlXPathCompMultiplicativeExpr:
9572  * @ctxt:  the XPath Parser context
9573  *
9574  *  [26]   MultiplicativeExpr ::=   UnaryExpr
9575  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
9576  *                   | MultiplicativeExpr 'div' UnaryExpr
9577  *                   | MultiplicativeExpr 'mod' UnaryExpr
9578  *  [34]   MultiplyOperator ::=   '*'
9579  *
9580  * Compile an Additive expression.
9581  */
9582 
9583 static void
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt)9584 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
9585     xmlXPathCompUnaryExpr(ctxt);
9586     CHECK_ERROR;
9587     SKIP_BLANKS;
9588     while ((CUR == '*') ||
9589            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
9590            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
9591 	int op = -1;
9592 	int op1 = ctxt->comp->last;
9593 
9594         if (CUR == '*') {
9595 	    op = 0;
9596 	    NEXT;
9597 	} else if (CUR == 'd') {
9598 	    op = 1;
9599 	    SKIP(3);
9600 	} else if (CUR == 'm') {
9601 	    op = 2;
9602 	    SKIP(3);
9603 	}
9604 	SKIP_BLANKS;
9605         xmlXPathCompUnaryExpr(ctxt);
9606 	CHECK_ERROR;
9607 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
9608 	SKIP_BLANKS;
9609     }
9610 }
9611 
9612 /**
9613  * xmlXPathCompAdditiveExpr:
9614  * @ctxt:  the XPath Parser context
9615  *
9616  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
9617  *                   | AdditiveExpr '+' MultiplicativeExpr
9618  *                   | AdditiveExpr '-' MultiplicativeExpr
9619  *
9620  * Compile an Additive expression.
9621  */
9622 
9623 static void
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt)9624 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
9625 
9626     xmlXPathCompMultiplicativeExpr(ctxt);
9627     CHECK_ERROR;
9628     SKIP_BLANKS;
9629     while ((CUR == '+') || (CUR == '-')) {
9630 	int plus;
9631 	int op1 = ctxt->comp->last;
9632 
9633         if (CUR == '+') plus = 1;
9634 	else plus = 0;
9635 	NEXT;
9636 	SKIP_BLANKS;
9637         xmlXPathCompMultiplicativeExpr(ctxt);
9638 	CHECK_ERROR;
9639 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
9640 	SKIP_BLANKS;
9641     }
9642 }
9643 
9644 /**
9645  * xmlXPathCompRelationalExpr:
9646  * @ctxt:  the XPath Parser context
9647  *
9648  *  [24]   RelationalExpr ::=   AdditiveExpr
9649  *                 | RelationalExpr '<' AdditiveExpr
9650  *                 | RelationalExpr '>' AdditiveExpr
9651  *                 | RelationalExpr '<=' AdditiveExpr
9652  *                 | RelationalExpr '>=' AdditiveExpr
9653  *
9654  *  A <= B > C is allowed ? Answer from James, yes with
9655  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
9656  *  which is basically what got implemented.
9657  *
9658  * Compile a Relational expression, then push the result
9659  * on the stack
9660  */
9661 
9662 static void
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt)9663 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
9664     xmlXPathCompAdditiveExpr(ctxt);
9665     CHECK_ERROR;
9666     SKIP_BLANKS;
9667     while ((CUR == '<') || (CUR == '>')) {
9668 	int inf, strict;
9669 	int op1 = ctxt->comp->last;
9670 
9671         if (CUR == '<') inf = 1;
9672 	else inf = 0;
9673 	if (NXT(1) == '=') strict = 0;
9674 	else strict = 1;
9675 	NEXT;
9676 	if (!strict) NEXT;
9677 	SKIP_BLANKS;
9678         xmlXPathCompAdditiveExpr(ctxt);
9679 	CHECK_ERROR;
9680 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
9681 	SKIP_BLANKS;
9682     }
9683 }
9684 
9685 /**
9686  * xmlXPathCompEqualityExpr:
9687  * @ctxt:  the XPath Parser context
9688  *
9689  *  [23]   EqualityExpr ::=   RelationalExpr
9690  *                 | EqualityExpr '=' RelationalExpr
9691  *                 | EqualityExpr '!=' RelationalExpr
9692  *
9693  *  A != B != C is allowed ? Answer from James, yes with
9694  *  (RelationalExpr = RelationalExpr) = RelationalExpr
9695  *  (RelationalExpr != RelationalExpr) != RelationalExpr
9696  *  which is basically what got implemented.
9697  *
9698  * Compile an Equality expression.
9699  *
9700  */
9701 static void
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt)9702 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
9703     xmlXPathCompRelationalExpr(ctxt);
9704     CHECK_ERROR;
9705     SKIP_BLANKS;
9706     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
9707 	int eq;
9708 	int op1 = ctxt->comp->last;
9709 
9710         if (CUR == '=') eq = 1;
9711 	else eq = 0;
9712 	NEXT;
9713 	if (!eq) NEXT;
9714 	SKIP_BLANKS;
9715         xmlXPathCompRelationalExpr(ctxt);
9716 	CHECK_ERROR;
9717 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
9718 	SKIP_BLANKS;
9719     }
9720 }
9721 
9722 /**
9723  * xmlXPathCompAndExpr:
9724  * @ctxt:  the XPath Parser context
9725  *
9726  *  [22]   AndExpr ::=   EqualityExpr
9727  *                 | AndExpr 'and' EqualityExpr
9728  *
9729  * Compile an AND expression.
9730  *
9731  */
9732 static void
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt)9733 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
9734     xmlXPathCompEqualityExpr(ctxt);
9735     CHECK_ERROR;
9736     SKIP_BLANKS;
9737     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
9738 	int op1 = ctxt->comp->last;
9739         SKIP(3);
9740 	SKIP_BLANKS;
9741         xmlXPathCompEqualityExpr(ctxt);
9742 	CHECK_ERROR;
9743 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
9744 	SKIP_BLANKS;
9745     }
9746 }
9747 
9748 /**
9749  * xmlXPathCompileExpr:
9750  * @ctxt:  the XPath Parser context
9751  *
9752  *  [14]   Expr ::=   OrExpr
9753  *  [21]   OrExpr ::=   AndExpr
9754  *                 | OrExpr 'or' AndExpr
9755  *
9756  * Parse and compile an expression
9757  */
9758 static void
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt,int sort)9759 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
9760     xmlXPathContextPtr xpctxt = ctxt->context;
9761 
9762     if (xpctxt != NULL) {
9763         if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
9764             XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9765         /*
9766          * Parsing a single '(' pushes about 10 functions on the call stack
9767          * before recursing!
9768          */
9769         xpctxt->depth += 10;
9770     }
9771 
9772     xmlXPathCompAndExpr(ctxt);
9773     CHECK_ERROR;
9774     SKIP_BLANKS;
9775     while ((CUR == 'o') && (NXT(1) == 'r')) {
9776 	int op1 = ctxt->comp->last;
9777         SKIP(2);
9778 	SKIP_BLANKS;
9779         xmlXPathCompAndExpr(ctxt);
9780 	CHECK_ERROR;
9781 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
9782 	SKIP_BLANKS;
9783     }
9784     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
9785 	/* more ops could be optimized too */
9786 	/*
9787 	* This is the main place to eliminate sorting for
9788 	* operations which don't require a sorted node-set.
9789 	* E.g. count().
9790 	*/
9791 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
9792     }
9793 
9794     if (xpctxt != NULL)
9795         xpctxt->depth -= 10;
9796 }
9797 
9798 /**
9799  * xmlXPathCompPredicate:
9800  * @ctxt:  the XPath Parser context
9801  * @filter:  act as a filter
9802  *
9803  *  [8]   Predicate ::=   '[' PredicateExpr ']'
9804  *  [9]   PredicateExpr ::=   Expr
9805  *
9806  * Compile a predicate expression
9807  */
9808 static void
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt,int filter)9809 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
9810     int op1 = ctxt->comp->last;
9811 
9812     SKIP_BLANKS;
9813     if (CUR != '[') {
9814 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9815     }
9816     NEXT;
9817     SKIP_BLANKS;
9818 
9819     ctxt->comp->last = -1;
9820     /*
9821     * This call to xmlXPathCompileExpr() will deactivate sorting
9822     * of the predicate result.
9823     * TODO: Sorting is still activated for filters, since I'm not
9824     *  sure if needed. Normally sorting should not be needed, since
9825     *  a filter can only diminish the number of items in a sequence,
9826     *  but won't change its order; so if the initial sequence is sorted,
9827     *  subsequent sorting is not needed.
9828     */
9829     if (! filter)
9830 	xmlXPathCompileExpr(ctxt, 0);
9831     else
9832 	xmlXPathCompileExpr(ctxt, 1);
9833     CHECK_ERROR;
9834 
9835     if (CUR != ']') {
9836 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9837     }
9838 
9839     if (filter)
9840 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
9841     else
9842 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
9843 
9844     NEXT;
9845     SKIP_BLANKS;
9846 }
9847 
9848 /**
9849  * xmlXPathCompNodeTest:
9850  * @ctxt:  the XPath Parser context
9851  * @test:  pointer to a xmlXPathTestVal
9852  * @type:  pointer to a xmlXPathTypeVal
9853  * @prefix:  placeholder for a possible name prefix
9854  *
9855  * [7] NodeTest ::=   NameTest
9856  *		    | NodeType '(' ')'
9857  *		    | 'processing-instruction' '(' Literal ')'
9858  *
9859  * [37] NameTest ::=  '*'
9860  *		    | NCName ':' '*'
9861  *		    | QName
9862  * [38] NodeType ::= 'comment'
9863  *		   | 'text'
9864  *		   | 'processing-instruction'
9865  *		   | 'node'
9866  *
9867  * Returns the name found and updates @test, @type and @prefix appropriately
9868  */
9869 static xmlChar *
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt,xmlXPathTestVal * test,xmlXPathTypeVal * type,xmlChar ** prefix,xmlChar * name)9870 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
9871 	             xmlXPathTypeVal *type, xmlChar **prefix,
9872 		     xmlChar *name) {
9873     int blanks;
9874 
9875     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
9876 	return(NULL);
9877     }
9878     *type = (xmlXPathTypeVal) 0;
9879     *test = (xmlXPathTestVal) 0;
9880     *prefix = NULL;
9881     SKIP_BLANKS;
9882 
9883     if ((name == NULL) && (CUR == '*')) {
9884 	/*
9885 	 * All elements
9886 	 */
9887 	NEXT;
9888 	*test = NODE_TEST_ALL;
9889 	return(NULL);
9890     }
9891 
9892     if (name == NULL)
9893 	name = xmlXPathParseNCName(ctxt);
9894     if (name == NULL) {
9895 	XP_ERRORNULL(XPATH_EXPR_ERROR);
9896     }
9897 
9898     blanks = IS_BLANK_CH(CUR);
9899     SKIP_BLANKS;
9900     if (CUR == '(') {
9901 	NEXT;
9902 	/*
9903 	 * NodeType or PI search
9904 	 */
9905 	if (xmlStrEqual(name, BAD_CAST "comment"))
9906 	    *type = NODE_TYPE_COMMENT;
9907 	else if (xmlStrEqual(name, BAD_CAST "node"))
9908 	    *type = NODE_TYPE_NODE;
9909 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9910 	    *type = NODE_TYPE_PI;
9911 	else if (xmlStrEqual(name, BAD_CAST "text"))
9912 	    *type = NODE_TYPE_TEXT;
9913 	else {
9914 	    if (name != NULL)
9915 		xmlFree(name);
9916 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
9917 	}
9918 
9919 	*test = NODE_TEST_TYPE;
9920 
9921 	SKIP_BLANKS;
9922 	if (*type == NODE_TYPE_PI) {
9923 	    /*
9924 	     * Specific case: search a PI by name.
9925 	     */
9926 	    if (name != NULL)
9927 		xmlFree(name);
9928 	    name = NULL;
9929 	    if (CUR != ')') {
9930 		name = xmlXPathParseLiteral(ctxt);
9931 		*test = NODE_TEST_PI;
9932 		SKIP_BLANKS;
9933 	    }
9934 	}
9935 	if (CUR != ')') {
9936 	    if (name != NULL)
9937 		xmlFree(name);
9938 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
9939 	}
9940 	NEXT;
9941 	return(name);
9942     }
9943     *test = NODE_TEST_NAME;
9944     if ((!blanks) && (CUR == ':')) {
9945 	NEXT;
9946 
9947 	/*
9948 	 * Since currently the parser context don't have a
9949 	 * namespace list associated:
9950 	 * The namespace name for this prefix can be computed
9951 	 * only at evaluation time. The compilation is done
9952 	 * outside of any context.
9953 	 */
9954 #if 0
9955 	*prefix = xmlXPathNsLookup(ctxt->context, name);
9956 	if (name != NULL)
9957 	    xmlFree(name);
9958 	if (*prefix == NULL) {
9959 	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9960 	}
9961 #else
9962 	*prefix = name;
9963 #endif
9964 
9965 	if (CUR == '*') {
9966 	    /*
9967 	     * All elements
9968 	     */
9969 	    NEXT;
9970 	    *test = NODE_TEST_ALL;
9971 	    return(NULL);
9972 	}
9973 
9974 	name = xmlXPathParseNCName(ctxt);
9975 	if (name == NULL) {
9976 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
9977 	}
9978     }
9979     return(name);
9980 }
9981 
9982 /**
9983  * xmlXPathIsAxisName:
9984  * @name:  a preparsed name token
9985  *
9986  * [6] AxisName ::=   'ancestor'
9987  *                  | 'ancestor-or-self'
9988  *                  | 'attribute'
9989  *                  | 'child'
9990  *                  | 'descendant'
9991  *                  | 'descendant-or-self'
9992  *                  | 'following'
9993  *                  | 'following-sibling'
9994  *                  | 'namespace'
9995  *                  | 'parent'
9996  *                  | 'preceding'
9997  *                  | 'preceding-sibling'
9998  *                  | 'self'
9999  *
10000  * Returns the axis or 0
10001  */
10002 static xmlXPathAxisVal
xmlXPathIsAxisName(const xmlChar * name)10003 xmlXPathIsAxisName(const xmlChar *name) {
10004     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
10005     switch (name[0]) {
10006 	case 'a':
10007 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
10008 		ret = AXIS_ANCESTOR;
10009 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
10010 		ret = AXIS_ANCESTOR_OR_SELF;
10011 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
10012 		ret = AXIS_ATTRIBUTE;
10013 	    break;
10014 	case 'c':
10015 	    if (xmlStrEqual(name, BAD_CAST "child"))
10016 		ret = AXIS_CHILD;
10017 	    break;
10018 	case 'd':
10019 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
10020 		ret = AXIS_DESCENDANT;
10021 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
10022 		ret = AXIS_DESCENDANT_OR_SELF;
10023 	    break;
10024 	case 'f':
10025 	    if (xmlStrEqual(name, BAD_CAST "following"))
10026 		ret = AXIS_FOLLOWING;
10027 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
10028 		ret = AXIS_FOLLOWING_SIBLING;
10029 	    break;
10030 	case 'n':
10031 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
10032 		ret = AXIS_NAMESPACE;
10033 	    break;
10034 	case 'p':
10035 	    if (xmlStrEqual(name, BAD_CAST "parent"))
10036 		ret = AXIS_PARENT;
10037 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
10038 		ret = AXIS_PRECEDING;
10039 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
10040 		ret = AXIS_PRECEDING_SIBLING;
10041 	    break;
10042 	case 's':
10043 	    if (xmlStrEqual(name, BAD_CAST "self"))
10044 		ret = AXIS_SELF;
10045 	    break;
10046     }
10047     return(ret);
10048 }
10049 
10050 /**
10051  * xmlXPathCompStep:
10052  * @ctxt:  the XPath Parser context
10053  *
10054  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
10055  *                  | AbbreviatedStep
10056  *
10057  * [12] AbbreviatedStep ::=   '.' | '..'
10058  *
10059  * [5] AxisSpecifier ::= AxisName '::'
10060  *                  | AbbreviatedAxisSpecifier
10061  *
10062  * [13] AbbreviatedAxisSpecifier ::= '@'?
10063  *
10064  * Modified for XPtr range support as:
10065  *
10066  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
10067  *                     | AbbreviatedStep
10068  *                     | 'range-to' '(' Expr ')' Predicate*
10069  *
10070  * Compile one step in a Location Path
10071  * A location step of . is short for self::node(). This is
10072  * particularly useful in conjunction with //. For example, the
10073  * location path .//para is short for
10074  * self::node()/descendant-or-self::node()/child::para
10075  * and so will select all para descendant elements of the context
10076  * node.
10077  * Similarly, a location step of .. is short for parent::node().
10078  * For example, ../title is short for parent::node()/child::title
10079  * and so will select the title children of the parent of the context
10080  * node.
10081  */
10082 static void
xmlXPathCompStep(xmlXPathParserContextPtr ctxt)10083 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
10084     SKIP_BLANKS;
10085     if ((CUR == '.') && (NXT(1) == '.')) {
10086 	SKIP(2);
10087 	SKIP_BLANKS;
10088 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
10089 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10090     } else if (CUR == '.') {
10091 	NEXT;
10092 	SKIP_BLANKS;
10093     } else {
10094 	xmlChar *name = NULL;
10095 	xmlChar *prefix = NULL;
10096 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
10097 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
10098 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
10099 	int op1;
10100 
10101 	if (CUR == '*') {
10102 	    axis = AXIS_CHILD;
10103 	} else {
10104 	    if (name == NULL)
10105 		name = xmlXPathParseNCName(ctxt);
10106 	    if (name != NULL) {
10107 		axis = xmlXPathIsAxisName(name);
10108 		if (axis != 0) {
10109 		    SKIP_BLANKS;
10110 		    if ((CUR == ':') && (NXT(1) == ':')) {
10111 			SKIP(2);
10112 			xmlFree(name);
10113 			name = NULL;
10114 		    } else {
10115 			/* an element name can conflict with an axis one :-\ */
10116 			axis = AXIS_CHILD;
10117 		    }
10118 		} else {
10119 		    axis = AXIS_CHILD;
10120 		}
10121 	    } else if (CUR == '@') {
10122 		NEXT;
10123 		axis = AXIS_ATTRIBUTE;
10124 	    } else {
10125 		axis = AXIS_CHILD;
10126 	    }
10127 	}
10128 
10129         if (ctxt->error != XPATH_EXPRESSION_OK) {
10130             xmlFree(name);
10131             return;
10132         }
10133 
10134 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
10135 	if (test == 0)
10136 	    return;
10137 
10138         if ((prefix != NULL) && (ctxt->context != NULL) &&
10139 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
10140 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
10141 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
10142 	    }
10143 	}
10144 
10145 	op1 = ctxt->comp->last;
10146 	ctxt->comp->last = -1;
10147 
10148 	SKIP_BLANKS;
10149 	while (CUR == '[') {
10150 	    xmlXPathCompPredicate(ctxt, 0);
10151 	}
10152 
10153         if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
10154                            test, type, (void *)prefix, (void *)name) == -1) {
10155             xmlFree(prefix);
10156             xmlFree(name);
10157         }
10158     }
10159 }
10160 
10161 /**
10162  * xmlXPathCompRelativeLocationPath:
10163  * @ctxt:  the XPath Parser context
10164  *
10165  *  [3]   RelativeLocationPath ::=   Step
10166  *                     | RelativeLocationPath '/' Step
10167  *                     | AbbreviatedRelativeLocationPath
10168  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
10169  *
10170  * Compile a relative location path.
10171  */
10172 static void
xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt)10173 xmlXPathCompRelativeLocationPath
10174 (xmlXPathParserContextPtr ctxt) {
10175     SKIP_BLANKS;
10176     if ((CUR == '/') && (NXT(1) == '/')) {
10177 	SKIP(2);
10178 	SKIP_BLANKS;
10179 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10180 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10181     } else if (CUR == '/') {
10182 	    NEXT;
10183 	SKIP_BLANKS;
10184     }
10185     xmlXPathCompStep(ctxt);
10186     CHECK_ERROR;
10187     SKIP_BLANKS;
10188     while (CUR == '/') {
10189 	if ((CUR == '/') && (NXT(1) == '/')) {
10190 	    SKIP(2);
10191 	    SKIP_BLANKS;
10192 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10193 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10194 	    xmlXPathCompStep(ctxt);
10195 	} else if (CUR == '/') {
10196 	    NEXT;
10197 	    SKIP_BLANKS;
10198 	    xmlXPathCompStep(ctxt);
10199 	}
10200 	SKIP_BLANKS;
10201     }
10202 }
10203 
10204 /**
10205  * xmlXPathCompLocationPath:
10206  * @ctxt:  the XPath Parser context
10207  *
10208  *  [1]   LocationPath ::=   RelativeLocationPath
10209  *                     | AbsoluteLocationPath
10210  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
10211  *                     | AbbreviatedAbsoluteLocationPath
10212  *  [10]   AbbreviatedAbsoluteLocationPath ::=
10213  *                           '//' RelativeLocationPath
10214  *
10215  * Compile a location path
10216  *
10217  * // is short for /descendant-or-self::node()/. For example,
10218  * //para is short for /descendant-or-self::node()/child::para and
10219  * so will select any para element in the document (even a para element
10220  * that is a document element will be selected by //para since the
10221  * document element node is a child of the root node); div//para is
10222  * short for div/descendant-or-self::node()/child::para and so will
10223  * select all para descendants of div children.
10224  */
10225 static void
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt)10226 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
10227     SKIP_BLANKS;
10228     if (CUR != '/') {
10229         xmlXPathCompRelativeLocationPath(ctxt);
10230     } else {
10231 	while (CUR == '/') {
10232 	    if ((CUR == '/') && (NXT(1) == '/')) {
10233 		SKIP(2);
10234 		SKIP_BLANKS;
10235 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10236 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10237 		xmlXPathCompRelativeLocationPath(ctxt);
10238 	    } else if (CUR == '/') {
10239 		NEXT;
10240 		SKIP_BLANKS;
10241 		if ((CUR != 0 ) &&
10242 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
10243 		     (CUR == '@') || (CUR == '*')))
10244 		    xmlXPathCompRelativeLocationPath(ctxt);
10245 	    }
10246 	    CHECK_ERROR;
10247 	}
10248     }
10249 }
10250 
10251 /************************************************************************
10252  *									*
10253  *		XPath precompiled expression evaluation			*
10254  *									*
10255  ************************************************************************/
10256 
10257 static int
10258 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
10259 
10260 /**
10261  * xmlXPathNodeSetFilter:
10262  * @ctxt:  the XPath Parser context
10263  * @set: the node set to filter
10264  * @filterOpIndex: the index of the predicate/filter op
10265  * @minPos: minimum position in the filtered set (1-based)
10266  * @maxPos: maximum position in the filtered set (1-based)
10267  * @hasNsNodes: true if the node set may contain namespace nodes
10268  *
10269  * Filter a node set, keeping only nodes for which the predicate expression
10270  * matches. Afterwards, keep only nodes between minPos and maxPos in the
10271  * filtered result.
10272  */
10273 static void
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,xmlNodeSetPtr set,int filterOpIndex,int minPos,int maxPos,int hasNsNodes)10274 xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
10275 		      xmlNodeSetPtr set,
10276 		      int filterOpIndex,
10277                       int minPos, int maxPos,
10278 		      int hasNsNodes)
10279 {
10280     xmlXPathContextPtr xpctxt;
10281     xmlNodePtr oldnode;
10282     xmlDocPtr olddoc;
10283     xmlXPathStepOpPtr filterOp;
10284     int oldcs, oldpp;
10285     int i, j, pos;
10286 
10287     if ((set == NULL) || (set->nodeNr == 0))
10288         return;
10289 
10290     /*
10291     * Check if the node set contains a sufficient number of nodes for
10292     * the requested range.
10293     */
10294     if (set->nodeNr < minPos) {
10295         xmlXPathNodeSetClear(set, hasNsNodes);
10296         return;
10297     }
10298 
10299     xpctxt = ctxt->context;
10300     oldnode = xpctxt->node;
10301     olddoc = xpctxt->doc;
10302     oldcs = xpctxt->contextSize;
10303     oldpp = xpctxt->proximityPosition;
10304     filterOp = &ctxt->comp->steps[filterOpIndex];
10305 
10306     xpctxt->contextSize = set->nodeNr;
10307 
10308     for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
10309         xmlNodePtr node = set->nodeTab[i];
10310         int res;
10311 
10312         xpctxt->node = node;
10313         xpctxt->proximityPosition = i + 1;
10314 
10315         /*
10316         * Also set the xpath document in case things like
10317         * key() are evaluated in the predicate.
10318         *
10319         * TODO: Get real doc for namespace nodes.
10320         */
10321         if ((node->type != XML_NAMESPACE_DECL) &&
10322             (node->doc != NULL))
10323             xpctxt->doc = node->doc;
10324 
10325         res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
10326 
10327         if (ctxt->error != XPATH_EXPRESSION_OK)
10328             break;
10329         if (res < 0) {
10330             /* Shouldn't happen */
10331             xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
10332             break;
10333         }
10334 
10335         if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
10336             if (i != j) {
10337                 set->nodeTab[j] = node;
10338                 set->nodeTab[i] = NULL;
10339             }
10340 
10341             j += 1;
10342         } else {
10343             /* Remove the entry from the initial node set. */
10344             set->nodeTab[i] = NULL;
10345             if (node->type == XML_NAMESPACE_DECL)
10346                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10347         }
10348 
10349         if (res != 0) {
10350             if (pos == maxPos) {
10351                 i += 1;
10352                 break;
10353             }
10354 
10355             pos += 1;
10356         }
10357     }
10358 
10359     /* Free remaining nodes. */
10360     if (hasNsNodes) {
10361         for (; i < set->nodeNr; i++) {
10362             xmlNodePtr node = set->nodeTab[i];
10363             if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
10364                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10365         }
10366     }
10367 
10368     set->nodeNr = j;
10369 
10370     /* If too many elements were removed, shrink table to preserve memory. */
10371     if ((set->nodeMax > XML_NODESET_DEFAULT) &&
10372         (set->nodeNr < set->nodeMax / 2)) {
10373         xmlNodePtr *tmp;
10374         int nodeMax = set->nodeNr;
10375 
10376         if (nodeMax < XML_NODESET_DEFAULT)
10377             nodeMax = XML_NODESET_DEFAULT;
10378         tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
10379                 nodeMax * sizeof(xmlNodePtr));
10380         if (tmp == NULL) {
10381             xmlXPathPErrMemory(ctxt);
10382         } else {
10383             set->nodeTab = tmp;
10384             set->nodeMax = nodeMax;
10385         }
10386     }
10387 
10388     xpctxt->node = oldnode;
10389     xpctxt->doc = olddoc;
10390     xpctxt->contextSize = oldcs;
10391     xpctxt->proximityPosition = oldpp;
10392 }
10393 
10394 /**
10395  * xmlXPathCompOpEvalPredicate:
10396  * @ctxt:  the XPath Parser context
10397  * @op: the predicate op
10398  * @set: the node set to filter
10399  * @minPos: minimum position in the filtered set (1-based)
10400  * @maxPos: maximum position in the filtered set (1-based)
10401  * @hasNsNodes: true if the node set may contain namespace nodes
10402  *
10403  * Filter a node set, keeping only nodes for which the sequence of predicate
10404  * expressions matches. Afterwards, keep only nodes between minPos and maxPos
10405  * in the filtered result.
10406  */
10407 static void
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int minPos,int maxPos,int hasNsNodes)10408 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
10409 			    xmlXPathStepOpPtr op,
10410 			    xmlNodeSetPtr set,
10411                             int minPos, int maxPos,
10412 			    int hasNsNodes)
10413 {
10414     if (op->ch1 != -1) {
10415 	xmlXPathCompExprPtr comp = ctxt->comp;
10416 	/*
10417 	* Process inner predicates first.
10418 	*/
10419 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
10420             XP_ERROR(XPATH_INVALID_OPERAND);
10421 	}
10422         if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10423             XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10424         ctxt->context->depth += 1;
10425 	xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
10426                                     1, set->nodeNr, hasNsNodes);
10427         ctxt->context->depth -= 1;
10428 	CHECK_ERROR;
10429     }
10430 
10431     if (op->ch2 != -1)
10432         xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
10433 }
10434 
10435 static int
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int * maxPos)10436 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
10437 			    xmlXPathStepOpPtr op,
10438 			    int *maxPos)
10439 {
10440 
10441     xmlXPathStepOpPtr exprOp;
10442 
10443     /*
10444     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
10445     */
10446 
10447     /*
10448     * If not -1, then ch1 will point to:
10449     * 1) For predicates (XPATH_OP_PREDICATE):
10450     *    - an inner predicate operator
10451     * 2) For filters (XPATH_OP_FILTER):
10452     *    - an inner filter operator OR
10453     *    - an expression selecting the node set.
10454     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
10455     */
10456     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
10457 	return(0);
10458 
10459     if (op->ch2 != -1) {
10460 	exprOp = &ctxt->comp->steps[op->ch2];
10461     } else
10462 	return(0);
10463 
10464     if ((exprOp != NULL) &&
10465 	(exprOp->op == XPATH_OP_VALUE) &&
10466 	(exprOp->value4 != NULL) &&
10467 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
10468     {
10469         double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
10470 
10471 	/*
10472 	* We have a "[n]" predicate here.
10473 	* TODO: Unfortunately this simplistic test here is not
10474 	* able to detect a position() predicate in compound
10475 	* expressions like "[@attr = 'a" and position() = 1],
10476 	* and even not the usage of position() in
10477 	* "[position() = 1]"; thus - obviously - a position-range,
10478 	* like it "[position() < 5]", is also not detected.
10479 	* Maybe we could rewrite the AST to ease the optimization.
10480 	*/
10481 
10482         if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
10483 	    *maxPos = (int) floatval;
10484             if (floatval == (double) *maxPos)
10485                 return(1);
10486         }
10487     }
10488     return(0);
10489 }
10490 
10491 static int
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first,xmlNodePtr * last,int toBool)10492 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
10493                            xmlXPathStepOpPtr op,
10494 			   xmlNodePtr * first, xmlNodePtr * last,
10495 			   int toBool)
10496 {
10497 
10498 #define XP_TEST_HIT \
10499     if (hasAxisRange != 0) { \
10500 	if (++pos == maxPos) { \
10501 	    if (addNode(seq, cur) < 0) \
10502 	        xmlXPathPErrMemory(ctxt); \
10503 	    goto axis_range_end; } \
10504     } else { \
10505 	if (addNode(seq, cur) < 0) \
10506 	    xmlXPathPErrMemory(ctxt); \
10507 	if (breakOnFirstHit) goto first_hit; }
10508 
10509 #define XP_TEST_HIT_NS \
10510     if (hasAxisRange != 0) { \
10511 	if (++pos == maxPos) { \
10512 	    hasNsNodes = 1; \
10513 	    if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
10514 	        xmlXPathPErrMemory(ctxt); \
10515 	goto axis_range_end; } \
10516     } else { \
10517 	hasNsNodes = 1; \
10518 	if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
10519 	    xmlXPathPErrMemory(ctxt); \
10520 	if (breakOnFirstHit) goto first_hit; }
10521 
10522     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
10523     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
10524     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
10525     const xmlChar *prefix = op->value4;
10526     const xmlChar *name = op->value5;
10527     const xmlChar *URI = NULL;
10528 
10529     int total = 0, hasNsNodes = 0;
10530     /* The popped object holding the context nodes */
10531     xmlXPathObjectPtr obj;
10532     /* The set of context nodes for the node tests */
10533     xmlNodeSetPtr contextSeq;
10534     int contextIdx;
10535     xmlNodePtr contextNode;
10536     /* The final resulting node set wrt to all context nodes */
10537     xmlNodeSetPtr outSeq;
10538     /*
10539     * The temporary resulting node set wrt 1 context node.
10540     * Used to feed predicate evaluation.
10541     */
10542     xmlNodeSetPtr seq;
10543     xmlNodePtr cur;
10544     /* First predicate operator */
10545     xmlXPathStepOpPtr predOp;
10546     int maxPos; /* The requested position() (when a "[n]" predicate) */
10547     int hasPredicateRange, hasAxisRange, pos;
10548     int breakOnFirstHit;
10549 
10550     xmlXPathTraversalFunction next = NULL;
10551     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
10552     xmlXPathNodeSetMergeFunction mergeAndClear;
10553     xmlNodePtr oldContextNode;
10554     xmlXPathContextPtr xpctxt = ctxt->context;
10555 
10556 
10557     CHECK_TYPE0(XPATH_NODESET);
10558     obj = valuePop(ctxt);
10559     /*
10560     * Setup namespaces.
10561     */
10562     if (prefix != NULL) {
10563         URI = xmlXPathNsLookup(xpctxt, prefix);
10564         if (URI == NULL) {
10565 	    xmlXPathReleaseObject(xpctxt, obj);
10566             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10567 	}
10568     }
10569     /*
10570     * Setup axis.
10571     *
10572     * MAYBE FUTURE TODO: merging optimizations:
10573     * - If the nodes to be traversed wrt to the initial nodes and
10574     *   the current axis cannot overlap, then we could avoid searching
10575     *   for duplicates during the merge.
10576     *   But the question is how/when to evaluate if they cannot overlap.
10577     *   Example: if we know that for two initial nodes, the one is
10578     *   not in the ancestor-or-self axis of the other, then we could safely
10579     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
10580     *   the descendant-or-self axis.
10581     */
10582     mergeAndClear = xmlXPathNodeSetMergeAndClear;
10583     switch (axis) {
10584         case AXIS_ANCESTOR:
10585             first = NULL;
10586             next = xmlXPathNextAncestor;
10587             break;
10588         case AXIS_ANCESTOR_OR_SELF:
10589             first = NULL;
10590             next = xmlXPathNextAncestorOrSelf;
10591             break;
10592         case AXIS_ATTRIBUTE:
10593             first = NULL;
10594 	    last = NULL;
10595             next = xmlXPathNextAttribute;
10596 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10597             break;
10598         case AXIS_CHILD:
10599 	    last = NULL;
10600 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
10601 		(type == NODE_TYPE_NODE))
10602 	    {
10603 		/*
10604 		* Optimization if an element node type is 'element'.
10605 		*/
10606 		next = xmlXPathNextChildElement;
10607 	    } else
10608 		next = xmlXPathNextChild;
10609 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10610             break;
10611         case AXIS_DESCENDANT:
10612 	    last = NULL;
10613             next = xmlXPathNextDescendant;
10614             break;
10615         case AXIS_DESCENDANT_OR_SELF:
10616 	    last = NULL;
10617             next = xmlXPathNextDescendantOrSelf;
10618             break;
10619         case AXIS_FOLLOWING:
10620 	    last = NULL;
10621             next = xmlXPathNextFollowing;
10622             break;
10623         case AXIS_FOLLOWING_SIBLING:
10624 	    last = NULL;
10625             next = xmlXPathNextFollowingSibling;
10626             break;
10627         case AXIS_NAMESPACE:
10628             first = NULL;
10629 	    last = NULL;
10630             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
10631 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10632             break;
10633         case AXIS_PARENT:
10634             first = NULL;
10635             next = xmlXPathNextParent;
10636             break;
10637         case AXIS_PRECEDING:
10638             first = NULL;
10639             next = xmlXPathNextPrecedingInternal;
10640             break;
10641         case AXIS_PRECEDING_SIBLING:
10642             first = NULL;
10643             next = xmlXPathNextPrecedingSibling;
10644             break;
10645         case AXIS_SELF:
10646             first = NULL;
10647 	    last = NULL;
10648             next = xmlXPathNextSelf;
10649 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10650             break;
10651     }
10652 
10653     if (next == NULL) {
10654 	xmlXPathReleaseObject(xpctxt, obj);
10655         return(0);
10656     }
10657     contextSeq = obj->nodesetval;
10658     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
10659         valuePush(ctxt, obj);
10660         return(0);
10661     }
10662     /*
10663     * Predicate optimization ---------------------------------------------
10664     * If this step has a last predicate, which contains a position(),
10665     * then we'll optimize (although not exactly "position()", but only
10666     * the  short-hand form, i.e., "[n]".
10667     *
10668     * Example - expression "/foo[parent::bar][1]":
10669     *
10670     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
10671     *   ROOT                               -- op->ch1
10672     *   PREDICATE                          -- op->ch2 (predOp)
10673     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
10674     *       SORT
10675     *         COLLECT  'parent' 'name' 'node' bar
10676     *           NODE
10677     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
10678     *
10679     */
10680     maxPos = 0;
10681     predOp = NULL;
10682     hasPredicateRange = 0;
10683     hasAxisRange = 0;
10684     if (op->ch2 != -1) {
10685 	/*
10686 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
10687 	*/
10688 	predOp = &ctxt->comp->steps[op->ch2];
10689 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
10690 	    if (predOp->ch1 != -1) {
10691 		/*
10692 		* Use the next inner predicate operator.
10693 		*/
10694 		predOp = &ctxt->comp->steps[predOp->ch1];
10695 		hasPredicateRange = 1;
10696 	    } else {
10697 		/*
10698 		* There's no other predicate than the [n] predicate.
10699 		*/
10700 		predOp = NULL;
10701 		hasAxisRange = 1;
10702 	    }
10703 	}
10704     }
10705     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
10706     /*
10707     * Axis traversal -----------------------------------------------------
10708     */
10709     /*
10710      * 2.3 Node Tests
10711      *  - For the attribute axis, the principal node type is attribute.
10712      *  - For the namespace axis, the principal node type is namespace.
10713      *  - For other axes, the principal node type is element.
10714      *
10715      * A node test * is true for any node of the
10716      * principal node type. For example, child::* will
10717      * select all element children of the context node
10718      */
10719     oldContextNode = xpctxt->node;
10720     addNode = xmlXPathNodeSetAddUnique;
10721     outSeq = NULL;
10722     seq = NULL;
10723     contextNode = NULL;
10724     contextIdx = 0;
10725 
10726 
10727     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
10728            (ctxt->error == XPATH_EXPRESSION_OK)) {
10729 	xpctxt->node = contextSeq->nodeTab[contextIdx++];
10730 
10731 	if (seq == NULL) {
10732 	    seq = xmlXPathNodeSetCreate(NULL);
10733 	    if (seq == NULL) {
10734                 xmlXPathPErrMemory(ctxt);
10735 		total = 0;
10736 		goto error;
10737 	    }
10738 	}
10739 	/*
10740 	* Traverse the axis and test the nodes.
10741 	*/
10742 	pos = 0;
10743 	cur = NULL;
10744 	hasNsNodes = 0;
10745         do {
10746             if (OP_LIMIT_EXCEEDED(ctxt, 1))
10747                 goto error;
10748 
10749             cur = next(ctxt, cur);
10750             if (cur == NULL)
10751                 break;
10752 
10753 	    /*
10754 	    * QUESTION TODO: What does the "first" and "last" stuff do?
10755 	    */
10756             if ((first != NULL) && (*first != NULL)) {
10757 		if (*first == cur)
10758 		    break;
10759 		if (((total % 256) == 0) &&
10760 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10761 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
10762 #else
10763 		    (xmlXPathCmpNodes(*first, cur) >= 0))
10764 #endif
10765 		{
10766 		    break;
10767 		}
10768 	    }
10769 	    if ((last != NULL) && (*last != NULL)) {
10770 		if (*last == cur)
10771 		    break;
10772 		if (((total % 256) == 0) &&
10773 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10774 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
10775 #else
10776 		    (xmlXPathCmpNodes(cur, *last) >= 0))
10777 #endif
10778 		{
10779 		    break;
10780 		}
10781 	    }
10782 
10783             total++;
10784 
10785 	    switch (test) {
10786                 case NODE_TEST_NONE:
10787 		    total = 0;
10788 		    goto error;
10789                 case NODE_TEST_TYPE:
10790 		    if (type == NODE_TYPE_NODE) {
10791 			switch (cur->type) {
10792 			    case XML_DOCUMENT_NODE:
10793 			    case XML_HTML_DOCUMENT_NODE:
10794 			    case XML_ELEMENT_NODE:
10795 			    case XML_ATTRIBUTE_NODE:
10796 			    case XML_PI_NODE:
10797 			    case XML_COMMENT_NODE:
10798 			    case XML_CDATA_SECTION_NODE:
10799 			    case XML_TEXT_NODE:
10800 				XP_TEST_HIT
10801 				break;
10802 			    case XML_NAMESPACE_DECL: {
10803 				if (axis == AXIS_NAMESPACE) {
10804 				    XP_TEST_HIT_NS
10805 				} else {
10806 	                            hasNsNodes = 1;
10807 				    XP_TEST_HIT
10808 				}
10809 				break;
10810                             }
10811 			    default:
10812 				break;
10813 			}
10814 		    } else if (cur->type == (xmlElementType) type) {
10815 			if (cur->type == XML_NAMESPACE_DECL)
10816 			    XP_TEST_HIT_NS
10817 			else
10818 			    XP_TEST_HIT
10819 		    } else if ((type == NODE_TYPE_TEXT) &&
10820 			 (cur->type == XML_CDATA_SECTION_NODE))
10821 		    {
10822 			XP_TEST_HIT
10823 		    }
10824 		    break;
10825                 case NODE_TEST_PI:
10826                     if ((cur->type == XML_PI_NODE) &&
10827                         ((name == NULL) || xmlStrEqual(name, cur->name)))
10828 		    {
10829 			XP_TEST_HIT
10830                     }
10831                     break;
10832                 case NODE_TEST_ALL:
10833                     if (axis == AXIS_ATTRIBUTE) {
10834                         if (cur->type == XML_ATTRIBUTE_NODE)
10835 			{
10836                             if (prefix == NULL)
10837 			    {
10838 				XP_TEST_HIT
10839                             } else if ((cur->ns != NULL) &&
10840 				(xmlStrEqual(URI, cur->ns->href)))
10841 			    {
10842 				XP_TEST_HIT
10843                             }
10844                         }
10845                     } else if (axis == AXIS_NAMESPACE) {
10846                         if (cur->type == XML_NAMESPACE_DECL)
10847 			{
10848 			    XP_TEST_HIT_NS
10849                         }
10850                     } else {
10851                         if (cur->type == XML_ELEMENT_NODE) {
10852                             if (prefix == NULL)
10853 			    {
10854 				XP_TEST_HIT
10855 
10856                             } else if ((cur->ns != NULL) &&
10857 				(xmlStrEqual(URI, cur->ns->href)))
10858 			    {
10859 				XP_TEST_HIT
10860                             }
10861                         }
10862                     }
10863                     break;
10864                 case NODE_TEST_NS:{
10865                         /* TODO */
10866                         break;
10867                     }
10868                 case NODE_TEST_NAME:
10869                     if (axis == AXIS_ATTRIBUTE) {
10870                         if (cur->type != XML_ATTRIBUTE_NODE)
10871 			    break;
10872 		    } else if (axis == AXIS_NAMESPACE) {
10873                         if (cur->type != XML_NAMESPACE_DECL)
10874 			    break;
10875 		    } else {
10876 		        if (cur->type != XML_ELEMENT_NODE)
10877 			    break;
10878 		    }
10879                     switch (cur->type) {
10880                         case XML_ELEMENT_NODE:
10881                             if (xmlStrEqual(name, cur->name)) {
10882                                 if (prefix == NULL) {
10883                                     if (cur->ns == NULL)
10884 				    {
10885 					XP_TEST_HIT
10886                                     }
10887                                 } else {
10888                                     if ((cur->ns != NULL) &&
10889                                         (xmlStrEqual(URI, cur->ns->href)))
10890 				    {
10891 					XP_TEST_HIT
10892                                     }
10893                                 }
10894                             }
10895                             break;
10896                         case XML_ATTRIBUTE_NODE:{
10897                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
10898 
10899                                 if (xmlStrEqual(name, attr->name)) {
10900                                     if (prefix == NULL) {
10901                                         if ((attr->ns == NULL) ||
10902                                             (attr->ns->prefix == NULL))
10903 					{
10904 					    XP_TEST_HIT
10905                                         }
10906                                     } else {
10907                                         if ((attr->ns != NULL) &&
10908                                             (xmlStrEqual(URI,
10909 					      attr->ns->href)))
10910 					{
10911 					    XP_TEST_HIT
10912                                         }
10913                                     }
10914                                 }
10915                                 break;
10916                             }
10917                         case XML_NAMESPACE_DECL:
10918                             if (cur->type == XML_NAMESPACE_DECL) {
10919                                 xmlNsPtr ns = (xmlNsPtr) cur;
10920 
10921                                 if ((ns->prefix != NULL) && (name != NULL)
10922                                     && (xmlStrEqual(ns->prefix, name)))
10923 				{
10924 				    XP_TEST_HIT_NS
10925                                 }
10926                             }
10927                             break;
10928                         default:
10929                             break;
10930                     }
10931                     break;
10932 	    } /* switch(test) */
10933         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
10934 
10935 	goto apply_predicates;
10936 
10937 axis_range_end: /* ----------------------------------------------------- */
10938 	/*
10939 	* We have a "/foo[n]", and position() = n was reached.
10940 	* Note that we can have as well "/foo/::parent::foo[1]", so
10941 	* a duplicate-aware merge is still needed.
10942 	* Merge with the result.
10943 	*/
10944 	if (outSeq == NULL) {
10945 	    outSeq = seq;
10946 	    seq = NULL;
10947 	} else {
10948 	    outSeq = mergeAndClear(outSeq, seq);
10949             if (outSeq == NULL)
10950                 xmlXPathPErrMemory(ctxt);
10951         }
10952 	/*
10953 	* Break if only a true/false result was requested.
10954 	*/
10955 	if (toBool)
10956 	    break;
10957 	continue;
10958 
10959 first_hit: /* ---------------------------------------------------------- */
10960 	/*
10961 	* Break if only a true/false result was requested and
10962 	* no predicates existed and a node test succeeded.
10963 	*/
10964 	if (outSeq == NULL) {
10965 	    outSeq = seq;
10966 	    seq = NULL;
10967 	} else {
10968 	    outSeq = mergeAndClear(outSeq, seq);
10969             if (outSeq == NULL)
10970                 xmlXPathPErrMemory(ctxt);
10971         }
10972 	break;
10973 
10974 apply_predicates: /* --------------------------------------------------- */
10975         if (ctxt->error != XPATH_EXPRESSION_OK)
10976 	    goto error;
10977 
10978         /*
10979 	* Apply predicates.
10980 	*/
10981         if ((predOp != NULL) && (seq->nodeNr > 0)) {
10982 	    /*
10983 	    * E.g. when we have a "/foo[some expression][n]".
10984 	    */
10985 	    /*
10986 	    * QUESTION TODO: The old predicate evaluation took into
10987 	    *  account location-sets.
10988 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
10989 	    *  Do we expect such a set here?
10990 	    *  All what I learned now from the evaluation semantics
10991 	    *  does not indicate that a location-set will be processed
10992 	    *  here, so this looks OK.
10993 	    */
10994 	    /*
10995 	    * Iterate over all predicates, starting with the outermost
10996 	    * predicate.
10997 	    * TODO: Problem: we cannot execute the inner predicates first
10998 	    *  since we cannot go back *up* the operator tree!
10999 	    *  Options we have:
11000 	    *  1) Use of recursive functions (like is it currently done
11001 	    *     via xmlXPathCompOpEval())
11002 	    *  2) Add a predicate evaluation information stack to the
11003 	    *     context struct
11004 	    *  3) Change the way the operators are linked; we need a
11005 	    *     "parent" field on xmlXPathStepOp
11006 	    *
11007 	    * For the moment, I'll try to solve this with a recursive
11008 	    * function: xmlXPathCompOpEvalPredicate().
11009 	    */
11010 	    if (hasPredicateRange != 0)
11011 		xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
11012 					    hasNsNodes);
11013 	    else
11014 		xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
11015 					    hasNsNodes);
11016 
11017 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
11018 		total = 0;
11019 		goto error;
11020 	    }
11021         }
11022 
11023         if (seq->nodeNr > 0) {
11024 	    /*
11025 	    * Add to result set.
11026 	    */
11027 	    if (outSeq == NULL) {
11028 		outSeq = seq;
11029 		seq = NULL;
11030 	    } else {
11031 		outSeq = mergeAndClear(outSeq, seq);
11032                 if (outSeq == NULL)
11033                     xmlXPathPErrMemory(ctxt);
11034 	    }
11035 
11036             if (toBool)
11037                 break;
11038 	}
11039     }
11040 
11041 error:
11042     if ((obj->boolval) && (obj->user != NULL)) {
11043 	/*
11044 	* QUESTION TODO: What does this do and why?
11045 	* TODO: Do we have to do this also for the "error"
11046 	* cleanup further down?
11047 	*/
11048 	ctxt->value->boolval = 1;
11049 	ctxt->value->user = obj->user;
11050 	obj->user = NULL;
11051 	obj->boolval = 0;
11052     }
11053     xmlXPathReleaseObject(xpctxt, obj);
11054 
11055     /*
11056     * Ensure we return at least an empty set.
11057     */
11058     if (outSeq == NULL) {
11059 	if ((seq != NULL) && (seq->nodeNr == 0)) {
11060 	    outSeq = seq;
11061         } else {
11062 	    outSeq = xmlXPathNodeSetCreate(NULL);
11063             if (outSeq == NULL)
11064                 xmlXPathPErrMemory(ctxt);
11065         }
11066     }
11067     if ((seq != NULL) && (seq != outSeq)) {
11068 	 xmlXPathFreeNodeSet(seq);
11069     }
11070     /*
11071     * Hand over the result. Better to push the set also in
11072     * case of errors.
11073     */
11074     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, outSeq));
11075     /*
11076     * Reset the context node.
11077     */
11078     xpctxt->node = oldContextNode;
11079     /*
11080     * When traversing the namespace axis in "toBool" mode, it's
11081     * possible that tmpNsList wasn't freed.
11082     */
11083     if (xpctxt->tmpNsList != NULL) {
11084         xmlFree(xpctxt->tmpNsList);
11085         xpctxt->tmpNsList = NULL;
11086     }
11087 
11088     return(total);
11089 }
11090 
11091 static int
11092 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11093 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
11094 
11095 /**
11096  * xmlXPathCompOpEvalFirst:
11097  * @ctxt:  the XPath parser context with the compiled expression
11098  * @op:  an XPath compiled operation
11099  * @first:  the first elem found so far
11100  *
11101  * Evaluate the Precompiled XPath operation searching only the first
11102  * element in document order
11103  *
11104  * Returns the number of examined objects.
11105  */
11106 static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)11107 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
11108                         xmlXPathStepOpPtr op, xmlNodePtr * first)
11109 {
11110     int total = 0, cur;
11111     xmlXPathCompExprPtr comp;
11112     xmlXPathObjectPtr arg1, arg2;
11113 
11114     CHECK_ERROR0;
11115     if (OP_LIMIT_EXCEEDED(ctxt, 1))
11116         return(0);
11117     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11118         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11119     ctxt->context->depth += 1;
11120     comp = ctxt->comp;
11121     switch (op->op) {
11122         case XPATH_OP_END:
11123             break;
11124         case XPATH_OP_UNION:
11125             total =
11126                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11127                                         first);
11128 	    CHECK_ERROR0;
11129             if ((ctxt->value != NULL)
11130                 && (ctxt->value->type == XPATH_NODESET)
11131                 && (ctxt->value->nodesetval != NULL)
11132                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
11133                 /*
11134                  * limit tree traversing to first node in the result
11135                  */
11136 		/*
11137 		* OPTIMIZE TODO: This implicitly sorts
11138 		*  the result, even if not needed. E.g. if the argument
11139 		*  of the count() function, no sorting is needed.
11140 		* OPTIMIZE TODO: How do we know if the node-list wasn't
11141 		*  already sorted?
11142 		*/
11143 		if (ctxt->value->nodesetval->nodeNr > 1)
11144 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
11145                 *first = ctxt->value->nodesetval->nodeTab[0];
11146             }
11147             cur =
11148                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
11149                                         first);
11150 	    CHECK_ERROR0;
11151 
11152             arg2 = valuePop(ctxt);
11153             arg1 = valuePop(ctxt);
11154             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11155                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11156 	        xmlXPathReleaseObject(ctxt->context, arg1);
11157 	        xmlXPathReleaseObject(ctxt->context, arg2);
11158                 XP_ERROR0(XPATH_INVALID_TYPE);
11159             }
11160             if ((ctxt->context->opLimit != 0) &&
11161                 (((arg1->nodesetval != NULL) &&
11162                   (xmlXPathCheckOpLimit(ctxt,
11163                                         arg1->nodesetval->nodeNr) < 0)) ||
11164                  ((arg2->nodesetval != NULL) &&
11165                   (xmlXPathCheckOpLimit(ctxt,
11166                                         arg2->nodesetval->nodeNr) < 0)))) {
11167 	        xmlXPathReleaseObject(ctxt->context, arg1);
11168 	        xmlXPathReleaseObject(ctxt->context, arg2);
11169                 break;
11170             }
11171 
11172             if ((arg2->nodesetval != NULL) &&
11173                 (arg2->nodesetval->nodeNr != 0)) {
11174                 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11175                                                         arg2->nodesetval);
11176                 if (arg1->nodesetval == NULL)
11177                     xmlXPathPErrMemory(ctxt);
11178             }
11179             valuePush(ctxt, arg1);
11180 	    xmlXPathReleaseObject(ctxt->context, arg2);
11181             /* optimizer */
11182 	    if (total > cur)
11183 		xmlXPathCompSwap(op);
11184             total += cur;
11185             break;
11186         case XPATH_OP_ROOT:
11187             xmlXPathRoot(ctxt);
11188             break;
11189         case XPATH_OP_NODE:
11190             if (op->ch1 != -1)
11191                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11192 	    CHECK_ERROR0;
11193             if (op->ch2 != -1)
11194                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11195 	    CHECK_ERROR0;
11196 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11197 		ctxt->context->node));
11198             break;
11199         case XPATH_OP_COLLECT:{
11200                 if (op->ch1 == -1)
11201                     break;
11202 
11203                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11204 		CHECK_ERROR0;
11205 
11206                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
11207                 break;
11208             }
11209         case XPATH_OP_VALUE:
11210             valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11211             break;
11212         case XPATH_OP_SORT:
11213             if (op->ch1 != -1)
11214                 total +=
11215                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11216                                             first);
11217 	    CHECK_ERROR0;
11218             if ((ctxt->value != NULL)
11219                 && (ctxt->value->type == XPATH_NODESET)
11220                 && (ctxt->value->nodesetval != NULL)
11221 		&& (ctxt->value->nodesetval->nodeNr > 1))
11222                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11223             break;
11224 #ifdef XP_OPTIMIZED_FILTER_FIRST
11225 	case XPATH_OP_FILTER:
11226                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
11227             break;
11228 #endif
11229         default:
11230             total += xmlXPathCompOpEval(ctxt, op);
11231             break;
11232     }
11233 
11234     ctxt->context->depth -= 1;
11235     return(total);
11236 }
11237 
11238 /**
11239  * xmlXPathCompOpEvalLast:
11240  * @ctxt:  the XPath parser context with the compiled expression
11241  * @op:  an XPath compiled operation
11242  * @last:  the last elem found so far
11243  *
11244  * Evaluate the Precompiled XPath operation searching only the last
11245  * element in document order
11246  *
11247  * Returns the number of nodes traversed
11248  */
11249 static int
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * last)11250 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
11251                        xmlNodePtr * last)
11252 {
11253     int total = 0, cur;
11254     xmlXPathCompExprPtr comp;
11255     xmlXPathObjectPtr arg1, arg2;
11256 
11257     CHECK_ERROR0;
11258     if (OP_LIMIT_EXCEEDED(ctxt, 1))
11259         return(0);
11260     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11261         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11262     ctxt->context->depth += 1;
11263     comp = ctxt->comp;
11264     switch (op->op) {
11265         case XPATH_OP_END:
11266             break;
11267         case XPATH_OP_UNION:
11268             total =
11269                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
11270 	    CHECK_ERROR0;
11271             if ((ctxt->value != NULL)
11272                 && (ctxt->value->type == XPATH_NODESET)
11273                 && (ctxt->value->nodesetval != NULL)
11274                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
11275                 /*
11276                  * limit tree traversing to first node in the result
11277                  */
11278 		if (ctxt->value->nodesetval->nodeNr > 1)
11279 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
11280                 *last =
11281                     ctxt->value->nodesetval->nodeTab[ctxt->value->
11282                                                      nodesetval->nodeNr -
11283                                                      1];
11284             }
11285             cur =
11286                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
11287 	    CHECK_ERROR0;
11288             if ((ctxt->value != NULL)
11289                 && (ctxt->value->type == XPATH_NODESET)
11290                 && (ctxt->value->nodesetval != NULL)
11291                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
11292             }
11293 
11294             arg2 = valuePop(ctxt);
11295             arg1 = valuePop(ctxt);
11296             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11297                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11298 	        xmlXPathReleaseObject(ctxt->context, arg1);
11299 	        xmlXPathReleaseObject(ctxt->context, arg2);
11300                 XP_ERROR0(XPATH_INVALID_TYPE);
11301             }
11302             if ((ctxt->context->opLimit != 0) &&
11303                 (((arg1->nodesetval != NULL) &&
11304                   (xmlXPathCheckOpLimit(ctxt,
11305                                         arg1->nodesetval->nodeNr) < 0)) ||
11306                  ((arg2->nodesetval != NULL) &&
11307                   (xmlXPathCheckOpLimit(ctxt,
11308                                         arg2->nodesetval->nodeNr) < 0)))) {
11309 	        xmlXPathReleaseObject(ctxt->context, arg1);
11310 	        xmlXPathReleaseObject(ctxt->context, arg2);
11311                 break;
11312             }
11313 
11314             if ((arg2->nodesetval != NULL) &&
11315                 (arg2->nodesetval->nodeNr != 0)) {
11316                 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11317                                                         arg2->nodesetval);
11318                 if (arg1->nodesetval == NULL)
11319                     xmlXPathPErrMemory(ctxt);
11320             }
11321             valuePush(ctxt, arg1);
11322 	    xmlXPathReleaseObject(ctxt->context, arg2);
11323             /* optimizer */
11324 	    if (total > cur)
11325 		xmlXPathCompSwap(op);
11326             total += cur;
11327             break;
11328         case XPATH_OP_ROOT:
11329             xmlXPathRoot(ctxt);
11330             break;
11331         case XPATH_OP_NODE:
11332             if (op->ch1 != -1)
11333                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11334 	    CHECK_ERROR0;
11335             if (op->ch2 != -1)
11336                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11337 	    CHECK_ERROR0;
11338 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11339 		ctxt->context->node));
11340             break;
11341         case XPATH_OP_COLLECT:{
11342                 if (op->ch1 == -1)
11343                     break;
11344 
11345                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11346 		CHECK_ERROR0;
11347 
11348                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
11349                 break;
11350             }
11351         case XPATH_OP_VALUE:
11352             valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11353             break;
11354         case XPATH_OP_SORT:
11355             if (op->ch1 != -1)
11356                 total +=
11357                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
11358                                            last);
11359 	    CHECK_ERROR0;
11360             if ((ctxt->value != NULL)
11361                 && (ctxt->value->type == XPATH_NODESET)
11362                 && (ctxt->value->nodesetval != NULL)
11363 		&& (ctxt->value->nodesetval->nodeNr > 1))
11364                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11365             break;
11366         default:
11367             total += xmlXPathCompOpEval(ctxt, op);
11368             break;
11369     }
11370 
11371     ctxt->context->depth -= 1;
11372     return (total);
11373 }
11374 
11375 #ifdef XP_OPTIMIZED_FILTER_FIRST
11376 static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)11377 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11378 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
11379 {
11380     int total = 0;
11381     xmlXPathCompExprPtr comp;
11382     xmlXPathObjectPtr obj;
11383     xmlNodeSetPtr set;
11384 
11385     CHECK_ERROR0;
11386     comp = ctxt->comp;
11387     /*
11388     * Optimization for ()[last()] selection i.e. the last elem
11389     */
11390     if ((op->ch1 != -1) && (op->ch2 != -1) &&
11391 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11392 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11393 	int f = comp->steps[op->ch2].ch1;
11394 
11395 	if ((f != -1) &&
11396 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11397 	    (comp->steps[f].value5 == NULL) &&
11398 	    (comp->steps[f].value == 0) &&
11399 	    (comp->steps[f].value4 != NULL) &&
11400 	    (xmlStrEqual
11401 	    (comp->steps[f].value4, BAD_CAST "last"))) {
11402 	    xmlNodePtr last = NULL;
11403 
11404 	    total +=
11405 		xmlXPathCompOpEvalLast(ctxt,
11406 		    &comp->steps[op->ch1],
11407 		    &last);
11408 	    CHECK_ERROR0;
11409 	    /*
11410 	    * The nodeset should be in document order,
11411 	    * Keep only the last value
11412 	    */
11413 	    if ((ctxt->value != NULL) &&
11414 		(ctxt->value->type == XPATH_NODESET) &&
11415 		(ctxt->value->nodesetval != NULL) &&
11416 		(ctxt->value->nodesetval->nodeTab != NULL) &&
11417 		(ctxt->value->nodesetval->nodeNr > 1)) {
11418                 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11419 		*first = *(ctxt->value->nodesetval->nodeTab);
11420 	    }
11421 	    return (total);
11422 	}
11423     }
11424 
11425     if (op->ch1 != -1)
11426 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11427     CHECK_ERROR0;
11428     if (op->ch2 == -1)
11429 	return (total);
11430     if (ctxt->value == NULL)
11431 	return (total);
11432 
11433     /*
11434      * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
11435      * the stack. We have to temporarily remove the nodeset object from the
11436      * stack to avoid freeing it prematurely.
11437      */
11438     CHECK_TYPE0(XPATH_NODESET);
11439     obj = valuePop(ctxt);
11440     set = obj->nodesetval;
11441     if (set != NULL) {
11442         xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
11443         if (set->nodeNr > 0)
11444             *first = set->nodeTab[0];
11445     }
11446     valuePush(ctxt, obj);
11447 
11448     return (total);
11449 }
11450 #endif /* XP_OPTIMIZED_FILTER_FIRST */
11451 
11452 /**
11453  * xmlXPathCompOpEval:
11454  * @ctxt:  the XPath parser context with the compiled expression
11455  * @op:  an XPath compiled operation
11456  *
11457  * Evaluate the Precompiled XPath operation
11458  * Returns the number of nodes traversed
11459  */
11460 static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op)11461 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
11462 {
11463     int total = 0;
11464     int equal, ret;
11465     xmlXPathCompExprPtr comp;
11466     xmlXPathObjectPtr arg1, arg2;
11467 
11468     CHECK_ERROR0;
11469     if (OP_LIMIT_EXCEEDED(ctxt, 1))
11470         return(0);
11471     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11472         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11473     ctxt->context->depth += 1;
11474     comp = ctxt->comp;
11475     switch (op->op) {
11476         case XPATH_OP_END:
11477             break;
11478         case XPATH_OP_AND:
11479             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11480 	    CHECK_ERROR0;
11481             xmlXPathBooleanFunction(ctxt, 1);
11482             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
11483                 break;
11484             arg2 = valuePop(ctxt);
11485             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11486 	    if (ctxt->error) {
11487 		xmlXPathFreeObject(arg2);
11488 		break;
11489 	    }
11490             xmlXPathBooleanFunction(ctxt, 1);
11491             if (ctxt->value != NULL)
11492                 ctxt->value->boolval &= arg2->boolval;
11493 	    xmlXPathReleaseObject(ctxt->context, arg2);
11494             break;
11495         case XPATH_OP_OR:
11496             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11497 	    CHECK_ERROR0;
11498             xmlXPathBooleanFunction(ctxt, 1);
11499             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
11500                 break;
11501             arg2 = valuePop(ctxt);
11502             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11503 	    if (ctxt->error) {
11504 		xmlXPathFreeObject(arg2);
11505 		break;
11506 	    }
11507             xmlXPathBooleanFunction(ctxt, 1);
11508             if (ctxt->value != NULL)
11509                 ctxt->value->boolval |= arg2->boolval;
11510 	    xmlXPathReleaseObject(ctxt->context, arg2);
11511             break;
11512         case XPATH_OP_EQUAL:
11513             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11514 	    CHECK_ERROR0;
11515             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11516 	    CHECK_ERROR0;
11517 	    if (op->value)
11518 		equal = xmlXPathEqualValues(ctxt);
11519 	    else
11520 		equal = xmlXPathNotEqualValues(ctxt);
11521 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, equal));
11522             break;
11523         case XPATH_OP_CMP:
11524             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11525 	    CHECK_ERROR0;
11526             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11527 	    CHECK_ERROR0;
11528             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
11529 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
11530             break;
11531         case XPATH_OP_PLUS:
11532             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11533 	    CHECK_ERROR0;
11534             if (op->ch2 != -1) {
11535                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11536 	    }
11537 	    CHECK_ERROR0;
11538             if (op->value == 0)
11539                 xmlXPathSubValues(ctxt);
11540             else if (op->value == 1)
11541                 xmlXPathAddValues(ctxt);
11542             else if (op->value == 2)
11543                 xmlXPathValueFlipSign(ctxt);
11544             else if (op->value == 3) {
11545                 CAST_TO_NUMBER;
11546                 CHECK_TYPE0(XPATH_NUMBER);
11547             }
11548             break;
11549         case XPATH_OP_MULT:
11550             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11551 	    CHECK_ERROR0;
11552             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11553 	    CHECK_ERROR0;
11554             if (op->value == 0)
11555                 xmlXPathMultValues(ctxt);
11556             else if (op->value == 1)
11557                 xmlXPathDivValues(ctxt);
11558             else if (op->value == 2)
11559                 xmlXPathModValues(ctxt);
11560             break;
11561         case XPATH_OP_UNION:
11562             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11563 	    CHECK_ERROR0;
11564             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11565 	    CHECK_ERROR0;
11566 
11567             arg2 = valuePop(ctxt);
11568             arg1 = valuePop(ctxt);
11569             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11570                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11571 	        xmlXPathReleaseObject(ctxt->context, arg1);
11572 	        xmlXPathReleaseObject(ctxt->context, arg2);
11573                 XP_ERROR0(XPATH_INVALID_TYPE);
11574             }
11575             if ((ctxt->context->opLimit != 0) &&
11576                 (((arg1->nodesetval != NULL) &&
11577                   (xmlXPathCheckOpLimit(ctxt,
11578                                         arg1->nodesetval->nodeNr) < 0)) ||
11579                  ((arg2->nodesetval != NULL) &&
11580                   (xmlXPathCheckOpLimit(ctxt,
11581                                         arg2->nodesetval->nodeNr) < 0)))) {
11582 	        xmlXPathReleaseObject(ctxt->context, arg1);
11583 	        xmlXPathReleaseObject(ctxt->context, arg2);
11584                 break;
11585             }
11586 
11587 	    if (((arg2->nodesetval != NULL) &&
11588 		 (arg2->nodesetval->nodeNr != 0)))
11589 	    {
11590 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11591 							arg2->nodesetval);
11592                 if (arg1->nodesetval == NULL)
11593                     xmlXPathPErrMemory(ctxt);
11594 	    }
11595 
11596             valuePush(ctxt, arg1);
11597 	    xmlXPathReleaseObject(ctxt->context, arg2);
11598             break;
11599         case XPATH_OP_ROOT:
11600             xmlXPathRoot(ctxt);
11601             break;
11602         case XPATH_OP_NODE:
11603             if (op->ch1 != -1)
11604                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11605 	    CHECK_ERROR0;
11606             if (op->ch2 != -1)
11607                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11608 	    CHECK_ERROR0;
11609 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11610                                                     ctxt->context->node));
11611             break;
11612         case XPATH_OP_COLLECT:{
11613                 if (op->ch1 == -1)
11614                     break;
11615 
11616                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11617 		CHECK_ERROR0;
11618 
11619                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
11620                 break;
11621             }
11622         case XPATH_OP_VALUE:
11623             valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11624             break;
11625         case XPATH_OP_VARIABLE:{
11626 		xmlXPathObjectPtr val;
11627 
11628                 if (op->ch1 != -1)
11629                     total +=
11630                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11631                 if (op->value5 == NULL) {
11632 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
11633 		    if (val == NULL)
11634 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
11635                     valuePush(ctxt, val);
11636 		} else {
11637                     const xmlChar *URI;
11638 
11639                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
11640                     if (URI == NULL) {
11641                         XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11642                         break;
11643                     }
11644 		    val = xmlXPathVariableLookupNS(ctxt->context,
11645                                                        op->value4, URI);
11646 		    if (val == NULL)
11647 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
11648                     valuePush(ctxt, val);
11649                 }
11650                 break;
11651             }
11652         case XPATH_OP_FUNCTION:{
11653                 xmlXPathFunction func;
11654                 const xmlChar *oldFunc, *oldFuncURI;
11655 		int i;
11656                 int frame;
11657 
11658                 frame = ctxt->valueNr;
11659                 if (op->ch1 != -1) {
11660                     total +=
11661                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11662                     if (ctxt->error != XPATH_EXPRESSION_OK)
11663                         break;
11664                 }
11665 		if (ctxt->valueNr < frame + op->value)
11666 		    XP_ERROR0(XPATH_INVALID_OPERAND);
11667 		for (i = 0; i < op->value; i++) {
11668 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL)
11669 			XP_ERROR0(XPATH_INVALID_OPERAND);
11670                 }
11671                 if (op->cache != NULL)
11672                     func = op->cache;
11673                 else {
11674                     const xmlChar *URI = NULL;
11675 
11676                     if (op->value5 == NULL)
11677                         func =
11678                             xmlXPathFunctionLookup(ctxt->context,
11679                                                    op->value4);
11680                     else {
11681                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
11682                         if (URI == NULL)
11683                             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11684                         func = xmlXPathFunctionLookupNS(ctxt->context,
11685                                                         op->value4, URI);
11686                     }
11687                     if (func == NULL)
11688                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
11689                     op->cache = func;
11690                     op->cacheURI = (void *) URI;
11691                 }
11692                 oldFunc = ctxt->context->function;
11693                 oldFuncURI = ctxt->context->functionURI;
11694                 ctxt->context->function = op->value4;
11695                 ctxt->context->functionURI = op->cacheURI;
11696                 func(ctxt, op->value);
11697                 ctxt->context->function = oldFunc;
11698                 ctxt->context->functionURI = oldFuncURI;
11699                 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
11700                     (ctxt->valueNr != frame + 1))
11701                     XP_ERROR0(XPATH_STACK_ERROR);
11702                 break;
11703             }
11704         case XPATH_OP_ARG:
11705             if (op->ch1 != -1) {
11706                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11707 	        CHECK_ERROR0;
11708             }
11709             if (op->ch2 != -1) {
11710                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11711 	        CHECK_ERROR0;
11712 	    }
11713             break;
11714         case XPATH_OP_PREDICATE:
11715         case XPATH_OP_FILTER:{
11716                 xmlXPathObjectPtr obj;
11717                 xmlNodeSetPtr set;
11718 
11719                 /*
11720                  * Optimization for ()[1] selection i.e. the first elem
11721                  */
11722                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
11723 #ifdef XP_OPTIMIZED_FILTER_FIRST
11724 		    /*
11725 		    * FILTER TODO: Can we assume that the inner processing
11726 		    *  will result in an ordered list if we have an
11727 		    *  XPATH_OP_FILTER?
11728 		    *  What about an additional field or flag on
11729 		    *  xmlXPathObject like @sorted ? This way we wouldn't need
11730 		    *  to assume anything, so it would be more robust and
11731 		    *  easier to optimize.
11732 		    */
11733                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
11734 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
11735 #else
11736 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11737 #endif
11738                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
11739                     xmlXPathObjectPtr val;
11740 
11741                     val = comp->steps[op->ch2].value4;
11742                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
11743                         (val->floatval == 1.0)) {
11744                         xmlNodePtr first = NULL;
11745 
11746                         total +=
11747                             xmlXPathCompOpEvalFirst(ctxt,
11748                                                     &comp->steps[op->ch1],
11749                                                     &first);
11750 			CHECK_ERROR0;
11751                         /*
11752                          * The nodeset should be in document order,
11753                          * Keep only the first value
11754                          */
11755                         if ((ctxt->value != NULL) &&
11756                             (ctxt->value->type == XPATH_NODESET) &&
11757                             (ctxt->value->nodesetval != NULL) &&
11758                             (ctxt->value->nodesetval->nodeNr > 1))
11759                             xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
11760                                                         1, 1);
11761                         break;
11762                     }
11763                 }
11764                 /*
11765                  * Optimization for ()[last()] selection i.e. the last elem
11766                  */
11767                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
11768                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11769                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11770                     int f = comp->steps[op->ch2].ch1;
11771 
11772                     if ((f != -1) &&
11773                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11774                         (comp->steps[f].value5 == NULL) &&
11775                         (comp->steps[f].value == 0) &&
11776                         (comp->steps[f].value4 != NULL) &&
11777                         (xmlStrEqual
11778                          (comp->steps[f].value4, BAD_CAST "last"))) {
11779                         xmlNodePtr last = NULL;
11780 
11781                         total +=
11782                             xmlXPathCompOpEvalLast(ctxt,
11783                                                    &comp->steps[op->ch1],
11784                                                    &last);
11785 			CHECK_ERROR0;
11786                         /*
11787                          * The nodeset should be in document order,
11788                          * Keep only the last value
11789                          */
11790                         if ((ctxt->value != NULL) &&
11791                             (ctxt->value->type == XPATH_NODESET) &&
11792                             (ctxt->value->nodesetval != NULL) &&
11793                             (ctxt->value->nodesetval->nodeTab != NULL) &&
11794                             (ctxt->value->nodesetval->nodeNr > 1))
11795                             xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11796                         break;
11797                     }
11798                 }
11799 		/*
11800 		* Process inner predicates first.
11801 		* Example "index[parent::book][1]":
11802 		* ...
11803 		*   PREDICATE   <-- we are here "[1]"
11804 		*     PREDICATE <-- process "[parent::book]" first
11805 		*       SORT
11806 		*         COLLECT  'parent' 'name' 'node' book
11807 		*           NODE
11808 		*     ELEM Object is a number : 1
11809 		*/
11810                 if (op->ch1 != -1)
11811                     total +=
11812                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11813 		CHECK_ERROR0;
11814                 if (op->ch2 == -1)
11815                     break;
11816                 if (ctxt->value == NULL)
11817                     break;
11818 
11819                 /*
11820                  * In case of errors, xmlXPathNodeSetFilter can pop additional
11821                  * nodes from the stack. We have to temporarily remove the
11822                  * nodeset object from the stack to avoid freeing it
11823                  * prematurely.
11824                  */
11825                 CHECK_TYPE0(XPATH_NODESET);
11826                 obj = valuePop(ctxt);
11827                 set = obj->nodesetval;
11828                 if (set != NULL)
11829                     xmlXPathNodeSetFilter(ctxt, set, op->ch2,
11830                                           1, set->nodeNr, 1);
11831                 valuePush(ctxt, obj);
11832                 break;
11833             }
11834         case XPATH_OP_SORT:
11835             if (op->ch1 != -1)
11836                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11837 	    CHECK_ERROR0;
11838             if ((ctxt->value != NULL) &&
11839                 (ctxt->value->type == XPATH_NODESET) &&
11840                 (ctxt->value->nodesetval != NULL) &&
11841 		(ctxt->value->nodesetval->nodeNr > 1))
11842 	    {
11843                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11844 	    }
11845             break;
11846         default:
11847             XP_ERROR0(XPATH_INVALID_OPERAND);
11848             break;
11849     }
11850 
11851     ctxt->context->depth -= 1;
11852     return (total);
11853 }
11854 
11855 /**
11856  * xmlXPathCompOpEvalToBoolean:
11857  * @ctxt:  the XPath parser context
11858  *
11859  * Evaluates if the expression evaluates to true.
11860  *
11861  * Returns 1 if true, 0 if false and -1 on API or internal errors.
11862  */
11863 static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int isPredicate)11864 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
11865 			    xmlXPathStepOpPtr op,
11866 			    int isPredicate)
11867 {
11868     xmlXPathObjectPtr resObj = NULL;
11869 
11870 start:
11871     if (OP_LIMIT_EXCEEDED(ctxt, 1))
11872         return(0);
11873     /* comp = ctxt->comp; */
11874     switch (op->op) {
11875         case XPATH_OP_END:
11876             return (0);
11877 	case XPATH_OP_VALUE:
11878 	    resObj = (xmlXPathObjectPtr) op->value4;
11879 	    if (isPredicate)
11880 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
11881 	    return(xmlXPathCastToBoolean(resObj));
11882 	case XPATH_OP_SORT:
11883 	    /*
11884 	    * We don't need sorting for boolean results. Skip this one.
11885 	    */
11886             if (op->ch1 != -1) {
11887 		op = &ctxt->comp->steps[op->ch1];
11888 		goto start;
11889 	    }
11890 	    return(0);
11891 	case XPATH_OP_COLLECT:
11892 	    if (op->ch1 == -1)
11893 		return(0);
11894 
11895             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
11896 	    if (ctxt->error != XPATH_EXPRESSION_OK)
11897 		return(-1);
11898 
11899             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
11900 	    if (ctxt->error != XPATH_EXPRESSION_OK)
11901 		return(-1);
11902 
11903 	    resObj = valuePop(ctxt);
11904 	    if (resObj == NULL)
11905 		return(-1);
11906 	    break;
11907 	default:
11908 	    /*
11909 	    * Fallback to call xmlXPathCompOpEval().
11910 	    */
11911 	    xmlXPathCompOpEval(ctxt, op);
11912 	    if (ctxt->error != XPATH_EXPRESSION_OK)
11913 		return(-1);
11914 
11915 	    resObj = valuePop(ctxt);
11916 	    if (resObj == NULL)
11917 		return(-1);
11918 	    break;
11919     }
11920 
11921     if (resObj) {
11922 	int res;
11923 
11924 	if (resObj->type == XPATH_BOOLEAN) {
11925 	    res = resObj->boolval;
11926 	} else if (isPredicate) {
11927 	    /*
11928 	    * For predicates a result of type "number" is handled
11929 	    * differently:
11930 	    * SPEC XPath 1.0:
11931 	    * "If the result is a number, the result will be converted
11932 	    *  to true if the number is equal to the context position
11933 	    *  and will be converted to false otherwise;"
11934 	    */
11935 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
11936 	} else {
11937 	    res = xmlXPathCastToBoolean(resObj);
11938 	}
11939 	xmlXPathReleaseObject(ctxt->context, resObj);
11940 	return(res);
11941     }
11942 
11943     return(0);
11944 }
11945 
11946 #ifdef XPATH_STREAMING
11947 /**
11948  * xmlXPathRunStreamEval:
11949  * @pctxt:  the XPath parser context with the compiled expression
11950  *
11951  * Evaluate the Precompiled Streamable XPath expression in the given context.
11952  */
11953 static int
xmlXPathRunStreamEval(xmlXPathParserContextPtr pctxt,xmlPatternPtr comp,xmlXPathObjectPtr * resultSeq,int toBool)11954 xmlXPathRunStreamEval(xmlXPathParserContextPtr pctxt, xmlPatternPtr comp,
11955 		      xmlXPathObjectPtr *resultSeq, int toBool)
11956 {
11957     int max_depth, min_depth;
11958     int from_root;
11959     int ret, depth;
11960     int eval_all_nodes;
11961     xmlNodePtr cur = NULL, limit = NULL;
11962     xmlStreamCtxtPtr patstream = NULL;
11963     xmlXPathContextPtr ctxt = pctxt->context;
11964 
11965     if ((ctxt == NULL) || (comp == NULL))
11966         return(-1);
11967     max_depth = xmlPatternMaxDepth(comp);
11968     if (max_depth == -1)
11969         return(-1);
11970     if (max_depth == -2)
11971         max_depth = 10000;
11972     min_depth = xmlPatternMinDepth(comp);
11973     if (min_depth == -1)
11974         return(-1);
11975     from_root = xmlPatternFromRoot(comp);
11976     if (from_root < 0)
11977         return(-1);
11978 #if 0
11979     printf("stream eval: depth %d from root %d\n", max_depth, from_root);
11980 #endif
11981 
11982     if (! toBool) {
11983 	if (resultSeq == NULL)
11984 	    return(-1);
11985 	*resultSeq = xmlXPathCacheNewNodeSet(pctxt, NULL);
11986 	if (*resultSeq == NULL)
11987 	    return(-1);
11988     }
11989 
11990     /*
11991      * handle the special cases of "/" amd "." being matched
11992      */
11993     if (min_depth == 0) {
11994         int res;
11995 
11996 	if (from_root) {
11997 	    /* Select "/" */
11998 	    if (toBool)
11999 		return(1);
12000             res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
12001                                            (xmlNodePtr) ctxt->doc);
12002 	} else {
12003 	    /* Select "self::node()" */
12004 	    if (toBool)
12005 		return(1);
12006             res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
12007                                            ctxt->node);
12008 	}
12009 
12010         if (res < 0)
12011             xmlXPathPErrMemory(pctxt);
12012     }
12013     if (max_depth == 0) {
12014 	return(0);
12015     }
12016 
12017     if (from_root) {
12018         cur = (xmlNodePtr)ctxt->doc;
12019     } else if (ctxt->node != NULL) {
12020         switch (ctxt->node->type) {
12021             case XML_ELEMENT_NODE:
12022             case XML_DOCUMENT_NODE:
12023             case XML_DOCUMENT_FRAG_NODE:
12024             case XML_HTML_DOCUMENT_NODE:
12025 	        cur = ctxt->node;
12026 		break;
12027             case XML_ATTRIBUTE_NODE:
12028             case XML_TEXT_NODE:
12029             case XML_CDATA_SECTION_NODE:
12030             case XML_ENTITY_REF_NODE:
12031             case XML_ENTITY_NODE:
12032             case XML_PI_NODE:
12033             case XML_COMMENT_NODE:
12034             case XML_NOTATION_NODE:
12035             case XML_DTD_NODE:
12036             case XML_DOCUMENT_TYPE_NODE:
12037             case XML_ELEMENT_DECL:
12038             case XML_ATTRIBUTE_DECL:
12039             case XML_ENTITY_DECL:
12040             case XML_NAMESPACE_DECL:
12041             case XML_XINCLUDE_START:
12042             case XML_XINCLUDE_END:
12043 		break;
12044 	}
12045 	limit = cur;
12046     }
12047     if (cur == NULL) {
12048         return(0);
12049     }
12050 
12051     patstream = xmlPatternGetStreamCtxt(comp);
12052     if (patstream == NULL) {
12053         xmlXPathPErrMemory(pctxt);
12054 	return(-1);
12055     }
12056 
12057     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
12058 
12059     if (from_root) {
12060 	ret = xmlStreamPush(patstream, NULL, NULL);
12061 	if (ret < 0) {
12062 	} else if (ret == 1) {
12063 	    if (toBool)
12064 		goto return_1;
12065 	    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) < 0)
12066                 xmlXPathPErrMemory(pctxt);
12067 	}
12068     }
12069     depth = 0;
12070     goto scan_children;
12071 next_node:
12072     do {
12073         if (ctxt->opLimit != 0) {
12074             if (ctxt->opCount >= ctxt->opLimit) {
12075                 xmlXPathErr(ctxt, XPATH_RECURSION_LIMIT_EXCEEDED);
12076                 xmlFreeStreamCtxt(patstream);
12077                 return(-1);
12078             }
12079             ctxt->opCount++;
12080         }
12081 
12082 	switch (cur->type) {
12083 	    case XML_ELEMENT_NODE:
12084 	    case XML_TEXT_NODE:
12085 	    case XML_CDATA_SECTION_NODE:
12086 	    case XML_COMMENT_NODE:
12087 	    case XML_PI_NODE:
12088 		if (cur->type == XML_ELEMENT_NODE) {
12089 		    ret = xmlStreamPush(patstream, cur->name,
12090 				(cur->ns ? cur->ns->href : NULL));
12091 		} else if (eval_all_nodes)
12092 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
12093 		else
12094 		    break;
12095 
12096 		if (ret < 0) {
12097 		    xmlXPathPErrMemory(pctxt);
12098 		} else if (ret == 1) {
12099 		    if (toBool)
12100 			goto return_1;
12101 		    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
12102                                                  cur) < 0)
12103                         xmlXPathPErrMemory(pctxt);
12104 		}
12105 		if ((cur->children == NULL) || (depth >= max_depth)) {
12106 		    ret = xmlStreamPop(patstream);
12107 		    while (cur->next != NULL) {
12108 			cur = cur->next;
12109 			if ((cur->type != XML_ENTITY_DECL) &&
12110 			    (cur->type != XML_DTD_NODE))
12111 			    goto next_node;
12112 		    }
12113 		}
12114 	    default:
12115 		break;
12116 	}
12117 
12118 scan_children:
12119 	if (cur->type == XML_NAMESPACE_DECL) break;
12120 	if ((cur->children != NULL) && (depth < max_depth)) {
12121 	    /*
12122 	     * Do not descend on entities declarations
12123 	     */
12124 	    if (cur->children->type != XML_ENTITY_DECL) {
12125 		cur = cur->children;
12126 		depth++;
12127 		/*
12128 		 * Skip DTDs
12129 		 */
12130 		if (cur->type != XML_DTD_NODE)
12131 		    continue;
12132 	    }
12133 	}
12134 
12135 	if (cur == limit)
12136 	    break;
12137 
12138 	while (cur->next != NULL) {
12139 	    cur = cur->next;
12140 	    if ((cur->type != XML_ENTITY_DECL) &&
12141 		(cur->type != XML_DTD_NODE))
12142 		goto next_node;
12143 	}
12144 
12145 	do {
12146 	    cur = cur->parent;
12147 	    depth--;
12148 	    if ((cur == NULL) || (cur == limit) ||
12149                 (cur->type == XML_DOCUMENT_NODE))
12150 	        goto done;
12151 	    if (cur->type == XML_ELEMENT_NODE) {
12152 		ret = xmlStreamPop(patstream);
12153 	    } else if ((eval_all_nodes) &&
12154 		((cur->type == XML_TEXT_NODE) ||
12155 		 (cur->type == XML_CDATA_SECTION_NODE) ||
12156 		 (cur->type == XML_COMMENT_NODE) ||
12157 		 (cur->type == XML_PI_NODE)))
12158 	    {
12159 		ret = xmlStreamPop(patstream);
12160 	    }
12161 	    if (cur->next != NULL) {
12162 		cur = cur->next;
12163 		break;
12164 	    }
12165 	} while (cur != NULL);
12166 
12167     } while ((cur != NULL) && (depth >= 0));
12168 
12169 done:
12170 
12171     if (patstream)
12172 	xmlFreeStreamCtxt(patstream);
12173     return(0);
12174 
12175 return_1:
12176     if (patstream)
12177 	xmlFreeStreamCtxt(patstream);
12178     return(1);
12179 }
12180 #endif /* XPATH_STREAMING */
12181 
12182 /**
12183  * xmlXPathRunEval:
12184  * @ctxt:  the XPath parser context with the compiled expression
12185  * @toBool:  evaluate to a boolean result
12186  *
12187  * Evaluate the Precompiled XPath expression in the given context.
12188  */
12189 static int
xmlXPathRunEval(xmlXPathParserContextPtr ctxt,int toBool)12190 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
12191 {
12192     xmlXPathCompExprPtr comp;
12193     int oldDepth;
12194 
12195     if ((ctxt == NULL) || (ctxt->comp == NULL))
12196 	return(-1);
12197 
12198     if (ctxt->valueTab == NULL) {
12199 	/* Allocate the value stack */
12200 	ctxt->valueTab = (xmlXPathObjectPtr *)
12201 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
12202 	if (ctxt->valueTab == NULL) {
12203 	    xmlXPathPErrMemory(ctxt);
12204 	    return(-1);
12205 	}
12206 	ctxt->valueNr = 0;
12207 	ctxt->valueMax = 10;
12208 	ctxt->value = NULL;
12209     }
12210 #ifdef XPATH_STREAMING
12211     if (ctxt->comp->stream) {
12212 	int res;
12213 
12214 	if (toBool) {
12215 	    /*
12216 	    * Evaluation to boolean result.
12217 	    */
12218 	    res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, NULL, 1);
12219 	    if (res != -1)
12220 		return(res);
12221 	} else {
12222 	    xmlXPathObjectPtr resObj = NULL;
12223 
12224 	    /*
12225 	    * Evaluation to a sequence.
12226 	    */
12227 	    res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, &resObj, 0);
12228 
12229 	    if ((res != -1) && (resObj != NULL)) {
12230 		valuePush(ctxt, resObj);
12231 		return(0);
12232 	    }
12233 	    if (resObj != NULL)
12234 		xmlXPathReleaseObject(ctxt->context, resObj);
12235 	}
12236 	/*
12237 	* QUESTION TODO: This falls back to normal XPath evaluation
12238 	* if res == -1. Is this intended?
12239 	*/
12240     }
12241 #endif
12242     comp = ctxt->comp;
12243     if (comp->last < 0) {
12244         xmlXPathErr(ctxt, XPATH_STACK_ERROR);
12245 	return(-1);
12246     }
12247     oldDepth = ctxt->context->depth;
12248     if (toBool)
12249 	return(xmlXPathCompOpEvalToBoolean(ctxt,
12250 	    &comp->steps[comp->last], 0));
12251     else
12252 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
12253     ctxt->context->depth = oldDepth;
12254 
12255     return(0);
12256 }
12257 
12258 /************************************************************************
12259  *									*
12260  *			Public interfaces				*
12261  *									*
12262  ************************************************************************/
12263 
12264 /**
12265  * xmlXPathEvalPredicate:
12266  * @ctxt:  the XPath context
12267  * @res:  the Predicate Expression evaluation result
12268  *
12269  * Evaluate a predicate result for the current node.
12270  * A PredicateExpr is evaluated by evaluating the Expr and converting
12271  * the result to a boolean. If the result is a number, the result will
12272  * be converted to true if the number is equal to the position of the
12273  * context node in the context node list (as returned by the position
12274  * function) and will be converted to false otherwise; if the result
12275  * is not a number, then the result will be converted as if by a call
12276  * to the boolean function.
12277  *
12278  * Returns 1 if predicate is true, 0 otherwise
12279  */
12280 int
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt,xmlXPathObjectPtr res)12281 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
12282     if ((ctxt == NULL) || (res == NULL)) return(0);
12283     switch (res->type) {
12284         case XPATH_BOOLEAN:
12285 	    return(res->boolval);
12286         case XPATH_NUMBER:
12287 	    return(res->floatval == ctxt->proximityPosition);
12288         case XPATH_NODESET:
12289         case XPATH_XSLT_TREE:
12290 	    if (res->nodesetval == NULL)
12291 		return(0);
12292 	    return(res->nodesetval->nodeNr != 0);
12293         case XPATH_STRING:
12294 	    return((res->stringval != NULL) &&
12295 	           (xmlStrlen(res->stringval) != 0));
12296         default:
12297 	    break;
12298     }
12299     return(0);
12300 }
12301 
12302 /**
12303  * xmlXPathEvaluatePredicateResult:
12304  * @ctxt:  the XPath Parser context
12305  * @res:  the Predicate Expression evaluation result
12306  *
12307  * Evaluate a predicate result for the current node.
12308  * A PredicateExpr is evaluated by evaluating the Expr and converting
12309  * the result to a boolean. If the result is a number, the result will
12310  * be converted to true if the number is equal to the position of the
12311  * context node in the context node list (as returned by the position
12312  * function) and will be converted to false otherwise; if the result
12313  * is not a number, then the result will be converted as if by a call
12314  * to the boolean function.
12315  *
12316  * Returns 1 if predicate is true, 0 otherwise
12317  */
12318 int
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr res)12319 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
12320                                 xmlXPathObjectPtr res) {
12321     if ((ctxt == NULL) || (res == NULL)) return(0);
12322     switch (res->type) {
12323         case XPATH_BOOLEAN:
12324 	    return(res->boolval);
12325         case XPATH_NUMBER:
12326 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
12327 	    return((res->floatval == ctxt->context->proximityPosition) &&
12328 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
12329 #else
12330 	    return(res->floatval == ctxt->context->proximityPosition);
12331 #endif
12332         case XPATH_NODESET:
12333         case XPATH_XSLT_TREE:
12334 	    if (res->nodesetval == NULL)
12335 		return(0);
12336 	    return(res->nodesetval->nodeNr != 0);
12337         case XPATH_STRING:
12338 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
12339         default:
12340 	    break;
12341     }
12342     return(0);
12343 }
12344 
12345 #ifdef XPATH_STREAMING
12346 /**
12347  * xmlXPathTryStreamCompile:
12348  * @ctxt: an XPath context
12349  * @str:  the XPath expression
12350  *
12351  * Try to compile the XPath expression as a streamable subset.
12352  *
12353  * Returns the compiled expression or NULL if failed to compile.
12354  */
12355 static xmlXPathCompExprPtr
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt,const xmlChar * str)12356 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
12357     /*
12358      * Optimization: use streaming patterns when the XPath expression can
12359      * be compiled to a stream lookup
12360      */
12361     xmlPatternPtr stream;
12362     xmlXPathCompExprPtr comp;
12363     xmlDictPtr dict = NULL;
12364     const xmlChar **namespaces = NULL;
12365     xmlNsPtr ns;
12366     int i, j;
12367 
12368     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
12369         (!xmlStrchr(str, '@'))) {
12370 	const xmlChar *tmp;
12371         int res;
12372 
12373 	/*
12374 	 * We don't try to handle expressions using the verbose axis
12375 	 * specifiers ("::"), just the simplified form at this point.
12376 	 * Additionally, if there is no list of namespaces available and
12377 	 *  there's a ":" in the expression, indicating a prefixed QName,
12378 	 *  then we won't try to compile either. xmlPatterncompile() needs
12379 	 *  to have a list of namespaces at compilation time in order to
12380 	 *  compile prefixed name tests.
12381 	 */
12382 	tmp = xmlStrchr(str, ':');
12383 	if ((tmp != NULL) &&
12384 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
12385 	    return(NULL);
12386 
12387 	if (ctxt != NULL) {
12388 	    dict = ctxt->dict;
12389 	    if (ctxt->nsNr > 0) {
12390 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
12391 		if (namespaces == NULL) {
12392 		    xmlXPathErrMemory(ctxt);
12393 		    return(NULL);
12394 		}
12395 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
12396 		    ns = ctxt->namespaces[j];
12397 		    namespaces[i++] = ns->href;
12398 		    namespaces[i++] = ns->prefix;
12399 		}
12400 		namespaces[i++] = NULL;
12401 		namespaces[i] = NULL;
12402 	    }
12403 	}
12404 
12405 	res = xmlPatternCompileSafe(str, dict, XML_PATTERN_XPATH, namespaces,
12406                                     &stream);
12407 	if (namespaces != NULL) {
12408 	    xmlFree((xmlChar **)namespaces);
12409 	}
12410         if (res < 0) {
12411             xmlXPathErrMemory(ctxt);
12412             return(NULL);
12413         }
12414 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
12415 	    comp = xmlXPathNewCompExpr();
12416 	    if (comp == NULL) {
12417 		xmlXPathErrMemory(ctxt);
12418 	        xmlFreePattern(stream);
12419 		return(NULL);
12420 	    }
12421 	    comp->stream = stream;
12422 	    comp->dict = dict;
12423 	    if (comp->dict)
12424 		xmlDictReference(comp->dict);
12425 	    return(comp);
12426 	}
12427 	xmlFreePattern(stream);
12428     }
12429     return(NULL);
12430 }
12431 #endif /* XPATH_STREAMING */
12432 
12433 static void
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,xmlXPathStepOpPtr op)12434 xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
12435                            xmlXPathStepOpPtr op)
12436 {
12437     xmlXPathCompExprPtr comp = pctxt->comp;
12438     xmlXPathContextPtr ctxt;
12439 
12440     /*
12441     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
12442     * internal representation.
12443     */
12444 
12445     if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
12446         (op->ch1 != -1) &&
12447         (op->ch2 == -1 /* no predicate */))
12448     {
12449         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
12450 
12451         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
12452             ((xmlXPathAxisVal) prevop->value ==
12453                 AXIS_DESCENDANT_OR_SELF) &&
12454             (prevop->ch2 == -1) &&
12455             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
12456             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
12457         {
12458             /*
12459             * This is a "descendant-or-self::node()" without predicates.
12460             * Try to eliminate it.
12461             */
12462 
12463             switch ((xmlXPathAxisVal) op->value) {
12464                 case AXIS_CHILD:
12465                 case AXIS_DESCENDANT:
12466                     /*
12467                     * Convert "descendant-or-self::node()/child::" or
12468                     * "descendant-or-self::node()/descendant::" to
12469                     * "descendant::"
12470                     */
12471                     op->ch1   = prevop->ch1;
12472                     op->value = AXIS_DESCENDANT;
12473                     break;
12474                 case AXIS_SELF:
12475                 case AXIS_DESCENDANT_OR_SELF:
12476                     /*
12477                     * Convert "descendant-or-self::node()/self::" or
12478                     * "descendant-or-self::node()/descendant-or-self::" to
12479                     * to "descendant-or-self::"
12480                     */
12481                     op->ch1   = prevop->ch1;
12482                     op->value = AXIS_DESCENDANT_OR_SELF;
12483                     break;
12484                 default:
12485                     break;
12486             }
12487 	}
12488     }
12489 
12490     /* OP_VALUE has invalid ch1. */
12491     if (op->op == XPATH_OP_VALUE)
12492         return;
12493 
12494     /* Recurse */
12495     ctxt = pctxt->context;
12496     if (ctxt != NULL) {
12497         if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
12498             return;
12499         ctxt->depth += 1;
12500     }
12501     if (op->ch1 != -1)
12502         xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
12503     if (op->ch2 != -1)
12504 	xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
12505     if (ctxt != NULL)
12506         ctxt->depth -= 1;
12507 }
12508 
12509 /**
12510  * xmlXPathCtxtCompile:
12511  * @ctxt: an XPath context
12512  * @str:  the XPath expression
12513  *
12514  * Compile an XPath expression
12515  *
12516  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
12517  *         the caller has to free the object.
12518  */
12519 xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt,const xmlChar * str)12520 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
12521     xmlXPathParserContextPtr pctxt;
12522     xmlXPathCompExprPtr comp;
12523     int oldDepth = 0;
12524 
12525 #ifdef XPATH_STREAMING
12526     comp = xmlXPathTryStreamCompile(ctxt, str);
12527     if (comp != NULL)
12528         return(comp);
12529 #endif
12530 
12531     xmlInitParser();
12532 
12533     pctxt = xmlXPathNewParserContext(str, ctxt);
12534     if (pctxt == NULL)
12535         return NULL;
12536     if (ctxt != NULL)
12537         oldDepth = ctxt->depth;
12538     xmlXPathCompileExpr(pctxt, 1);
12539     if (ctxt != NULL)
12540         ctxt->depth = oldDepth;
12541 
12542     if( pctxt->error != XPATH_EXPRESSION_OK )
12543     {
12544         xmlXPathFreeParserContext(pctxt);
12545         return(NULL);
12546     }
12547 
12548     if (*pctxt->cur != 0) {
12549 	/*
12550 	 * aleksey: in some cases this line prints *second* error message
12551 	 * (see bug #78858) and probably this should be fixed.
12552 	 * However, we are not sure that all error messages are printed
12553 	 * out in other places. It's not critical so we leave it as-is for now
12554 	 */
12555 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
12556 	comp = NULL;
12557     } else {
12558 	comp = pctxt->comp;
12559 	if ((comp->nbStep > 1) && (comp->last >= 0)) {
12560             if (ctxt != NULL)
12561                 oldDepth = ctxt->depth;
12562 	    xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
12563             if (ctxt != NULL)
12564                 ctxt->depth = oldDepth;
12565 	}
12566 	pctxt->comp = NULL;
12567     }
12568     xmlXPathFreeParserContext(pctxt);
12569 
12570     if (comp != NULL) {
12571 	comp->expr = xmlStrdup(str);
12572     }
12573     return(comp);
12574 }
12575 
12576 /**
12577  * xmlXPathCompile:
12578  * @str:  the XPath expression
12579  *
12580  * Compile an XPath expression
12581  *
12582  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
12583  *         the caller has to free the object.
12584  */
12585 xmlXPathCompExprPtr
xmlXPathCompile(const xmlChar * str)12586 xmlXPathCompile(const xmlChar *str) {
12587     return(xmlXPathCtxtCompile(NULL, str));
12588 }
12589 
12590 /**
12591  * xmlXPathCompiledEvalInternal:
12592  * @comp:  the compiled XPath expression
12593  * @ctxt:  the XPath context
12594  * @resObj: the resulting XPath object or NULL
12595  * @toBool: 1 if only a boolean result is requested
12596  *
12597  * Evaluate the Precompiled XPath expression in the given context.
12598  * The caller has to free @resObj.
12599  *
12600  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12601  *         the caller has to free the object.
12602  */
12603 static int
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt,xmlXPathObjectPtr * resObjPtr,int toBool)12604 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
12605 			     xmlXPathContextPtr ctxt,
12606 			     xmlXPathObjectPtr *resObjPtr,
12607 			     int toBool)
12608 {
12609     xmlXPathParserContextPtr pctxt;
12610     xmlXPathObjectPtr resObj = NULL;
12611 #ifndef LIBXML_THREAD_ENABLED
12612     static int reentance = 0;
12613 #endif
12614     int res;
12615 
12616     if (comp == NULL)
12617 	return(-1);
12618     xmlInitParser();
12619 
12620     xmlResetError(&ctxt->lastError);
12621 
12622 #ifndef LIBXML_THREAD_ENABLED
12623     reentance++;
12624     if (reentance > 1)
12625 	xmlXPathDisableOptimizer = 1;
12626 #endif
12627 
12628     pctxt = xmlXPathCompParserContext(comp, ctxt);
12629     if (pctxt == NULL)
12630         return(-1);
12631     res = xmlXPathRunEval(pctxt, toBool);
12632 
12633     if (pctxt->error == XPATH_EXPRESSION_OK) {
12634         if (pctxt->valueNr != ((toBool) ? 0 : 1))
12635             xmlXPathErr(pctxt, XPATH_STACK_ERROR);
12636         else if (!toBool)
12637             resObj = valuePop(pctxt);
12638     }
12639 
12640     if (resObjPtr)
12641         *resObjPtr = resObj;
12642     else
12643         xmlXPathReleaseObject(ctxt, resObj);
12644 
12645     pctxt->comp = NULL;
12646     xmlXPathFreeParserContext(pctxt);
12647 #ifndef LIBXML_THREAD_ENABLED
12648     reentance--;
12649 #endif
12650 
12651     return(res);
12652 }
12653 
12654 /**
12655  * xmlXPathCompiledEval:
12656  * @comp:  the compiled XPath expression
12657  * @ctx:  the XPath context
12658  *
12659  * Evaluate the Precompiled XPath expression in the given context.
12660  *
12661  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12662  *         the caller has to free the object.
12663  */
12664 xmlXPathObjectPtr
xmlXPathCompiledEval(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctx)12665 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
12666 {
12667     xmlXPathObjectPtr res = NULL;
12668 
12669     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
12670     return(res);
12671 }
12672 
12673 /**
12674  * xmlXPathCompiledEvalToBoolean:
12675  * @comp:  the compiled XPath expression
12676  * @ctxt:  the XPath context
12677  *
12678  * Applies the XPath boolean() function on the result of the given
12679  * compiled expression.
12680  *
12681  * Returns 1 if the expression evaluated to true, 0 if to false and
12682  *         -1 in API and internal errors.
12683  */
12684 int
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)12685 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
12686 			      xmlXPathContextPtr ctxt)
12687 {
12688     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
12689 }
12690 
12691 /**
12692  * xmlXPathEvalExpr:
12693  * @ctxt:  the XPath Parser context
12694  *
12695  * Parse and evaluate an XPath expression in the given context,
12696  * then push the result on the context stack
12697  */
12698 void
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt)12699 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
12700 #ifdef XPATH_STREAMING
12701     xmlXPathCompExprPtr comp;
12702 #endif
12703     int oldDepth = 0;
12704 
12705     if (ctxt == NULL)
12706         return;
12707     if (ctxt->context->lastError.code != 0)
12708         return;
12709 
12710 #ifdef XPATH_STREAMING
12711     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
12712     if ((comp == NULL) &&
12713         (ctxt->context->lastError.code == XML_ERR_NO_MEMORY)) {
12714         xmlXPathPErrMemory(ctxt);
12715         return;
12716     }
12717     if (comp != NULL) {
12718         if (ctxt->comp != NULL)
12719 	    xmlXPathFreeCompExpr(ctxt->comp);
12720         ctxt->comp = comp;
12721     } else
12722 #endif
12723     {
12724         if (ctxt->context != NULL)
12725             oldDepth = ctxt->context->depth;
12726 	xmlXPathCompileExpr(ctxt, 1);
12727         if (ctxt->context != NULL)
12728             ctxt->context->depth = oldDepth;
12729         CHECK_ERROR;
12730 
12731         /* Check for trailing characters. */
12732         if (*ctxt->cur != 0)
12733             XP_ERROR(XPATH_EXPR_ERROR);
12734 
12735 	if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
12736             if (ctxt->context != NULL)
12737                 oldDepth = ctxt->context->depth;
12738 	    xmlXPathOptimizeExpression(ctxt,
12739 		&ctxt->comp->steps[ctxt->comp->last]);
12740             if (ctxt->context != NULL)
12741                 ctxt->context->depth = oldDepth;
12742         }
12743     }
12744 
12745     xmlXPathRunEval(ctxt, 0);
12746 }
12747 
12748 /**
12749  * xmlXPathEval:
12750  * @str:  the XPath expression
12751  * @ctx:  the XPath context
12752  *
12753  * Evaluate the XPath Location Path in the given context.
12754  *
12755  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12756  *         the caller has to free the object.
12757  */
12758 xmlXPathObjectPtr
xmlXPathEval(const xmlChar * str,xmlXPathContextPtr ctx)12759 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
12760     xmlXPathParserContextPtr ctxt;
12761     xmlXPathObjectPtr res;
12762 
12763     if (ctx == NULL)
12764         return(NULL);
12765 
12766     xmlInitParser();
12767 
12768     xmlResetError(&ctx->lastError);
12769 
12770     ctxt = xmlXPathNewParserContext(str, ctx);
12771     if (ctxt == NULL)
12772         return NULL;
12773     xmlXPathEvalExpr(ctxt);
12774 
12775     if (ctxt->error != XPATH_EXPRESSION_OK) {
12776 	res = NULL;
12777     } else if (ctxt->valueNr != 1) {
12778         xmlXPathErr(ctxt, XPATH_STACK_ERROR);
12779 	res = NULL;
12780     } else {
12781 	res = valuePop(ctxt);
12782     }
12783 
12784     xmlXPathFreeParserContext(ctxt);
12785     return(res);
12786 }
12787 
12788 /**
12789  * xmlXPathSetContextNode:
12790  * @node: the node to to use as the context node
12791  * @ctx:  the XPath context
12792  *
12793  * Sets 'node' as the context node. The node must be in the same
12794  * document as that associated with the context.
12795  *
12796  * Returns -1 in case of error or 0 if successful
12797  */
12798 int
xmlXPathSetContextNode(xmlNodePtr node,xmlXPathContextPtr ctx)12799 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
12800     if ((node == NULL) || (ctx == NULL))
12801         return(-1);
12802 
12803     if (node->doc == ctx->doc) {
12804         ctx->node = node;
12805 	return(0);
12806     }
12807     return(-1);
12808 }
12809 
12810 /**
12811  * xmlXPathNodeEval:
12812  * @node: the node to to use as the context node
12813  * @str:  the XPath expression
12814  * @ctx:  the XPath context
12815  *
12816  * Evaluate the XPath Location Path in the given context. The node 'node'
12817  * is set as the context node. The context node is not restored.
12818  *
12819  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12820  *         the caller has to free the object.
12821  */
12822 xmlXPathObjectPtr
xmlXPathNodeEval(xmlNodePtr node,const xmlChar * str,xmlXPathContextPtr ctx)12823 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
12824     if (str == NULL)
12825         return(NULL);
12826     if (xmlXPathSetContextNode(node, ctx) < 0)
12827         return(NULL);
12828     return(xmlXPathEval(str, ctx));
12829 }
12830 
12831 /**
12832  * xmlXPathEvalExpression:
12833  * @str:  the XPath expression
12834  * @ctxt:  the XPath context
12835  *
12836  * Alias for xmlXPathEval().
12837  *
12838  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12839  *         the caller has to free the object.
12840  */
12841 xmlXPathObjectPtr
xmlXPathEvalExpression(const xmlChar * str,xmlXPathContextPtr ctxt)12842 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
12843     return(xmlXPathEval(str, ctxt));
12844 }
12845 
12846 /************************************************************************
12847  *									*
12848  *	Extra functions not pertaining to the XPath spec		*
12849  *									*
12850  ************************************************************************/
12851 /**
12852  * xmlXPathEscapeUriFunction:
12853  * @ctxt:  the XPath Parser context
12854  * @nargs:  the number of arguments
12855  *
12856  * Implement the escape-uri() XPath function
12857  *    string escape-uri(string $str, bool $escape-reserved)
12858  *
12859  * This function applies the URI escaping rules defined in section 2 of [RFC
12860  * 2396] to the string supplied as $uri-part, which typically represents all
12861  * or part of a URI. The effect of the function is to replace any special
12862  * character in the string by an escape sequence of the form %xx%yy...,
12863  * where xxyy... is the hexadecimal representation of the octets used to
12864  * represent the character in UTF-8.
12865  *
12866  * The set of characters that are escaped depends on the setting of the
12867  * boolean argument $escape-reserved.
12868  *
12869  * If $escape-reserved is true, all characters are escaped other than lower
12870  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
12871  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
12872  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
12873  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
12874  * A-F).
12875  *
12876  * If $escape-reserved is false, the behavior differs in that characters
12877  * referred to in [RFC 2396] as reserved characters are not escaped. These
12878  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
12879  *
12880  * [RFC 2396] does not define whether escaped URIs should use lower case or
12881  * upper case for hexadecimal digits. To ensure that escaped URIs can be
12882  * compared using string comparison functions, this function must always use
12883  * the upper-case letters A-F.
12884  *
12885  * Generally, $escape-reserved should be set to true when escaping a string
12886  * that is to form a single part of a URI, and to false when escaping an
12887  * entire URI or URI reference.
12888  *
12889  * In the case of non-ascii characters, the string is encoded according to
12890  * utf-8 and then converted according to RFC 2396.
12891  *
12892  * Examples
12893  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
12894  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
12895  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
12896  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
12897  *
12898  */
12899 static void
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt,int nargs)12900 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
12901     xmlXPathObjectPtr str;
12902     int escape_reserved;
12903     xmlBufPtr target;
12904     xmlChar *cptr;
12905     xmlChar escape[4];
12906 
12907     CHECK_ARITY(2);
12908 
12909     escape_reserved = xmlXPathPopBoolean(ctxt);
12910 
12911     CAST_TO_STRING;
12912     str = valuePop(ctxt);
12913 
12914     target = xmlBufCreateSize(64);
12915 
12916     escape[0] = '%';
12917     escape[3] = 0;
12918 
12919     if (target) {
12920 	for (cptr = str->stringval; *cptr; cptr++) {
12921 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
12922 		(*cptr >= 'a' && *cptr <= 'z') ||
12923 		(*cptr >= '0' && *cptr <= '9') ||
12924 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
12925 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
12926 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
12927 		(*cptr == '%' &&
12928 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
12929 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
12930 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
12931 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
12932 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
12933 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
12934 		(!escape_reserved &&
12935 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
12936 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
12937 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
12938 		  *cptr == ','))) {
12939 		xmlBufAdd(target, cptr, 1);
12940 	    } else {
12941 		if ((*cptr >> 4) < 10)
12942 		    escape[1] = '0' + (*cptr >> 4);
12943 		else
12944 		    escape[1] = 'A' - 10 + (*cptr >> 4);
12945 		if ((*cptr & 0xF) < 10)
12946 		    escape[2] = '0' + (*cptr & 0xF);
12947 		else
12948 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
12949 
12950 		xmlBufAdd(target, &escape[0], 3);
12951 	    }
12952 	}
12953     }
12954     valuePush(ctxt, xmlXPathCacheNewString(ctxt, xmlBufContent(target)));
12955     xmlBufFree(target);
12956     xmlXPathReleaseObject(ctxt->context, str);
12957 }
12958 
12959 /**
12960  * xmlXPathRegisterAllFunctions:
12961  * @ctxt:  the XPath context
12962  *
12963  * Registers all default XPath functions in this context
12964  */
12965 void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)12966 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
12967 {
12968     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
12969                          xmlXPathBooleanFunction);
12970     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
12971                          xmlXPathCeilingFunction);
12972     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
12973                          xmlXPathCountFunction);
12974     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
12975                          xmlXPathConcatFunction);
12976     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
12977                          xmlXPathContainsFunction);
12978     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
12979                          xmlXPathIdFunction);
12980     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
12981                          xmlXPathFalseFunction);
12982     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
12983                          xmlXPathFloorFunction);
12984     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
12985                          xmlXPathLastFunction);
12986     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
12987                          xmlXPathLangFunction);
12988     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
12989                          xmlXPathLocalNameFunction);
12990     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
12991                          xmlXPathNotFunction);
12992     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
12993                          xmlXPathNameFunction);
12994     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
12995                          xmlXPathNamespaceURIFunction);
12996     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
12997                          xmlXPathNormalizeFunction);
12998     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
12999                          xmlXPathNumberFunction);
13000     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
13001                          xmlXPathPositionFunction);
13002     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
13003                          xmlXPathRoundFunction);
13004     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
13005                          xmlXPathStringFunction);
13006     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
13007                          xmlXPathStringLengthFunction);
13008     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
13009                          xmlXPathStartsWithFunction);
13010     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
13011                          xmlXPathSubstringFunction);
13012     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
13013                          xmlXPathSubstringBeforeFunction);
13014     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
13015                          xmlXPathSubstringAfterFunction);
13016     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
13017                          xmlXPathSumFunction);
13018     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
13019                          xmlXPathTrueFunction);
13020     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
13021                          xmlXPathTranslateFunction);
13022 
13023     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
13024 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
13025                          xmlXPathEscapeUriFunction);
13026 }
13027 
13028 #endif /* LIBXML_XPATH_ENABLED */
13029