xref: /aosp_15_r20/external/libxml2/xpath.c (revision 7c5688314b92172186c154356a6374bf7684c3ca)
1 /*
2  * xpath.c: XML Path Language implementation
3  *          XPath is a language for addressing parts of an XML document,
4  *          designed to be used by both XSLT and XPointer
5  *
6  * Reference: W3C Recommendation 16 November 1999
7  *     http://www.w3.org/TR/1999/REC-xpath-19991116
8  * Public reference:
9  *     http://www.w3.org/TR/xpath
10  *
11  * See Copyright for the status of this software
12  *
13  * Author: [email protected]
14  *
15  */
16 
17 /* To avoid EBCDIC trouble when parsing on zOS */
18 #if defined(__MVS__)
19 #pragma convert("ISO8859-1")
20 #endif
21 
22 #define IN_LIBXML
23 #include "libxml.h"
24 
25 #include <limits.h>
26 #include <string.h>
27 #include <stddef.h>
28 #include <math.h>
29 #include <float.h>
30 #include <ctype.h>
31 
32 #include <libxml/xmlmemory.h>
33 #include <libxml/tree.h>
34 #include <libxml/xpath.h>
35 #include <libxml/xpathInternals.h>
36 #include <libxml/parserInternals.h>
37 #include <libxml/hash.h>
38 #ifdef LIBXML_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)
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 /*
216  * TODO: when compatibility allows remove all "fake node libxslt" strings
217  *       the test should just be name[0] = ' '
218  */
219 
220 static const xmlNs xmlXPathXMLNamespaceStruct = {
221     NULL,
222     XML_NAMESPACE_DECL,
223     XML_XML_NAMESPACE,
224     BAD_CAST "xml",
225     NULL,
226     NULL
227 };
228 static const xmlNs *const xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
229 
230 static void
231 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes);
232 
233 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
234 /**
235  * xmlXPathCmpNodesExt:
236  * @node1:  the first node
237  * @node2:  the second node
238  *
239  * Compare two nodes w.r.t document order.
240  * This one is optimized for handling of non-element nodes.
241  *
242  * Returns -2 in case of error 1 if first point < second point, 0 if
243  *         it's the same node, -1 otherwise
244  */
245 static int
xmlXPathCmpNodesExt(xmlNodePtr node1,xmlNodePtr node2)246 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
247     int depth1, depth2;
248     int misc = 0, precedence1 = 0, precedence2 = 0;
249     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
250     xmlNodePtr cur, root;
251     ptrdiff_t l1, l2;
252 
253     if ((node1 == NULL) || (node2 == NULL))
254 	return(-2);
255 
256     if (node1 == node2)
257 	return(0);
258 
259     /*
260      * a couple of optimizations which will avoid computations in most cases
261      */
262     switch (node1->type) {
263 	case XML_ELEMENT_NODE:
264 	    if (node2->type == XML_ELEMENT_NODE) {
265 		if ((0 > (ptrdiff_t) node1->content) &&
266 		    (0 > (ptrdiff_t) node2->content) &&
267 		    (node1->doc == node2->doc))
268 		{
269 		    l1 = -((ptrdiff_t) node1->content);
270 		    l2 = -((ptrdiff_t) node2->content);
271 		    if (l1 < l2)
272 			return(1);
273 		    if (l1 > l2)
274 			return(-1);
275 		} else
276 		    goto turtle_comparison;
277 	    }
278 	    break;
279 	case XML_ATTRIBUTE_NODE:
280 	    precedence1 = 1; /* element is owner */
281 	    miscNode1 = node1;
282 	    node1 = node1->parent;
283 	    misc = 1;
284 	    break;
285 	case XML_TEXT_NODE:
286 	case XML_CDATA_SECTION_NODE:
287 	case XML_COMMENT_NODE:
288 	case XML_PI_NODE: {
289 	    miscNode1 = node1;
290 	    /*
291 	    * Find nearest element node.
292 	    */
293 	    if (node1->prev != NULL) {
294 		do {
295 		    node1 = node1->prev;
296 		    if (node1->type == XML_ELEMENT_NODE) {
297 			precedence1 = 3; /* element in prev-sibl axis */
298 			break;
299 		    }
300 		    if (node1->prev == NULL) {
301 			precedence1 = 2; /* element is parent */
302 			/*
303 			* URGENT TODO: Are there any cases, where the
304 			* parent of such a node is not an element node?
305 			*/
306 			node1 = node1->parent;
307 			break;
308 		    }
309 		} while (1);
310 	    } else {
311 		precedence1 = 2; /* element is parent */
312 		node1 = node1->parent;
313 	    }
314 	    if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
315 		(0 <= (ptrdiff_t) node1->content)) {
316 		/*
317 		* Fallback for whatever case.
318 		*/
319 		node1 = miscNode1;
320 		precedence1 = 0;
321 	    } else
322 		misc = 1;
323 	}
324 	    break;
325 	case XML_NAMESPACE_DECL:
326 	    /*
327 	    * TODO: why do we return 1 for namespace nodes?
328 	    */
329 	    return(1);
330 	default:
331 	    break;
332     }
333     switch (node2->type) {
334 	case XML_ELEMENT_NODE:
335 	    break;
336 	case XML_ATTRIBUTE_NODE:
337 	    precedence2 = 1; /* element is owner */
338 	    miscNode2 = node2;
339 	    node2 = node2->parent;
340 	    misc = 1;
341 	    break;
342 	case XML_TEXT_NODE:
343 	case XML_CDATA_SECTION_NODE:
344 	case XML_COMMENT_NODE:
345 	case XML_PI_NODE: {
346 	    miscNode2 = node2;
347 	    if (node2->prev != NULL) {
348 		do {
349 		    node2 = node2->prev;
350 		    if (node2->type == XML_ELEMENT_NODE) {
351 			precedence2 = 3; /* element in prev-sibl axis */
352 			break;
353 		    }
354 		    if (node2->prev == NULL) {
355 			precedence2 = 2; /* element is parent */
356 			node2 = node2->parent;
357 			break;
358 		    }
359 		} while (1);
360 	    } else {
361 		precedence2 = 2; /* element is parent */
362 		node2 = node2->parent;
363 	    }
364 	    if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
365 		(0 <= (ptrdiff_t) node2->content))
366 	    {
367 		node2 = miscNode2;
368 		precedence2 = 0;
369 	    } else
370 		misc = 1;
371 	}
372 	    break;
373 	case XML_NAMESPACE_DECL:
374 	    return(1);
375 	default:
376 	    break;
377     }
378     if (misc) {
379 	if (node1 == node2) {
380 	    if (precedence1 == precedence2) {
381 		/*
382 		* The ugly case; but normally there aren't many
383 		* adjacent non-element nodes around.
384 		*/
385 		cur = miscNode2->prev;
386 		while (cur != NULL) {
387 		    if (cur == miscNode1)
388 			return(1);
389 		    if (cur->type == XML_ELEMENT_NODE)
390 			return(-1);
391 		    cur = cur->prev;
392 		}
393 		return (-1);
394 	    } else {
395 		/*
396 		* Evaluate based on higher precedence wrt to the element.
397 		* TODO: This assumes attributes are sorted before content.
398 		*   Is this 100% correct?
399 		*/
400 		if (precedence1 < precedence2)
401 		    return(1);
402 		else
403 		    return(-1);
404 	    }
405 	}
406 	/*
407 	* Special case: One of the helper-elements is contained by the other.
408 	* <foo>
409 	*   <node2>
410 	*     <node1>Text-1(precedence1 == 2)</node1>
411 	*   </node2>
412 	*   Text-6(precedence2 == 3)
413 	* </foo>
414 	*/
415 	if ((precedence2 == 3) && (precedence1 > 1)) {
416 	    cur = node1->parent;
417 	    while (cur) {
418 		if (cur == node2)
419 		    return(1);
420 		cur = cur->parent;
421 	    }
422 	}
423 	if ((precedence1 == 3) && (precedence2 > 1)) {
424 	    cur = node2->parent;
425 	    while (cur) {
426 		if (cur == node1)
427 		    return(-1);
428 		cur = cur->parent;
429 	    }
430 	}
431     }
432 
433     /*
434      * Speedup using document order if available.
435      */
436     if ((node1->type == XML_ELEMENT_NODE) &&
437 	(node2->type == XML_ELEMENT_NODE) &&
438 	(0 > (ptrdiff_t) node1->content) &&
439 	(0 > (ptrdiff_t) node2->content) &&
440 	(node1->doc == node2->doc)) {
441 
442 	l1 = -((ptrdiff_t) node1->content);
443 	l2 = -((ptrdiff_t) node2->content);
444 	if (l1 < l2)
445 	    return(1);
446 	if (l1 > l2)
447 	    return(-1);
448     }
449 
450 turtle_comparison:
451 
452     if (node1 == node2->prev)
453 	return(1);
454     if (node1 == node2->next)
455 	return(-1);
456     /*
457      * compute depth to root
458      */
459     for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
460 	if (cur->parent == node1)
461 	    return(1);
462 	depth2++;
463     }
464     root = cur;
465     for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
466 	if (cur->parent == node2)
467 	    return(-1);
468 	depth1++;
469     }
470     /*
471      * Distinct document (or distinct entities :-( ) case.
472      */
473     if (root != cur) {
474 	return(-2);
475     }
476     /*
477      * get the nearest common ancestor.
478      */
479     while (depth1 > depth2) {
480 	depth1--;
481 	node1 = node1->parent;
482     }
483     while (depth2 > depth1) {
484 	depth2--;
485 	node2 = node2->parent;
486     }
487     while (node1->parent != node2->parent) {
488 	node1 = node1->parent;
489 	node2 = node2->parent;
490 	/* should not happen but just in case ... */
491 	if ((node1 == NULL) || (node2 == NULL))
492 	    return(-2);
493     }
494     /*
495      * Find who's first.
496      */
497     if (node1 == node2->prev)
498 	return(1);
499     if (node1 == node2->next)
500 	return(-1);
501     /*
502      * Speedup using document order if available.
503      */
504     if ((node1->type == XML_ELEMENT_NODE) &&
505 	(node2->type == XML_ELEMENT_NODE) &&
506 	(0 > (ptrdiff_t) node1->content) &&
507 	(0 > (ptrdiff_t) node2->content) &&
508 	(node1->doc == node2->doc)) {
509 
510 	l1 = -((ptrdiff_t) node1->content);
511 	l2 = -((ptrdiff_t) node2->content);
512 	if (l1 < l2)
513 	    return(1);
514 	if (l1 > l2)
515 	    return(-1);
516     }
517 
518     for (cur = node1->next;cur != NULL;cur = cur->next)
519 	if (cur == node2)
520 	    return(1);
521     return(-1); /* assume there is no sibling list corruption */
522 }
523 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
524 
525 /*
526  * Wrapper for the Timsort algorithm from timsort.h
527  */
528 #ifdef WITH_TIM_SORT
529 #define SORT_NAME libxml_domnode
530 #define SORT_TYPE xmlNodePtr
531 /**
532  * wrap_cmp:
533  * @x: a node
534  * @y: another node
535  *
536  * Comparison function for the Timsort implementation
537  *
538  * Returns -2 in case of error -1 if first point < second point, 0 if
539  *         it's the same node, +1 otherwise
540  */
541 static
542 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
543 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
wrap_cmp(xmlNodePtr x,xmlNodePtr y)544     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
545     {
546         int res = xmlXPathCmpNodesExt(x, y);
547         return res == -2 ? res : -res;
548     }
549 #else
wrap_cmp(xmlNodePtr x,xmlNodePtr y)550     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
551     {
552         int res = xmlXPathCmpNodes(x, y);
553         return res == -2 ? res : -res;
554     }
555 #endif
556 #define SORT_CMP(x, y)  (wrap_cmp(x, y))
557 #include "timsort.h"
558 #endif /* WITH_TIM_SORT */
559 
560 /************************************************************************
561  *									*
562  *			Error handling routines				*
563  *									*
564  ************************************************************************/
565 
566 /**
567  * XP_ERRORNULL:
568  * @X:  the error code
569  *
570  * Macro to raise an XPath error and return NULL.
571  */
572 #define XP_ERRORNULL(X)							\
573     { xmlXPathErr(ctxt, X); return(NULL); }
574 
575 /*
576  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
577  */
578 static const char* const xmlXPathErrorMessages[] = {
579     "Ok\n",
580     "Number encoding\n",
581     "Unfinished literal\n",
582     "Start of literal\n",
583     "Expected $ for variable reference\n",
584     "Undefined variable\n",
585     "Invalid predicate\n",
586     "Invalid expression\n",
587     "Missing closing curly brace\n",
588     "Unregistered function\n",
589     "Invalid operand\n",
590     "Invalid type\n",
591     "Invalid number of arguments\n",
592     "Invalid context size\n",
593     "Invalid context position\n",
594     "Memory allocation error\n",
595     "Syntax error\n",
596     "Resource error\n",
597     "Sub resource error\n",
598     "Undefined namespace prefix\n",
599     "Encoding error\n",
600     "Char out of XML range\n",
601     "Invalid or incomplete context\n",
602     "Stack usage error\n",
603     "Forbidden variable\n",
604     "Operation limit exceeded\n",
605     "Recursion limit exceeded\n",
606     "?? Unknown error ??\n"	/* Must be last in the list! */
607 };
608 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /	\
609 		   sizeof(xmlXPathErrorMessages[0])) - 1)
610 /**
611  * xmlXPathErrMemory:
612  * @ctxt:  an XPath context
613  *
614  * Handle a memory allocation failure.
615  */
616 void
xmlXPathErrMemory(xmlXPathContextPtr ctxt)617 xmlXPathErrMemory(xmlXPathContextPtr ctxt)
618 {
619     if (ctxt == NULL)
620         return;
621     xmlRaiseMemoryError(ctxt->error, NULL, ctxt->userData, XML_FROM_XPATH,
622                         &ctxt->lastError);
623 }
624 
625 /**
626  * xmlXPathPErrMemory:
627  * @ctxt:  an XPath parser context
628  *
629  * Handle a memory allocation failure.
630  */
631 void
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt)632 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt)
633 {
634     if (ctxt == NULL)
635         return;
636     ctxt->error = XPATH_MEMORY_ERROR;
637     xmlXPathErrMemory(ctxt->context);
638 }
639 
640 /**
641  * xmlXPathErr:
642  * @ctxt:  a XPath parser context
643  * @code:  the error code
644  *
645  * Handle an XPath error
646  */
647 void
xmlXPathErr(xmlXPathParserContextPtr ctxt,int code)648 xmlXPathErr(xmlXPathParserContextPtr ctxt, int code)
649 {
650     xmlStructuredErrorFunc schannel = NULL;
651     xmlGenericErrorFunc channel = NULL;
652     void *data = NULL;
653     xmlNodePtr node = NULL;
654     int res;
655 
656     if (ctxt == NULL)
657         return;
658     if ((code < 0) || (code > MAXERRNO))
659 	code = MAXERRNO;
660     /* Only report the first error */
661     if (ctxt->error != 0)
662         return;
663 
664     ctxt->error = code;
665 
666     if (ctxt->context != NULL) {
667         xmlErrorPtr err = &ctxt->context->lastError;
668 
669         /* Don't overwrite memory error. */
670         if (err->code == XML_ERR_NO_MEMORY)
671             return;
672 
673         /* cleanup current last error */
674         xmlResetError(err);
675 
676         err->domain = XML_FROM_XPATH;
677         err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK;
678         err->level = XML_ERR_ERROR;
679         if (ctxt->base != NULL) {
680             err->str1 = (char *) xmlStrdup(ctxt->base);
681             if (err->str1 == NULL) {
682                 xmlXPathPErrMemory(ctxt);
683                 return;
684             }
685         }
686         err->int1 = ctxt->cur - ctxt->base;
687         err->node = ctxt->context->debugNode;
688 
689         schannel = ctxt->context->error;
690         data = ctxt->context->userData;
691         node = ctxt->context->debugNode;
692     }
693 
694     if (schannel == NULL) {
695         channel = xmlGenericError;
696         data = xmlGenericErrorContext;
697     }
698 
699     res = xmlRaiseError(schannel, channel, data, NULL, node, XML_FROM_XPATH,
700                         code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
701                         XML_ERR_ERROR, NULL, 0,
702                         (const char *) ctxt->base, NULL, NULL,
703                         ctxt->cur - ctxt->base, 0,
704                         "%s", xmlXPathErrorMessages[code]);
705     if (res < 0)
706         xmlXPathPErrMemory(ctxt);
707 }
708 
709 /**
710  * xmlXPatherror:
711  * @ctxt:  the XPath Parser context
712  * @file:  the file name
713  * @line:  the line number
714  * @no:  the error number
715  *
716  * Formats an error message.
717  */
718 void
xmlXPatherror(xmlXPathParserContextPtr ctxt,const char * file ATTRIBUTE_UNUSED,int line ATTRIBUTE_UNUSED,int no)719 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
720               int line ATTRIBUTE_UNUSED, int no) {
721     xmlXPathErr(ctxt, no);
722 }
723 
724 /**
725  * xmlXPathCheckOpLimit:
726  * @ctxt:  the XPath Parser context
727  * @opCount:  the number of operations to be added
728  *
729  * Adds opCount to the running total of operations and returns -1 if the
730  * operation limit is exceeded. Returns 0 otherwise.
731  */
732 static int
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt,unsigned long opCount)733 xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
734     xmlXPathContextPtr xpctxt = ctxt->context;
735 
736     if ((opCount > xpctxt->opLimit) ||
737         (xpctxt->opCount > xpctxt->opLimit - opCount)) {
738         xpctxt->opCount = xpctxt->opLimit;
739         xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
740         return(-1);
741     }
742 
743     xpctxt->opCount += opCount;
744     return(0);
745 }
746 
747 #define OP_LIMIT_EXCEEDED(ctxt, n) \
748     ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
749 
750 /************************************************************************
751  *									*
752  *			Parser Types					*
753  *									*
754  ************************************************************************/
755 
756 /*
757  * Types are private:
758  */
759 
760 typedef enum {
761     XPATH_OP_END=0,
762     XPATH_OP_AND,
763     XPATH_OP_OR,
764     XPATH_OP_EQUAL,
765     XPATH_OP_CMP,
766     XPATH_OP_PLUS,
767     XPATH_OP_MULT,
768     XPATH_OP_UNION,
769     XPATH_OP_ROOT,
770     XPATH_OP_NODE,
771     XPATH_OP_COLLECT,
772     XPATH_OP_VALUE, /* 11 */
773     XPATH_OP_VARIABLE,
774     XPATH_OP_FUNCTION,
775     XPATH_OP_ARG,
776     XPATH_OP_PREDICATE,
777     XPATH_OP_FILTER, /* 16 */
778     XPATH_OP_SORT /* 17 */
779 } xmlXPathOp;
780 
781 typedef enum {
782     AXIS_ANCESTOR = 1,
783     AXIS_ANCESTOR_OR_SELF,
784     AXIS_ATTRIBUTE,
785     AXIS_CHILD,
786     AXIS_DESCENDANT,
787     AXIS_DESCENDANT_OR_SELF,
788     AXIS_FOLLOWING,
789     AXIS_FOLLOWING_SIBLING,
790     AXIS_NAMESPACE,
791     AXIS_PARENT,
792     AXIS_PRECEDING,
793     AXIS_PRECEDING_SIBLING,
794     AXIS_SELF
795 } xmlXPathAxisVal;
796 
797 typedef enum {
798     NODE_TEST_NONE = 0,
799     NODE_TEST_TYPE = 1,
800     NODE_TEST_PI = 2,
801     NODE_TEST_ALL = 3,
802     NODE_TEST_NS = 4,
803     NODE_TEST_NAME = 5
804 } xmlXPathTestVal;
805 
806 typedef enum {
807     NODE_TYPE_NODE = 0,
808     NODE_TYPE_COMMENT = XML_COMMENT_NODE,
809     NODE_TYPE_TEXT = XML_TEXT_NODE,
810     NODE_TYPE_PI = XML_PI_NODE
811 } xmlXPathTypeVal;
812 
813 typedef struct _xmlXPathStepOp xmlXPathStepOp;
814 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
815 struct _xmlXPathStepOp {
816     xmlXPathOp op;		/* The identifier of the operation */
817     int ch1;			/* First child */
818     int ch2;			/* Second child */
819     int value;
820     int value2;
821     int value3;
822     void *value4;
823     void *value5;
824     xmlXPathFunction cache;
825     void *cacheURI;
826 };
827 
828 struct _xmlXPathCompExpr {
829     int nbStep;			/* Number of steps in this expression */
830     int maxStep;		/* Maximum number of steps allocated */
831     xmlXPathStepOp *steps;	/* ops for computation of this expression */
832     int last;			/* index of last step in expression */
833     xmlChar *expr;		/* the expression being computed */
834     xmlDictPtr dict;		/* the dictionary to use if any */
835 #ifdef XPATH_STREAMING
836     xmlPatternPtr stream;
837 #endif
838 };
839 
840 /************************************************************************
841  *									*
842  *			Forward declarations				*
843  *									*
844  ************************************************************************/
845 
846 static void
847 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
848 static int
849 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
850                         xmlXPathStepOpPtr op, xmlNodePtr *first);
851 static int
852 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
853 			    xmlXPathStepOpPtr op,
854 			    int isPredicate);
855 static void
856 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
857 
858 /************************************************************************
859  *									*
860  *			Parser Type functions				*
861  *									*
862  ************************************************************************/
863 
864 /**
865  * xmlXPathNewCompExpr:
866  *
867  * Create a new Xpath component
868  *
869  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
870  */
871 static xmlXPathCompExprPtr
xmlXPathNewCompExpr(void)872 xmlXPathNewCompExpr(void) {
873     xmlXPathCompExprPtr cur;
874 
875     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
876     if (cur == NULL)
877 	return(NULL);
878     memset(cur, 0, sizeof(xmlXPathCompExpr));
879     cur->maxStep = 10;
880     cur->nbStep = 0;
881     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
882 	                                   sizeof(xmlXPathStepOp));
883     if (cur->steps == NULL) {
884 	xmlFree(cur);
885 	return(NULL);
886     }
887     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
888     cur->last = -1;
889     return(cur);
890 }
891 
892 /**
893  * xmlXPathFreeCompExpr:
894  * @comp:  an XPATH comp
895  *
896  * Free up the memory allocated by @comp
897  */
898 void
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)899 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
900 {
901     xmlXPathStepOpPtr op;
902     int i;
903 
904     if (comp == NULL)
905         return;
906     if (comp->dict == NULL) {
907 	for (i = 0; i < comp->nbStep; i++) {
908 	    op = &comp->steps[i];
909 	    if (op->value4 != NULL) {
910 		if (op->op == XPATH_OP_VALUE)
911 		    xmlXPathFreeObject(op->value4);
912 		else
913 		    xmlFree(op->value4);
914 	    }
915 	    if (op->value5 != NULL)
916 		xmlFree(op->value5);
917 	}
918     } else {
919 	for (i = 0; i < comp->nbStep; i++) {
920 	    op = &comp->steps[i];
921 	    if (op->value4 != NULL) {
922 		if (op->op == XPATH_OP_VALUE)
923 		    xmlXPathFreeObject(op->value4);
924 	    }
925 	}
926         xmlDictFree(comp->dict);
927     }
928     if (comp->steps != NULL) {
929         xmlFree(comp->steps);
930     }
931 #ifdef XPATH_STREAMING
932     if (comp->stream != NULL) {
933         xmlFreePatternList(comp->stream);
934     }
935 #endif
936     if (comp->expr != NULL) {
937         xmlFree(comp->expr);
938     }
939 
940     xmlFree(comp);
941 }
942 
943 /**
944  * xmlXPathCompExprAdd:
945  * @comp:  the compiled expression
946  * @ch1: first child index
947  * @ch2: second child index
948  * @op:  an op
949  * @value:  the first int value
950  * @value2:  the second int value
951  * @value3:  the third int value
952  * @value4:  the first string value
953  * @value5:  the second string value
954  *
955  * Add a step to an XPath Compiled Expression
956  *
957  * Returns -1 in case of failure, the index otherwise
958  */
959 static int
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt,int ch1,int ch2,xmlXPathOp op,int value,int value2,int value3,void * value4,void * value5)960 xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
961    xmlXPathOp op, int value,
962    int value2, int value3, void *value4, void *value5) {
963     xmlXPathCompExprPtr comp = ctxt->comp;
964     if (comp->nbStep >= comp->maxStep) {
965 	xmlXPathStepOp *real;
966 
967         if (comp->maxStep >= XPATH_MAX_STEPS) {
968 	    xmlXPathPErrMemory(ctxt);
969 	    return(-1);
970         }
971 	comp->maxStep *= 2;
972 	real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
973 		                      comp->maxStep * sizeof(xmlXPathStepOp));
974 	if (real == NULL) {
975 	    comp->maxStep /= 2;
976 	    xmlXPathPErrMemory(ctxt);
977 	    return(-1);
978 	}
979 	comp->steps = real;
980     }
981     comp->last = comp->nbStep;
982     comp->steps[comp->nbStep].ch1 = ch1;
983     comp->steps[comp->nbStep].ch2 = ch2;
984     comp->steps[comp->nbStep].op = op;
985     comp->steps[comp->nbStep].value = value;
986     comp->steps[comp->nbStep].value2 = value2;
987     comp->steps[comp->nbStep].value3 = value3;
988     if ((comp->dict != NULL) &&
989         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
990 	 (op == XPATH_OP_COLLECT))) {
991         if (value4 != NULL) {
992 	    comp->steps[comp->nbStep].value4 = (xmlChar *)
993 	        (void *)xmlDictLookup(comp->dict, value4, -1);
994 	    xmlFree(value4);
995 	} else
996 	    comp->steps[comp->nbStep].value4 = NULL;
997         if (value5 != NULL) {
998 	    comp->steps[comp->nbStep].value5 = (xmlChar *)
999 	        (void *)xmlDictLookup(comp->dict, value5, -1);
1000 	    xmlFree(value5);
1001 	} else
1002 	    comp->steps[comp->nbStep].value5 = NULL;
1003     } else {
1004 	comp->steps[comp->nbStep].value4 = value4;
1005 	comp->steps[comp->nbStep].value5 = value5;
1006     }
1007     comp->steps[comp->nbStep].cache = NULL;
1008     return(comp->nbStep++);
1009 }
1010 
1011 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5)	\
1012     xmlXPathCompExprAdd(ctxt, (op1), (op2),			\
1013 	                (op), (val), (val2), (val3), (val4), (val5))
1014 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)			\
1015     xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,		\
1016 	                (op), (val), (val2), (val3), (val4), (val5))
1017 
1018 #define PUSH_LEAVE_EXPR(op, val, val2)					\
1019 xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1020 
1021 #define PUSH_UNARY_EXPR(op, ch, val, val2)				\
1022 xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1023 
1024 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)			\
1025 xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),			\
1026 			(val), (val2), 0 ,NULL ,NULL)
1027 
1028 /************************************************************************
1029  *									*
1030  *		XPath object cache structures				*
1031  *									*
1032  ************************************************************************/
1033 
1034 /* #define XP_DEFAULT_CACHE_ON */
1035 
1036 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1037 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1038 struct _xmlXPathContextCache {
1039     xmlXPathObjectPtr nodesetObjs;  /* stringval points to next */
1040     xmlXPathObjectPtr miscObjs;     /* stringval points to next */
1041     int numNodeset;
1042     int maxNodeset;
1043     int numMisc;
1044     int maxMisc;
1045 };
1046 
1047 /************************************************************************
1048  *									*
1049  *		Debugging related functions				*
1050  *									*
1051  ************************************************************************/
1052 
1053 #ifdef LIBXML_DEBUG_ENABLED
1054 static void
xmlXPathDebugDumpNode(FILE * output,xmlNodePtr cur,int depth)1055 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1056     int i;
1057     char shift[100];
1058 
1059     for (i = 0;((i < depth) && (i < 25));i++)
1060         shift[2 * i] = shift[2 * i + 1] = ' ';
1061     shift[2 * i] = shift[2 * i + 1] = 0;
1062     if (cur == NULL) {
1063 	fprintf(output, "%s", shift);
1064 	fprintf(output, "Node is NULL !\n");
1065 	return;
1066 
1067     }
1068 
1069     if ((cur->type == XML_DOCUMENT_NODE) ||
1070 	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
1071 	fprintf(output, "%s", shift);
1072 	fprintf(output, " /\n");
1073     } else if (cur->type == XML_ATTRIBUTE_NODE)
1074 	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1075     else
1076 	xmlDebugDumpOneNode(output, cur, depth);
1077 }
1078 static void
xmlXPathDebugDumpNodeList(FILE * output,xmlNodePtr cur,int depth)1079 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1080     xmlNodePtr tmp;
1081     int i;
1082     char shift[100];
1083 
1084     for (i = 0;((i < depth) && (i < 25));i++)
1085         shift[2 * i] = shift[2 * i + 1] = ' ';
1086     shift[2 * i] = shift[2 * i + 1] = 0;
1087     if (cur == NULL) {
1088 	fprintf(output, "%s", shift);
1089 	fprintf(output, "Node is NULL !\n");
1090 	return;
1091 
1092     }
1093 
1094     while (cur != NULL) {
1095 	tmp = cur;
1096 	cur = cur->next;
1097 	xmlDebugDumpOneNode(output, tmp, depth);
1098     }
1099 }
1100 
1101 static void
xmlXPathDebugDumpNodeSet(FILE * output,xmlNodeSetPtr cur,int depth)1102 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1103     int i;
1104     char shift[100];
1105 
1106     for (i = 0;((i < depth) && (i < 25));i++)
1107         shift[2 * i] = shift[2 * i + 1] = ' ';
1108     shift[2 * i] = shift[2 * i + 1] = 0;
1109 
1110     if (cur == NULL) {
1111 	fprintf(output, "%s", shift);
1112 	fprintf(output, "NodeSet is NULL !\n");
1113 	return;
1114 
1115     }
1116 
1117     if (cur != NULL) {
1118 	fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1119 	for (i = 0;i < cur->nodeNr;i++) {
1120 	    fprintf(output, "%s", shift);
1121 	    fprintf(output, "%d", i + 1);
1122 	    xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1123 	}
1124     }
1125 }
1126 
1127 static void
xmlXPathDebugDumpValueTree(FILE * output,xmlNodeSetPtr cur,int depth)1128 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1129     int i;
1130     char shift[100];
1131 
1132     for (i = 0;((i < depth) && (i < 25));i++)
1133         shift[2 * i] = shift[2 * i + 1] = ' ';
1134     shift[2 * i] = shift[2 * i + 1] = 0;
1135 
1136     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1137 	fprintf(output, "%s", shift);
1138 	fprintf(output, "Value Tree is NULL !\n");
1139 	return;
1140 
1141     }
1142 
1143     fprintf(output, "%s", shift);
1144     fprintf(output, "%d", i + 1);
1145     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1146 }
1147 
1148 /**
1149  * xmlXPathDebugDumpObject:
1150  * @output:  the FILE * to dump the output
1151  * @cur:  the object to inspect
1152  * @depth:  indentation level
1153  *
1154  * Dump the content of the object for debugging purposes
1155  */
1156 void
xmlXPathDebugDumpObject(FILE * output,xmlXPathObjectPtr cur,int depth)1157 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1158     int i;
1159     char shift[100];
1160 
1161     if (output == NULL) return;
1162 
1163     for (i = 0;((i < depth) && (i < 25));i++)
1164         shift[2 * i] = shift[2 * i + 1] = ' ';
1165     shift[2 * i] = shift[2 * i + 1] = 0;
1166 
1167 
1168     fprintf(output, "%s", shift);
1169 
1170     if (cur == NULL) {
1171         fprintf(output, "Object is empty (NULL)\n");
1172 	return;
1173     }
1174     switch(cur->type) {
1175         case XPATH_UNDEFINED:
1176 	    fprintf(output, "Object is uninitialized\n");
1177 	    break;
1178         case XPATH_NODESET:
1179 	    fprintf(output, "Object is a Node Set :\n");
1180 	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1181 	    break;
1182 	case XPATH_XSLT_TREE:
1183 	    fprintf(output, "Object is an XSLT value tree :\n");
1184 	    xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1185 	    break;
1186         case XPATH_BOOLEAN:
1187 	    fprintf(output, "Object is a Boolean : ");
1188 	    if (cur->boolval) fprintf(output, "true\n");
1189 	    else fprintf(output, "false\n");
1190 	    break;
1191         case XPATH_NUMBER:
1192 	    switch (xmlXPathIsInf(cur->floatval)) {
1193 	    case 1:
1194 		fprintf(output, "Object is a number : Infinity\n");
1195 		break;
1196 	    case -1:
1197 		fprintf(output, "Object is a number : -Infinity\n");
1198 		break;
1199 	    default:
1200 		if (xmlXPathIsNaN(cur->floatval)) {
1201 		    fprintf(output, "Object is a number : NaN\n");
1202 		} else if (cur->floatval == 0) {
1203                     /* Omit sign for negative zero. */
1204 		    fprintf(output, "Object is a number : 0\n");
1205 		} else {
1206 		    fprintf(output, "Object is a number : %0g\n", cur->floatval);
1207 		}
1208 	    }
1209 	    break;
1210         case XPATH_STRING:
1211 	    fprintf(output, "Object is a string : ");
1212 	    xmlDebugDumpString(output, cur->stringval);
1213 	    fprintf(output, "\n");
1214 	    break;
1215 	case XPATH_USERS:
1216 	    fprintf(output, "Object is user defined\n");
1217 	    break;
1218     }
1219 }
1220 
1221 static void
xmlXPathDebugDumpStepOp(FILE * output,xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op,int depth)1222 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1223 	                     xmlXPathStepOpPtr op, int depth) {
1224     int i;
1225     char shift[100];
1226 
1227     for (i = 0;((i < depth) && (i < 25));i++)
1228         shift[2 * i] = shift[2 * i + 1] = ' ';
1229     shift[2 * i] = shift[2 * i + 1] = 0;
1230 
1231     fprintf(output, "%s", shift);
1232     if (op == NULL) {
1233 	fprintf(output, "Step is NULL\n");
1234 	return;
1235     }
1236     switch (op->op) {
1237         case XPATH_OP_END:
1238 	    fprintf(output, "END"); break;
1239         case XPATH_OP_AND:
1240 	    fprintf(output, "AND"); break;
1241         case XPATH_OP_OR:
1242 	    fprintf(output, "OR"); break;
1243         case XPATH_OP_EQUAL:
1244 	     if (op->value)
1245 		 fprintf(output, "EQUAL =");
1246 	     else
1247 		 fprintf(output, "EQUAL !=");
1248 	     break;
1249         case XPATH_OP_CMP:
1250 	     if (op->value)
1251 		 fprintf(output, "CMP <");
1252 	     else
1253 		 fprintf(output, "CMP >");
1254 	     if (!op->value2)
1255 		 fprintf(output, "=");
1256 	     break;
1257         case XPATH_OP_PLUS:
1258 	     if (op->value == 0)
1259 		 fprintf(output, "PLUS -");
1260 	     else if (op->value == 1)
1261 		 fprintf(output, "PLUS +");
1262 	     else if (op->value == 2)
1263 		 fprintf(output, "PLUS unary -");
1264 	     else if (op->value == 3)
1265 		 fprintf(output, "PLUS unary - -");
1266 	     break;
1267         case XPATH_OP_MULT:
1268 	     if (op->value == 0)
1269 		 fprintf(output, "MULT *");
1270 	     else if (op->value == 1)
1271 		 fprintf(output, "MULT div");
1272 	     else
1273 		 fprintf(output, "MULT mod");
1274 	     break;
1275         case XPATH_OP_UNION:
1276 	     fprintf(output, "UNION"); break;
1277         case XPATH_OP_ROOT:
1278 	     fprintf(output, "ROOT"); break;
1279         case XPATH_OP_NODE:
1280 	     fprintf(output, "NODE"); break;
1281         case XPATH_OP_SORT:
1282 	     fprintf(output, "SORT"); break;
1283         case XPATH_OP_COLLECT: {
1284 	    xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1285 	    xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1286 	    xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1287 	    const xmlChar *prefix = op->value4;
1288 	    const xmlChar *name = op->value5;
1289 
1290 	    fprintf(output, "COLLECT ");
1291 	    switch (axis) {
1292 		case AXIS_ANCESTOR:
1293 		    fprintf(output, " 'ancestors' "); break;
1294 		case AXIS_ANCESTOR_OR_SELF:
1295 		    fprintf(output, " 'ancestors-or-self' "); break;
1296 		case AXIS_ATTRIBUTE:
1297 		    fprintf(output, " 'attributes' "); break;
1298 		case AXIS_CHILD:
1299 		    fprintf(output, " 'child' "); break;
1300 		case AXIS_DESCENDANT:
1301 		    fprintf(output, " 'descendant' "); break;
1302 		case AXIS_DESCENDANT_OR_SELF:
1303 		    fprintf(output, " 'descendant-or-self' "); break;
1304 		case AXIS_FOLLOWING:
1305 		    fprintf(output, " 'following' "); break;
1306 		case AXIS_FOLLOWING_SIBLING:
1307 		    fprintf(output, " 'following-siblings' "); break;
1308 		case AXIS_NAMESPACE:
1309 		    fprintf(output, " 'namespace' "); break;
1310 		case AXIS_PARENT:
1311 		    fprintf(output, " 'parent' "); break;
1312 		case AXIS_PRECEDING:
1313 		    fprintf(output, " 'preceding' "); break;
1314 		case AXIS_PRECEDING_SIBLING:
1315 		    fprintf(output, " 'preceding-sibling' "); break;
1316 		case AXIS_SELF:
1317 		    fprintf(output, " 'self' "); break;
1318 	    }
1319 	    switch (test) {
1320                 case NODE_TEST_NONE:
1321 		    fprintf(output, "'none' "); break;
1322                 case NODE_TEST_TYPE:
1323 		    fprintf(output, "'type' "); break;
1324                 case NODE_TEST_PI:
1325 		    fprintf(output, "'PI' "); break;
1326                 case NODE_TEST_ALL:
1327 		    fprintf(output, "'all' "); break;
1328                 case NODE_TEST_NS:
1329 		    fprintf(output, "'namespace' "); break;
1330                 case NODE_TEST_NAME:
1331 		    fprintf(output, "'name' "); break;
1332 	    }
1333 	    switch (type) {
1334                 case NODE_TYPE_NODE:
1335 		    fprintf(output, "'node' "); break;
1336                 case NODE_TYPE_COMMENT:
1337 		    fprintf(output, "'comment' "); break;
1338                 case NODE_TYPE_TEXT:
1339 		    fprintf(output, "'text' "); break;
1340                 case NODE_TYPE_PI:
1341 		    fprintf(output, "'PI' "); break;
1342 	    }
1343 	    if (prefix != NULL)
1344 		fprintf(output, "%s:", prefix);
1345 	    if (name != NULL)
1346 		fprintf(output, "%s", (const char *) name);
1347 	    break;
1348 
1349         }
1350 	case XPATH_OP_VALUE: {
1351 	    xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1352 
1353 	    fprintf(output, "ELEM ");
1354 	    xmlXPathDebugDumpObject(output, object, 0);
1355 	    goto finish;
1356 	}
1357 	case XPATH_OP_VARIABLE: {
1358 	    const xmlChar *prefix = op->value5;
1359 	    const xmlChar *name = op->value4;
1360 
1361 	    if (prefix != NULL)
1362 		fprintf(output, "VARIABLE %s:%s", prefix, name);
1363 	    else
1364 		fprintf(output, "VARIABLE %s", name);
1365 	    break;
1366 	}
1367 	case XPATH_OP_FUNCTION: {
1368 	    int nbargs = op->value;
1369 	    const xmlChar *prefix = op->value5;
1370 	    const xmlChar *name = op->value4;
1371 
1372 	    if (prefix != NULL)
1373 		fprintf(output, "FUNCTION %s:%s(%d args)",
1374 			prefix, name, nbargs);
1375 	    else
1376 		fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1377 	    break;
1378 	}
1379         case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1380         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1381         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1382 	default:
1383         fprintf(output, "UNKNOWN %d\n", op->op); return;
1384     }
1385     fprintf(output, "\n");
1386 finish:
1387     if (op->ch1 >= 0)
1388 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1389     if (op->ch2 >= 0)
1390 	xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1391 }
1392 
1393 /**
1394  * xmlXPathDebugDumpCompExpr:
1395  * @output:  the FILE * for the output
1396  * @comp:  the precompiled XPath expression
1397  * @depth:  the indentation level.
1398  *
1399  * Dumps the tree of the compiled XPath expression.
1400  */
1401 void
xmlXPathDebugDumpCompExpr(FILE * output,xmlXPathCompExprPtr comp,int depth)1402 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1403 	                  int depth) {
1404     int i;
1405     char shift[100];
1406 
1407     if ((output == NULL) || (comp == NULL)) return;
1408 
1409     for (i = 0;((i < depth) && (i < 25));i++)
1410         shift[2 * i] = shift[2 * i + 1] = ' ';
1411     shift[2 * i] = shift[2 * i + 1] = 0;
1412 
1413     fprintf(output, "%s", shift);
1414 
1415 #ifdef XPATH_STREAMING
1416     if (comp->stream) {
1417         fprintf(output, "Streaming Expression\n");
1418     } else
1419 #endif
1420     {
1421         fprintf(output, "Compiled Expression : %d elements\n",
1422                 comp->nbStep);
1423         i = comp->last;
1424         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1425     }
1426 }
1427 
1428 #endif /* LIBXML_DEBUG_ENABLED */
1429 
1430 /************************************************************************
1431  *									*
1432  *			XPath object caching				*
1433  *									*
1434  ************************************************************************/
1435 
1436 /**
1437  * xmlXPathNewCache:
1438  *
1439  * Create a new object cache
1440  *
1441  * Returns the xmlXPathCache just allocated.
1442  */
1443 static xmlXPathContextCachePtr
xmlXPathNewCache(void)1444 xmlXPathNewCache(void)
1445 {
1446     xmlXPathContextCachePtr ret;
1447 
1448     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1449     if (ret == NULL)
1450 	return(NULL);
1451     memset(ret, 0 , sizeof(xmlXPathContextCache));
1452     ret->maxNodeset = 100;
1453     ret->maxMisc = 100;
1454     return(ret);
1455 }
1456 
1457 static void
xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)1458 xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)
1459 {
1460     while (list != NULL) {
1461         xmlXPathObjectPtr next;
1462 
1463         next = (void *) list->stringval;
1464 
1465 	if (list->nodesetval != NULL) {
1466 	    if (list->nodesetval->nodeTab != NULL)
1467 		xmlFree(list->nodesetval->nodeTab);
1468 	    xmlFree(list->nodesetval);
1469 	}
1470 	xmlFree(list);
1471 
1472         list = next;
1473     }
1474 }
1475 
1476 static void
xmlXPathFreeCache(xmlXPathContextCachePtr cache)1477 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1478 {
1479     if (cache == NULL)
1480 	return;
1481     if (cache->nodesetObjs)
1482 	xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1483     if (cache->miscObjs)
1484 	xmlXPathCacheFreeObjectList(cache->miscObjs);
1485     xmlFree(cache);
1486 }
1487 
1488 /**
1489  * xmlXPathContextSetCache:
1490  *
1491  * @ctxt:  the XPath context
1492  * @active: enables/disables (creates/frees) the cache
1493  * @value: a value with semantics dependent on @options
1494  * @options: options (currently only the value 0 is used)
1495  *
1496  * Creates/frees an object cache on the XPath context.
1497  * If activates XPath objects (xmlXPathObject) will be cached internally
1498  * to be reused.
1499  * @options:
1500  *   0: This will set the XPath object caching:
1501  *      @value:
1502  *        This will set the maximum number of XPath objects
1503  *        to be cached per slot
1504  *        There are two slots for node-set and misc objects.
1505  *        Use <0 for the default number (100).
1506  *   Other values for @options have currently no effect.
1507  *
1508  * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1509  */
1510 int
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,int active,int value,int options)1511 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1512 			int active,
1513 			int value,
1514 			int options)
1515 {
1516     if (ctxt == NULL)
1517 	return(-1);
1518     if (active) {
1519 	xmlXPathContextCachePtr cache;
1520 
1521 	if (ctxt->cache == NULL) {
1522 	    ctxt->cache = xmlXPathNewCache();
1523 	    if (ctxt->cache == NULL) {
1524                 xmlXPathErrMemory(ctxt);
1525 		return(-1);
1526             }
1527 	}
1528 	cache = (xmlXPathContextCachePtr) ctxt->cache;
1529 	if (options == 0) {
1530 	    if (value < 0)
1531 		value = 100;
1532 	    cache->maxNodeset = value;
1533 	    cache->maxMisc = value;
1534 	}
1535     } else if (ctxt->cache != NULL) {
1536 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1537 	ctxt->cache = NULL;
1538     }
1539     return(0);
1540 }
1541 
1542 /**
1543  * xmlXPathCacheWrapNodeSet:
1544  * @pctxt: the XPath context
1545  * @val:  the NodePtr value
1546  *
1547  * This is the cached version of xmlXPathWrapNodeSet().
1548  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1549  *
1550  * Returns the created or reused object.
1551  *
1552  * In case of error the node set is destroyed and NULL is returned.
1553  */
1554 static xmlXPathObjectPtr
xmlXPathCacheWrapNodeSet(xmlXPathParserContextPtr pctxt,xmlNodeSetPtr val)1555 xmlXPathCacheWrapNodeSet(xmlXPathParserContextPtr pctxt, xmlNodeSetPtr val)
1556 {
1557     xmlXPathObjectPtr ret;
1558     xmlXPathContextPtr ctxt = pctxt->context;
1559 
1560     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1561 	xmlXPathContextCachePtr cache =
1562 	    (xmlXPathContextCachePtr) ctxt->cache;
1563 
1564 	if (cache->miscObjs != NULL) {
1565 	    ret = cache->miscObjs;
1566             cache->miscObjs = (void *) ret->stringval;
1567             cache->numMisc -= 1;
1568             ret->stringval = NULL;
1569 	    ret->type = XPATH_NODESET;
1570 	    ret->nodesetval = val;
1571 	    return(ret);
1572 	}
1573     }
1574 
1575     ret = xmlXPathWrapNodeSet(val);
1576     if (ret == NULL)
1577         xmlXPathPErrMemory(pctxt);
1578     return(ret);
1579 }
1580 
1581 /**
1582  * xmlXPathCacheWrapString:
1583  * @pctxt the XPath context
1584  * @val:  the xmlChar * value
1585  *
1586  * This is the cached version of xmlXPathWrapString().
1587  * Wraps the @val string into an XPath object.
1588  *
1589  * Returns the created or reused object.
1590  */
1591 static xmlXPathObjectPtr
xmlXPathCacheWrapString(xmlXPathParserContextPtr pctxt,xmlChar * val)1592 xmlXPathCacheWrapString(xmlXPathParserContextPtr pctxt, xmlChar *val)
1593 {
1594     xmlXPathObjectPtr ret;
1595     xmlXPathContextPtr ctxt = pctxt->context;
1596 
1597     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1598 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1599 
1600 	if (cache->miscObjs != NULL) {
1601 	    ret = cache->miscObjs;
1602             cache->miscObjs = (void *) ret->stringval;
1603             cache->numMisc -= 1;
1604 	    ret->type = XPATH_STRING;
1605 	    ret->stringval = val;
1606 	    return(ret);
1607 	}
1608     }
1609 
1610     ret = xmlXPathWrapString(val);
1611     if (ret == NULL)
1612         xmlXPathPErrMemory(pctxt);
1613     return(ret);
1614 }
1615 
1616 /**
1617  * xmlXPathCacheNewNodeSet:
1618  * @pctxt the XPath context
1619  * @val:  the NodePtr value
1620  *
1621  * This is the cached version of xmlXPathNewNodeSet().
1622  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
1623  * it with the single Node @val
1624  *
1625  * Returns the created or reused object.
1626  */
1627 static xmlXPathObjectPtr
xmlXPathCacheNewNodeSet(xmlXPathParserContextPtr pctxt,xmlNodePtr val)1628 xmlXPathCacheNewNodeSet(xmlXPathParserContextPtr pctxt, xmlNodePtr val)
1629 {
1630     xmlXPathObjectPtr ret;
1631     xmlXPathContextPtr ctxt = pctxt->context;
1632 
1633     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1634 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1635 
1636 	if (cache->nodesetObjs != NULL) {
1637 	    /*
1638 	    * Use the nodeset-cache.
1639 	    */
1640 	    ret = cache->nodesetObjs;
1641             cache->nodesetObjs = (void *) ret->stringval;
1642             cache->numNodeset -= 1;
1643             ret->stringval = NULL;
1644 	    ret->type = XPATH_NODESET;
1645 	    ret->boolval = 0;
1646 	    if (val) {
1647 		if ((ret->nodesetval->nodeMax == 0) ||
1648 		    (val->type == XML_NAMESPACE_DECL))
1649 		{
1650 		    if (xmlXPathNodeSetAddUnique(ret->nodesetval, val) < 0)
1651                         xmlXPathPErrMemory(pctxt);
1652 		} else {
1653 		    ret->nodesetval->nodeTab[0] = val;
1654 		    ret->nodesetval->nodeNr = 1;
1655 		}
1656 	    }
1657 	    return(ret);
1658 	} else if (cache->miscObjs != NULL) {
1659             xmlNodeSetPtr set;
1660 	    /*
1661 	    * Fallback to misc-cache.
1662 	    */
1663 
1664 	    set = xmlXPathNodeSetCreate(val);
1665 	    if (set == NULL) {
1666                 xmlXPathPErrMemory(pctxt);
1667 		return(NULL);
1668 	    }
1669 
1670 	    ret = cache->miscObjs;
1671             cache->miscObjs = (void *) ret->stringval;
1672             cache->numMisc -= 1;
1673             ret->stringval = NULL;
1674 	    ret->type = XPATH_NODESET;
1675 	    ret->boolval = 0;
1676 	    ret->nodesetval = set;
1677 	    return(ret);
1678 	}
1679     }
1680     ret = xmlXPathNewNodeSet(val);
1681     if (ret == NULL)
1682         xmlXPathPErrMemory(pctxt);
1683     return(ret);
1684 }
1685 
1686 /**
1687  * xmlXPathCacheNewString:
1688  * @pctxt the XPath context
1689  * @val:  the xmlChar * value
1690  *
1691  * This is the cached version of xmlXPathNewString().
1692  * Acquire an xmlXPathObjectPtr of type string and of value @val
1693  *
1694  * Returns the created or reused object.
1695  */
1696 static xmlXPathObjectPtr
xmlXPathCacheNewString(xmlXPathParserContextPtr pctxt,const xmlChar * val)1697 xmlXPathCacheNewString(xmlXPathParserContextPtr pctxt, const xmlChar *val)
1698 {
1699     xmlXPathObjectPtr ret;
1700     xmlXPathContextPtr ctxt = pctxt->context;
1701 
1702     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1703 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1704 
1705 	if (cache->miscObjs != NULL) {
1706             xmlChar *copy;
1707 
1708             if (val == NULL)
1709                 val = BAD_CAST "";
1710             copy = xmlStrdup(val);
1711             if (copy == NULL) {
1712                 xmlXPathPErrMemory(pctxt);
1713                 return(NULL);
1714             }
1715 
1716 	    ret = cache->miscObjs;
1717             cache->miscObjs = (void *) ret->stringval;
1718             cache->numMisc -= 1;
1719 	    ret->type = XPATH_STRING;
1720             ret->stringval = copy;
1721 	    return(ret);
1722 	}
1723     }
1724 
1725     ret = xmlXPathNewString(val);
1726     if (ret == NULL)
1727         xmlXPathPErrMemory(pctxt);
1728     return(ret);
1729 }
1730 
1731 /**
1732  * xmlXPathCacheNewCString:
1733  * @pctxt the XPath context
1734  * @val:  the char * value
1735  *
1736  * This is the cached version of xmlXPathNewCString().
1737  * Acquire an xmlXPathObjectPtr of type string and of value @val
1738  *
1739  * Returns the created or reused object.
1740  */
1741 static xmlXPathObjectPtr
xmlXPathCacheNewCString(xmlXPathParserContextPtr pctxt,const char * val)1742 xmlXPathCacheNewCString(xmlXPathParserContextPtr pctxt, const char *val)
1743 {
1744     return xmlXPathCacheNewString(pctxt, BAD_CAST val);
1745 }
1746 
1747 /**
1748  * xmlXPathCacheNewBoolean:
1749  * @pctxt the XPath context
1750  * @val:  the boolean value
1751  *
1752  * This is the cached version of xmlXPathNewBoolean().
1753  * Acquires an xmlXPathObjectPtr of type boolean and of value @val
1754  *
1755  * Returns the created or reused object.
1756  */
1757 static xmlXPathObjectPtr
xmlXPathCacheNewBoolean(xmlXPathParserContextPtr pctxt,int val)1758 xmlXPathCacheNewBoolean(xmlXPathParserContextPtr pctxt, int val)
1759 {
1760     xmlXPathObjectPtr ret;
1761     xmlXPathContextPtr ctxt = pctxt->context;
1762 
1763     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1764 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1765 
1766 	if (cache->miscObjs != NULL) {
1767 	    ret = cache->miscObjs;
1768             cache->miscObjs = (void *) ret->stringval;
1769             cache->numMisc -= 1;
1770             ret->stringval = NULL;
1771 	    ret->type = XPATH_BOOLEAN;
1772 	    ret->boolval = (val != 0);
1773 	    return(ret);
1774 	}
1775     }
1776 
1777     ret = xmlXPathNewBoolean(val);
1778     if (ret == NULL)
1779         xmlXPathPErrMemory(pctxt);
1780     return(ret);
1781 }
1782 
1783 /**
1784  * xmlXPathCacheNewFloat:
1785  * @pctxt the XPath context
1786  * @val:  the double value
1787  *
1788  * This is the cached version of xmlXPathNewFloat().
1789  * Acquires an xmlXPathObjectPtr of type double and of value @val
1790  *
1791  * Returns the created or reused object.
1792  */
1793 static xmlXPathObjectPtr
xmlXPathCacheNewFloat(xmlXPathParserContextPtr pctxt,double val)1794 xmlXPathCacheNewFloat(xmlXPathParserContextPtr pctxt, double val)
1795 {
1796     xmlXPathObjectPtr ret;
1797     xmlXPathContextPtr ctxt = pctxt->context;
1798 
1799     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1800 	xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1801 
1802 	if (cache->miscObjs != NULL) {
1803 	    ret = cache->miscObjs;
1804             cache->miscObjs = (void *) ret->stringval;
1805             cache->numMisc -= 1;
1806             ret->stringval = NULL;
1807 	    ret->type = XPATH_NUMBER;
1808 	    ret->floatval = val;
1809 	    return(ret);
1810 	}
1811     }
1812 
1813     ret = xmlXPathNewFloat(val);
1814     if (ret == NULL)
1815         xmlXPathPErrMemory(pctxt);
1816     return(ret);
1817 }
1818 
1819 /**
1820  * xmlXPathCacheObjectCopy:
1821  * @pctxt the XPath context
1822  * @val:  the original object
1823  *
1824  * This is the cached version of xmlXPathObjectCopy().
1825  * Acquire a copy of a given object
1826  *
1827  * Returns a created or reused created object.
1828  */
1829 static xmlXPathObjectPtr
xmlXPathCacheObjectCopy(xmlXPathParserContextPtr pctxt,xmlXPathObjectPtr val)1830 xmlXPathCacheObjectCopy(xmlXPathParserContextPtr pctxt, xmlXPathObjectPtr val)
1831 {
1832     xmlXPathObjectPtr ret;
1833     xmlXPathContextPtr ctxt = pctxt->context;
1834 
1835     if (val == NULL)
1836 	return(NULL);
1837 
1838     if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1839 	switch (val->type) {
1840             case XPATH_NODESET: {
1841                 xmlNodeSetPtr set;
1842 
1843                 set = xmlXPathNodeSetMerge(NULL, val->nodesetval);
1844                 if (set == NULL) {
1845                     xmlXPathPErrMemory(pctxt);
1846                     return(NULL);
1847                 }
1848                 return(xmlXPathCacheWrapNodeSet(pctxt, set));
1849             }
1850 	    case XPATH_STRING:
1851 		return(xmlXPathCacheNewString(pctxt, val->stringval));
1852 	    case XPATH_BOOLEAN:
1853 		return(xmlXPathCacheNewBoolean(pctxt, val->boolval));
1854 	    case XPATH_NUMBER:
1855 		return(xmlXPathCacheNewFloat(pctxt, val->floatval));
1856 	    default:
1857 		break;
1858 	}
1859     }
1860     ret = xmlXPathObjectCopy(val);
1861     if (ret == NULL)
1862         xmlXPathPErrMemory(pctxt);
1863     return(ret);
1864 }
1865 
1866 /************************************************************************
1867  *									*
1868  *		Parser stacks related functions and macros		*
1869  *									*
1870  ************************************************************************/
1871 
1872 /**
1873  * xmlXPathCastToNumberInternal:
1874  * @ctxt:  parser context
1875  * @val:  an XPath object
1876  *
1877  * Converts an XPath object to its number value
1878  *
1879  * Returns the number value
1880  */
1881 static double
xmlXPathCastToNumberInternal(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr val)1882 xmlXPathCastToNumberInternal(xmlXPathParserContextPtr ctxt,
1883                              xmlXPathObjectPtr val) {
1884     double ret = 0.0;
1885 
1886     if (val == NULL)
1887 	return(xmlXPathNAN);
1888     switch (val->type) {
1889     case XPATH_UNDEFINED:
1890 	ret = xmlXPathNAN;
1891 	break;
1892     case XPATH_NODESET:
1893     case XPATH_XSLT_TREE: {
1894         xmlChar *str;
1895 
1896 	str = xmlXPathCastNodeSetToString(val->nodesetval);
1897         if (str == NULL) {
1898             xmlXPathPErrMemory(ctxt);
1899             ret = xmlXPathNAN;
1900         } else {
1901 	    ret = xmlXPathCastStringToNumber(str);
1902             xmlFree(str);
1903         }
1904 	break;
1905     }
1906     case XPATH_STRING:
1907 	ret = xmlXPathCastStringToNumber(val->stringval);
1908 	break;
1909     case XPATH_NUMBER:
1910 	ret = val->floatval;
1911 	break;
1912     case XPATH_BOOLEAN:
1913 	ret = xmlXPathCastBooleanToNumber(val->boolval);
1914 	break;
1915     case XPATH_USERS:
1916 	/* TODO */
1917 	ret = xmlXPathNAN;
1918 	break;
1919     }
1920     return(ret);
1921 }
1922 
1923 /**
1924  * valuePop:
1925  * @ctxt: an XPath evaluation context
1926  *
1927  * Pops the top XPath object from the value stack
1928  *
1929  * Returns the XPath object just removed
1930  */
1931 xmlXPathObjectPtr
valuePop(xmlXPathParserContextPtr ctxt)1932 valuePop(xmlXPathParserContextPtr ctxt)
1933 {
1934     xmlXPathObjectPtr ret;
1935 
1936     if ((ctxt == NULL) || (ctxt->valueNr <= 0))
1937         return (NULL);
1938 
1939     ctxt->valueNr--;
1940     if (ctxt->valueNr > 0)
1941         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1942     else
1943         ctxt->value = NULL;
1944     ret = ctxt->valueTab[ctxt->valueNr];
1945     ctxt->valueTab[ctxt->valueNr] = NULL;
1946     return (ret);
1947 }
1948 /**
1949  * valuePush:
1950  * @ctxt:  an XPath evaluation context
1951  * @value:  the XPath object
1952  *
1953  * Pushes a new XPath object on top of the value stack. If value is NULL,
1954  * a memory error is recorded in the parser context.
1955  *
1956  * Returns the number of items on the value stack, or -1 in case of error.
1957  *
1958  * The object is destroyed in case of error.
1959  */
1960 int
valuePush(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr value)1961 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1962 {
1963     if (ctxt == NULL) return(-1);
1964     if (value == NULL) {
1965         /*
1966          * A NULL value typically indicates that a memory allocation failed.
1967          */
1968         xmlXPathPErrMemory(ctxt);
1969         return(-1);
1970     }
1971     if (ctxt->valueNr >= ctxt->valueMax) {
1972         xmlXPathObjectPtr *tmp;
1973 
1974         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
1975             xmlXPathPErrMemory(ctxt);
1976             xmlXPathFreeObject(value);
1977             return (-1);
1978         }
1979         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1980                                              2 * ctxt->valueMax *
1981                                              sizeof(ctxt->valueTab[0]));
1982         if (tmp == NULL) {
1983             xmlXPathPErrMemory(ctxt);
1984             xmlXPathFreeObject(value);
1985             return (-1);
1986         }
1987         ctxt->valueMax *= 2;
1988 	ctxt->valueTab = tmp;
1989     }
1990     ctxt->valueTab[ctxt->valueNr] = value;
1991     ctxt->value = value;
1992     return (ctxt->valueNr++);
1993 }
1994 
1995 /**
1996  * xmlXPathPopBoolean:
1997  * @ctxt:  an XPath parser context
1998  *
1999  * Pops a boolean from the stack, handling conversion if needed.
2000  * Check error with #xmlXPathCheckError.
2001  *
2002  * Returns the boolean
2003  */
2004 int
xmlXPathPopBoolean(xmlXPathParserContextPtr ctxt)2005 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2006     xmlXPathObjectPtr obj;
2007     int ret;
2008 
2009     obj = valuePop(ctxt);
2010     if (obj == NULL) {
2011 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2012 	return(0);
2013     }
2014     if (obj->type != XPATH_BOOLEAN)
2015 	ret = xmlXPathCastToBoolean(obj);
2016     else
2017         ret = obj->boolval;
2018     xmlXPathReleaseObject(ctxt->context, obj);
2019     return(ret);
2020 }
2021 
2022 /**
2023  * xmlXPathPopNumber:
2024  * @ctxt:  an XPath parser context
2025  *
2026  * Pops a number from the stack, handling conversion if needed.
2027  * Check error with #xmlXPathCheckError.
2028  *
2029  * Returns the number
2030  */
2031 double
xmlXPathPopNumber(xmlXPathParserContextPtr ctxt)2032 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2033     xmlXPathObjectPtr obj;
2034     double ret;
2035 
2036     obj = valuePop(ctxt);
2037     if (obj == NULL) {
2038 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2039 	return(0);
2040     }
2041     if (obj->type != XPATH_NUMBER)
2042 	ret = xmlXPathCastToNumberInternal(ctxt, obj);
2043     else
2044         ret = obj->floatval;
2045     xmlXPathReleaseObject(ctxt->context, obj);
2046     return(ret);
2047 }
2048 
2049 /**
2050  * xmlXPathPopString:
2051  * @ctxt:  an XPath parser context
2052  *
2053  * Pops a string from the stack, handling conversion if needed.
2054  * Check error with #xmlXPathCheckError.
2055  *
2056  * Returns the string
2057  */
2058 xmlChar *
xmlXPathPopString(xmlXPathParserContextPtr ctxt)2059 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2060     xmlXPathObjectPtr obj;
2061     xmlChar * ret;
2062 
2063     obj = valuePop(ctxt);
2064     if (obj == NULL) {
2065 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2066 	return(NULL);
2067     }
2068     ret = xmlXPathCastToString(obj);
2069     if (ret == NULL)
2070         xmlXPathPErrMemory(ctxt);
2071     xmlXPathReleaseObject(ctxt->context, obj);
2072     return(ret);
2073 }
2074 
2075 /**
2076  * xmlXPathPopNodeSet:
2077  * @ctxt:  an XPath parser context
2078  *
2079  * Pops a node-set from the stack, handling conversion if needed.
2080  * Check error with #xmlXPathCheckError.
2081  *
2082  * Returns the node-set
2083  */
2084 xmlNodeSetPtr
xmlXPathPopNodeSet(xmlXPathParserContextPtr ctxt)2085 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2086     xmlXPathObjectPtr obj;
2087     xmlNodeSetPtr ret;
2088 
2089     if (ctxt == NULL) return(NULL);
2090     if (ctxt->value == NULL) {
2091 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2092 	return(NULL);
2093     }
2094     if (!xmlXPathStackIsNodeSet(ctxt)) {
2095 	xmlXPathSetTypeError(ctxt);
2096 	return(NULL);
2097     }
2098     obj = valuePop(ctxt);
2099     ret = obj->nodesetval;
2100     obj->nodesetval = NULL;
2101     xmlXPathReleaseObject(ctxt->context, obj);
2102     return(ret);
2103 }
2104 
2105 /**
2106  * xmlXPathPopExternal:
2107  * @ctxt:  an XPath parser context
2108  *
2109  * Pops an external object from the stack, handling conversion if needed.
2110  * Check error with #xmlXPathCheckError.
2111  *
2112  * Returns the object
2113  */
2114 void *
xmlXPathPopExternal(xmlXPathParserContextPtr ctxt)2115 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2116     xmlXPathObjectPtr obj;
2117     void * ret;
2118 
2119     if ((ctxt == NULL) || (ctxt->value == NULL)) {
2120 	xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2121 	return(NULL);
2122     }
2123     if (ctxt->value->type != XPATH_USERS) {
2124 	xmlXPathSetTypeError(ctxt);
2125 	return(NULL);
2126     }
2127     obj = valuePop(ctxt);
2128     ret = obj->user;
2129     obj->user = NULL;
2130     xmlXPathReleaseObject(ctxt->context, obj);
2131     return(ret);
2132 }
2133 
2134 /*
2135  * Macros for accessing the content. Those should be used only by the parser,
2136  * and not exported.
2137  *
2138  * Dirty macros, i.e. one need to make assumption on the context to use them
2139  *
2140  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2141  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2142  *           in ISO-Latin or UTF-8.
2143  *           This should be used internally by the parser
2144  *           only to compare to ASCII values otherwise it would break when
2145  *           running with UTF-8 encoding.
2146  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2147  *           to compare on ASCII based substring.
2148  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2149  *           strings within the parser.
2150  *   CURRENT Returns the current char value, with the full decoding of
2151  *           UTF-8 if we are using this mode. It returns an int.
2152  *   NEXT    Skip to the next character, this does the proper decoding
2153  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2154  *           It returns the pointer to the current xmlChar.
2155  */
2156 
2157 #define CUR (*ctxt->cur)
2158 #define SKIP(val) ctxt->cur += (val)
2159 #define NXT(val) ctxt->cur[(val)]
2160 #define CUR_PTR ctxt->cur
2161 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2162 
2163 #define COPY_BUF(b, i, v)						\
2164     if (v < 0x80) b[i++] = v;						\
2165     else i += xmlCopyCharMultiByte(&b[i],v)
2166 
2167 #define NEXTL(l)  ctxt->cur += l
2168 
2169 #define SKIP_BLANKS							\
2170     while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2171 
2172 #define CURRENT (*ctxt->cur)
2173 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
2174 
2175 
2176 #ifndef DBL_DIG
2177 #define DBL_DIG 16
2178 #endif
2179 #ifndef DBL_EPSILON
2180 #define DBL_EPSILON 1E-9
2181 #endif
2182 
2183 #define UPPER_DOUBLE 1E9
2184 #define LOWER_DOUBLE 1E-5
2185 #define	LOWER_DOUBLE_EXP 5
2186 
2187 #define INTEGER_DIGITS DBL_DIG
2188 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2189 #define EXPONENT_DIGITS (3 + 2)
2190 
2191 /**
2192  * xmlXPathFormatNumber:
2193  * @number:     number to format
2194  * @buffer:     output buffer
2195  * @buffersize: size of output buffer
2196  *
2197  * Convert the number into a string representation.
2198  */
2199 static void
xmlXPathFormatNumber(double number,char buffer[],int buffersize)2200 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2201 {
2202     switch (xmlXPathIsInf(number)) {
2203     case 1:
2204 	if (buffersize > (int)sizeof("Infinity"))
2205 	    snprintf(buffer, buffersize, "Infinity");
2206 	break;
2207     case -1:
2208 	if (buffersize > (int)sizeof("-Infinity"))
2209 	    snprintf(buffer, buffersize, "-Infinity");
2210 	break;
2211     default:
2212 	if (xmlXPathIsNaN(number)) {
2213 	    if (buffersize > (int)sizeof("NaN"))
2214 		snprintf(buffer, buffersize, "NaN");
2215 	} else if (number == 0) {
2216             /* Omit sign for negative zero. */
2217 	    snprintf(buffer, buffersize, "0");
2218 	} else if ((number > INT_MIN) && (number < INT_MAX) &&
2219                    (number == (int) number)) {
2220 	    char work[30];
2221 	    char *ptr, *cur;
2222 	    int value = (int) number;
2223 
2224             ptr = &buffer[0];
2225 	    if (value == 0) {
2226 		*ptr++ = '0';
2227 	    } else {
2228 		snprintf(work, 29, "%d", value);
2229 		cur = &work[0];
2230 		while ((*cur) && (ptr - buffer < buffersize)) {
2231 		    *ptr++ = *cur++;
2232 		}
2233 	    }
2234 	    if (ptr - buffer < buffersize) {
2235 		*ptr = 0;
2236 	    } else if (buffersize > 0) {
2237 		ptr--;
2238 		*ptr = 0;
2239 	    }
2240 	} else {
2241 	    /*
2242 	      For the dimension of work,
2243 	          DBL_DIG is number of significant digits
2244 		  EXPONENT is only needed for "scientific notation"
2245 	          3 is sign, decimal point, and terminating zero
2246 		  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2247 	      Note that this dimension is slightly (a few characters)
2248 	      larger than actually necessary.
2249 	    */
2250 	    char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2251 	    int integer_place, fraction_place;
2252 	    char *ptr;
2253 	    char *after_fraction;
2254 	    double absolute_value;
2255 	    int size;
2256 
2257 	    absolute_value = fabs(number);
2258 
2259 	    /*
2260 	     * First choose format - scientific or regular floating point.
2261 	     * In either case, result is in work, and after_fraction points
2262 	     * just past the fractional part.
2263 	    */
2264 	    if ( ((absolute_value > UPPER_DOUBLE) ||
2265 		  (absolute_value < LOWER_DOUBLE)) &&
2266 		 (absolute_value != 0.0) ) {
2267 		/* Use scientific notation */
2268 		integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2269 		fraction_place = DBL_DIG - 1;
2270 		size = snprintf(work, sizeof(work),"%*.*e",
2271 			 integer_place, fraction_place, number);
2272 		while ((size > 0) && (work[size] != 'e')) size--;
2273 
2274 	    }
2275 	    else {
2276 		/* Use regular notation */
2277 		if (absolute_value > 0.0) {
2278 		    integer_place = (int)log10(absolute_value);
2279 		    if (integer_place > 0)
2280 		        fraction_place = DBL_DIG - integer_place - 1;
2281 		    else
2282 		        fraction_place = DBL_DIG - integer_place;
2283 		} else {
2284 		    fraction_place = 1;
2285 		}
2286 		size = snprintf(work, sizeof(work), "%0.*f",
2287 				fraction_place, number);
2288 	    }
2289 
2290 	    /* Remove leading spaces sometimes inserted by snprintf */
2291 	    while (work[0] == ' ') {
2292 	        for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2293 		size--;
2294 	    }
2295 
2296 	    /* Remove fractional trailing zeroes */
2297 	    after_fraction = work + size;
2298 	    ptr = after_fraction;
2299 	    while (*(--ptr) == '0')
2300 		;
2301 	    if (*ptr != '.')
2302 	        ptr++;
2303 	    while ((*ptr++ = *after_fraction++) != 0);
2304 
2305 	    /* Finally copy result back to caller */
2306 	    size = strlen(work) + 1;
2307 	    if (size > buffersize) {
2308 		work[buffersize - 1] = 0;
2309 		size = buffersize;
2310 	    }
2311 	    memmove(buffer, work, size);
2312 	}
2313 	break;
2314     }
2315 }
2316 
2317 
2318 /************************************************************************
2319  *									*
2320  *			Routines to handle NodeSets			*
2321  *									*
2322  ************************************************************************/
2323 
2324 /**
2325  * xmlXPathOrderDocElems:
2326  * @doc:  an input document
2327  *
2328  * Call this routine to speed up XPath computation on static documents.
2329  * This stamps all the element nodes with the document order
2330  * Like for line information, the order is kept in the element->content
2331  * field, the value stored is actually - the node number (starting at -1)
2332  * to be able to differentiate from line numbers.
2333  *
2334  * Returns the number of elements found in the document or -1 in case
2335  *    of error.
2336  */
2337 long
xmlXPathOrderDocElems(xmlDocPtr doc)2338 xmlXPathOrderDocElems(xmlDocPtr doc) {
2339     ptrdiff_t count = 0;
2340     xmlNodePtr cur;
2341 
2342     if (doc == NULL)
2343 	return(-1);
2344     cur = doc->children;
2345     while (cur != NULL) {
2346 	if (cur->type == XML_ELEMENT_NODE) {
2347 	    cur->content = (void *) (-(++count));
2348 	    if (cur->children != NULL) {
2349 		cur = cur->children;
2350 		continue;
2351 	    }
2352 	}
2353 	if (cur->next != NULL) {
2354 	    cur = cur->next;
2355 	    continue;
2356 	}
2357 	do {
2358 	    cur = cur->parent;
2359 	    if (cur == NULL)
2360 		break;
2361 	    if (cur == (xmlNodePtr) doc) {
2362 		cur = NULL;
2363 		break;
2364 	    }
2365 	    if (cur->next != NULL) {
2366 		cur = cur->next;
2367 		break;
2368 	    }
2369 	} while (cur != NULL);
2370     }
2371     return(count);
2372 }
2373 
2374 /**
2375  * xmlXPathCmpNodes:
2376  * @node1:  the first node
2377  * @node2:  the second node
2378  *
2379  * Compare two nodes w.r.t document order
2380  *
2381  * Returns -2 in case of error 1 if first point < second point, 0 if
2382  *         it's the same node, -1 otherwise
2383  */
2384 int
xmlXPathCmpNodes(xmlNodePtr node1,xmlNodePtr node2)2385 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2386     int depth1, depth2;
2387     int attr1 = 0, attr2 = 0;
2388     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2389     xmlNodePtr cur, root;
2390 
2391     if ((node1 == NULL) || (node2 == NULL))
2392 	return(-2);
2393     /*
2394      * a couple of optimizations which will avoid computations in most cases
2395      */
2396     if (node1 == node2)		/* trivial case */
2397 	return(0);
2398     if (node1->type == XML_ATTRIBUTE_NODE) {
2399 	attr1 = 1;
2400 	attrNode1 = node1;
2401 	node1 = node1->parent;
2402     }
2403     if (node2->type == XML_ATTRIBUTE_NODE) {
2404 	attr2 = 1;
2405 	attrNode2 = node2;
2406 	node2 = node2->parent;
2407     }
2408     if (node1 == node2) {
2409 	if (attr1 == attr2) {
2410 	    /* not required, but we keep attributes in order */
2411 	    if (attr1 != 0) {
2412 	        cur = attrNode2->prev;
2413 		while (cur != NULL) {
2414 		    if (cur == attrNode1)
2415 		        return (1);
2416 		    cur = cur->prev;
2417 		}
2418 		return (-1);
2419 	    }
2420 	    return(0);
2421 	}
2422 	if (attr2 == 1)
2423 	    return(1);
2424 	return(-1);
2425     }
2426     if ((node1->type == XML_NAMESPACE_DECL) ||
2427         (node2->type == XML_NAMESPACE_DECL))
2428 	return(1);
2429     if (node1 == node2->prev)
2430 	return(1);
2431     if (node1 == node2->next)
2432 	return(-1);
2433 
2434     /*
2435      * Speedup using document order if available.
2436      */
2437     if ((node1->type == XML_ELEMENT_NODE) &&
2438 	(node2->type == XML_ELEMENT_NODE) &&
2439 	(0 > (ptrdiff_t) node1->content) &&
2440 	(0 > (ptrdiff_t) node2->content) &&
2441 	(node1->doc == node2->doc)) {
2442 	ptrdiff_t l1, l2;
2443 
2444 	l1 = -((ptrdiff_t) node1->content);
2445 	l2 = -((ptrdiff_t) node2->content);
2446 	if (l1 < l2)
2447 	    return(1);
2448 	if (l1 > l2)
2449 	    return(-1);
2450     }
2451 
2452     /*
2453      * compute depth to root
2454      */
2455     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2456 	if (cur->parent == node1)
2457 	    return(1);
2458 	depth2++;
2459     }
2460     root = cur;
2461     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2462 	if (cur->parent == node2)
2463 	    return(-1);
2464 	depth1++;
2465     }
2466     /*
2467      * Distinct document (or distinct entities :-( ) case.
2468      */
2469     if (root != cur) {
2470 	return(-2);
2471     }
2472     /*
2473      * get the nearest common ancestor.
2474      */
2475     while (depth1 > depth2) {
2476 	depth1--;
2477 	node1 = node1->parent;
2478     }
2479     while (depth2 > depth1) {
2480 	depth2--;
2481 	node2 = node2->parent;
2482     }
2483     while (node1->parent != node2->parent) {
2484 	node1 = node1->parent;
2485 	node2 = node2->parent;
2486 	/* should not happen but just in case ... */
2487 	if ((node1 == NULL) || (node2 == NULL))
2488 	    return(-2);
2489     }
2490     /*
2491      * Find who's first.
2492      */
2493     if (node1 == node2->prev)
2494 	return(1);
2495     if (node1 == node2->next)
2496 	return(-1);
2497     /*
2498      * Speedup using document order if available.
2499      */
2500     if ((node1->type == XML_ELEMENT_NODE) &&
2501 	(node2->type == XML_ELEMENT_NODE) &&
2502 	(0 > (ptrdiff_t) node1->content) &&
2503 	(0 > (ptrdiff_t) node2->content) &&
2504 	(node1->doc == node2->doc)) {
2505 	ptrdiff_t l1, l2;
2506 
2507 	l1 = -((ptrdiff_t) node1->content);
2508 	l2 = -((ptrdiff_t) node2->content);
2509 	if (l1 < l2)
2510 	    return(1);
2511 	if (l1 > l2)
2512 	    return(-1);
2513     }
2514 
2515     for (cur = node1->next;cur != NULL;cur = cur->next)
2516 	if (cur == node2)
2517 	    return(1);
2518     return(-1); /* assume there is no sibling list corruption */
2519 }
2520 
2521 /**
2522  * xmlXPathNodeSetSort:
2523  * @set:  the node set
2524  *
2525  * Sort the node set in document order
2526  */
2527 void
xmlXPathNodeSetSort(xmlNodeSetPtr set)2528 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
2529 #ifndef WITH_TIM_SORT
2530     int i, j, incr, len;
2531     xmlNodePtr tmp;
2532 #endif
2533 
2534     if (set == NULL)
2535 	return;
2536 
2537 #ifndef WITH_TIM_SORT
2538     /*
2539      * Use the old Shell's sort implementation to sort the node-set
2540      * Timsort ought to be quite faster
2541      */
2542     len = set->nodeNr;
2543     for (incr = len / 2; incr > 0; incr /= 2) {
2544 	for (i = incr; i < len; i++) {
2545 	    j = i - incr;
2546 	    while (j >= 0) {
2547 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2548 		if (xmlXPathCmpNodesExt(set->nodeTab[j],
2549 			set->nodeTab[j + incr]) == -1)
2550 #else
2551 		if (xmlXPathCmpNodes(set->nodeTab[j],
2552 			set->nodeTab[j + incr]) == -1)
2553 #endif
2554 		{
2555 		    tmp = set->nodeTab[j];
2556 		    set->nodeTab[j] = set->nodeTab[j + incr];
2557 		    set->nodeTab[j + incr] = tmp;
2558 		    j -= incr;
2559 		} else
2560 		    break;
2561 	    }
2562 	}
2563     }
2564 #else /* WITH_TIM_SORT */
2565     libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2566 #endif /* WITH_TIM_SORT */
2567 }
2568 
2569 #define XML_NODESET_DEFAULT	10
2570 /**
2571  * xmlXPathNodeSetDupNs:
2572  * @node:  the parent node of the namespace XPath node
2573  * @ns:  the libxml namespace declaration node.
2574  *
2575  * Namespace node in libxml don't match the XPath semantic. In a node set
2576  * the namespace nodes are duplicated and the next pointer is set to the
2577  * parent node in the XPath semantic.
2578  *
2579  * Returns the newly created object.
2580  */
2581 static xmlNodePtr
xmlXPathNodeSetDupNs(xmlNodePtr node,xmlNsPtr ns)2582 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2583     xmlNsPtr cur;
2584 
2585     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2586 	return(NULL);
2587     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
2588 	return((xmlNodePtr) ns);
2589 
2590     /*
2591      * Allocate a new Namespace and fill the fields.
2592      */
2593     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2594     if (cur == NULL)
2595 	return(NULL);
2596     memset(cur, 0, sizeof(xmlNs));
2597     cur->type = XML_NAMESPACE_DECL;
2598     if (ns->href != NULL) {
2599 	cur->href = xmlStrdup(ns->href);
2600         if (cur->href == NULL) {
2601             xmlFree(cur);
2602             return(NULL);
2603         }
2604     }
2605     if (ns->prefix != NULL) {
2606 	cur->prefix = xmlStrdup(ns->prefix);
2607         if (cur->prefix == NULL) {
2608             xmlFree((xmlChar *) cur->href);
2609             xmlFree(cur);
2610             return(NULL);
2611         }
2612     }
2613     cur->next = (xmlNsPtr) node;
2614     return((xmlNodePtr) cur);
2615 }
2616 
2617 /**
2618  * xmlXPathNodeSetFreeNs:
2619  * @ns:  the XPath namespace node found in a nodeset.
2620  *
2621  * Namespace nodes in libxml don't match the XPath semantic. In a node set
2622  * the namespace nodes are duplicated and the next pointer is set to the
2623  * parent node in the XPath semantic. Check if such a node needs to be freed
2624  */
2625 void
xmlXPathNodeSetFreeNs(xmlNsPtr ns)2626 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
2627     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2628 	return;
2629 
2630     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2631 	if (ns->href != NULL)
2632 	    xmlFree((xmlChar *)ns->href);
2633 	if (ns->prefix != NULL)
2634 	    xmlFree((xmlChar *)ns->prefix);
2635 	xmlFree(ns);
2636     }
2637 }
2638 
2639 /**
2640  * xmlXPathNodeSetCreate:
2641  * @val:  an initial xmlNodePtr, or NULL
2642  *
2643  * Create a new xmlNodeSetPtr of type double and of value @val
2644  *
2645  * Returns the newly created object.
2646  */
2647 xmlNodeSetPtr
xmlXPathNodeSetCreate(xmlNodePtr val)2648 xmlXPathNodeSetCreate(xmlNodePtr val) {
2649     xmlNodeSetPtr ret;
2650 
2651     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2652     if (ret == NULL)
2653 	return(NULL);
2654     memset(ret, 0 , sizeof(xmlNodeSet));
2655     if (val != NULL) {
2656         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2657 					     sizeof(xmlNodePtr));
2658 	if (ret->nodeTab == NULL) {
2659 	    xmlFree(ret);
2660 	    return(NULL);
2661 	}
2662 	memset(ret->nodeTab, 0 ,
2663 	       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2664         ret->nodeMax = XML_NODESET_DEFAULT;
2665 	if (val->type == XML_NAMESPACE_DECL) {
2666 	    xmlNsPtr ns = (xmlNsPtr) val;
2667             xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2668 
2669             if (nsNode == NULL) {
2670                 xmlXPathFreeNodeSet(ret);
2671                 return(NULL);
2672             }
2673 	    ret->nodeTab[ret->nodeNr++] = nsNode;
2674 	} else
2675 	    ret->nodeTab[ret->nodeNr++] = val;
2676     }
2677     return(ret);
2678 }
2679 
2680 /**
2681  * xmlXPathNodeSetContains:
2682  * @cur:  the node-set
2683  * @val:  the node
2684  *
2685  * checks whether @cur contains @val
2686  *
2687  * Returns true (1) if @cur contains @val, false (0) otherwise
2688  */
2689 int
xmlXPathNodeSetContains(xmlNodeSetPtr cur,xmlNodePtr val)2690 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
2691     int i;
2692 
2693     if ((cur == NULL) || (val == NULL)) return(0);
2694     if (val->type == XML_NAMESPACE_DECL) {
2695 	for (i = 0; i < cur->nodeNr; i++) {
2696 	    if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2697 		xmlNsPtr ns1, ns2;
2698 
2699 		ns1 = (xmlNsPtr) val;
2700 		ns2 = (xmlNsPtr) cur->nodeTab[i];
2701 		if (ns1 == ns2)
2702 		    return(1);
2703 		if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
2704 	            (xmlStrEqual(ns1->prefix, ns2->prefix)))
2705 		    return(1);
2706 	    }
2707 	}
2708     } else {
2709 	for (i = 0; i < cur->nodeNr; i++) {
2710 	    if (cur->nodeTab[i] == val)
2711 		return(1);
2712 	}
2713     }
2714     return(0);
2715 }
2716 
2717 /**
2718  * xmlXPathNodeSetAddNs:
2719  * @cur:  the initial node set
2720  * @node:  the hosting node
2721  * @ns:  a the namespace node
2722  *
2723  * add a new namespace node to an existing NodeSet
2724  *
2725  * Returns 0 in case of success and -1 in case of error
2726  */
2727 int
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur,xmlNodePtr node,xmlNsPtr ns)2728 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
2729     int i;
2730     xmlNodePtr nsNode;
2731 
2732     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
2733         (ns->type != XML_NAMESPACE_DECL) ||
2734 	(node->type != XML_ELEMENT_NODE))
2735 	return(-1);
2736 
2737     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2738     /*
2739      * prevent duplicates
2740      */
2741     for (i = 0;i < cur->nodeNr;i++) {
2742         if ((cur->nodeTab[i] != NULL) &&
2743 	    (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
2744 	    (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
2745 	    (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
2746 	    return(0);
2747     }
2748 
2749     /*
2750      * grow the nodeTab if needed
2751      */
2752     if (cur->nodeMax == 0) {
2753         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2754 					     sizeof(xmlNodePtr));
2755 	if (cur->nodeTab == NULL)
2756 	    return(-1);
2757 	memset(cur->nodeTab, 0 ,
2758 	       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2759         cur->nodeMax = XML_NODESET_DEFAULT;
2760     } else if (cur->nodeNr == cur->nodeMax) {
2761         xmlNodePtr *temp;
2762 
2763         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2764             return(-1);
2765 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2766 				      sizeof(xmlNodePtr));
2767 	if (temp == NULL)
2768 	    return(-1);
2769         cur->nodeMax *= 2;
2770 	cur->nodeTab = temp;
2771     }
2772     nsNode = xmlXPathNodeSetDupNs(node, ns);
2773     if(nsNode == NULL)
2774         return(-1);
2775     cur->nodeTab[cur->nodeNr++] = nsNode;
2776     return(0);
2777 }
2778 
2779 /**
2780  * xmlXPathNodeSetAdd:
2781  * @cur:  the initial node set
2782  * @val:  a new xmlNodePtr
2783  *
2784  * add a new xmlNodePtr to an existing NodeSet
2785  *
2786  * Returns 0 in case of success, and -1 in case of error
2787  */
2788 int
xmlXPathNodeSetAdd(xmlNodeSetPtr cur,xmlNodePtr val)2789 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
2790     int i;
2791 
2792     if ((cur == NULL) || (val == NULL)) return(-1);
2793 
2794     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2795     /*
2796      * prevent duplicates
2797      */
2798     for (i = 0;i < cur->nodeNr;i++)
2799         if (cur->nodeTab[i] == val) return(0);
2800 
2801     /*
2802      * grow the nodeTab if needed
2803      */
2804     if (cur->nodeMax == 0) {
2805         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2806 					     sizeof(xmlNodePtr));
2807 	if (cur->nodeTab == NULL)
2808 	    return(-1);
2809 	memset(cur->nodeTab, 0 ,
2810 	       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2811         cur->nodeMax = XML_NODESET_DEFAULT;
2812     } else if (cur->nodeNr == cur->nodeMax) {
2813         xmlNodePtr *temp;
2814 
2815         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2816             return(-1);
2817 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2818 				      sizeof(xmlNodePtr));
2819 	if (temp == NULL)
2820 	    return(-1);
2821         cur->nodeMax *= 2;
2822 	cur->nodeTab = temp;
2823     }
2824     if (val->type == XML_NAMESPACE_DECL) {
2825 	xmlNsPtr ns = (xmlNsPtr) val;
2826         xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2827 
2828         if (nsNode == NULL)
2829             return(-1);
2830 	cur->nodeTab[cur->nodeNr++] = nsNode;
2831     } else
2832 	cur->nodeTab[cur->nodeNr++] = val;
2833     return(0);
2834 }
2835 
2836 /**
2837  * xmlXPathNodeSetAddUnique:
2838  * @cur:  the initial node set
2839  * @val:  a new xmlNodePtr
2840  *
2841  * add a new xmlNodePtr to an existing NodeSet, optimized version
2842  * when we are sure the node is not already in the set.
2843  *
2844  * Returns 0 in case of success and -1 in case of failure
2845  */
2846 int
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur,xmlNodePtr val)2847 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
2848     if ((cur == NULL) || (val == NULL)) return(-1);
2849 
2850     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2851     /*
2852      * grow the nodeTab if needed
2853      */
2854     if (cur->nodeMax == 0) {
2855         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2856 					     sizeof(xmlNodePtr));
2857 	if (cur->nodeTab == NULL)
2858 	    return(-1);
2859 	memset(cur->nodeTab, 0 ,
2860 	       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2861         cur->nodeMax = XML_NODESET_DEFAULT;
2862     } else if (cur->nodeNr == cur->nodeMax) {
2863         xmlNodePtr *temp;
2864 
2865         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2866             return(-1);
2867 	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2868 				      sizeof(xmlNodePtr));
2869 	if (temp == NULL)
2870 	    return(-1);
2871 	cur->nodeTab = temp;
2872         cur->nodeMax *= 2;
2873     }
2874     if (val->type == XML_NAMESPACE_DECL) {
2875 	xmlNsPtr ns = (xmlNsPtr) val;
2876         xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2877 
2878         if (nsNode == NULL)
2879             return(-1);
2880 	cur->nodeTab[cur->nodeNr++] = nsNode;
2881     } else
2882 	cur->nodeTab[cur->nodeNr++] = val;
2883     return(0);
2884 }
2885 
2886 /**
2887  * xmlXPathNodeSetMerge:
2888  * @val1:  the first NodeSet or NULL
2889  * @val2:  the second NodeSet
2890  *
2891  * Merges two nodesets, all nodes from @val2 are added to @val1
2892  * if @val1 is NULL, a new set is created and copied from @val2
2893  *
2894  * Returns @val1 once extended or NULL in case of error.
2895  *
2896  * Frees @val1 in case of error.
2897  */
2898 xmlNodeSetPtr
xmlXPathNodeSetMerge(xmlNodeSetPtr val1,xmlNodeSetPtr val2)2899 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
2900     int i, j, initNr, skip;
2901     xmlNodePtr n1, n2;
2902 
2903     if (val1 == NULL) {
2904 	val1 = xmlXPathNodeSetCreate(NULL);
2905         if (val1 == NULL)
2906             return (NULL);
2907     }
2908     if (val2 == NULL)
2909         return(val1);
2910 
2911     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2912     initNr = val1->nodeNr;
2913 
2914     for (i = 0;i < val2->nodeNr;i++) {
2915 	n2 = val2->nodeTab[i];
2916 	/*
2917 	 * check against duplicates
2918 	 */
2919 	skip = 0;
2920 	for (j = 0; j < initNr; j++) {
2921 	    n1 = val1->nodeTab[j];
2922 	    if (n1 == n2) {
2923 		skip = 1;
2924 		break;
2925 	    } else if ((n1->type == XML_NAMESPACE_DECL) &&
2926 		       (n2->type == XML_NAMESPACE_DECL)) {
2927 		if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2928 		    (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2929 			((xmlNsPtr) n2)->prefix)))
2930 		{
2931 		    skip = 1;
2932 		    break;
2933 		}
2934 	    }
2935 	}
2936 	if (skip)
2937 	    continue;
2938 
2939 	/*
2940 	 * grow the nodeTab if needed
2941 	 */
2942 	if (val1->nodeMax == 0) {
2943 	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2944 						    sizeof(xmlNodePtr));
2945 	    if (val1->nodeTab == NULL)
2946 		goto error;
2947 	    memset(val1->nodeTab, 0 ,
2948 		   XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2949 	    val1->nodeMax = XML_NODESET_DEFAULT;
2950 	} else if (val1->nodeNr == val1->nodeMax) {
2951 	    xmlNodePtr *temp;
2952 
2953             if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2954                 goto error;
2955 	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
2956 					     sizeof(xmlNodePtr));
2957 	    if (temp == NULL)
2958 		goto error;
2959 	    val1->nodeTab = temp;
2960 	    val1->nodeMax *= 2;
2961 	}
2962 	if (n2->type == XML_NAMESPACE_DECL) {
2963 	    xmlNsPtr ns = (xmlNsPtr) n2;
2964             xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2965 
2966             if (nsNode == NULL)
2967                 goto error;
2968 	    val1->nodeTab[val1->nodeNr++] = nsNode;
2969 	} else
2970 	    val1->nodeTab[val1->nodeNr++] = n2;
2971     }
2972 
2973     return(val1);
2974 
2975 error:
2976     xmlXPathFreeNodeSet(val1);
2977     return(NULL);
2978 }
2979 
2980 
2981 /**
2982  * xmlXPathNodeSetMergeAndClear:
2983  * @set1:  the first NodeSet or NULL
2984  * @set2:  the second NodeSet
2985  *
2986  * Merges two nodesets, all nodes from @set2 are added to @set1.
2987  * Checks for duplicate nodes. Clears set2.
2988  *
2989  * Returns @set1 once extended or NULL in case of error.
2990  *
2991  * Frees @set1 in case of error.
2992  */
2993 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1,xmlNodeSetPtr set2)2994 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
2995 {
2996     {
2997 	int i, j, initNbSet1;
2998 	xmlNodePtr n1, n2;
2999 
3000 	initNbSet1 = set1->nodeNr;
3001 	for (i = 0;i < set2->nodeNr;i++) {
3002 	    n2 = set2->nodeTab[i];
3003 	    /*
3004 	    * Skip duplicates.
3005 	    */
3006 	    for (j = 0; j < initNbSet1; j++) {
3007 		n1 = set1->nodeTab[j];
3008 		if (n1 == n2) {
3009 		    goto skip_node;
3010 		} else if ((n1->type == XML_NAMESPACE_DECL) &&
3011 		    (n2->type == XML_NAMESPACE_DECL))
3012 		{
3013 		    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3014 			(xmlStrEqual(((xmlNsPtr) n1)->prefix,
3015 			((xmlNsPtr) n2)->prefix)))
3016 		    {
3017 			/*
3018 			* Free the namespace node.
3019 			*/
3020 			xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3021 			goto skip_node;
3022 		    }
3023 		}
3024 	    }
3025 	    /*
3026 	    * grow the nodeTab if needed
3027 	    */
3028 	    if (set1->nodeMax == 0) {
3029 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3030 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3031 		if (set1->nodeTab == NULL)
3032 		    goto error;
3033 		memset(set1->nodeTab, 0,
3034 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3035 		set1->nodeMax = XML_NODESET_DEFAULT;
3036 	    } else if (set1->nodeNr >= set1->nodeMax) {
3037 		xmlNodePtr *temp;
3038 
3039                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
3040                     goto error;
3041 		temp = (xmlNodePtr *) xmlRealloc(
3042 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3043 		if (temp == NULL)
3044 		    goto error;
3045 		set1->nodeTab = temp;
3046 		set1->nodeMax *= 2;
3047 	    }
3048 	    set1->nodeTab[set1->nodeNr++] = n2;
3049 skip_node:
3050             set2->nodeTab[i] = NULL;
3051 	}
3052     }
3053     set2->nodeNr = 0;
3054     return(set1);
3055 
3056 error:
3057     xmlXPathFreeNodeSet(set1);
3058     xmlXPathNodeSetClear(set2, 1);
3059     return(NULL);
3060 }
3061 
3062 /**
3063  * xmlXPathNodeSetMergeAndClearNoDupls:
3064  * @set1:  the first NodeSet or NULL
3065  * @set2:  the second NodeSet
3066  *
3067  * Merges two nodesets, all nodes from @set2 are added to @set1.
3068  * Doesn't check for duplicate nodes. Clears set2.
3069  *
3070  * Returns @set1 once extended or NULL in case of error.
3071  *
3072  * Frees @set1 in case of error.
3073  */
3074 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1,xmlNodeSetPtr set2)3075 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3076 {
3077     {
3078 	int i;
3079 	xmlNodePtr n2;
3080 
3081 	for (i = 0;i < set2->nodeNr;i++) {
3082 	    n2 = set2->nodeTab[i];
3083 	    if (set1->nodeMax == 0) {
3084 		set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3085 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3086 		if (set1->nodeTab == NULL)
3087 		    goto error;
3088 		memset(set1->nodeTab, 0,
3089 		    XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3090 		set1->nodeMax = XML_NODESET_DEFAULT;
3091 	    } else if (set1->nodeNr >= set1->nodeMax) {
3092 		xmlNodePtr *temp;
3093 
3094                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
3095                     goto error;
3096 		temp = (xmlNodePtr *) xmlRealloc(
3097 		    set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3098 		if (temp == NULL)
3099 		    goto error;
3100 		set1->nodeTab = temp;
3101 		set1->nodeMax *= 2;
3102 	    }
3103 	    set1->nodeTab[set1->nodeNr++] = n2;
3104             set2->nodeTab[i] = NULL;
3105 	}
3106     }
3107     set2->nodeNr = 0;
3108     return(set1);
3109 
3110 error:
3111     xmlXPathFreeNodeSet(set1);
3112     xmlXPathNodeSetClear(set2, 1);
3113     return(NULL);
3114 }
3115 
3116 /**
3117  * xmlXPathNodeSetDel:
3118  * @cur:  the initial node set
3119  * @val:  an xmlNodePtr
3120  *
3121  * Removes an xmlNodePtr from an existing NodeSet
3122  */
3123 void
xmlXPathNodeSetDel(xmlNodeSetPtr cur,xmlNodePtr val)3124 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3125     int i;
3126 
3127     if (cur == NULL) return;
3128     if (val == NULL) return;
3129 
3130     /*
3131      * find node in nodeTab
3132      */
3133     for (i = 0;i < cur->nodeNr;i++)
3134         if (cur->nodeTab[i] == val) break;
3135 
3136     if (i >= cur->nodeNr) {	/* not found */
3137         return;
3138     }
3139     if ((cur->nodeTab[i] != NULL) &&
3140 	(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
3141 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
3142     cur->nodeNr--;
3143     for (;i < cur->nodeNr;i++)
3144         cur->nodeTab[i] = cur->nodeTab[i + 1];
3145     cur->nodeTab[cur->nodeNr] = NULL;
3146 }
3147 
3148 /**
3149  * xmlXPathNodeSetRemove:
3150  * @cur:  the initial node set
3151  * @val:  the index to remove
3152  *
3153  * Removes an entry from an existing NodeSet list.
3154  */
3155 void
xmlXPathNodeSetRemove(xmlNodeSetPtr cur,int val)3156 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
3157     if (cur == NULL) return;
3158     if (val >= cur->nodeNr) return;
3159     if ((cur->nodeTab[val] != NULL) &&
3160 	(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
3161 	xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
3162     cur->nodeNr--;
3163     for (;val < cur->nodeNr;val++)
3164         cur->nodeTab[val] = cur->nodeTab[val + 1];
3165     cur->nodeTab[cur->nodeNr] = NULL;
3166 }
3167 
3168 /**
3169  * xmlXPathFreeNodeSet:
3170  * @obj:  the xmlNodeSetPtr to free
3171  *
3172  * Free the NodeSet compound (not the actual nodes !).
3173  */
3174 void
xmlXPathFreeNodeSet(xmlNodeSetPtr obj)3175 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
3176     if (obj == NULL) return;
3177     if (obj->nodeTab != NULL) {
3178 	int i;
3179 
3180 	/* @@ with_ns to check whether namespace nodes should be looked at @@ */
3181 	for (i = 0;i < obj->nodeNr;i++)
3182 	    if ((obj->nodeTab[i] != NULL) &&
3183 		(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3184 		xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3185 	xmlFree(obj->nodeTab);
3186     }
3187     xmlFree(obj);
3188 }
3189 
3190 /**
3191  * xmlXPathNodeSetClearFromPos:
3192  * @set: the node set to be cleared
3193  * @pos: the start position to clear from
3194  *
3195  * Clears the list from temporary XPath objects (e.g. namespace nodes
3196  * are feed) starting with the entry at @pos, but does *not* free the list
3197  * itself. Sets the length of the list to @pos.
3198  */
3199 static void
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set,int pos,int hasNsNodes)3200 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
3201 {
3202     if ((set == NULL) || (pos >= set->nodeNr))
3203 	return;
3204     else if ((hasNsNodes)) {
3205 	int i;
3206 	xmlNodePtr node;
3207 
3208 	for (i = pos; i < set->nodeNr; i++) {
3209 	    node = set->nodeTab[i];
3210 	    if ((node != NULL) &&
3211 		(node->type == XML_NAMESPACE_DECL))
3212 		xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3213 	}
3214     }
3215     set->nodeNr = pos;
3216 }
3217 
3218 /**
3219  * xmlXPathNodeSetClear:
3220  * @set:  the node set to clear
3221  *
3222  * Clears the list from all temporary XPath objects (e.g. namespace nodes
3223  * are feed), but does *not* free the list itself. Sets the length of the
3224  * list to 0.
3225  */
3226 static void
xmlXPathNodeSetClear(xmlNodeSetPtr set,int hasNsNodes)3227 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
3228 {
3229     xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3230 }
3231 
3232 /**
3233  * xmlXPathNodeSetKeepLast:
3234  * @set: the node set to be cleared
3235  *
3236  * Move the last node to the first position and clear temporary XPath objects
3237  * (e.g. namespace nodes) from all other nodes. Sets the length of the list
3238  * to 1.
3239  */
3240 static void
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)3241 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
3242 {
3243     int i;
3244     xmlNodePtr node;
3245 
3246     if ((set == NULL) || (set->nodeNr <= 1))
3247 	return;
3248     for (i = 0; i < set->nodeNr - 1; i++) {
3249         node = set->nodeTab[i];
3250         if ((node != NULL) &&
3251             (node->type == XML_NAMESPACE_DECL))
3252             xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3253     }
3254     set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
3255     set->nodeNr = 1;
3256 }
3257 
3258 /**
3259  * xmlXPathNewNodeSet:
3260  * @val:  the NodePtr value
3261  *
3262  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3263  * it with the single Node @val
3264  *
3265  * Returns the newly created object.
3266  */
3267 xmlXPathObjectPtr
xmlXPathNewNodeSet(xmlNodePtr val)3268 xmlXPathNewNodeSet(xmlNodePtr val) {
3269     xmlXPathObjectPtr ret;
3270 
3271     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3272     if (ret == NULL)
3273 	return(NULL);
3274     memset(ret, 0 , sizeof(xmlXPathObject));
3275     ret->type = XPATH_NODESET;
3276     ret->boolval = 0;
3277     ret->nodesetval = xmlXPathNodeSetCreate(val);
3278     if (ret->nodesetval == NULL) {
3279         xmlFree(ret);
3280         return(NULL);
3281     }
3282     /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3283     return(ret);
3284 }
3285 
3286 /**
3287  * xmlXPathNewValueTree:
3288  * @val:  the NodePtr value
3289  *
3290  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
3291  * it with the tree root @val
3292  *
3293  * Returns the newly created object.
3294  */
3295 xmlXPathObjectPtr
xmlXPathNewValueTree(xmlNodePtr val)3296 xmlXPathNewValueTree(xmlNodePtr val) {
3297     xmlXPathObjectPtr ret;
3298 
3299     ret = xmlXPathNewNodeSet(val);
3300     if (ret == NULL)
3301 	return(NULL);
3302     ret->type = XPATH_XSLT_TREE;
3303 
3304     return(ret);
3305 }
3306 
3307 /**
3308  * xmlXPathNewNodeSetList:
3309  * @val:  an existing NodeSet
3310  *
3311  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3312  * it with the Nodeset @val
3313  *
3314  * Returns the newly created object.
3315  */
3316 xmlXPathObjectPtr
xmlXPathNewNodeSetList(xmlNodeSetPtr val)3317 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
3318 {
3319     xmlXPathObjectPtr ret;
3320 
3321     if (val == NULL)
3322         ret = NULL;
3323     else if (val->nodeTab == NULL)
3324         ret = xmlXPathNewNodeSet(NULL);
3325     else {
3326         ret = xmlXPathNewNodeSet(val->nodeTab[0]);
3327         if (ret) {
3328             ret->nodesetval = xmlXPathNodeSetMerge(NULL, val);
3329             if (ret->nodesetval == NULL) {
3330                 xmlFree(ret);
3331                 return(NULL);
3332             }
3333         }
3334     }
3335 
3336     return (ret);
3337 }
3338 
3339 /**
3340  * xmlXPathWrapNodeSet:
3341  * @val:  the NodePtr value
3342  *
3343  * Wrap the Nodeset @val in a new xmlXPathObjectPtr
3344  *
3345  * Returns the newly created object.
3346  *
3347  * In case of error the node set is destroyed and NULL is returned.
3348  */
3349 xmlXPathObjectPtr
xmlXPathWrapNodeSet(xmlNodeSetPtr val)3350 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
3351     xmlXPathObjectPtr ret;
3352 
3353     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3354     if (ret == NULL) {
3355         xmlXPathFreeNodeSet(val);
3356 	return(NULL);
3357     }
3358     memset(ret, 0 , sizeof(xmlXPathObject));
3359     ret->type = XPATH_NODESET;
3360     ret->nodesetval = val;
3361     return(ret);
3362 }
3363 
3364 /**
3365  * xmlXPathFreeNodeSetList:
3366  * @obj:  an existing NodeSetList object
3367  *
3368  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
3369  * the list contrary to xmlXPathFreeObject().
3370  */
3371 void
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj)3372 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
3373     if (obj == NULL) return;
3374     xmlFree(obj);
3375 }
3376 
3377 /**
3378  * xmlXPathDifference:
3379  * @nodes1:  a node-set
3380  * @nodes2:  a node-set
3381  *
3382  * Implements the EXSLT - Sets difference() function:
3383  *    node-set set:difference (node-set, node-set)
3384  *
3385  * Returns the difference between the two node sets, or nodes1 if
3386  *         nodes2 is empty
3387  */
3388 xmlNodeSetPtr
xmlXPathDifference(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3389 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3390     xmlNodeSetPtr ret;
3391     int i, l1;
3392     xmlNodePtr cur;
3393 
3394     if (xmlXPathNodeSetIsEmpty(nodes2))
3395 	return(nodes1);
3396 
3397     ret = xmlXPathNodeSetCreate(NULL);
3398     if (ret == NULL)
3399         return(NULL);
3400     if (xmlXPathNodeSetIsEmpty(nodes1))
3401 	return(ret);
3402 
3403     l1 = xmlXPathNodeSetGetLength(nodes1);
3404 
3405     for (i = 0; i < l1; i++) {
3406 	cur = xmlXPathNodeSetItem(nodes1, i);
3407 	if (!xmlXPathNodeSetContains(nodes2, cur)) {
3408 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3409                 xmlXPathFreeNodeSet(ret);
3410 	        return(NULL);
3411             }
3412 	}
3413     }
3414     return(ret);
3415 }
3416 
3417 /**
3418  * xmlXPathIntersection:
3419  * @nodes1:  a node-set
3420  * @nodes2:  a node-set
3421  *
3422  * Implements the EXSLT - Sets intersection() function:
3423  *    node-set set:intersection (node-set, node-set)
3424  *
3425  * Returns a node set comprising the nodes that are within both the
3426  *         node sets passed as arguments
3427  */
3428 xmlNodeSetPtr
xmlXPathIntersection(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3429 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3430     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
3431     int i, l1;
3432     xmlNodePtr cur;
3433 
3434     if (ret == NULL)
3435         return(ret);
3436     if (xmlXPathNodeSetIsEmpty(nodes1))
3437 	return(ret);
3438     if (xmlXPathNodeSetIsEmpty(nodes2))
3439 	return(ret);
3440 
3441     l1 = xmlXPathNodeSetGetLength(nodes1);
3442 
3443     for (i = 0; i < l1; i++) {
3444 	cur = xmlXPathNodeSetItem(nodes1, i);
3445 	if (xmlXPathNodeSetContains(nodes2, cur)) {
3446 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3447                 xmlXPathFreeNodeSet(ret);
3448 	        return(NULL);
3449             }
3450 	}
3451     }
3452     return(ret);
3453 }
3454 
3455 /**
3456  * xmlXPathDistinctSorted:
3457  * @nodes:  a node-set, sorted by document order
3458  *
3459  * Implements the EXSLT - Sets distinct() function:
3460  *    node-set set:distinct (node-set)
3461  *
3462  * Returns a subset of the nodes contained in @nodes, or @nodes if
3463  *         it is empty
3464  */
3465 xmlNodeSetPtr
xmlXPathDistinctSorted(xmlNodeSetPtr nodes)3466 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
3467     xmlNodeSetPtr ret;
3468     xmlHashTablePtr hash;
3469     int i, l;
3470     xmlChar * strval;
3471     xmlNodePtr cur;
3472 
3473     if (xmlXPathNodeSetIsEmpty(nodes))
3474 	return(nodes);
3475 
3476     ret = xmlXPathNodeSetCreate(NULL);
3477     if (ret == NULL)
3478         return(ret);
3479     l = xmlXPathNodeSetGetLength(nodes);
3480     hash = xmlHashCreate (l);
3481     for (i = 0; i < l; i++) {
3482 	cur = xmlXPathNodeSetItem(nodes, i);
3483 	strval = xmlXPathCastNodeToString(cur);
3484 	if (xmlHashLookup(hash, strval) == NULL) {
3485 	    if (xmlHashAddEntry(hash, strval, strval) < 0) {
3486                 xmlFree(strval);
3487                 goto error;
3488             }
3489 	    if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3490 	        goto error;
3491 	} else {
3492 	    xmlFree(strval);
3493 	}
3494     }
3495     xmlHashFree(hash, xmlHashDefaultDeallocator);
3496     return(ret);
3497 
3498 error:
3499     xmlHashFree(hash, xmlHashDefaultDeallocator);
3500     xmlXPathFreeNodeSet(ret);
3501     return(NULL);
3502 }
3503 
3504 /**
3505  * xmlXPathDistinct:
3506  * @nodes:  a node-set
3507  *
3508  * Implements the EXSLT - Sets distinct() function:
3509  *    node-set set:distinct (node-set)
3510  * @nodes is sorted by document order, then #exslSetsDistinctSorted
3511  * is called with the sorted node-set
3512  *
3513  * Returns a subset of the nodes contained in @nodes, or @nodes if
3514  *         it is empty
3515  */
3516 xmlNodeSetPtr
xmlXPathDistinct(xmlNodeSetPtr nodes)3517 xmlXPathDistinct (xmlNodeSetPtr nodes) {
3518     if (xmlXPathNodeSetIsEmpty(nodes))
3519 	return(nodes);
3520 
3521     xmlXPathNodeSetSort(nodes);
3522     return(xmlXPathDistinctSorted(nodes));
3523 }
3524 
3525 /**
3526  * xmlXPathHasSameNodes:
3527  * @nodes1:  a node-set
3528  * @nodes2:  a node-set
3529  *
3530  * Implements the EXSLT - Sets has-same-nodes function:
3531  *    boolean set:has-same-node(node-set, node-set)
3532  *
3533  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
3534  *         otherwise
3535  */
3536 int
xmlXPathHasSameNodes(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3537 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3538     int i, l;
3539     xmlNodePtr cur;
3540 
3541     if (xmlXPathNodeSetIsEmpty(nodes1) ||
3542 	xmlXPathNodeSetIsEmpty(nodes2))
3543 	return(0);
3544 
3545     l = xmlXPathNodeSetGetLength(nodes1);
3546     for (i = 0; i < l; i++) {
3547 	cur = xmlXPathNodeSetItem(nodes1, i);
3548 	if (xmlXPathNodeSetContains(nodes2, cur))
3549 	    return(1);
3550     }
3551     return(0);
3552 }
3553 
3554 /**
3555  * xmlXPathNodeLeadingSorted:
3556  * @nodes: a node-set, sorted by document order
3557  * @node: a node
3558  *
3559  * Implements the EXSLT - Sets leading() function:
3560  *    node-set set:leading (node-set, node-set)
3561  *
3562  * Returns the nodes in @nodes that precede @node in document order,
3563  *         @nodes if @node is NULL or an empty node-set if @nodes
3564  *         doesn't contain @node
3565  */
3566 xmlNodeSetPtr
xmlXPathNodeLeadingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)3567 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3568     int i, l;
3569     xmlNodePtr cur;
3570     xmlNodeSetPtr ret;
3571 
3572     if (node == NULL)
3573 	return(nodes);
3574 
3575     ret = xmlXPathNodeSetCreate(NULL);
3576     if (ret == NULL)
3577         return(ret);
3578     if (xmlXPathNodeSetIsEmpty(nodes) ||
3579 	(!xmlXPathNodeSetContains(nodes, node)))
3580 	return(ret);
3581 
3582     l = xmlXPathNodeSetGetLength(nodes);
3583     for (i = 0; i < l; i++) {
3584 	cur = xmlXPathNodeSetItem(nodes, i);
3585 	if (cur == node)
3586 	    break;
3587 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3588             xmlXPathFreeNodeSet(ret);
3589 	    return(NULL);
3590         }
3591     }
3592     return(ret);
3593 }
3594 
3595 /**
3596  * xmlXPathNodeLeading:
3597  * @nodes:  a node-set
3598  * @node:  a node
3599  *
3600  * Implements the EXSLT - Sets leading() function:
3601  *    node-set set:leading (node-set, node-set)
3602  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
3603  * is called.
3604  *
3605  * Returns the nodes in @nodes that precede @node in document order,
3606  *         @nodes if @node is NULL or an empty node-set if @nodes
3607  *         doesn't contain @node
3608  */
3609 xmlNodeSetPtr
xmlXPathNodeLeading(xmlNodeSetPtr nodes,xmlNodePtr node)3610 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
3611     xmlXPathNodeSetSort(nodes);
3612     return(xmlXPathNodeLeadingSorted(nodes, node));
3613 }
3614 
3615 /**
3616  * xmlXPathLeadingSorted:
3617  * @nodes1:  a node-set, sorted by document order
3618  * @nodes2:  a node-set, sorted by document order
3619  *
3620  * Implements the EXSLT - Sets leading() function:
3621  *    node-set set:leading (node-set, node-set)
3622  *
3623  * Returns the nodes in @nodes1 that precede the first node in @nodes2
3624  *         in document order, @nodes1 if @nodes2 is NULL or empty or
3625  *         an empty node-set if @nodes1 doesn't contain @nodes2
3626  */
3627 xmlNodeSetPtr
xmlXPathLeadingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3628 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3629     if (xmlXPathNodeSetIsEmpty(nodes2))
3630 	return(nodes1);
3631     return(xmlXPathNodeLeadingSorted(nodes1,
3632 				     xmlXPathNodeSetItem(nodes2, 1)));
3633 }
3634 
3635 /**
3636  * xmlXPathLeading:
3637  * @nodes1:  a node-set
3638  * @nodes2:  a node-set
3639  *
3640  * Implements the EXSLT - Sets leading() function:
3641  *    node-set set:leading (node-set, node-set)
3642  * @nodes1 and @nodes2 are sorted by document order, then
3643  * #exslSetsLeadingSorted is called.
3644  *
3645  * Returns the nodes in @nodes1 that precede the first node in @nodes2
3646  *         in document order, @nodes1 if @nodes2 is NULL or empty or
3647  *         an empty node-set if @nodes1 doesn't contain @nodes2
3648  */
3649 xmlNodeSetPtr
xmlXPathLeading(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3650 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3651     if (xmlXPathNodeSetIsEmpty(nodes2))
3652 	return(nodes1);
3653     if (xmlXPathNodeSetIsEmpty(nodes1))
3654 	return(xmlXPathNodeSetCreate(NULL));
3655     xmlXPathNodeSetSort(nodes1);
3656     xmlXPathNodeSetSort(nodes2);
3657     return(xmlXPathNodeLeadingSorted(nodes1,
3658 				     xmlXPathNodeSetItem(nodes2, 1)));
3659 }
3660 
3661 /**
3662  * xmlXPathNodeTrailingSorted:
3663  * @nodes: a node-set, sorted by document order
3664  * @node: a node
3665  *
3666  * Implements the EXSLT - Sets trailing() function:
3667  *    node-set set:trailing (node-set, node-set)
3668  *
3669  * Returns the nodes in @nodes that follow @node in document order,
3670  *         @nodes if @node is NULL or an empty node-set if @nodes
3671  *         doesn't contain @node
3672  */
3673 xmlNodeSetPtr
xmlXPathNodeTrailingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)3674 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3675     int i, l;
3676     xmlNodePtr cur;
3677     xmlNodeSetPtr ret;
3678 
3679     if (node == NULL)
3680 	return(nodes);
3681 
3682     ret = xmlXPathNodeSetCreate(NULL);
3683     if (ret == NULL)
3684         return(ret);
3685     if (xmlXPathNodeSetIsEmpty(nodes) ||
3686 	(!xmlXPathNodeSetContains(nodes, node)))
3687 	return(ret);
3688 
3689     l = xmlXPathNodeSetGetLength(nodes);
3690     for (i = l - 1; i >= 0; i--) {
3691 	cur = xmlXPathNodeSetItem(nodes, i);
3692 	if (cur == node)
3693 	    break;
3694 	if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3695             xmlXPathFreeNodeSet(ret);
3696 	    return(NULL);
3697         }
3698     }
3699     xmlXPathNodeSetSort(ret);	/* bug 413451 */
3700     return(ret);
3701 }
3702 
3703 /**
3704  * xmlXPathNodeTrailing:
3705  * @nodes:  a node-set
3706  * @node:  a node
3707  *
3708  * Implements the EXSLT - Sets trailing() function:
3709  *    node-set set:trailing (node-set, node-set)
3710  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
3711  * is called.
3712  *
3713  * Returns the nodes in @nodes that follow @node in document order,
3714  *         @nodes if @node is NULL or an empty node-set if @nodes
3715  *         doesn't contain @node
3716  */
3717 xmlNodeSetPtr
xmlXPathNodeTrailing(xmlNodeSetPtr nodes,xmlNodePtr node)3718 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
3719     xmlXPathNodeSetSort(nodes);
3720     return(xmlXPathNodeTrailingSorted(nodes, node));
3721 }
3722 
3723 /**
3724  * xmlXPathTrailingSorted:
3725  * @nodes1:  a node-set, sorted by document order
3726  * @nodes2:  a node-set, sorted by document order
3727  *
3728  * Implements the EXSLT - Sets trailing() function:
3729  *    node-set set:trailing (node-set, node-set)
3730  *
3731  * Returns the nodes in @nodes1 that follow the first node in @nodes2
3732  *         in document order, @nodes1 if @nodes2 is NULL or empty or
3733  *         an empty node-set if @nodes1 doesn't contain @nodes2
3734  */
3735 xmlNodeSetPtr
xmlXPathTrailingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3736 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3737     if (xmlXPathNodeSetIsEmpty(nodes2))
3738 	return(nodes1);
3739     return(xmlXPathNodeTrailingSorted(nodes1,
3740 				      xmlXPathNodeSetItem(nodes2, 0)));
3741 }
3742 
3743 /**
3744  * xmlXPathTrailing:
3745  * @nodes1:  a node-set
3746  * @nodes2:  a node-set
3747  *
3748  * Implements the EXSLT - Sets trailing() function:
3749  *    node-set set:trailing (node-set, node-set)
3750  * @nodes1 and @nodes2 are sorted by document order, then
3751  * #xmlXPathTrailingSorted is called.
3752  *
3753  * Returns the nodes in @nodes1 that follow the first node in @nodes2
3754  *         in document order, @nodes1 if @nodes2 is NULL or empty or
3755  *         an empty node-set if @nodes1 doesn't contain @nodes2
3756  */
3757 xmlNodeSetPtr
xmlXPathTrailing(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3758 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3759     if (xmlXPathNodeSetIsEmpty(nodes2))
3760 	return(nodes1);
3761     if (xmlXPathNodeSetIsEmpty(nodes1))
3762 	return(xmlXPathNodeSetCreate(NULL));
3763     xmlXPathNodeSetSort(nodes1);
3764     xmlXPathNodeSetSort(nodes2);
3765     return(xmlXPathNodeTrailingSorted(nodes1,
3766 				      xmlXPathNodeSetItem(nodes2, 0)));
3767 }
3768 
3769 /************************************************************************
3770  *									*
3771  *		Routines to handle extra functions			*
3772  *									*
3773  ************************************************************************/
3774 
3775 /**
3776  * xmlXPathRegisterFunc:
3777  * @ctxt:  the XPath context
3778  * @name:  the function name
3779  * @f:  the function implementation or NULL
3780  *
3781  * Register a new function. If @f is NULL it unregisters the function
3782  *
3783  * Returns 0 in case of success, -1 in case of error
3784  */
3785 int
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathFunction f)3786 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
3787 		     xmlXPathFunction f) {
3788     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
3789 }
3790 
3791 /**
3792  * xmlXPathRegisterFuncNS:
3793  * @ctxt:  the XPath context
3794  * @name:  the function name
3795  * @ns_uri:  the function namespace URI
3796  * @f:  the function implementation or NULL
3797  *
3798  * Register a new function. If @f is NULL it unregisters the function
3799  *
3800  * Returns 0 in case of success, -1 in case of error
3801  */
3802 int
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathFunction f)3803 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3804 		       const xmlChar *ns_uri, xmlXPathFunction f) {
3805     int ret;
3806 
3807     if (ctxt == NULL)
3808 	return(-1);
3809     if (name == NULL)
3810 	return(-1);
3811 
3812     if (ctxt->funcHash == NULL)
3813 	ctxt->funcHash = xmlHashCreate(0);
3814     if (ctxt->funcHash == NULL) {
3815         xmlXPathErrMemory(ctxt);
3816 	return(-1);
3817     }
3818     if (f == NULL)
3819         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
3820 XML_IGNORE_FPTR_CAST_WARNINGS
3821     ret = xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f);
3822 XML_POP_WARNINGS
3823     if (ret < 0) {
3824         xmlXPathErrMemory(ctxt);
3825         return(-1);
3826     }
3827 
3828     return(0);
3829 }
3830 
3831 /**
3832  * xmlXPathRegisterFuncLookup:
3833  * @ctxt:  the XPath context
3834  * @f:  the lookup function
3835  * @funcCtxt:  the lookup data
3836  *
3837  * Registers an external mechanism to do function lookup.
3838  */
3839 void
xmlXPathRegisterFuncLookup(xmlXPathContextPtr ctxt,xmlXPathFuncLookupFunc f,void * funcCtxt)3840 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
3841 			    xmlXPathFuncLookupFunc f,
3842 			    void *funcCtxt) {
3843     if (ctxt == NULL)
3844 	return;
3845     ctxt->funcLookupFunc = f;
3846     ctxt->funcLookupData = funcCtxt;
3847 }
3848 
3849 /**
3850  * xmlXPathFunctionLookup:
3851  * @ctxt:  the XPath context
3852  * @name:  the function name
3853  *
3854  * Search in the Function array of the context for the given
3855  * function.
3856  *
3857  * Returns the xmlXPathFunction or NULL if not found
3858  */
3859 xmlXPathFunction
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt,const xmlChar * name)3860 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
3861     if (ctxt == NULL)
3862 	return (NULL);
3863 
3864     if (ctxt->funcLookupFunc != NULL) {
3865 	xmlXPathFunction ret;
3866 	xmlXPathFuncLookupFunc f;
3867 
3868 	f = ctxt->funcLookupFunc;
3869 	ret = f(ctxt->funcLookupData, name, NULL);
3870 	if (ret != NULL)
3871 	    return(ret);
3872     }
3873     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
3874 }
3875 
3876 /**
3877  * xmlXPathFunctionLookupNS:
3878  * @ctxt:  the XPath context
3879  * @name:  the function name
3880  * @ns_uri:  the function namespace URI
3881  *
3882  * Search in the Function array of the context for the given
3883  * function.
3884  *
3885  * Returns the xmlXPathFunction or NULL if not found
3886  */
3887 xmlXPathFunction
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)3888 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3889 			 const xmlChar *ns_uri) {
3890     xmlXPathFunction ret;
3891 
3892     if (ctxt == NULL)
3893 	return(NULL);
3894     if (name == NULL)
3895 	return(NULL);
3896 
3897     if (ctxt->funcLookupFunc != NULL) {
3898 	xmlXPathFuncLookupFunc f;
3899 
3900 	f = ctxt->funcLookupFunc;
3901 	ret = f(ctxt->funcLookupData, name, ns_uri);
3902 	if (ret != NULL)
3903 	    return(ret);
3904     }
3905 
3906     if (ctxt->funcHash == NULL)
3907 	return(NULL);
3908 
3909 XML_IGNORE_FPTR_CAST_WARNINGS
3910     ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
3911 XML_POP_WARNINGS
3912     return(ret);
3913 }
3914 
3915 /**
3916  * xmlXPathRegisteredFuncsCleanup:
3917  * @ctxt:  the XPath context
3918  *
3919  * Cleanup the XPath context data associated to registered functions
3920  */
3921 void
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt)3922 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
3923     if (ctxt == NULL)
3924 	return;
3925 
3926     xmlHashFree(ctxt->funcHash, NULL);
3927     ctxt->funcHash = NULL;
3928 }
3929 
3930 /************************************************************************
3931  *									*
3932  *			Routines to handle Variables			*
3933  *									*
3934  ************************************************************************/
3935 
3936 /**
3937  * xmlXPathRegisterVariable:
3938  * @ctxt:  the XPath context
3939  * @name:  the variable name
3940  * @value:  the variable value or NULL
3941  *
3942  * Register a new variable value. If @value is NULL it unregisters
3943  * the variable
3944  *
3945  * Returns 0 in case of success, -1 in case of error
3946  */
3947 int
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathObjectPtr value)3948 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
3949 			 xmlXPathObjectPtr value) {
3950     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
3951 }
3952 
3953 /**
3954  * xmlXPathRegisterVariableNS:
3955  * @ctxt:  the XPath context
3956  * @name:  the variable name
3957  * @ns_uri:  the variable namespace URI
3958  * @value:  the variable value or NULL
3959  *
3960  * Register a new variable value. If @value is NULL it unregisters
3961  * the variable
3962  *
3963  * Returns 0 in case of success, -1 in case of error
3964  */
3965 int
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathObjectPtr value)3966 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3967 			   const xmlChar *ns_uri,
3968 			   xmlXPathObjectPtr value) {
3969     if (ctxt == NULL)
3970 	return(-1);
3971     if (name == NULL)
3972 	return(-1);
3973 
3974     if (ctxt->varHash == NULL)
3975 	ctxt->varHash = xmlHashCreate(0);
3976     if (ctxt->varHash == NULL)
3977 	return(-1);
3978     if (value == NULL)
3979         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
3980 	                           xmlXPathFreeObjectEntry));
3981     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
3982 			       (void *) value, xmlXPathFreeObjectEntry));
3983 }
3984 
3985 /**
3986  * xmlXPathRegisterVariableLookup:
3987  * @ctxt:  the XPath context
3988  * @f:  the lookup function
3989  * @data:  the lookup data
3990  *
3991  * register an external mechanism to do variable lookup
3992  */
3993 void
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,xmlXPathVariableLookupFunc f,void * data)3994 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
3995 	 xmlXPathVariableLookupFunc f, void *data) {
3996     if (ctxt == NULL)
3997 	return;
3998     ctxt->varLookupFunc = f;
3999     ctxt->varLookupData = data;
4000 }
4001 
4002 /**
4003  * xmlXPathVariableLookup:
4004  * @ctxt:  the XPath context
4005  * @name:  the variable name
4006  *
4007  * Search in the Variable array of the context for the given
4008  * variable value.
4009  *
4010  * Returns a copy of the value or NULL if not found
4011  */
4012 xmlXPathObjectPtr
xmlXPathVariableLookup(xmlXPathContextPtr ctxt,const xmlChar * name)4013 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4014     if (ctxt == NULL)
4015 	return(NULL);
4016 
4017     if (ctxt->varLookupFunc != NULL) {
4018 	xmlXPathObjectPtr ret;
4019 
4020 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4021 	        (ctxt->varLookupData, name, NULL);
4022 	return(ret);
4023     }
4024     return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4025 }
4026 
4027 /**
4028  * xmlXPathVariableLookupNS:
4029  * @ctxt:  the XPath context
4030  * @name:  the variable name
4031  * @ns_uri:  the variable namespace URI
4032  *
4033  * Search in the Variable array of the context for the given
4034  * variable value.
4035  *
4036  * Returns the a copy of the value or NULL if not found
4037  */
4038 xmlXPathObjectPtr
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4039 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4040 			 const xmlChar *ns_uri) {
4041     if (ctxt == NULL)
4042 	return(NULL);
4043 
4044     if (ctxt->varLookupFunc != NULL) {
4045 	xmlXPathObjectPtr ret;
4046 
4047 	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4048 	        (ctxt->varLookupData, name, ns_uri);
4049 	if (ret != NULL) return(ret);
4050     }
4051 
4052     if (ctxt->varHash == NULL)
4053 	return(NULL);
4054     if (name == NULL)
4055 	return(NULL);
4056 
4057     return(xmlXPathObjectCopy(xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4058 }
4059 
4060 /**
4061  * xmlXPathRegisteredVariablesCleanup:
4062  * @ctxt:  the XPath context
4063  *
4064  * Cleanup the XPath context data associated to registered variables
4065  */
4066 void
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt)4067 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4068     if (ctxt == NULL)
4069 	return;
4070 
4071     xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
4072     ctxt->varHash = NULL;
4073 }
4074 
4075 /**
4076  * xmlXPathRegisterNs:
4077  * @ctxt:  the XPath context
4078  * @prefix:  the namespace prefix cannot be NULL or empty string
4079  * @ns_uri:  the namespace name
4080  *
4081  * Register a new namespace. If @ns_uri is NULL it unregisters
4082  * the namespace
4083  *
4084  * Returns 0 in case of success, -1 in case of error
4085  */
4086 int
xmlXPathRegisterNs(xmlXPathContextPtr ctxt,const xmlChar * prefix,const xmlChar * ns_uri)4087 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4088 			   const xmlChar *ns_uri) {
4089     xmlChar *copy;
4090 
4091     if (ctxt == NULL)
4092 	return(-1);
4093     if (prefix == NULL)
4094 	return(-1);
4095     if (prefix[0] == 0)
4096 	return(-1);
4097 
4098     if (ctxt->nsHash == NULL)
4099 	ctxt->nsHash = xmlHashCreate(10);
4100     if (ctxt->nsHash == NULL) {
4101         xmlXPathErrMemory(ctxt);
4102 	return(-1);
4103     }
4104     if (ns_uri == NULL)
4105         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
4106 	                          xmlHashDefaultDeallocator));
4107 
4108     copy = xmlStrdup(ns_uri);
4109     if (copy == NULL) {
4110         xmlXPathErrMemory(ctxt);
4111         return(-1);
4112     }
4113     if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
4114                            xmlHashDefaultDeallocator) < 0) {
4115         xmlXPathErrMemory(ctxt);
4116         xmlFree(copy);
4117         return(-1);
4118     }
4119 
4120     return(0);
4121 }
4122 
4123 /**
4124  * xmlXPathNsLookup:
4125  * @ctxt:  the XPath context
4126  * @prefix:  the namespace prefix value
4127  *
4128  * Search in the namespace declaration array of the context for the given
4129  * namespace name associated to the given prefix
4130  *
4131  * Returns the value or NULL if not found
4132  */
4133 const xmlChar *
xmlXPathNsLookup(xmlXPathContextPtr ctxt,const xmlChar * prefix)4134 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
4135     if (ctxt == NULL)
4136 	return(NULL);
4137     if (prefix == NULL)
4138 	return(NULL);
4139 
4140     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4141 	return(XML_XML_NAMESPACE);
4142 
4143     if (ctxt->namespaces != NULL) {
4144 	int i;
4145 
4146 	for (i = 0;i < ctxt->nsNr;i++) {
4147 	    if ((ctxt->namespaces[i] != NULL) &&
4148 		(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4149 		return(ctxt->namespaces[i]->href);
4150 	}
4151     }
4152 
4153     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4154 }
4155 
4156 /**
4157  * xmlXPathRegisteredNsCleanup:
4158  * @ctxt:  the XPath context
4159  *
4160  * Cleanup the XPath context data associated to registered variables
4161  */
4162 void
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt)4163 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
4164     if (ctxt == NULL)
4165 	return;
4166 
4167     xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4168     ctxt->nsHash = NULL;
4169 }
4170 
4171 /************************************************************************
4172  *									*
4173  *			Routines to handle Values			*
4174  *									*
4175  ************************************************************************/
4176 
4177 /* Allocations are terrible, one needs to optimize all this !!! */
4178 
4179 /**
4180  * xmlXPathNewFloat:
4181  * @val:  the double value
4182  *
4183  * Create a new xmlXPathObjectPtr of type double and of value @val
4184  *
4185  * Returns the newly created object.
4186  */
4187 xmlXPathObjectPtr
xmlXPathNewFloat(double val)4188 xmlXPathNewFloat(double val) {
4189     xmlXPathObjectPtr ret;
4190 
4191     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4192     if (ret == NULL)
4193 	return(NULL);
4194     memset(ret, 0 , sizeof(xmlXPathObject));
4195     ret->type = XPATH_NUMBER;
4196     ret->floatval = val;
4197     return(ret);
4198 }
4199 
4200 /**
4201  * xmlXPathNewBoolean:
4202  * @val:  the boolean value
4203  *
4204  * Create a new xmlXPathObjectPtr of type boolean and of value @val
4205  *
4206  * Returns the newly created object.
4207  */
4208 xmlXPathObjectPtr
xmlXPathNewBoolean(int val)4209 xmlXPathNewBoolean(int val) {
4210     xmlXPathObjectPtr ret;
4211 
4212     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4213     if (ret == NULL)
4214 	return(NULL);
4215     memset(ret, 0 , sizeof(xmlXPathObject));
4216     ret->type = XPATH_BOOLEAN;
4217     ret->boolval = (val != 0);
4218     return(ret);
4219 }
4220 
4221 /**
4222  * xmlXPathNewString:
4223  * @val:  the xmlChar * value
4224  *
4225  * Create a new xmlXPathObjectPtr of type string and of value @val
4226  *
4227  * Returns the newly created object.
4228  */
4229 xmlXPathObjectPtr
xmlXPathNewString(const xmlChar * val)4230 xmlXPathNewString(const xmlChar *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_STRING;
4238     if (val == NULL)
4239         val = BAD_CAST "";
4240     ret->stringval = xmlStrdup(val);
4241     if (ret->stringval == NULL) {
4242         xmlFree(ret);
4243         return(NULL);
4244     }
4245     return(ret);
4246 }
4247 
4248 /**
4249  * xmlXPathWrapString:
4250  * @val:  the xmlChar * value
4251  *
4252  * Wraps the @val string into an XPath object.
4253  *
4254  * Returns the newly created object.
4255  *
4256  * Frees @val in case of error.
4257  */
4258 xmlXPathObjectPtr
xmlXPathWrapString(xmlChar * val)4259 xmlXPathWrapString (xmlChar *val) {
4260     xmlXPathObjectPtr ret;
4261 
4262     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4263     if (ret == NULL) {
4264         xmlFree(val);
4265 	return(NULL);
4266     }
4267     memset(ret, 0 , sizeof(xmlXPathObject));
4268     ret->type = XPATH_STRING;
4269     ret->stringval = val;
4270     return(ret);
4271 }
4272 
4273 /**
4274  * xmlXPathNewCString:
4275  * @val:  the char * value
4276  *
4277  * Create a new xmlXPathObjectPtr of type string and of value @val
4278  *
4279  * Returns the newly created object.
4280  */
4281 xmlXPathObjectPtr
xmlXPathNewCString(const char * val)4282 xmlXPathNewCString(const char *val) {
4283     return(xmlXPathNewString(BAD_CAST val));
4284 }
4285 
4286 /**
4287  * xmlXPathWrapCString:
4288  * @val:  the char * value
4289  *
4290  * Wraps a string into an XPath object.
4291  *
4292  * Returns the newly created object.
4293  */
4294 xmlXPathObjectPtr
xmlXPathWrapCString(char * val)4295 xmlXPathWrapCString (char * val) {
4296     return(xmlXPathWrapString((xmlChar *)(val)));
4297 }
4298 
4299 /**
4300  * xmlXPathWrapExternal:
4301  * @val:  the user data
4302  *
4303  * Wraps the @val data into an XPath object.
4304  *
4305  * Returns the newly created object.
4306  */
4307 xmlXPathObjectPtr
xmlXPathWrapExternal(void * val)4308 xmlXPathWrapExternal (void *val) {
4309     xmlXPathObjectPtr ret;
4310 
4311     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4312     if (ret == NULL)
4313 	return(NULL);
4314     memset(ret, 0 , sizeof(xmlXPathObject));
4315     ret->type = XPATH_USERS;
4316     ret->user = val;
4317     return(ret);
4318 }
4319 
4320 /**
4321  * xmlXPathObjectCopy:
4322  * @val:  the original object
4323  *
4324  * allocate a new copy of a given object
4325  *
4326  * Returns the newly created object.
4327  */
4328 xmlXPathObjectPtr
xmlXPathObjectCopy(xmlXPathObjectPtr val)4329 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
4330     xmlXPathObjectPtr ret;
4331 
4332     if (val == NULL)
4333 	return(NULL);
4334 
4335     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4336     if (ret == NULL)
4337 	return(NULL);
4338     memcpy(ret, val , sizeof(xmlXPathObject));
4339     switch (val->type) {
4340 	case XPATH_BOOLEAN:
4341 	case XPATH_NUMBER:
4342 	    break;
4343 	case XPATH_STRING:
4344 	    ret->stringval = xmlStrdup(val->stringval);
4345             if (ret->stringval == NULL) {
4346                 xmlFree(ret);
4347                 return(NULL);
4348             }
4349 	    break;
4350 	case XPATH_XSLT_TREE:
4351 	case XPATH_NODESET:
4352 	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
4353             if (ret->nodesetval == NULL) {
4354                 xmlFree(ret);
4355                 return(NULL);
4356             }
4357 	    /* Do not deallocate the copied tree value */
4358 	    ret->boolval = 0;
4359 	    break;
4360         case XPATH_USERS:
4361 	    ret->user = val->user;
4362 	    break;
4363         default:
4364             xmlFree(ret);
4365             ret = NULL;
4366 	    break;
4367     }
4368     return(ret);
4369 }
4370 
4371 /**
4372  * xmlXPathFreeObject:
4373  * @obj:  the object to free
4374  *
4375  * Free up an xmlXPathObjectPtr object.
4376  */
4377 void
xmlXPathFreeObject(xmlXPathObjectPtr obj)4378 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
4379     if (obj == NULL) return;
4380     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4381         if (obj->nodesetval != NULL)
4382             xmlXPathFreeNodeSet(obj->nodesetval);
4383     } else if (obj->type == XPATH_STRING) {
4384 	if (obj->stringval != NULL)
4385 	    xmlFree(obj->stringval);
4386     }
4387     xmlFree(obj);
4388 }
4389 
4390 static void
xmlXPathFreeObjectEntry(void * obj,const xmlChar * name ATTRIBUTE_UNUSED)4391 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
4392     xmlXPathFreeObject((xmlXPathObjectPtr) obj);
4393 }
4394 
4395 /**
4396  * xmlXPathReleaseObject:
4397  * @obj:  the xmlXPathObjectPtr to free or to cache
4398  *
4399  * Depending on the state of the cache this frees the given
4400  * XPath object or stores it in the cache.
4401  */
4402 static void
xmlXPathReleaseObject(xmlXPathContextPtr ctxt,xmlXPathObjectPtr obj)4403 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
4404 {
4405     if (obj == NULL)
4406 	return;
4407     if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4408 	 xmlXPathFreeObject(obj);
4409     } else {
4410 	xmlXPathContextCachePtr cache =
4411 	    (xmlXPathContextCachePtr) ctxt->cache;
4412 
4413 	switch (obj->type) {
4414 	    case XPATH_NODESET:
4415 	    case XPATH_XSLT_TREE:
4416 		if (obj->nodesetval != NULL) {
4417 		    if ((obj->nodesetval->nodeMax <= 40) &&
4418 			(cache->numNodeset < cache->maxNodeset)) {
4419                         obj->stringval = (void *) cache->nodesetObjs;
4420                         cache->nodesetObjs = obj;
4421                         cache->numNodeset += 1;
4422 			goto obj_cached;
4423 		    } else {
4424 			xmlXPathFreeNodeSet(obj->nodesetval);
4425 			obj->nodesetval = NULL;
4426 		    }
4427 		}
4428 		break;
4429 	    case XPATH_STRING:
4430 		if (obj->stringval != NULL)
4431 		    xmlFree(obj->stringval);
4432                 obj->stringval = NULL;
4433 		break;
4434 	    case XPATH_BOOLEAN:
4435 	    case XPATH_NUMBER:
4436 		break;
4437 	    default:
4438 		goto free_obj;
4439 	}
4440 
4441 	/*
4442 	* Fallback to adding to the misc-objects slot.
4443 	*/
4444         if (cache->numMisc >= cache->maxMisc)
4445 	    goto free_obj;
4446         obj->stringval = (void *) cache->miscObjs;
4447         cache->miscObjs = obj;
4448         cache->numMisc += 1;
4449 
4450 obj_cached:
4451         obj->boolval = 0;
4452 	if (obj->nodesetval != NULL) {
4453 	    xmlNodeSetPtr tmpset = obj->nodesetval;
4454 
4455 	    /*
4456 	    * Due to those nasty ns-nodes, we need to traverse
4457 	    * the list and free the ns-nodes.
4458 	    */
4459 	    if (tmpset->nodeNr > 0) {
4460 		int i;
4461 		xmlNodePtr node;
4462 
4463 		for (i = 0; i < tmpset->nodeNr; i++) {
4464 		    node = tmpset->nodeTab[i];
4465 		    if ((node != NULL) &&
4466 			(node->type == XML_NAMESPACE_DECL))
4467 		    {
4468 			xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4469 		    }
4470 		}
4471 	    }
4472 	    tmpset->nodeNr = 0;
4473         }
4474 
4475 	return;
4476 
4477 free_obj:
4478 	/*
4479 	* Cache is full; free the object.
4480 	*/
4481 	if (obj->nodesetval != NULL)
4482 	    xmlXPathFreeNodeSet(obj->nodesetval);
4483 	xmlFree(obj);
4484     }
4485 }
4486 
4487 
4488 /************************************************************************
4489  *									*
4490  *			Type Casting Routines				*
4491  *									*
4492  ************************************************************************/
4493 
4494 /**
4495  * xmlXPathCastBooleanToString:
4496  * @val:  a boolean
4497  *
4498  * Converts a boolean to its string value.
4499  *
4500  * Returns a newly allocated string.
4501  */
4502 xmlChar *
xmlXPathCastBooleanToString(int val)4503 xmlXPathCastBooleanToString (int val) {
4504     xmlChar *ret;
4505     if (val)
4506 	ret = xmlStrdup((const xmlChar *) "true");
4507     else
4508 	ret = xmlStrdup((const xmlChar *) "false");
4509     return(ret);
4510 }
4511 
4512 /**
4513  * xmlXPathCastNumberToString:
4514  * @val:  a number
4515  *
4516  * Converts a number to its string value.
4517  *
4518  * Returns a newly allocated string.
4519  */
4520 xmlChar *
xmlXPathCastNumberToString(double val)4521 xmlXPathCastNumberToString (double val) {
4522     xmlChar *ret;
4523     switch (xmlXPathIsInf(val)) {
4524     case 1:
4525 	ret = xmlStrdup((const xmlChar *) "Infinity");
4526 	break;
4527     case -1:
4528 	ret = xmlStrdup((const xmlChar *) "-Infinity");
4529 	break;
4530     default:
4531 	if (xmlXPathIsNaN(val)) {
4532 	    ret = xmlStrdup((const xmlChar *) "NaN");
4533 	} else if (val == 0) {
4534             /* Omit sign for negative zero. */
4535 	    ret = xmlStrdup((const xmlChar *) "0");
4536 	} else {
4537 	    /* could be improved */
4538 	    char buf[100];
4539 	    xmlXPathFormatNumber(val, buf, 99);
4540 	    buf[99] = 0;
4541 	    ret = xmlStrdup((const xmlChar *) buf);
4542 	}
4543     }
4544     return(ret);
4545 }
4546 
4547 /**
4548  * xmlXPathCastNodeToString:
4549  * @node:  a node
4550  *
4551  * Converts a node to its string value.
4552  *
4553  * Returns a newly allocated string.
4554  */
4555 xmlChar *
xmlXPathCastNodeToString(xmlNodePtr node)4556 xmlXPathCastNodeToString (xmlNodePtr node) {
4557     return(xmlNodeGetContent(node));
4558 }
4559 
4560 /**
4561  * xmlXPathCastNodeSetToString:
4562  * @ns:  a node-set
4563  *
4564  * Converts a node-set to its string value.
4565  *
4566  * Returns a newly allocated string.
4567  */
4568 xmlChar *
xmlXPathCastNodeSetToString(xmlNodeSetPtr ns)4569 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
4570     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
4571 	return(xmlStrdup((const xmlChar *) ""));
4572 
4573     if (ns->nodeNr > 1)
4574 	xmlXPathNodeSetSort(ns);
4575     return(xmlXPathCastNodeToString(ns->nodeTab[0]));
4576 }
4577 
4578 /**
4579  * xmlXPathCastToString:
4580  * @val:  an XPath object
4581  *
4582  * Converts an existing object to its string() equivalent
4583  *
4584  * Returns the allocated string value of the object, NULL in case of error.
4585  *         It's up to the caller to free the string memory with xmlFree().
4586  */
4587 xmlChar *
xmlXPathCastToString(xmlXPathObjectPtr val)4588 xmlXPathCastToString(xmlXPathObjectPtr val) {
4589     xmlChar *ret = NULL;
4590 
4591     if (val == NULL)
4592 	return(xmlStrdup((const xmlChar *) ""));
4593     switch (val->type) {
4594 	case XPATH_UNDEFINED:
4595 	    ret = xmlStrdup((const xmlChar *) "");
4596 	    break;
4597         case XPATH_NODESET:
4598         case XPATH_XSLT_TREE:
4599 	    ret = xmlXPathCastNodeSetToString(val->nodesetval);
4600 	    break;
4601 	case XPATH_STRING:
4602 	    return(xmlStrdup(val->stringval));
4603         case XPATH_BOOLEAN:
4604 	    ret = xmlXPathCastBooleanToString(val->boolval);
4605 	    break;
4606 	case XPATH_NUMBER: {
4607 	    ret = xmlXPathCastNumberToString(val->floatval);
4608 	    break;
4609 	}
4610 	case XPATH_USERS:
4611 	    /* TODO */
4612 	    ret = xmlStrdup((const xmlChar *) "");
4613 	    break;
4614     }
4615     return(ret);
4616 }
4617 
4618 /**
4619  * xmlXPathConvertString:
4620  * @val:  an XPath object
4621  *
4622  * Converts an existing object to its string() equivalent
4623  *
4624  * Returns the new object, the old one is freed (or the operation
4625  *         is done directly on @val)
4626  */
4627 xmlXPathObjectPtr
xmlXPathConvertString(xmlXPathObjectPtr val)4628 xmlXPathConvertString(xmlXPathObjectPtr val) {
4629     xmlChar *res = NULL;
4630 
4631     if (val == NULL)
4632 	return(xmlXPathNewCString(""));
4633 
4634     switch (val->type) {
4635     case XPATH_UNDEFINED:
4636 	break;
4637     case XPATH_NODESET:
4638     case XPATH_XSLT_TREE:
4639 	res = xmlXPathCastNodeSetToString(val->nodesetval);
4640 	break;
4641     case XPATH_STRING:
4642 	return(val);
4643     case XPATH_BOOLEAN:
4644 	res = xmlXPathCastBooleanToString(val->boolval);
4645 	break;
4646     case XPATH_NUMBER:
4647 	res = xmlXPathCastNumberToString(val->floatval);
4648 	break;
4649     case XPATH_USERS:
4650 	/* TODO */
4651 	break;
4652     }
4653     xmlXPathFreeObject(val);
4654     if (res == NULL)
4655 	return(xmlXPathNewCString(""));
4656     return(xmlXPathWrapString(res));
4657 }
4658 
4659 /**
4660  * xmlXPathCastBooleanToNumber:
4661  * @val:  a boolean
4662  *
4663  * Converts a boolean to its number value
4664  *
4665  * Returns the number value
4666  */
4667 double
xmlXPathCastBooleanToNumber(int val)4668 xmlXPathCastBooleanToNumber(int val) {
4669     if (val)
4670 	return(1.0);
4671     return(0.0);
4672 }
4673 
4674 /**
4675  * xmlXPathCastStringToNumber:
4676  * @val:  a string
4677  *
4678  * Converts a string to its number value
4679  *
4680  * Returns the number value
4681  */
4682 double
xmlXPathCastStringToNumber(const xmlChar * val)4683 xmlXPathCastStringToNumber(const xmlChar * val) {
4684     return(xmlXPathStringEvalNumber(val));
4685 }
4686 
4687 /**
4688  * xmlXPathNodeToNumberInternal:
4689  * @node:  a node
4690  *
4691  * Converts a node to its number value
4692  *
4693  * Returns the number value
4694  */
4695 static double
xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr node)4696 xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt, xmlNodePtr node) {
4697     xmlChar *strval;
4698     double ret;
4699 
4700     if (node == NULL)
4701 	return(xmlXPathNAN);
4702     strval = xmlXPathCastNodeToString(node);
4703     if (strval == NULL) {
4704         xmlXPathPErrMemory(ctxt);
4705 	return(xmlXPathNAN);
4706     }
4707     ret = xmlXPathCastStringToNumber(strval);
4708     xmlFree(strval);
4709 
4710     return(ret);
4711 }
4712 
4713 /**
4714  * xmlXPathCastNodeToNumber:
4715  * @node:  a node
4716  *
4717  * Converts a node to its number value
4718  *
4719  * Returns the number value
4720  */
4721 double
xmlXPathCastNodeToNumber(xmlNodePtr node)4722 xmlXPathCastNodeToNumber (xmlNodePtr node) {
4723     return(xmlXPathNodeToNumberInternal(NULL, node));
4724 }
4725 
4726 /**
4727  * xmlXPathCastNodeSetToNumber:
4728  * @ns:  a node-set
4729  *
4730  * Converts a node-set to its number value
4731  *
4732  * Returns the number value
4733  */
4734 double
xmlXPathCastNodeSetToNumber(xmlNodeSetPtr ns)4735 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
4736     xmlChar *str;
4737     double ret;
4738 
4739     if (ns == NULL)
4740 	return(xmlXPathNAN);
4741     str = xmlXPathCastNodeSetToString(ns);
4742     ret = xmlXPathCastStringToNumber(str);
4743     xmlFree(str);
4744     return(ret);
4745 }
4746 
4747 /**
4748  * xmlXPathCastToNumber:
4749  * @val:  an XPath object
4750  *
4751  * Converts an XPath object to its number value
4752  *
4753  * Returns the number value
4754  */
4755 double
xmlXPathCastToNumber(xmlXPathObjectPtr val)4756 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
4757     return(xmlXPathCastToNumberInternal(NULL, val));
4758 }
4759 
4760 /**
4761  * xmlXPathConvertNumber:
4762  * @val:  an XPath object
4763  *
4764  * Converts an existing object to its number() equivalent
4765  *
4766  * Returns the new object, the old one is freed (or the operation
4767  *         is done directly on @val)
4768  */
4769 xmlXPathObjectPtr
xmlXPathConvertNumber(xmlXPathObjectPtr val)4770 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
4771     xmlXPathObjectPtr ret;
4772 
4773     if (val == NULL)
4774 	return(xmlXPathNewFloat(0.0));
4775     if (val->type == XPATH_NUMBER)
4776 	return(val);
4777     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
4778     xmlXPathFreeObject(val);
4779     return(ret);
4780 }
4781 
4782 /**
4783  * xmlXPathCastNumberToBoolean:
4784  * @val:  a number
4785  *
4786  * Converts a number to its boolean value
4787  *
4788  * Returns the boolean value
4789  */
4790 int
xmlXPathCastNumberToBoolean(double val)4791 xmlXPathCastNumberToBoolean (double val) {
4792      if (xmlXPathIsNaN(val) || (val == 0.0))
4793 	 return(0);
4794      return(1);
4795 }
4796 
4797 /**
4798  * xmlXPathCastStringToBoolean:
4799  * @val:  a string
4800  *
4801  * Converts a string to its boolean value
4802  *
4803  * Returns the boolean value
4804  */
4805 int
xmlXPathCastStringToBoolean(const xmlChar * val)4806 xmlXPathCastStringToBoolean (const xmlChar *val) {
4807     if ((val == NULL) || (xmlStrlen(val) == 0))
4808 	return(0);
4809     return(1);
4810 }
4811 
4812 /**
4813  * xmlXPathCastNodeSetToBoolean:
4814  * @ns:  a node-set
4815  *
4816  * Converts a node-set to its boolean value
4817  *
4818  * Returns the boolean value
4819  */
4820 int
xmlXPathCastNodeSetToBoolean(xmlNodeSetPtr ns)4821 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
4822     if ((ns == NULL) || (ns->nodeNr == 0))
4823 	return(0);
4824     return(1);
4825 }
4826 
4827 /**
4828  * xmlXPathCastToBoolean:
4829  * @val:  an XPath object
4830  *
4831  * Converts an XPath object to its boolean value
4832  *
4833  * Returns the boolean value
4834  */
4835 int
xmlXPathCastToBoolean(xmlXPathObjectPtr val)4836 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
4837     int ret = 0;
4838 
4839     if (val == NULL)
4840 	return(0);
4841     switch (val->type) {
4842     case XPATH_UNDEFINED:
4843 	ret = 0;
4844 	break;
4845     case XPATH_NODESET:
4846     case XPATH_XSLT_TREE:
4847 	ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
4848 	break;
4849     case XPATH_STRING:
4850 	ret = xmlXPathCastStringToBoolean(val->stringval);
4851 	break;
4852     case XPATH_NUMBER:
4853 	ret = xmlXPathCastNumberToBoolean(val->floatval);
4854 	break;
4855     case XPATH_BOOLEAN:
4856 	ret = val->boolval;
4857 	break;
4858     case XPATH_USERS:
4859 	/* TODO */
4860 	ret = 0;
4861 	break;
4862     }
4863     return(ret);
4864 }
4865 
4866 
4867 /**
4868  * xmlXPathConvertBoolean:
4869  * @val:  an XPath object
4870  *
4871  * Converts an existing object to its boolean() equivalent
4872  *
4873  * Returns the new object, the old one is freed (or the operation
4874  *         is done directly on @val)
4875  */
4876 xmlXPathObjectPtr
xmlXPathConvertBoolean(xmlXPathObjectPtr val)4877 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
4878     xmlXPathObjectPtr ret;
4879 
4880     if (val == NULL)
4881 	return(xmlXPathNewBoolean(0));
4882     if (val->type == XPATH_BOOLEAN)
4883 	return(val);
4884     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
4885     xmlXPathFreeObject(val);
4886     return(ret);
4887 }
4888 
4889 /************************************************************************
4890  *									*
4891  *		Routines to handle XPath contexts			*
4892  *									*
4893  ************************************************************************/
4894 
4895 /**
4896  * xmlXPathNewContext:
4897  * @doc:  the XML document
4898  *
4899  * Create a new xmlXPathContext
4900  *
4901  * Returns the xmlXPathContext just allocated. The caller will need to free it.
4902  */
4903 xmlXPathContextPtr
xmlXPathNewContext(xmlDocPtr doc)4904 xmlXPathNewContext(xmlDocPtr doc) {
4905     xmlXPathContextPtr ret;
4906 
4907     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
4908     if (ret == NULL)
4909 	return(NULL);
4910     memset(ret, 0 , sizeof(xmlXPathContext));
4911     ret->doc = doc;
4912     ret->node = NULL;
4913 
4914     ret->varHash = NULL;
4915 
4916     ret->nb_types = 0;
4917     ret->max_types = 0;
4918     ret->types = NULL;
4919 
4920     ret->nb_axis = 0;
4921     ret->max_axis = 0;
4922     ret->axis = NULL;
4923 
4924     ret->nsHash = NULL;
4925     ret->user = NULL;
4926 
4927     ret->contextSize = -1;
4928     ret->proximityPosition = -1;
4929 
4930 #ifdef XP_DEFAULT_CACHE_ON
4931     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
4932 	xmlXPathFreeContext(ret);
4933 	return(NULL);
4934     }
4935 #endif
4936 
4937     xmlXPathRegisterAllFunctions(ret);
4938 
4939     if (ret->lastError.code != XML_ERR_OK) {
4940 	xmlXPathFreeContext(ret);
4941 	return(NULL);
4942     }
4943 
4944     return(ret);
4945 }
4946 
4947 /**
4948  * xmlXPathFreeContext:
4949  * @ctxt:  the context to free
4950  *
4951  * Free up an xmlXPathContext
4952  */
4953 void
xmlXPathFreeContext(xmlXPathContextPtr ctxt)4954 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
4955     if (ctxt == NULL) return;
4956 
4957     if (ctxt->cache != NULL)
4958 	xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
4959     xmlXPathRegisteredNsCleanup(ctxt);
4960     xmlXPathRegisteredFuncsCleanup(ctxt);
4961     xmlXPathRegisteredVariablesCleanup(ctxt);
4962     xmlResetError(&ctxt->lastError);
4963     xmlFree(ctxt);
4964 }
4965 
4966 /**
4967  * xmlXPathSetErrorHandler:
4968  * @ctxt:  the XPath context
4969  * @handler:  error handler
4970  * @data:  user data which will be passed to the handler
4971  *
4972  * Register a callback function that will be called on errors and
4973  * warnings. If handler is NULL, the error handler will be deactivated.
4974  *
4975  * Available since 2.13.0.
4976  */
4977 void
xmlXPathSetErrorHandler(xmlXPathContextPtr ctxt,xmlStructuredErrorFunc handler,void * data)4978 xmlXPathSetErrorHandler(xmlXPathContextPtr ctxt,
4979                         xmlStructuredErrorFunc handler, void *data) {
4980     if (ctxt == NULL)
4981         return;
4982 
4983     ctxt->error = handler;
4984     ctxt->userData = data;
4985 }
4986 
4987 /************************************************************************
4988  *									*
4989  *		Routines to handle XPath parser contexts		*
4990  *									*
4991  ************************************************************************/
4992 
4993 /**
4994  * xmlXPathNewParserContext:
4995  * @str:  the XPath expression
4996  * @ctxt:  the XPath context
4997  *
4998  * Create a new xmlXPathParserContext
4999  *
5000  * Returns the xmlXPathParserContext just allocated.
5001  */
5002 xmlXPathParserContextPtr
xmlXPathNewParserContext(const xmlChar * str,xmlXPathContextPtr ctxt)5003 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
5004     xmlXPathParserContextPtr ret;
5005 
5006     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5007     if (ret == NULL) {
5008         xmlXPathErrMemory(ctxt);
5009 	return(NULL);
5010     }
5011     memset(ret, 0 , sizeof(xmlXPathParserContext));
5012     ret->cur = ret->base = str;
5013     ret->context = ctxt;
5014 
5015     ret->comp = xmlXPathNewCompExpr();
5016     if (ret->comp == NULL) {
5017         xmlXPathErrMemory(ctxt);
5018 	xmlFree(ret->valueTab);
5019 	xmlFree(ret);
5020 	return(NULL);
5021     }
5022     if ((ctxt != NULL) && (ctxt->dict != NULL)) {
5023         ret->comp->dict = ctxt->dict;
5024 	xmlDictReference(ret->comp->dict);
5025     }
5026 
5027     return(ret);
5028 }
5029 
5030 /**
5031  * xmlXPathCompParserContext:
5032  * @comp:  the XPath compiled expression
5033  * @ctxt:  the XPath context
5034  *
5035  * Create a new xmlXPathParserContext when processing a compiled expression
5036  *
5037  * Returns the xmlXPathParserContext just allocated.
5038  */
5039 static xmlXPathParserContextPtr
xmlXPathCompParserContext(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)5040 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
5041     xmlXPathParserContextPtr ret;
5042 
5043     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5044     if (ret == NULL) {
5045         xmlXPathErrMemory(ctxt);
5046 	return(NULL);
5047     }
5048     memset(ret, 0 , sizeof(xmlXPathParserContext));
5049 
5050     /* Allocate the value stack */
5051     ret->valueTab = (xmlXPathObjectPtr *)
5052                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
5053     if (ret->valueTab == NULL) {
5054 	xmlFree(ret);
5055 	xmlXPathErrMemory(ctxt);
5056 	return(NULL);
5057     }
5058     ret->valueNr = 0;
5059     ret->valueMax = 10;
5060     ret->value = NULL;
5061 
5062     ret->context = ctxt;
5063     ret->comp = comp;
5064 
5065     return(ret);
5066 }
5067 
5068 /**
5069  * xmlXPathFreeParserContext:
5070  * @ctxt:  the context to free
5071  *
5072  * Free up an xmlXPathParserContext
5073  */
5074 void
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt)5075 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
5076     int i;
5077 
5078     if (ctxt->valueTab != NULL) {
5079         for (i = 0; i < ctxt->valueNr; i++) {
5080             if (ctxt->context)
5081                 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
5082             else
5083                 xmlXPathFreeObject(ctxt->valueTab[i]);
5084         }
5085         xmlFree(ctxt->valueTab);
5086     }
5087     if (ctxt->comp != NULL) {
5088 #ifdef XPATH_STREAMING
5089 	if (ctxt->comp->stream != NULL) {
5090 	    xmlFreePatternList(ctxt->comp->stream);
5091 	    ctxt->comp->stream = NULL;
5092 	}
5093 #endif
5094 	xmlXPathFreeCompExpr(ctxt->comp);
5095     }
5096     xmlFree(ctxt);
5097 }
5098 
5099 /************************************************************************
5100  *									*
5101  *		The implicit core function library			*
5102  *									*
5103  ************************************************************************/
5104 
5105 /**
5106  * xmlXPathNodeValHash:
5107  * @node:  a node pointer
5108  *
5109  * Function computing the beginning of the string value of the node,
5110  * used to speed up comparisons
5111  *
5112  * Returns an int usable as a hash
5113  */
5114 static unsigned int
xmlXPathNodeValHash(xmlNodePtr node)5115 xmlXPathNodeValHash(xmlNodePtr node) {
5116     int len = 2;
5117     const xmlChar * string = NULL;
5118     xmlNodePtr tmp = NULL;
5119     unsigned int ret = 0;
5120 
5121     if (node == NULL)
5122 	return(0);
5123 
5124     if (node->type == XML_DOCUMENT_NODE) {
5125 	tmp = xmlDocGetRootElement((xmlDocPtr) node);
5126 	if (tmp == NULL)
5127 	    node = node->children;
5128 	else
5129 	    node = tmp;
5130 
5131 	if (node == NULL)
5132 	    return(0);
5133     }
5134 
5135     switch (node->type) {
5136 	case XML_COMMENT_NODE:
5137 	case XML_PI_NODE:
5138 	case XML_CDATA_SECTION_NODE:
5139 	case XML_TEXT_NODE:
5140 	    string = node->content;
5141 	    if (string == NULL)
5142 		return(0);
5143 	    if (string[0] == 0)
5144 		return(0);
5145 	    return(string[0] + (string[1] << 8));
5146 	case XML_NAMESPACE_DECL:
5147 	    string = ((xmlNsPtr)node)->href;
5148 	    if (string == NULL)
5149 		return(0);
5150 	    if (string[0] == 0)
5151 		return(0);
5152 	    return(string[0] + (string[1] << 8));
5153 	case XML_ATTRIBUTE_NODE:
5154 	    tmp = ((xmlAttrPtr) node)->children;
5155 	    break;
5156 	case XML_ELEMENT_NODE:
5157 	    tmp = node->children;
5158 	    break;
5159 	default:
5160 	    return(0);
5161     }
5162     while (tmp != NULL) {
5163 	switch (tmp->type) {
5164 	    case XML_CDATA_SECTION_NODE:
5165 	    case XML_TEXT_NODE:
5166 		string = tmp->content;
5167 		break;
5168 	    default:
5169                 string = NULL;
5170 		break;
5171 	}
5172 	if ((string != NULL) && (string[0] != 0)) {
5173 	    if (len == 1) {
5174 		return(ret + (string[0] << 8));
5175 	    }
5176 	    if (string[1] == 0) {
5177 		len = 1;
5178 		ret = string[0];
5179 	    } else {
5180 		return(string[0] + (string[1] << 8));
5181 	    }
5182 	}
5183 	/*
5184 	 * Skip to next node
5185 	 */
5186         if ((tmp->children != NULL) &&
5187             (tmp->type != XML_DTD_NODE) &&
5188             (tmp->type != XML_ENTITY_REF_NODE) &&
5189             (tmp->children->type != XML_ENTITY_DECL)) {
5190             tmp = tmp->children;
5191             continue;
5192 	}
5193 	if (tmp == node)
5194 	    break;
5195 
5196 	if (tmp->next != NULL) {
5197 	    tmp = tmp->next;
5198 	    continue;
5199 	}
5200 
5201 	do {
5202 	    tmp = tmp->parent;
5203 	    if (tmp == NULL)
5204 		break;
5205 	    if (tmp == node) {
5206 		tmp = NULL;
5207 		break;
5208 	    }
5209 	    if (tmp->next != NULL) {
5210 		tmp = tmp->next;
5211 		break;
5212 	    }
5213 	} while (tmp != NULL);
5214     }
5215     return(ret);
5216 }
5217 
5218 /**
5219  * xmlXPathStringHash:
5220  * @string:  a string
5221  *
5222  * Function computing the beginning of the string value of the node,
5223  * used to speed up comparisons
5224  *
5225  * Returns an int usable as a hash
5226  */
5227 static unsigned int
xmlXPathStringHash(const xmlChar * string)5228 xmlXPathStringHash(const xmlChar * string) {
5229     if (string == NULL)
5230 	return(0);
5231     if (string[0] == 0)
5232 	return(0);
5233     return(string[0] + (string[1] << 8));
5234 }
5235 
5236 /**
5237  * xmlXPathCompareNodeSetFloat:
5238  * @ctxt:  the XPath Parser context
5239  * @inf:  less than (1) or greater than (0)
5240  * @strict:  is the comparison strict
5241  * @arg:  the node set
5242  * @f:  the value
5243  *
5244  * Implement the compare operation between a nodeset and a number
5245  *     @ns < @val    (1, 1, ...
5246  *     @ns <= @val   (1, 0, ...
5247  *     @ns > @val    (0, 1, ...
5248  *     @ns >= @val   (0, 0, ...
5249  *
5250  * If one object to be compared is a node-set and the other is a number,
5251  * then the comparison will be true if and only if there is a node in the
5252  * node-set such that the result of performing the comparison on the number
5253  * to be compared and on the result of converting the string-value of that
5254  * node to a number using the number function is true.
5255  *
5256  * Returns 0 or 1 depending on the results of the test.
5257  */
5258 static int
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr f)5259 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
5260 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5261     int i, ret = 0;
5262     xmlNodeSetPtr ns;
5263     xmlChar *str2;
5264 
5265     if ((f == NULL) || (arg == NULL) ||
5266 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5267 	xmlXPathReleaseObject(ctxt->context, arg);
5268 	xmlXPathReleaseObject(ctxt->context, f);
5269         return(0);
5270     }
5271     ns = arg->nodesetval;
5272     if (ns != NULL) {
5273 	for (i = 0;i < ns->nodeNr;i++) {
5274 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5275 	     if (str2 != NULL) {
5276 		 valuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5277 		 xmlFree(str2);
5278 		 xmlXPathNumberFunction(ctxt, 1);
5279 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, f));
5280 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
5281 		 if (ret)
5282 		     break;
5283 	     } else {
5284                  xmlXPathPErrMemory(ctxt);
5285              }
5286 	}
5287     }
5288     xmlXPathReleaseObject(ctxt->context, arg);
5289     xmlXPathReleaseObject(ctxt->context, f);
5290     return(ret);
5291 }
5292 
5293 /**
5294  * xmlXPathCompareNodeSetString:
5295  * @ctxt:  the XPath Parser context
5296  * @inf:  less than (1) or greater than (0)
5297  * @strict:  is the comparison strict
5298  * @arg:  the node set
5299  * @s:  the value
5300  *
5301  * Implement the compare operation between a nodeset and a string
5302  *     @ns < @val    (1, 1, ...
5303  *     @ns <= @val   (1, 0, ...
5304  *     @ns > @val    (0, 1, ...
5305  *     @ns >= @val   (0, 0, ...
5306  *
5307  * If one object to be compared is a node-set and the other is a string,
5308  * then the comparison will be true if and only if there is a node in
5309  * the node-set such that the result of performing the comparison on the
5310  * string-value of the node and the other string is true.
5311  *
5312  * Returns 0 or 1 depending on the results of the test.
5313  */
5314 static int
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr s)5315 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
5316 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5317     int i, ret = 0;
5318     xmlNodeSetPtr ns;
5319     xmlChar *str2;
5320 
5321     if ((s == NULL) || (arg == NULL) ||
5322 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5323 	xmlXPathReleaseObject(ctxt->context, arg);
5324 	xmlXPathReleaseObject(ctxt->context, s);
5325         return(0);
5326     }
5327     ns = arg->nodesetval;
5328     if (ns != NULL) {
5329 	for (i = 0;i < ns->nodeNr;i++) {
5330 	     str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5331 	     if (str2 != NULL) {
5332 		 valuePush(ctxt,
5333 			   xmlXPathCacheNewString(ctxt, str2));
5334 		 xmlFree(str2);
5335 		 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, s));
5336 		 ret = xmlXPathCompareValues(ctxt, inf, strict);
5337 		 if (ret)
5338 		     break;
5339 	     } else {
5340                  xmlXPathPErrMemory(ctxt);
5341              }
5342 	}
5343     }
5344     xmlXPathReleaseObject(ctxt->context, arg);
5345     xmlXPathReleaseObject(ctxt->context, s);
5346     return(ret);
5347 }
5348 
5349 /**
5350  * xmlXPathCompareNodeSets:
5351  * @inf:  less than (1) or greater than (0)
5352  * @strict:  is the comparison strict
5353  * @arg1:  the first node set object
5354  * @arg2:  the second node set object
5355  *
5356  * Implement the compare operation on nodesets:
5357  *
5358  * If both objects to be compared are node-sets, then the comparison
5359  * will be true if and only if there is a node in the first node-set
5360  * and a node in the second node-set such that the result of performing
5361  * the comparison on the string-values of the two nodes is true.
5362  * ....
5363  * When neither object to be compared is a node-set and the operator
5364  * is <=, <, >= or >, then the objects are compared by converting both
5365  * objects to numbers and comparing the numbers according to IEEE 754.
5366  * ....
5367  * The number function converts its argument to a number as follows:
5368  *  - a string that consists of optional whitespace followed by an
5369  *    optional minus sign followed by a Number followed by whitespace
5370  *    is converted to the IEEE 754 number that is nearest (according
5371  *    to the IEEE 754 round-to-nearest rule) to the mathematical value
5372  *    represented by the string; any other string is converted to NaN
5373  *
5374  * Conclusion all nodes need to be converted first to their string value
5375  * and then the comparison must be done when possible
5376  */
5377 static int
xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)5378 xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt, int inf, int strict,
5379 	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5380     int i, j, init = 0;
5381     double val1;
5382     double *values2;
5383     int ret = 0;
5384     xmlNodeSetPtr ns1;
5385     xmlNodeSetPtr ns2;
5386 
5387     if ((arg1 == NULL) ||
5388 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5389 	xmlXPathFreeObject(arg2);
5390         return(0);
5391     }
5392     if ((arg2 == NULL) ||
5393 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
5394 	xmlXPathFreeObject(arg1);
5395 	xmlXPathFreeObject(arg2);
5396         return(0);
5397     }
5398 
5399     ns1 = arg1->nodesetval;
5400     ns2 = arg2->nodesetval;
5401 
5402     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5403 	xmlXPathFreeObject(arg1);
5404 	xmlXPathFreeObject(arg2);
5405 	return(0);
5406     }
5407     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5408 	xmlXPathFreeObject(arg1);
5409 	xmlXPathFreeObject(arg2);
5410 	return(0);
5411     }
5412 
5413     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5414     if (values2 == NULL) {
5415         xmlXPathPErrMemory(ctxt);
5416 	xmlXPathFreeObject(arg1);
5417 	xmlXPathFreeObject(arg2);
5418 	return(0);
5419     }
5420     for (i = 0;i < ns1->nodeNr;i++) {
5421 	val1 = xmlXPathNodeToNumberInternal(ctxt, ns1->nodeTab[i]);
5422 	if (xmlXPathIsNaN(val1))
5423 	    continue;
5424 	for (j = 0;j < ns2->nodeNr;j++) {
5425 	    if (init == 0) {
5426 		values2[j] = xmlXPathNodeToNumberInternal(ctxt,
5427                                                           ns2->nodeTab[j]);
5428 	    }
5429 	    if (xmlXPathIsNaN(values2[j]))
5430 		continue;
5431 	    if (inf && strict)
5432 		ret = (val1 < values2[j]);
5433 	    else if (inf && !strict)
5434 		ret = (val1 <= values2[j]);
5435 	    else if (!inf && strict)
5436 		ret = (val1 > values2[j]);
5437 	    else if (!inf && !strict)
5438 		ret = (val1 >= values2[j]);
5439 	    if (ret)
5440 		break;
5441 	}
5442 	if (ret)
5443 	    break;
5444 	init = 1;
5445     }
5446     xmlFree(values2);
5447     xmlXPathFreeObject(arg1);
5448     xmlXPathFreeObject(arg2);
5449     return(ret);
5450 }
5451 
5452 /**
5453  * xmlXPathCompareNodeSetValue:
5454  * @ctxt:  the XPath Parser context
5455  * @inf:  less than (1) or greater than (0)
5456  * @strict:  is the comparison strict
5457  * @arg:  the node set
5458  * @val:  the value
5459  *
5460  * Implement the compare operation between a nodeset and a value
5461  *     @ns < @val    (1, 1, ...
5462  *     @ns <= @val   (1, 0, ...
5463  *     @ns > @val    (0, 1, ...
5464  *     @ns >= @val   (0, 0, ...
5465  *
5466  * If one object to be compared is a node-set and the other is a boolean,
5467  * then the comparison will be true if and only if the result of performing
5468  * the comparison on the boolean and on the result of converting
5469  * the node-set to a boolean using the boolean function is true.
5470  *
5471  * Returns 0 or 1 depending on the results of the test.
5472  */
5473 static int
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr val)5474 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
5475 	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
5476     if ((val == NULL) || (arg == NULL) ||
5477 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5478         return(0);
5479 
5480     switch(val->type) {
5481         case XPATH_NUMBER:
5482 	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
5483         case XPATH_NODESET:
5484         case XPATH_XSLT_TREE:
5485 	    return(xmlXPathCompareNodeSets(ctxt, inf, strict, arg, val));
5486         case XPATH_STRING:
5487 	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
5488         case XPATH_BOOLEAN:
5489 	    valuePush(ctxt, arg);
5490 	    xmlXPathBooleanFunction(ctxt, 1);
5491 	    valuePush(ctxt, val);
5492 	    return(xmlXPathCompareValues(ctxt, inf, strict));
5493 	default:
5494             xmlXPathReleaseObject(ctxt->context, arg);
5495             xmlXPathReleaseObject(ctxt->context, val);
5496             XP_ERROR0(XPATH_INVALID_TYPE);
5497     }
5498     return(0);
5499 }
5500 
5501 /**
5502  * xmlXPathEqualNodeSetString:
5503  * @arg:  the nodeset object argument
5504  * @str:  the string to compare to.
5505  * @neq:  flag to show whether for '=' (0) or '!=' (1)
5506  *
5507  * Implement the equal operation on XPath objects content: @arg1 == @arg2
5508  * If one object to be compared is a node-set and the other is a string,
5509  * then the comparison will be true if and only if there is a node in
5510  * the node-set such that the result of performing the comparison on the
5511  * string-value of the node and the other string is true.
5512  *
5513  * Returns 0 or 1 depending on the results of the test.
5514  */
5515 static int
xmlXPathEqualNodeSetString(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,const xmlChar * str,int neq)5516 xmlXPathEqualNodeSetString(xmlXPathParserContextPtr ctxt,
5517                            xmlXPathObjectPtr arg, const xmlChar * str, int neq)
5518 {
5519     int i;
5520     xmlNodeSetPtr ns;
5521     xmlChar *str2;
5522     unsigned int hash;
5523 
5524     if ((str == NULL) || (arg == NULL) ||
5525         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5526         return (0);
5527     ns = arg->nodesetval;
5528     /*
5529      * A NULL nodeset compared with a string is always false
5530      * (since there is no node equal, and no node not equal)
5531      */
5532     if ((ns == NULL) || (ns->nodeNr <= 0) )
5533         return (0);
5534     hash = xmlXPathStringHash(str);
5535     for (i = 0; i < ns->nodeNr; i++) {
5536         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
5537             str2 = xmlNodeGetContent(ns->nodeTab[i]);
5538             if (str2 == NULL) {
5539                 xmlXPathPErrMemory(ctxt);
5540                 return(0);
5541             }
5542             if (xmlStrEqual(str, str2)) {
5543                 xmlFree(str2);
5544 		if (neq)
5545 		    continue;
5546                 return (1);
5547             } else if (neq) {
5548 		xmlFree(str2);
5549 		return (1);
5550 	    }
5551             xmlFree(str2);
5552         } else if (neq)
5553 	    return (1);
5554     }
5555     return (0);
5556 }
5557 
5558 /**
5559  * xmlXPathEqualNodeSetFloat:
5560  * @arg:  the nodeset object argument
5561  * @f:  the float to compare to
5562  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
5563  *
5564  * Implement the equal operation on XPath objects content: @arg1 == @arg2
5565  * If one object to be compared is a node-set and the other is a number,
5566  * then the comparison will be true if and only if there is a node in
5567  * the node-set such that the result of performing the comparison on the
5568  * number to be compared and on the result of converting the string-value
5569  * of that node to a number using the number function is true.
5570  *
5571  * Returns 0 or 1 depending on the results of the test.
5572  */
5573 static int
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,double f,int neq)5574 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
5575     xmlXPathObjectPtr arg, double f, int neq) {
5576   int i, ret=0;
5577   xmlNodeSetPtr ns;
5578   xmlChar *str2;
5579   xmlXPathObjectPtr val;
5580   double v;
5581 
5582     if ((arg == NULL) ||
5583 	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5584         return(0);
5585 
5586     ns = arg->nodesetval;
5587     if (ns != NULL) {
5588 	for (i=0;i<ns->nodeNr;i++) {
5589 	    str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5590 	    if (str2 != NULL) {
5591 		valuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5592 		xmlFree(str2);
5593 		xmlXPathNumberFunction(ctxt, 1);
5594                 CHECK_ERROR0;
5595 		val = valuePop(ctxt);
5596 		v = val->floatval;
5597 		xmlXPathReleaseObject(ctxt->context, val);
5598 		if (!xmlXPathIsNaN(v)) {
5599 		    if ((!neq) && (v==f)) {
5600 			ret = 1;
5601 			break;
5602 		    } else if ((neq) && (v!=f)) {
5603 			ret = 1;
5604 			break;
5605 		    }
5606 		} else {	/* NaN is unequal to any value */
5607 		    if (neq)
5608 			ret = 1;
5609 		}
5610 	    } else {
5611                 xmlXPathPErrMemory(ctxt);
5612             }
5613 	}
5614     }
5615 
5616     return(ret);
5617 }
5618 
5619 
5620 /**
5621  * xmlXPathEqualNodeSets:
5622  * @arg1:  first nodeset object argument
5623  * @arg2:  second nodeset object argument
5624  * @neq:   flag to show whether to test '=' (0) or '!=' (1)
5625  *
5626  * Implement the equal / not equal operation on XPath nodesets:
5627  * @arg1 == @arg2  or  @arg1 != @arg2
5628  * If both objects to be compared are node-sets, then the comparison
5629  * will be true if and only if there is a node in the first node-set and
5630  * a node in the second node-set such that the result of performing the
5631  * comparison on the string-values of the two nodes is true.
5632  *
5633  * (needless to say, this is a costly operation)
5634  *
5635  * Returns 0 or 1 depending on the results of the test.
5636  */
5637 static int
xmlXPathEqualNodeSets(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2,int neq)5638 xmlXPathEqualNodeSets(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr arg1,
5639                       xmlXPathObjectPtr arg2, int neq) {
5640     int i, j;
5641     unsigned int *hashs1;
5642     unsigned int *hashs2;
5643     xmlChar **values1;
5644     xmlChar **values2;
5645     int ret = 0;
5646     xmlNodeSetPtr ns1;
5647     xmlNodeSetPtr ns2;
5648 
5649     if ((arg1 == NULL) ||
5650 	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
5651         return(0);
5652     if ((arg2 == NULL) ||
5653 	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
5654         return(0);
5655 
5656     ns1 = arg1->nodesetval;
5657     ns2 = arg2->nodesetval;
5658 
5659     if ((ns1 == NULL) || (ns1->nodeNr <= 0))
5660 	return(0);
5661     if ((ns2 == NULL) || (ns2->nodeNr <= 0))
5662 	return(0);
5663 
5664     /*
5665      * for equal, check if there is a node pertaining to both sets
5666      */
5667     if (neq == 0)
5668 	for (i = 0;i < ns1->nodeNr;i++)
5669 	    for (j = 0;j < ns2->nodeNr;j++)
5670 		if (ns1->nodeTab[i] == ns2->nodeTab[j])
5671 		    return(1);
5672 
5673     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
5674     if (values1 == NULL) {
5675         xmlXPathPErrMemory(ctxt);
5676 	return(0);
5677     }
5678     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
5679     if (hashs1 == NULL) {
5680         xmlXPathPErrMemory(ctxt);
5681 	xmlFree(values1);
5682 	return(0);
5683     }
5684     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
5685     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
5686     if (values2 == NULL) {
5687         xmlXPathPErrMemory(ctxt);
5688 	xmlFree(hashs1);
5689 	xmlFree(values1);
5690 	return(0);
5691     }
5692     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
5693     if (hashs2 == NULL) {
5694         xmlXPathPErrMemory(ctxt);
5695 	xmlFree(hashs1);
5696 	xmlFree(values1);
5697 	xmlFree(values2);
5698 	return(0);
5699     }
5700     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
5701     for (i = 0;i < ns1->nodeNr;i++) {
5702 	hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
5703 	for (j = 0;j < ns2->nodeNr;j++) {
5704 	    if (i == 0)
5705 		hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
5706 	    if (hashs1[i] != hashs2[j]) {
5707 		if (neq) {
5708 		    ret = 1;
5709 		    break;
5710 		}
5711 	    }
5712 	    else {
5713 		if (values1[i] == NULL) {
5714 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
5715                     if (values1[i] == NULL)
5716                         xmlXPathPErrMemory(ctxt);
5717                 }
5718 		if (values2[j] == NULL) {
5719 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
5720                     if (values2[j] == NULL)
5721                         xmlXPathPErrMemory(ctxt);
5722                 }
5723 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
5724 		if (ret)
5725 		    break;
5726 	    }
5727 	}
5728 	if (ret)
5729 	    break;
5730     }
5731     for (i = 0;i < ns1->nodeNr;i++)
5732 	if (values1[i] != NULL)
5733 	    xmlFree(values1[i]);
5734     for (j = 0;j < ns2->nodeNr;j++)
5735 	if (values2[j] != NULL)
5736 	    xmlFree(values2[j]);
5737     xmlFree(values1);
5738     xmlFree(values2);
5739     xmlFree(hashs1);
5740     xmlFree(hashs2);
5741     return(ret);
5742 }
5743 
5744 static int
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)5745 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
5746   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5747     int ret = 0;
5748     /*
5749      *At this point we are assured neither arg1 nor arg2
5750      *is a nodeset, so we can just pick the appropriate routine.
5751      */
5752     switch (arg1->type) {
5753         case XPATH_UNDEFINED:
5754 	    break;
5755         case XPATH_BOOLEAN:
5756 	    switch (arg2->type) {
5757 	        case XPATH_UNDEFINED:
5758 		    break;
5759 		case XPATH_BOOLEAN:
5760 		    ret = (arg1->boolval == arg2->boolval);
5761 		    break;
5762 		case XPATH_NUMBER:
5763 		    ret = (arg1->boolval ==
5764 			   xmlXPathCastNumberToBoolean(arg2->floatval));
5765 		    break;
5766 		case XPATH_STRING:
5767 		    if ((arg2->stringval == NULL) ||
5768 			(arg2->stringval[0] == 0)) ret = 0;
5769 		    else
5770 			ret = 1;
5771 		    ret = (arg1->boolval == ret);
5772 		    break;
5773 		case XPATH_USERS:
5774 		    /* TODO */
5775 		    break;
5776 		case XPATH_NODESET:
5777 		case XPATH_XSLT_TREE:
5778 		    break;
5779 	    }
5780 	    break;
5781         case XPATH_NUMBER:
5782 	    switch (arg2->type) {
5783 	        case XPATH_UNDEFINED:
5784 		    break;
5785 		case XPATH_BOOLEAN:
5786 		    ret = (arg2->boolval==
5787 			   xmlXPathCastNumberToBoolean(arg1->floatval));
5788 		    break;
5789 		case XPATH_STRING:
5790 		    valuePush(ctxt, arg2);
5791 		    xmlXPathNumberFunction(ctxt, 1);
5792 		    arg2 = valuePop(ctxt);
5793                     if (ctxt->error)
5794                         break;
5795                     /* Falls through. */
5796 		case XPATH_NUMBER:
5797 		    /* Hand check NaN and Infinity equalities */
5798 		    if (xmlXPathIsNaN(arg1->floatval) ||
5799 			    xmlXPathIsNaN(arg2->floatval)) {
5800 		        ret = 0;
5801 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5802 		        if (xmlXPathIsInf(arg2->floatval) == 1)
5803 			    ret = 1;
5804 			else
5805 			    ret = 0;
5806 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5807 			if (xmlXPathIsInf(arg2->floatval) == -1)
5808 			    ret = 1;
5809 			else
5810 			    ret = 0;
5811 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5812 			if (xmlXPathIsInf(arg1->floatval) == 1)
5813 			    ret = 1;
5814 			else
5815 			    ret = 0;
5816 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5817 			if (xmlXPathIsInf(arg1->floatval) == -1)
5818 			    ret = 1;
5819 			else
5820 			    ret = 0;
5821 		    } else {
5822 		        ret = (arg1->floatval == arg2->floatval);
5823 		    }
5824 		    break;
5825 		case XPATH_USERS:
5826 		    /* TODO */
5827 		    break;
5828 		case XPATH_NODESET:
5829 		case XPATH_XSLT_TREE:
5830 		    break;
5831 	    }
5832 	    break;
5833         case XPATH_STRING:
5834 	    switch (arg2->type) {
5835 	        case XPATH_UNDEFINED:
5836 		    break;
5837 		case XPATH_BOOLEAN:
5838 		    if ((arg1->stringval == NULL) ||
5839 			(arg1->stringval[0] == 0)) ret = 0;
5840 		    else
5841 			ret = 1;
5842 		    ret = (arg2->boolval == ret);
5843 		    break;
5844 		case XPATH_STRING:
5845 		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
5846 		    break;
5847 		case XPATH_NUMBER:
5848 		    valuePush(ctxt, arg1);
5849 		    xmlXPathNumberFunction(ctxt, 1);
5850 		    arg1 = valuePop(ctxt);
5851                     if (ctxt->error)
5852                         break;
5853 		    /* Hand check NaN and Infinity equalities */
5854 		    if (xmlXPathIsNaN(arg1->floatval) ||
5855 			    xmlXPathIsNaN(arg2->floatval)) {
5856 		        ret = 0;
5857 		    } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5858 			if (xmlXPathIsInf(arg2->floatval) == 1)
5859 			    ret = 1;
5860 			else
5861 			    ret = 0;
5862 		    } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5863 			if (xmlXPathIsInf(arg2->floatval) == -1)
5864 			    ret = 1;
5865 			else
5866 			    ret = 0;
5867 		    } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5868 			if (xmlXPathIsInf(arg1->floatval) == 1)
5869 			    ret = 1;
5870 			else
5871 			    ret = 0;
5872 		    } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5873 			if (xmlXPathIsInf(arg1->floatval) == -1)
5874 			    ret = 1;
5875 			else
5876 			    ret = 0;
5877 		    } else {
5878 		        ret = (arg1->floatval == arg2->floatval);
5879 		    }
5880 		    break;
5881 		case XPATH_USERS:
5882 		    /* TODO */
5883 		    break;
5884 		case XPATH_NODESET:
5885 		case XPATH_XSLT_TREE:
5886 		    break;
5887 	    }
5888 	    break;
5889         case XPATH_USERS:
5890 	    /* TODO */
5891 	    break;
5892 	case XPATH_NODESET:
5893 	case XPATH_XSLT_TREE:
5894 	    break;
5895     }
5896     xmlXPathReleaseObject(ctxt->context, arg1);
5897     xmlXPathReleaseObject(ctxt->context, arg2);
5898     return(ret);
5899 }
5900 
5901 /**
5902  * xmlXPathEqualValues:
5903  * @ctxt:  the XPath Parser context
5904  *
5905  * Implement the equal operation on XPath objects content: @arg1 == @arg2
5906  *
5907  * Returns 0 or 1 depending on the results of the test.
5908  */
5909 int
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt)5910 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
5911     xmlXPathObjectPtr arg1, arg2, argtmp;
5912     int ret = 0;
5913 
5914     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5915     arg2 = valuePop(ctxt);
5916     arg1 = valuePop(ctxt);
5917     if ((arg1 == NULL) || (arg2 == NULL)) {
5918 	if (arg1 != NULL)
5919 	    xmlXPathReleaseObject(ctxt->context, arg1);
5920 	else
5921 	    xmlXPathReleaseObject(ctxt->context, arg2);
5922 	XP_ERROR0(XPATH_INVALID_OPERAND);
5923     }
5924 
5925     if (arg1 == arg2) {
5926 	xmlXPathFreeObject(arg1);
5927         return(1);
5928     }
5929 
5930     /*
5931      *If either argument is a nodeset, it's a 'special case'
5932      */
5933     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5934       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5935 	/*
5936 	 *Hack it to assure arg1 is the nodeset
5937 	 */
5938 	if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5939 		argtmp = arg2;
5940 		arg2 = arg1;
5941 		arg1 = argtmp;
5942 	}
5943 	switch (arg2->type) {
5944 	    case XPATH_UNDEFINED:
5945 		break;
5946 	    case XPATH_NODESET:
5947 	    case XPATH_XSLT_TREE:
5948 		ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 0);
5949 		break;
5950 	    case XPATH_BOOLEAN:
5951 		if ((arg1->nodesetval == NULL) ||
5952 		  (arg1->nodesetval->nodeNr == 0)) ret = 0;
5953 		else
5954 		    ret = 1;
5955 		ret = (ret == arg2->boolval);
5956 		break;
5957 	    case XPATH_NUMBER:
5958 		ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
5959 		break;
5960 	    case XPATH_STRING:
5961 		ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5962                                                  arg2->stringval, 0);
5963 		break;
5964 	    case XPATH_USERS:
5965 		/* TODO */
5966 		break;
5967 	}
5968 	xmlXPathReleaseObject(ctxt->context, arg1);
5969 	xmlXPathReleaseObject(ctxt->context, arg2);
5970 	return(ret);
5971     }
5972 
5973     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5974 }
5975 
5976 /**
5977  * xmlXPathNotEqualValues:
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
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt)5985 xmlXPathNotEqualValues(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 	xmlXPathReleaseObject(ctxt->context, arg1);
6002         return(0);
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, 1);
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, 1);
6034 		break;
6035 	    case XPATH_STRING:
6036 		ret = xmlXPathEqualNodeSetString(ctxt, arg1,
6037                                                  arg2->stringval, 1);
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  * xmlXPathCompareValues:
6053  * @ctxt:  the XPath Parser context
6054  * @inf:  less than (1) or greater than (0)
6055  * @strict:  is the comparison strict
6056  *
6057  * Implement the compare operation on XPath objects:
6058  *     @arg1 < @arg2    (1, 1, ...
6059  *     @arg1 <= @arg2   (1, 0, ...
6060  *     @arg1 > @arg2    (0, 1, ...
6061  *     @arg1 >= @arg2   (0, 0, ...
6062  *
6063  * When neither object to be compared is a node-set and the operator is
6064  * <=, <, >=, >, then the objects are compared by converted both objects
6065  * to numbers and comparing the numbers according to IEEE 754. The <
6066  * comparison will be true if and only if the first number is less than the
6067  * second number. The <= comparison will be true if and only if the first
6068  * number is less than or equal to the second number. The > comparison
6069  * will be true if and only if the first number is greater than the second
6070  * number. The >= comparison will be true if and only if the first number
6071  * is greater than or equal to the second number.
6072  *
6073  * Returns 1 if the comparison succeeded, 0 if it failed
6074  */
6075 int
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt,int inf,int strict)6076 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
6077     int ret = 0, arg1i = 0, arg2i = 0;
6078     xmlXPathObjectPtr arg1, arg2;
6079 
6080     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6081     arg2 = valuePop(ctxt);
6082     arg1 = valuePop(ctxt);
6083     if ((arg1 == NULL) || (arg2 == NULL)) {
6084 	if (arg1 != NULL)
6085 	    xmlXPathReleaseObject(ctxt->context, arg1);
6086 	else
6087 	    xmlXPathReleaseObject(ctxt->context, arg2);
6088 	XP_ERROR0(XPATH_INVALID_OPERAND);
6089     }
6090 
6091     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6092       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6093 	/*
6094 	 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
6095 	 * are not freed from within this routine; they will be freed from the
6096 	 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
6097 	 */
6098 	if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
6099 	  ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
6100 	    ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
6101 	} else {
6102 	    if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6103 		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
6104 			                          arg1, arg2);
6105 	    } else {
6106 		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
6107 			                          arg2, arg1);
6108 	    }
6109 	}
6110 	return(ret);
6111     }
6112 
6113     if (arg1->type != XPATH_NUMBER) {
6114 	valuePush(ctxt, arg1);
6115 	xmlXPathNumberFunction(ctxt, 1);
6116 	arg1 = valuePop(ctxt);
6117     }
6118     if (arg2->type != XPATH_NUMBER) {
6119 	valuePush(ctxt, arg2);
6120 	xmlXPathNumberFunction(ctxt, 1);
6121 	arg2 = valuePop(ctxt);
6122     }
6123     if (ctxt->error)
6124         goto error;
6125     /*
6126      * Add tests for infinity and nan
6127      * => feedback on 3.4 for Inf and NaN
6128      */
6129     /* Hand check NaN and Infinity comparisons */
6130     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
6131 	ret=0;
6132     } else {
6133 	arg1i=xmlXPathIsInf(arg1->floatval);
6134 	arg2i=xmlXPathIsInf(arg2->floatval);
6135 	if (inf && strict) {
6136 	    if ((arg1i == -1 && arg2i != -1) ||
6137 		(arg2i == 1 && arg1i != 1)) {
6138 		ret = 1;
6139 	    } else if (arg1i == 0 && arg2i == 0) {
6140 		ret = (arg1->floatval < arg2->floatval);
6141 	    } else {
6142 		ret = 0;
6143 	    }
6144 	}
6145 	else if (inf && !strict) {
6146 	    if (arg1i == -1 || arg2i == 1) {
6147 		ret = 1;
6148 	    } else if (arg1i == 0 && arg2i == 0) {
6149 		ret = (arg1->floatval <= arg2->floatval);
6150 	    } else {
6151 		ret = 0;
6152 	    }
6153 	}
6154 	else if (!inf && strict) {
6155 	    if ((arg1i == 1 && arg2i != 1) ||
6156 		(arg2i == -1 && arg1i != -1)) {
6157 		ret = 1;
6158 	    } else if (arg1i == 0 && arg2i == 0) {
6159 		ret = (arg1->floatval > arg2->floatval);
6160 	    } else {
6161 		ret = 0;
6162 	    }
6163 	}
6164 	else if (!inf && !strict) {
6165 	    if (arg1i == 1 || arg2i == -1) {
6166 		ret = 1;
6167 	    } else if (arg1i == 0 && arg2i == 0) {
6168 		ret = (arg1->floatval >= arg2->floatval);
6169 	    } else {
6170 		ret = 0;
6171 	    }
6172 	}
6173     }
6174 error:
6175     xmlXPathReleaseObject(ctxt->context, arg1);
6176     xmlXPathReleaseObject(ctxt->context, arg2);
6177     return(ret);
6178 }
6179 
6180 /**
6181  * xmlXPathValueFlipSign:
6182  * @ctxt:  the XPath Parser context
6183  *
6184  * Implement the unary - operation on an XPath object
6185  * The numeric operators convert their operands to numbers as if
6186  * by calling the number function.
6187  */
6188 void
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt)6189 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
6190     if ((ctxt == NULL) || (ctxt->context == NULL)) return;
6191     CAST_TO_NUMBER;
6192     CHECK_TYPE(XPATH_NUMBER);
6193     ctxt->value->floatval = -ctxt->value->floatval;
6194 }
6195 
6196 /**
6197  * xmlXPathAddValues:
6198  * @ctxt:  the XPath Parser context
6199  *
6200  * Implement the add operation on XPath objects:
6201  * The numeric operators convert their operands to numbers as if
6202  * by calling the number function.
6203  */
6204 void
xmlXPathAddValues(xmlXPathParserContextPtr ctxt)6205 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
6206     xmlXPathObjectPtr arg;
6207     double val;
6208 
6209     arg = valuePop(ctxt);
6210     if (arg == NULL)
6211 	XP_ERROR(XPATH_INVALID_OPERAND);
6212     val = xmlXPathCastToNumberInternal(ctxt, arg);
6213     xmlXPathReleaseObject(ctxt->context, arg);
6214     CAST_TO_NUMBER;
6215     CHECK_TYPE(XPATH_NUMBER);
6216     ctxt->value->floatval += val;
6217 }
6218 
6219 /**
6220  * xmlXPathSubValues:
6221  * @ctxt:  the XPath Parser context
6222  *
6223  * Implement the subtraction operation on XPath objects:
6224  * The numeric operators convert their operands to numbers as if
6225  * by calling the number function.
6226  */
6227 void
xmlXPathSubValues(xmlXPathParserContextPtr ctxt)6228 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
6229     xmlXPathObjectPtr arg;
6230     double val;
6231 
6232     arg = valuePop(ctxt);
6233     if (arg == NULL)
6234 	XP_ERROR(XPATH_INVALID_OPERAND);
6235     val = xmlXPathCastToNumberInternal(ctxt, arg);
6236     xmlXPathReleaseObject(ctxt->context, arg);
6237     CAST_TO_NUMBER;
6238     CHECK_TYPE(XPATH_NUMBER);
6239     ctxt->value->floatval -= val;
6240 }
6241 
6242 /**
6243  * xmlXPathMultValues:
6244  * @ctxt:  the XPath Parser context
6245  *
6246  * Implement the multiply operation on XPath objects:
6247  * The numeric operators convert their operands to numbers as if
6248  * by calling the number function.
6249  */
6250 void
xmlXPathMultValues(xmlXPathParserContextPtr ctxt)6251 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
6252     xmlXPathObjectPtr arg;
6253     double val;
6254 
6255     arg = valuePop(ctxt);
6256     if (arg == NULL)
6257 	XP_ERROR(XPATH_INVALID_OPERAND);
6258     val = xmlXPathCastToNumberInternal(ctxt, arg);
6259     xmlXPathReleaseObject(ctxt->context, arg);
6260     CAST_TO_NUMBER;
6261     CHECK_TYPE(XPATH_NUMBER);
6262     ctxt->value->floatval *= val;
6263 }
6264 
6265 /**
6266  * xmlXPathDivValues:
6267  * @ctxt:  the XPath Parser context
6268  *
6269  * Implement the div operation on XPath objects @arg1 / @arg2:
6270  * The numeric operators convert their operands to numbers as if
6271  * by calling the number function.
6272  */
6273 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
6274 void
xmlXPathDivValues(xmlXPathParserContextPtr ctxt)6275 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
6276     xmlXPathObjectPtr arg;
6277     double val;
6278 
6279     arg = valuePop(ctxt);
6280     if (arg == NULL)
6281 	XP_ERROR(XPATH_INVALID_OPERAND);
6282     val = xmlXPathCastToNumberInternal(ctxt, arg);
6283     xmlXPathReleaseObject(ctxt->context, arg);
6284     CAST_TO_NUMBER;
6285     CHECK_TYPE(XPATH_NUMBER);
6286     ctxt->value->floatval /= val;
6287 }
6288 
6289 /**
6290  * xmlXPathModValues:
6291  * @ctxt:  the XPath Parser context
6292  *
6293  * Implement the mod operation on XPath objects: @arg1 / @arg2
6294  * The numeric operators convert their operands to numbers as if
6295  * by calling the number function.
6296  */
6297 void
xmlXPathModValues(xmlXPathParserContextPtr ctxt)6298 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
6299     xmlXPathObjectPtr arg;
6300     double arg1, arg2;
6301 
6302     arg = valuePop(ctxt);
6303     if (arg == NULL)
6304 	XP_ERROR(XPATH_INVALID_OPERAND);
6305     arg2 = xmlXPathCastToNumberInternal(ctxt, arg);
6306     xmlXPathReleaseObject(ctxt->context, arg);
6307     CAST_TO_NUMBER;
6308     CHECK_TYPE(XPATH_NUMBER);
6309     arg1 = ctxt->value->floatval;
6310     if (arg2 == 0)
6311 	ctxt->value->floatval = xmlXPathNAN;
6312     else {
6313 	ctxt->value->floatval = fmod(arg1, arg2);
6314     }
6315 }
6316 
6317 /************************************************************************
6318  *									*
6319  *		The traversal functions					*
6320  *									*
6321  ************************************************************************/
6322 
6323 /*
6324  * A traversal function enumerates nodes along an axis.
6325  * Initially it must be called with NULL, and it indicates
6326  * termination on the axis by returning NULL.
6327  */
6328 typedef xmlNodePtr (*xmlXPathTraversalFunction)
6329                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
6330 
6331 /*
6332  * xmlXPathTraversalFunctionExt:
6333  * A traversal function enumerates nodes along an axis.
6334  * Initially it must be called with NULL, and it indicates
6335  * termination on the axis by returning NULL.
6336  * The context node of the traversal is specified via @contextNode.
6337  */
6338 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
6339                     (xmlNodePtr cur, xmlNodePtr contextNode);
6340 
6341 /*
6342  * xmlXPathNodeSetMergeFunction:
6343  * Used for merging node sets in xmlXPathCollectAndTest().
6344  */
6345 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
6346 		    (xmlNodeSetPtr, xmlNodeSetPtr);
6347 
6348 
6349 /**
6350  * xmlXPathNextSelf:
6351  * @ctxt:  the XPath Parser context
6352  * @cur:  the current node in the traversal
6353  *
6354  * Traversal function for the "self" direction
6355  * The self axis contains just the context node itself
6356  *
6357  * Returns the next element following that axis
6358  */
6359 xmlNodePtr
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6360 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6361     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6362     if (cur == NULL)
6363         return(ctxt->context->node);
6364     return(NULL);
6365 }
6366 
6367 /**
6368  * xmlXPathNextChild:
6369  * @ctxt:  the XPath Parser context
6370  * @cur:  the current node in the traversal
6371  *
6372  * Traversal function for the "child" direction
6373  * The child axis contains the children of the context node in document order.
6374  *
6375  * Returns the next element following that axis
6376  */
6377 xmlNodePtr
xmlXPathNextChild(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6378 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6379     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6380     if (cur == NULL) {
6381 	if (ctxt->context->node == NULL) return(NULL);
6382 	switch (ctxt->context->node->type) {
6383             case XML_ELEMENT_NODE:
6384             case XML_TEXT_NODE:
6385             case XML_CDATA_SECTION_NODE:
6386             case XML_ENTITY_REF_NODE:
6387             case XML_ENTITY_NODE:
6388             case XML_PI_NODE:
6389             case XML_COMMENT_NODE:
6390             case XML_NOTATION_NODE:
6391             case XML_DTD_NODE:
6392 		return(ctxt->context->node->children);
6393             case XML_DOCUMENT_NODE:
6394             case XML_DOCUMENT_TYPE_NODE:
6395             case XML_DOCUMENT_FRAG_NODE:
6396             case XML_HTML_DOCUMENT_NODE:
6397 		return(((xmlDocPtr) ctxt->context->node)->children);
6398 	    case XML_ELEMENT_DECL:
6399 	    case XML_ATTRIBUTE_DECL:
6400 	    case XML_ENTITY_DECL:
6401             case XML_ATTRIBUTE_NODE:
6402 	    case XML_NAMESPACE_DECL:
6403 	    case XML_XINCLUDE_START:
6404 	    case XML_XINCLUDE_END:
6405 		return(NULL);
6406 	}
6407 	return(NULL);
6408     }
6409     if ((cur->type == XML_DOCUMENT_NODE) ||
6410         (cur->type == XML_HTML_DOCUMENT_NODE))
6411 	return(NULL);
6412     return(cur->next);
6413 }
6414 
6415 /**
6416  * xmlXPathNextChildElement:
6417  * @ctxt:  the XPath Parser context
6418  * @cur:  the current node in the traversal
6419  *
6420  * Traversal function for the "child" direction and nodes of type element.
6421  * The child axis contains the children of the context node in document order.
6422  *
6423  * Returns the next element following that axis
6424  */
6425 static xmlNodePtr
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6426 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6427     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6428     if (cur == NULL) {
6429 	cur = ctxt->context->node;
6430 	if (cur == NULL) return(NULL);
6431 	/*
6432 	* Get the first element child.
6433 	*/
6434 	switch (cur->type) {
6435             case XML_ELEMENT_NODE:
6436 	    case XML_DOCUMENT_FRAG_NODE:
6437 	    case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
6438             case XML_ENTITY_NODE:
6439 		cur = cur->children;
6440 		if (cur != NULL) {
6441 		    if (cur->type == XML_ELEMENT_NODE)
6442 			return(cur);
6443 		    do {
6444 			cur = cur->next;
6445 		    } while ((cur != NULL) &&
6446 			(cur->type != XML_ELEMENT_NODE));
6447 		    return(cur);
6448 		}
6449 		return(NULL);
6450             case XML_DOCUMENT_NODE:
6451             case XML_HTML_DOCUMENT_NODE:
6452 		return(xmlDocGetRootElement((xmlDocPtr) cur));
6453 	    default:
6454 		return(NULL);
6455 	}
6456 	return(NULL);
6457     }
6458     /*
6459     * Get the next sibling element node.
6460     */
6461     switch (cur->type) {
6462 	case XML_ELEMENT_NODE:
6463 	case XML_TEXT_NODE:
6464 	case XML_ENTITY_REF_NODE:
6465 	case XML_ENTITY_NODE:
6466 	case XML_CDATA_SECTION_NODE:
6467 	case XML_PI_NODE:
6468 	case XML_COMMENT_NODE:
6469 	case XML_XINCLUDE_END:
6470 	    break;
6471 	/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
6472 	default:
6473 	    return(NULL);
6474     }
6475     if (cur->next != NULL) {
6476 	if (cur->next->type == XML_ELEMENT_NODE)
6477 	    return(cur->next);
6478 	cur = cur->next;
6479 	do {
6480 	    cur = cur->next;
6481 	} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
6482 	return(cur);
6483     }
6484     return(NULL);
6485 }
6486 
6487 /**
6488  * xmlXPathNextDescendant:
6489  * @ctxt:  the XPath Parser context
6490  * @cur:  the current node in the traversal
6491  *
6492  * Traversal function for the "descendant" direction
6493  * the descendant axis contains the descendants of the context node in document
6494  * order; a descendant is a child or a child of a child and so on.
6495  *
6496  * Returns the next element following that axis
6497  */
6498 xmlNodePtr
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6499 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6500     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6501     if (cur == NULL) {
6502 	if (ctxt->context->node == NULL)
6503 	    return(NULL);
6504 	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6505 	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
6506 	    return(NULL);
6507 
6508         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6509 	    return(ctxt->context->doc->children);
6510         return(ctxt->context->node->children);
6511     }
6512 
6513     if (cur->type == XML_NAMESPACE_DECL)
6514         return(NULL);
6515     if (cur->children != NULL) {
6516 	/*
6517 	 * Do not descend on entities declarations
6518 	 */
6519 	if (cur->children->type != XML_ENTITY_DECL) {
6520 	    cur = cur->children;
6521 	    /*
6522 	     * Skip DTDs
6523 	     */
6524 	    if (cur->type != XML_DTD_NODE)
6525 		return(cur);
6526 	}
6527     }
6528 
6529     if (cur == ctxt->context->node) return(NULL);
6530 
6531     while (cur->next != NULL) {
6532 	cur = cur->next;
6533 	if ((cur->type != XML_ENTITY_DECL) &&
6534 	    (cur->type != XML_DTD_NODE))
6535 	    return(cur);
6536     }
6537 
6538     do {
6539         cur = cur->parent;
6540 	if (cur == NULL) break;
6541 	if (cur == ctxt->context->node) return(NULL);
6542 	if (cur->next != NULL) {
6543 	    cur = cur->next;
6544 	    return(cur);
6545 	}
6546     } while (cur != NULL);
6547     return(cur);
6548 }
6549 
6550 /**
6551  * xmlXPathNextDescendantOrSelf:
6552  * @ctxt:  the XPath Parser context
6553  * @cur:  the current node in the traversal
6554  *
6555  * Traversal function for the "descendant-or-self" direction
6556  * the descendant-or-self axis contains the context node and the descendants
6557  * of the context node in document order; thus the context node is the first
6558  * node on the axis, and the first child of the context node is the second node
6559  * on the axis
6560  *
6561  * Returns the next element following that axis
6562  */
6563 xmlNodePtr
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6564 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6565     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6566     if (cur == NULL)
6567         return(ctxt->context->node);
6568 
6569     if (ctxt->context->node == NULL)
6570         return(NULL);
6571     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6572         (ctxt->context->node->type == XML_NAMESPACE_DECL))
6573         return(NULL);
6574 
6575     return(xmlXPathNextDescendant(ctxt, cur));
6576 }
6577 
6578 /**
6579  * xmlXPathNextParent:
6580  * @ctxt:  the XPath Parser context
6581  * @cur:  the current node in the traversal
6582  *
6583  * Traversal function for the "parent" direction
6584  * The parent axis contains the parent of the context node, if there is one.
6585  *
6586  * Returns the next element following that axis
6587  */
6588 xmlNodePtr
xmlXPathNextParent(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6589 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6590     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6591     /*
6592      * the parent of an attribute or namespace node is the element
6593      * to which the attribute or namespace node is attached
6594      * Namespace handling !!!
6595      */
6596     if (cur == NULL) {
6597 	if (ctxt->context->node == NULL) return(NULL);
6598 	switch (ctxt->context->node->type) {
6599             case XML_ELEMENT_NODE:
6600             case XML_TEXT_NODE:
6601             case XML_CDATA_SECTION_NODE:
6602             case XML_ENTITY_REF_NODE:
6603             case XML_ENTITY_NODE:
6604             case XML_PI_NODE:
6605             case XML_COMMENT_NODE:
6606             case XML_NOTATION_NODE:
6607             case XML_DTD_NODE:
6608 	    case XML_ELEMENT_DECL:
6609 	    case XML_ATTRIBUTE_DECL:
6610 	    case XML_XINCLUDE_START:
6611 	    case XML_XINCLUDE_END:
6612 	    case XML_ENTITY_DECL:
6613 		if (ctxt->context->node->parent == NULL)
6614 		    return((xmlNodePtr) ctxt->context->doc);
6615 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6616 		    ((ctxt->context->node->parent->name[0] == ' ') ||
6617 		     (xmlStrEqual(ctxt->context->node->parent->name,
6618 				 BAD_CAST "fake node libxslt"))))
6619 		    return(NULL);
6620 		return(ctxt->context->node->parent);
6621             case XML_ATTRIBUTE_NODE: {
6622 		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
6623 
6624 		return(att->parent);
6625 	    }
6626             case XML_DOCUMENT_NODE:
6627             case XML_DOCUMENT_TYPE_NODE:
6628             case XML_DOCUMENT_FRAG_NODE:
6629             case XML_HTML_DOCUMENT_NODE:
6630                 return(NULL);
6631 	    case XML_NAMESPACE_DECL: {
6632 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6633 
6634 		if ((ns->next != NULL) &&
6635 		    (ns->next->type != XML_NAMESPACE_DECL))
6636 		    return((xmlNodePtr) ns->next);
6637                 return(NULL);
6638 	    }
6639 	}
6640     }
6641     return(NULL);
6642 }
6643 
6644 /**
6645  * xmlXPathNextAncestor:
6646  * @ctxt:  the XPath Parser context
6647  * @cur:  the current node in the traversal
6648  *
6649  * Traversal function for the "ancestor" direction
6650  * the ancestor axis contains the ancestors of the context node; the ancestors
6651  * of the context node consist of the parent of context node and the parent's
6652  * parent and so on; the nodes are ordered in reverse document order; thus the
6653  * parent is the first node on the axis, and the parent's parent is the second
6654  * node on the axis
6655  *
6656  * Returns the next element following that axis
6657  */
6658 xmlNodePtr
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6659 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6660     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6661     /*
6662      * the parent of an attribute or namespace node is the element
6663      * to which the attribute or namespace node is attached
6664      * !!!!!!!!!!!!!
6665      */
6666     if (cur == NULL) {
6667 	if (ctxt->context->node == NULL) return(NULL);
6668 	switch (ctxt->context->node->type) {
6669             case XML_ELEMENT_NODE:
6670             case XML_TEXT_NODE:
6671             case XML_CDATA_SECTION_NODE:
6672             case XML_ENTITY_REF_NODE:
6673             case XML_ENTITY_NODE:
6674             case XML_PI_NODE:
6675             case XML_COMMENT_NODE:
6676 	    case XML_DTD_NODE:
6677 	    case XML_ELEMENT_DECL:
6678 	    case XML_ATTRIBUTE_DECL:
6679 	    case XML_ENTITY_DECL:
6680             case XML_NOTATION_NODE:
6681 	    case XML_XINCLUDE_START:
6682 	    case XML_XINCLUDE_END:
6683 		if (ctxt->context->node->parent == NULL)
6684 		    return((xmlNodePtr) ctxt->context->doc);
6685 		if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6686 		    ((ctxt->context->node->parent->name[0] == ' ') ||
6687 		     (xmlStrEqual(ctxt->context->node->parent->name,
6688 				 BAD_CAST "fake node libxslt"))))
6689 		    return(NULL);
6690 		return(ctxt->context->node->parent);
6691             case XML_ATTRIBUTE_NODE: {
6692 		xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
6693 
6694 		return(tmp->parent);
6695 	    }
6696             case XML_DOCUMENT_NODE:
6697             case XML_DOCUMENT_TYPE_NODE:
6698             case XML_DOCUMENT_FRAG_NODE:
6699             case XML_HTML_DOCUMENT_NODE:
6700                 return(NULL);
6701 	    case XML_NAMESPACE_DECL: {
6702 		xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6703 
6704 		if ((ns->next != NULL) &&
6705 		    (ns->next->type != XML_NAMESPACE_DECL))
6706 		    return((xmlNodePtr) ns->next);
6707 		/* Bad, how did that namespace end up here ? */
6708                 return(NULL);
6709 	    }
6710 	}
6711 	return(NULL);
6712     }
6713     if (cur == ctxt->context->doc->children)
6714 	return((xmlNodePtr) ctxt->context->doc);
6715     if (cur == (xmlNodePtr) ctxt->context->doc)
6716 	return(NULL);
6717     switch (cur->type) {
6718 	case XML_ELEMENT_NODE:
6719 	case XML_TEXT_NODE:
6720 	case XML_CDATA_SECTION_NODE:
6721 	case XML_ENTITY_REF_NODE:
6722 	case XML_ENTITY_NODE:
6723 	case XML_PI_NODE:
6724 	case XML_COMMENT_NODE:
6725 	case XML_NOTATION_NODE:
6726 	case XML_DTD_NODE:
6727         case XML_ELEMENT_DECL:
6728         case XML_ATTRIBUTE_DECL:
6729         case XML_ENTITY_DECL:
6730 	case XML_XINCLUDE_START:
6731 	case XML_XINCLUDE_END:
6732 	    if (cur->parent == NULL)
6733 		return(NULL);
6734 	    if ((cur->parent->type == XML_ELEMENT_NODE) &&
6735 		((cur->parent->name[0] == ' ') ||
6736 		 (xmlStrEqual(cur->parent->name,
6737 			      BAD_CAST "fake node libxslt"))))
6738 		return(NULL);
6739 	    return(cur->parent);
6740 	case XML_ATTRIBUTE_NODE: {
6741 	    xmlAttrPtr att = (xmlAttrPtr) cur;
6742 
6743 	    return(att->parent);
6744 	}
6745 	case XML_NAMESPACE_DECL: {
6746 	    xmlNsPtr ns = (xmlNsPtr) cur;
6747 
6748 	    if ((ns->next != NULL) &&
6749 	        (ns->next->type != XML_NAMESPACE_DECL))
6750 	        return((xmlNodePtr) ns->next);
6751 	    /* Bad, how did that namespace end up here ? */
6752             return(NULL);
6753 	}
6754 	case XML_DOCUMENT_NODE:
6755 	case XML_DOCUMENT_TYPE_NODE:
6756 	case XML_DOCUMENT_FRAG_NODE:
6757 	case XML_HTML_DOCUMENT_NODE:
6758 	    return(NULL);
6759     }
6760     return(NULL);
6761 }
6762 
6763 /**
6764  * xmlXPathNextAncestorOrSelf:
6765  * @ctxt:  the XPath Parser context
6766  * @cur:  the current node in the traversal
6767  *
6768  * Traversal function for the "ancestor-or-self" direction
6769  * he ancestor-or-self axis contains the context node and ancestors of
6770  * the context node in reverse document order; thus the context node is
6771  * the first node on the axis, and the context node's parent the second;
6772  * parent here is defined the same as with the parent axis.
6773  *
6774  * Returns the next element following that axis
6775  */
6776 xmlNodePtr
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6777 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6778     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6779     if (cur == NULL)
6780         return(ctxt->context->node);
6781     return(xmlXPathNextAncestor(ctxt, cur));
6782 }
6783 
6784 /**
6785  * xmlXPathNextFollowingSibling:
6786  * @ctxt:  the XPath Parser context
6787  * @cur:  the current node in the traversal
6788  *
6789  * Traversal function for the "following-sibling" direction
6790  * The following-sibling axis contains the following siblings of the context
6791  * node in document order.
6792  *
6793  * Returns the next element following that axis
6794  */
6795 xmlNodePtr
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6796 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6797     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6798     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6799 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
6800 	return(NULL);
6801     if (cur == (xmlNodePtr) ctxt->context->doc)
6802         return(NULL);
6803     if (cur == NULL)
6804         return(ctxt->context->node->next);
6805     return(cur->next);
6806 }
6807 
6808 /**
6809  * xmlXPathNextPrecedingSibling:
6810  * @ctxt:  the XPath Parser context
6811  * @cur:  the current node in the traversal
6812  *
6813  * Traversal function for the "preceding-sibling" direction
6814  * The preceding-sibling axis contains the preceding siblings of the context
6815  * node in reverse document order; the first preceding sibling is first on the
6816  * axis; the sibling preceding that node is the second on the axis and so on.
6817  *
6818  * Returns the next element following that axis
6819  */
6820 xmlNodePtr
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6821 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6822     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6823     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6824 	(ctxt->context->node->type == XML_NAMESPACE_DECL))
6825 	return(NULL);
6826     if (cur == (xmlNodePtr) ctxt->context->doc)
6827         return(NULL);
6828     if (cur == NULL)
6829         return(ctxt->context->node->prev);
6830     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
6831 	cur = cur->prev;
6832 	if (cur == NULL)
6833 	    return(ctxt->context->node->prev);
6834     }
6835     return(cur->prev);
6836 }
6837 
6838 /**
6839  * xmlXPathNextFollowing:
6840  * @ctxt:  the XPath Parser context
6841  * @cur:  the current node in the traversal
6842  *
6843  * Traversal function for the "following" direction
6844  * The following axis contains all nodes in the same document as the context
6845  * node that are after the context node in document order, excluding any
6846  * descendants and excluding attribute nodes and namespace nodes; the nodes
6847  * are ordered in document order
6848  *
6849  * Returns the next element following that axis
6850  */
6851 xmlNodePtr
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6852 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6853     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6854     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
6855         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
6856         return(cur->children);
6857 
6858     if (cur == NULL) {
6859         cur = ctxt->context->node;
6860         if (cur->type == XML_ATTRIBUTE_NODE) {
6861             cur = cur->parent;
6862         } else if (cur->type == XML_NAMESPACE_DECL) {
6863             xmlNsPtr ns = (xmlNsPtr) cur;
6864 
6865             if ((ns->next == NULL) ||
6866                 (ns->next->type == XML_NAMESPACE_DECL))
6867                 return (NULL);
6868             cur = (xmlNodePtr) ns->next;
6869         }
6870     }
6871     if (cur == NULL) return(NULL) ; /* ERROR */
6872     if (cur->next != NULL) return(cur->next) ;
6873     do {
6874         cur = cur->parent;
6875         if (cur == NULL) break;
6876         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
6877         if (cur->next != NULL) return(cur->next);
6878     } while (cur != NULL);
6879     return(cur);
6880 }
6881 
6882 /*
6883  * xmlXPathIsAncestor:
6884  * @ancestor:  the ancestor node
6885  * @node:  the current node
6886  *
6887  * Check that @ancestor is a @node's ancestor
6888  *
6889  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
6890  */
6891 static int
xmlXPathIsAncestor(xmlNodePtr ancestor,xmlNodePtr node)6892 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
6893     if ((ancestor == NULL) || (node == NULL)) return(0);
6894     if (node->type == XML_NAMESPACE_DECL)
6895         return(0);
6896     if (ancestor->type == XML_NAMESPACE_DECL)
6897         return(0);
6898     /* nodes need to be in the same document */
6899     if (ancestor->doc != node->doc) return(0);
6900     /* avoid searching if ancestor or node is the root node */
6901     if (ancestor == (xmlNodePtr) node->doc) return(1);
6902     if (node == (xmlNodePtr) ancestor->doc) return(0);
6903     while (node->parent != NULL) {
6904         if (node->parent == ancestor)
6905             return(1);
6906 	node = node->parent;
6907     }
6908     return(0);
6909 }
6910 
6911 /**
6912  * xmlXPathNextPreceding:
6913  * @ctxt:  the XPath Parser context
6914  * @cur:  the current node in the traversal
6915  *
6916  * Traversal function for the "preceding" direction
6917  * the preceding axis contains all nodes in the same document as the context
6918  * node that are before the context node in document order, excluding any
6919  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
6920  * ordered in reverse document order
6921  *
6922  * Returns the next element following that axis
6923  */
6924 xmlNodePtr
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6925 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
6926 {
6927     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6928     if (cur == NULL) {
6929         cur = ctxt->context->node;
6930         if (cur->type == XML_ATTRIBUTE_NODE) {
6931             cur = cur->parent;
6932         } else if (cur->type == XML_NAMESPACE_DECL) {
6933             xmlNsPtr ns = (xmlNsPtr) cur;
6934 
6935             if ((ns->next == NULL) ||
6936                 (ns->next->type == XML_NAMESPACE_DECL))
6937                 return (NULL);
6938             cur = (xmlNodePtr) ns->next;
6939         }
6940     }
6941     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
6942 	return (NULL);
6943     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6944 	cur = cur->prev;
6945     do {
6946         if (cur->prev != NULL) {
6947             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
6948             return (cur);
6949         }
6950 
6951         cur = cur->parent;
6952         if (cur == NULL)
6953             return (NULL);
6954         if (cur == ctxt->context->doc->children)
6955             return (NULL);
6956     } while (xmlXPathIsAncestor(cur, ctxt->context->node));
6957     return (cur);
6958 }
6959 
6960 /**
6961  * xmlXPathNextPrecedingInternal:
6962  * @ctxt:  the XPath Parser context
6963  * @cur:  the current node in the traversal
6964  *
6965  * Traversal function for the "preceding" direction
6966  * the preceding axis contains all nodes in the same document as the context
6967  * node that are before the context node in document order, excluding any
6968  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
6969  * ordered in reverse document order
6970  * This is a faster implementation but internal only since it requires a
6971  * state kept in the parser context: ctxt->ancestor.
6972  *
6973  * Returns the next element following that axis
6974  */
6975 static xmlNodePtr
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6976 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
6977                               xmlNodePtr cur)
6978 {
6979     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6980     if (cur == NULL) {
6981         cur = ctxt->context->node;
6982         if (cur == NULL)
6983             return (NULL);
6984         if (cur->type == XML_ATTRIBUTE_NODE) {
6985             cur = cur->parent;
6986         } else if (cur->type == XML_NAMESPACE_DECL) {
6987             xmlNsPtr ns = (xmlNsPtr) cur;
6988 
6989             if ((ns->next == NULL) ||
6990                 (ns->next->type == XML_NAMESPACE_DECL))
6991                 return (NULL);
6992             cur = (xmlNodePtr) ns->next;
6993         }
6994         ctxt->ancestor = cur->parent;
6995     }
6996     if (cur->type == XML_NAMESPACE_DECL)
6997         return(NULL);
6998     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6999 	cur = cur->prev;
7000     while (cur->prev == NULL) {
7001         cur = cur->parent;
7002         if (cur == NULL)
7003             return (NULL);
7004         if (cur == ctxt->context->doc->children)
7005             return (NULL);
7006         if (cur != ctxt->ancestor)
7007             return (cur);
7008         ctxt->ancestor = cur->parent;
7009     }
7010     cur = cur->prev;
7011     while (cur->last != NULL)
7012         cur = cur->last;
7013     return (cur);
7014 }
7015 
7016 /**
7017  * xmlXPathNextNamespace:
7018  * @ctxt:  the XPath Parser context
7019  * @cur:  the current attribute in the traversal
7020  *
7021  * Traversal function for the "namespace" direction
7022  * the namespace axis contains the namespace nodes of the context node;
7023  * the order of nodes on this axis is implementation-defined; the axis will
7024  * be empty unless the context node is an element
7025  *
7026  * We keep the XML namespace node at the end of the list.
7027  *
7028  * Returns the next element following that axis
7029  */
7030 xmlNodePtr
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7031 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7032     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7033     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
7034     if (cur == NULL) {
7035         if (ctxt->context->tmpNsList != NULL)
7036 	    xmlFree(ctxt->context->tmpNsList);
7037 	ctxt->context->tmpNsNr = 0;
7038         if (xmlGetNsListSafe(ctxt->context->doc, ctxt->context->node,
7039                              &ctxt->context->tmpNsList) < 0) {
7040             xmlXPathPErrMemory(ctxt);
7041             return(NULL);
7042         }
7043         if (ctxt->context->tmpNsList != NULL) {
7044             while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
7045                 ctxt->context->tmpNsNr++;
7046             }
7047         }
7048 	return((xmlNodePtr) xmlXPathXMLNamespace);
7049     }
7050     if (ctxt->context->tmpNsNr > 0) {
7051 	return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
7052     } else {
7053 	if (ctxt->context->tmpNsList != NULL)
7054 	    xmlFree(ctxt->context->tmpNsList);
7055 	ctxt->context->tmpNsList = NULL;
7056 	return(NULL);
7057     }
7058 }
7059 
7060 /**
7061  * xmlXPathNextAttribute:
7062  * @ctxt:  the XPath Parser context
7063  * @cur:  the current attribute in the traversal
7064  *
7065  * Traversal function for the "attribute" direction
7066  * TODO: support DTD inherited default attributes
7067  *
7068  * Returns the next element following that axis
7069  */
7070 xmlNodePtr
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7071 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7072     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7073     if (ctxt->context->node == NULL)
7074 	return(NULL);
7075     if (ctxt->context->node->type != XML_ELEMENT_NODE)
7076 	return(NULL);
7077     if (cur == NULL) {
7078         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7079 	    return(NULL);
7080         return((xmlNodePtr)ctxt->context->node->properties);
7081     }
7082     return((xmlNodePtr)cur->next);
7083 }
7084 
7085 /************************************************************************
7086  *									*
7087  *		NodeTest Functions					*
7088  *									*
7089  ************************************************************************/
7090 
7091 #define IS_FUNCTION			200
7092 
7093 
7094 /************************************************************************
7095  *									*
7096  *		Implicit tree core function library			*
7097  *									*
7098  ************************************************************************/
7099 
7100 /**
7101  * xmlXPathRoot:
7102  * @ctxt:  the XPath Parser context
7103  *
7104  * Initialize the context to the root of the document
7105  */
7106 void
xmlXPathRoot(xmlXPathParserContextPtr ctxt)7107 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
7108     if ((ctxt == NULL) || (ctxt->context == NULL))
7109 	return;
7110     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7111                                             (xmlNodePtr) ctxt->context->doc));
7112 }
7113 
7114 /************************************************************************
7115  *									*
7116  *		The explicit core function library			*
7117  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
7118  *									*
7119  ************************************************************************/
7120 
7121 
7122 /**
7123  * xmlXPathLastFunction:
7124  * @ctxt:  the XPath Parser context
7125  * @nargs:  the number of arguments
7126  *
7127  * Implement the last() XPath function
7128  *    number last()
7129  * The last function returns the number of nodes in the context node list.
7130  */
7131 void
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt,int nargs)7132 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7133     CHECK_ARITY(0);
7134     if (ctxt->context->contextSize >= 0) {
7135 	valuePush(ctxt,
7136 	    xmlXPathCacheNewFloat(ctxt, (double) ctxt->context->contextSize));
7137     } else {
7138 	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
7139     }
7140 }
7141 
7142 /**
7143  * xmlXPathPositionFunction:
7144  * @ctxt:  the XPath Parser context
7145  * @nargs:  the number of arguments
7146  *
7147  * Implement the position() XPath function
7148  *    number position()
7149  * The position function returns the position of the context node in the
7150  * context node list. The first position is 1, and so the last position
7151  * will be equal to last().
7152  */
7153 void
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt,int nargs)7154 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7155     CHECK_ARITY(0);
7156     if (ctxt->context->proximityPosition >= 0) {
7157 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7158             (double) ctxt->context->proximityPosition));
7159     } else {
7160 	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
7161     }
7162 }
7163 
7164 /**
7165  * xmlXPathCountFunction:
7166  * @ctxt:  the XPath Parser context
7167  * @nargs:  the number of arguments
7168  *
7169  * Implement the count() XPath function
7170  *    number count(node-set)
7171  */
7172 void
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt,int nargs)7173 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7174     xmlXPathObjectPtr cur;
7175 
7176     CHECK_ARITY(1);
7177     if ((ctxt->value == NULL) ||
7178 	((ctxt->value->type != XPATH_NODESET) &&
7179 	 (ctxt->value->type != XPATH_XSLT_TREE)))
7180 	XP_ERROR(XPATH_INVALID_TYPE);
7181     cur = valuePop(ctxt);
7182 
7183     if ((cur == NULL) || (cur->nodesetval == NULL))
7184 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
7185     else
7186 	valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7187 	    (double) cur->nodesetval->nodeNr));
7188     xmlXPathReleaseObject(ctxt->context, cur);
7189 }
7190 
7191 /**
7192  * xmlXPathGetElementsByIds:
7193  * @doc:  the document
7194  * @ids:  a whitespace separated list of IDs
7195  *
7196  * Selects elements by their unique ID.
7197  *
7198  * Returns a node-set of selected elements.
7199  */
7200 static xmlNodeSetPtr
xmlXPathGetElementsByIds(xmlDocPtr doc,const xmlChar * ids)7201 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
7202     xmlNodeSetPtr ret;
7203     const xmlChar *cur = ids;
7204     xmlChar *ID;
7205     xmlAttrPtr attr;
7206     xmlNodePtr elem = NULL;
7207 
7208     if (ids == NULL) return(NULL);
7209 
7210     ret = xmlXPathNodeSetCreate(NULL);
7211     if (ret == NULL)
7212         return(ret);
7213 
7214     while (IS_BLANK_CH(*cur)) cur++;
7215     while (*cur != 0) {
7216 	while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
7217 	    cur++;
7218 
7219         ID = xmlStrndup(ids, cur - ids);
7220 	if (ID == NULL) {
7221             xmlXPathFreeNodeSet(ret);
7222             return(NULL);
7223         }
7224         /*
7225          * We used to check the fact that the value passed
7226          * was an NCName, but this generated much troubles for
7227          * me and Aleksey Sanin, people blatantly violated that
7228          * constraint, like Visa3D spec.
7229          * if (xmlValidateNCName(ID, 1) == 0)
7230          */
7231         attr = xmlGetID(doc, ID);
7232         xmlFree(ID);
7233         if (attr != NULL) {
7234             if (attr->type == XML_ATTRIBUTE_NODE)
7235                 elem = attr->parent;
7236             else if (attr->type == XML_ELEMENT_NODE)
7237                 elem = (xmlNodePtr) attr;
7238             else
7239                 elem = NULL;
7240             if (elem != NULL) {
7241                 if (xmlXPathNodeSetAdd(ret, elem) < 0) {
7242                     xmlXPathFreeNodeSet(ret);
7243                     return(NULL);
7244                 }
7245             }
7246         }
7247 
7248 	while (IS_BLANK_CH(*cur)) cur++;
7249 	ids = cur;
7250     }
7251     return(ret);
7252 }
7253 
7254 /**
7255  * xmlXPathIdFunction:
7256  * @ctxt:  the XPath Parser context
7257  * @nargs:  the number of arguments
7258  *
7259  * Implement the id() XPath function
7260  *    node-set id(object)
7261  * The id function selects elements by their unique ID
7262  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
7263  * then the result is the union of the result of applying id to the
7264  * string value of each of the nodes in the argument node-set. When the
7265  * argument to id is of any other type, the argument is converted to a
7266  * string as if by a call to the string function; the string is split
7267  * into a whitespace-separated list of tokens (whitespace is any sequence
7268  * of characters matching the production S); the result is a node-set
7269  * containing the elements in the same document as the context node that
7270  * have a unique ID equal to any of the tokens in the list.
7271  */
7272 void
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt,int nargs)7273 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7274     xmlChar *tokens;
7275     xmlNodeSetPtr ret;
7276     xmlXPathObjectPtr obj;
7277 
7278     CHECK_ARITY(1);
7279     obj = valuePop(ctxt);
7280     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7281     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7282 	xmlNodeSetPtr ns;
7283 	int i;
7284 
7285 	ret = xmlXPathNodeSetCreate(NULL);
7286         if (ret == NULL)
7287             xmlXPathPErrMemory(ctxt);
7288 
7289 	if (obj->nodesetval != NULL) {
7290 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7291 		tokens =
7292 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7293                 if (tokens == NULL)
7294                     xmlXPathPErrMemory(ctxt);
7295 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7296                 if (ns == NULL)
7297                     xmlXPathPErrMemory(ctxt);
7298 		ret = xmlXPathNodeSetMerge(ret, ns);
7299                 if (ret == NULL)
7300                     xmlXPathPErrMemory(ctxt);
7301 		xmlXPathFreeNodeSet(ns);
7302 		if (tokens != NULL)
7303 		    xmlFree(tokens);
7304 	    }
7305 	}
7306 	xmlXPathReleaseObject(ctxt->context, obj);
7307 	valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7308 	return;
7309     }
7310     tokens = xmlXPathCastToString(obj);
7311     if (tokens == NULL)
7312         xmlXPathPErrMemory(ctxt);
7313     xmlXPathReleaseObject(ctxt->context, obj);
7314     ret = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7315     if (ret == NULL)
7316         xmlXPathPErrMemory(ctxt);
7317     xmlFree(tokens);
7318     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7319 }
7320 
7321 /**
7322  * xmlXPathLocalNameFunction:
7323  * @ctxt:  the XPath Parser context
7324  * @nargs:  the number of arguments
7325  *
7326  * Implement the local-name() XPath function
7327  *    string local-name(node-set?)
7328  * The local-name function returns a string containing the local part
7329  * of the name of the node in the argument node-set that is first in
7330  * document order. If the node-set is empty or the first node has no
7331  * name, an empty string is returned. If the argument is omitted it
7332  * defaults to the context node.
7333  */
7334 void
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt,int nargs)7335 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7336     xmlXPathObjectPtr cur;
7337 
7338     if (ctxt == NULL) return;
7339 
7340     if (nargs == 0) {
7341 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7342 	nargs = 1;
7343     }
7344 
7345     CHECK_ARITY(1);
7346     if ((ctxt->value == NULL) ||
7347 	((ctxt->value->type != XPATH_NODESET) &&
7348 	 (ctxt->value->type != XPATH_XSLT_TREE)))
7349 	XP_ERROR(XPATH_INVALID_TYPE);
7350     cur = valuePop(ctxt);
7351 
7352     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7353 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7354     } else {
7355 	int i = 0; /* Should be first in document order !!!!! */
7356 	switch (cur->nodesetval->nodeTab[i]->type) {
7357 	case XML_ELEMENT_NODE:
7358 	case XML_ATTRIBUTE_NODE:
7359 	case XML_PI_NODE:
7360 	    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7361 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7362 	    else
7363 		valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7364 			cur->nodesetval->nodeTab[i]->name));
7365 	    break;
7366 	case XML_NAMESPACE_DECL:
7367 	    valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7368 			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
7369 	    break;
7370 	default:
7371 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7372 	}
7373     }
7374     xmlXPathReleaseObject(ctxt->context, cur);
7375 }
7376 
7377 /**
7378  * xmlXPathNamespaceURIFunction:
7379  * @ctxt:  the XPath Parser context
7380  * @nargs:  the number of arguments
7381  *
7382  * Implement the namespace-uri() XPath function
7383  *    string namespace-uri(node-set?)
7384  * The namespace-uri function returns a string containing the
7385  * namespace URI of the expanded name of the node in the argument
7386  * node-set that is first in document order. If the node-set is empty,
7387  * the first node has no name, or the expanded name has no namespace
7388  * URI, an empty string is returned. If the argument is omitted it
7389  * defaults to the context node.
7390  */
7391 void
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt,int nargs)7392 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7393     xmlXPathObjectPtr cur;
7394 
7395     if (ctxt == NULL) return;
7396 
7397     if (nargs == 0) {
7398 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7399 	nargs = 1;
7400     }
7401     CHECK_ARITY(1);
7402     if ((ctxt->value == NULL) ||
7403 	((ctxt->value->type != XPATH_NODESET) &&
7404 	 (ctxt->value->type != XPATH_XSLT_TREE)))
7405 	XP_ERROR(XPATH_INVALID_TYPE);
7406     cur = valuePop(ctxt);
7407 
7408     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7409 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7410     } else {
7411 	int i = 0; /* Should be first in document order !!!!! */
7412 	switch (cur->nodesetval->nodeTab[i]->type) {
7413 	case XML_ELEMENT_NODE:
7414 	case XML_ATTRIBUTE_NODE:
7415 	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
7416 		valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7417 	    else
7418 		valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7419 			  cur->nodesetval->nodeTab[i]->ns->href));
7420 	    break;
7421 	default:
7422 	    valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7423 	}
7424     }
7425     xmlXPathReleaseObject(ctxt->context, cur);
7426 }
7427 
7428 /**
7429  * xmlXPathNameFunction:
7430  * @ctxt:  the XPath Parser context
7431  * @nargs:  the number of arguments
7432  *
7433  * Implement the name() XPath function
7434  *    string name(node-set?)
7435  * The name function returns a string containing a QName representing
7436  * the name of the node in the argument node-set that is first in document
7437  * order. The QName must represent the name with respect to the namespace
7438  * declarations in effect on the node whose name is being represented.
7439  * Typically, this will be the form in which the name occurred in the XML
7440  * source. This need not be the case if there are namespace declarations
7441  * in effect on the node that associate multiple prefixes with the same
7442  * namespace. However, an implementation may include information about
7443  * the original prefix in its representation of nodes; in this case, an
7444  * implementation can ensure that the returned string is always the same
7445  * as the QName used in the XML source. If the argument it omitted it
7446  * defaults to the context node.
7447  * Libxml keep the original prefix so the "real qualified name" used is
7448  * returned.
7449  */
7450 static void
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt,int nargs)7451 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
7452 {
7453     xmlXPathObjectPtr cur;
7454 
7455     if (nargs == 0) {
7456 	valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7457         nargs = 1;
7458     }
7459 
7460     CHECK_ARITY(1);
7461     if ((ctxt->value == NULL) ||
7462         ((ctxt->value->type != XPATH_NODESET) &&
7463          (ctxt->value->type != XPATH_XSLT_TREE)))
7464         XP_ERROR(XPATH_INVALID_TYPE);
7465     cur = valuePop(ctxt);
7466 
7467     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7468         valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7469     } else {
7470         int i = 0;              /* Should be first in document order !!!!! */
7471 
7472         switch (cur->nodesetval->nodeTab[i]->type) {
7473             case XML_ELEMENT_NODE:
7474             case XML_ATTRIBUTE_NODE:
7475 		if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7476 		    valuePush(ctxt,
7477 			xmlXPathCacheNewCString(ctxt, ""));
7478 		else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
7479                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
7480 		    valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7481 			    cur->nodesetval->nodeTab[i]->name));
7482 		} else {
7483 		    xmlChar *fullname;
7484 
7485 		    fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
7486 				     cur->nodesetval->nodeTab[i]->ns->prefix,
7487 				     NULL, 0);
7488 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
7489 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
7490 		    if (fullname == NULL)
7491                         xmlXPathPErrMemory(ctxt);
7492 		    valuePush(ctxt, xmlXPathCacheWrapString(ctxt, fullname));
7493                 }
7494                 break;
7495             default:
7496 		valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7497 		    cur->nodesetval->nodeTab[i]));
7498                 xmlXPathLocalNameFunction(ctxt, 1);
7499         }
7500     }
7501     xmlXPathReleaseObject(ctxt->context, cur);
7502 }
7503 
7504 
7505 /**
7506  * xmlXPathStringFunction:
7507  * @ctxt:  the XPath Parser context
7508  * @nargs:  the number of arguments
7509  *
7510  * Implement the string() XPath function
7511  *    string string(object?)
7512  * The string function converts an object to a string as follows:
7513  *    - A node-set is converted to a string by returning the value of
7514  *      the node in the node-set that is first in document order.
7515  *      If the node-set is empty, an empty string is returned.
7516  *    - A number is converted to a string as follows
7517  *      + NaN is converted to the string NaN
7518  *      + positive zero is converted to the string 0
7519  *      + negative zero is converted to the string 0
7520  *      + positive infinity is converted to the string Infinity
7521  *      + negative infinity is converted to the string -Infinity
7522  *      + if the number is an integer, the number is represented in
7523  *        decimal form as a Number with no decimal point and no leading
7524  *        zeros, preceded by a minus sign (-) if the number is negative
7525  *      + otherwise, the number is represented in decimal form as a
7526  *        Number including a decimal point with at least one digit
7527  *        before the decimal point and at least one digit after the
7528  *        decimal point, preceded by a minus sign (-) if the number
7529  *        is negative; there must be no leading zeros before the decimal
7530  *        point apart possibly from the one required digit immediately
7531  *        before the decimal point; beyond the one required digit
7532  *        after the decimal point there must be as many, but only as
7533  *        many, more digits as are needed to uniquely distinguish the
7534  *        number from all other IEEE 754 numeric values.
7535  *    - The boolean false value is converted to the string false.
7536  *      The boolean true value is converted to the string true.
7537  *
7538  * If the argument is omitted, it defaults to a node-set with the
7539  * context node as its only member.
7540  */
7541 void
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt,int nargs)7542 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7543     xmlXPathObjectPtr cur;
7544     xmlChar *stringval;
7545 
7546     if (ctxt == NULL) return;
7547     if (nargs == 0) {
7548         stringval = xmlXPathCastNodeToString(ctxt->context->node);
7549         if (stringval == NULL)
7550             xmlXPathPErrMemory(ctxt);
7551         valuePush(ctxt, xmlXPathCacheWrapString(ctxt, stringval));
7552 	return;
7553     }
7554 
7555     CHECK_ARITY(1);
7556     cur = valuePop(ctxt);
7557     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7558     if (cur->type != XPATH_STRING) {
7559         stringval = xmlXPathCastToString(cur);
7560         if (stringval == NULL)
7561             xmlXPathPErrMemory(ctxt);
7562         xmlXPathReleaseObject(ctxt->context, cur);
7563         cur = xmlXPathCacheWrapString(ctxt, stringval);
7564     }
7565     valuePush(ctxt, cur);
7566 }
7567 
7568 /**
7569  * xmlXPathStringLengthFunction:
7570  * @ctxt:  the XPath Parser context
7571  * @nargs:  the number of arguments
7572  *
7573  * Implement the string-length() XPath function
7574  *    number string-length(string?)
7575  * The string-length returns the number of characters in the string
7576  * (see [3.6 Strings]). If the argument is omitted, it defaults to
7577  * the context node converted to a string, in other words the value
7578  * of the context node.
7579  */
7580 void
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt,int nargs)7581 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7582     xmlXPathObjectPtr cur;
7583 
7584     if (nargs == 0) {
7585         if ((ctxt == NULL) || (ctxt->context == NULL))
7586 	    return;
7587 	if (ctxt->context->node == NULL) {
7588 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0));
7589 	} else {
7590 	    xmlChar *content;
7591 
7592 	    content = xmlXPathCastNodeToString(ctxt->context->node);
7593             if (content == NULL)
7594                 xmlXPathPErrMemory(ctxt);
7595 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7596 		xmlUTF8Strlen(content)));
7597 	    xmlFree(content);
7598 	}
7599 	return;
7600     }
7601     CHECK_ARITY(1);
7602     CAST_TO_STRING;
7603     CHECK_TYPE(XPATH_STRING);
7604     cur = valuePop(ctxt);
7605     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7606 	xmlUTF8Strlen(cur->stringval)));
7607     xmlXPathReleaseObject(ctxt->context, cur);
7608 }
7609 
7610 /**
7611  * xmlXPathConcatFunction:
7612  * @ctxt:  the XPath Parser context
7613  * @nargs:  the number of arguments
7614  *
7615  * Implement the concat() XPath function
7616  *    string concat(string, string, string*)
7617  * The concat function returns the concatenation of its arguments.
7618  */
7619 void
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt,int nargs)7620 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7621     xmlXPathObjectPtr cur, newobj;
7622     xmlChar *tmp;
7623 
7624     if (ctxt == NULL) return;
7625     if (nargs < 2) {
7626 	CHECK_ARITY(2);
7627     }
7628 
7629     CAST_TO_STRING;
7630     cur = valuePop(ctxt);
7631     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
7632 	xmlXPathReleaseObject(ctxt->context, cur);
7633 	return;
7634     }
7635     nargs--;
7636 
7637     while (nargs > 0) {
7638 	CAST_TO_STRING;
7639 	newobj = valuePop(ctxt);
7640 	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
7641 	    xmlXPathReleaseObject(ctxt->context, newobj);
7642 	    xmlXPathReleaseObject(ctxt->context, cur);
7643 	    XP_ERROR(XPATH_INVALID_TYPE);
7644 	}
7645 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
7646         if (tmp == NULL)
7647             xmlXPathPErrMemory(ctxt);
7648 	newobj->stringval = cur->stringval;
7649 	cur->stringval = tmp;
7650 	xmlXPathReleaseObject(ctxt->context, newobj);
7651 	nargs--;
7652     }
7653     valuePush(ctxt, cur);
7654 }
7655 
7656 /**
7657  * xmlXPathContainsFunction:
7658  * @ctxt:  the XPath Parser context
7659  * @nargs:  the number of arguments
7660  *
7661  * Implement the contains() XPath function
7662  *    boolean contains(string, string)
7663  * The contains function returns true if the first argument string
7664  * contains the second argument string, and otherwise returns false.
7665  */
7666 void
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt,int nargs)7667 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7668     xmlXPathObjectPtr hay, needle;
7669 
7670     CHECK_ARITY(2);
7671     CAST_TO_STRING;
7672     CHECK_TYPE(XPATH_STRING);
7673     needle = valuePop(ctxt);
7674     CAST_TO_STRING;
7675     hay = valuePop(ctxt);
7676 
7677     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7678 	xmlXPathReleaseObject(ctxt->context, hay);
7679 	xmlXPathReleaseObject(ctxt->context, needle);
7680 	XP_ERROR(XPATH_INVALID_TYPE);
7681     }
7682     if (xmlStrstr(hay->stringval, needle->stringval))
7683 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7684     else
7685 	valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7686     xmlXPathReleaseObject(ctxt->context, hay);
7687     xmlXPathReleaseObject(ctxt->context, needle);
7688 }
7689 
7690 /**
7691  * xmlXPathStartsWithFunction:
7692  * @ctxt:  the XPath Parser context
7693  * @nargs:  the number of arguments
7694  *
7695  * Implement the starts-with() XPath function
7696  *    boolean starts-with(string, string)
7697  * The starts-with function returns true if the first argument string
7698  * starts with the second argument string, and otherwise returns false.
7699  */
7700 void
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt,int nargs)7701 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7702     xmlXPathObjectPtr hay, needle;
7703     int n;
7704 
7705     CHECK_ARITY(2);
7706     CAST_TO_STRING;
7707     CHECK_TYPE(XPATH_STRING);
7708     needle = valuePop(ctxt);
7709     CAST_TO_STRING;
7710     hay = valuePop(ctxt);
7711 
7712     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7713 	xmlXPathReleaseObject(ctxt->context, hay);
7714 	xmlXPathReleaseObject(ctxt->context, needle);
7715 	XP_ERROR(XPATH_INVALID_TYPE);
7716     }
7717     n = xmlStrlen(needle->stringval);
7718     if (xmlStrncmp(hay->stringval, needle->stringval, n))
7719         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7720     else
7721         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7722     xmlXPathReleaseObject(ctxt->context, hay);
7723     xmlXPathReleaseObject(ctxt->context, needle);
7724 }
7725 
7726 /**
7727  * xmlXPathSubstringFunction:
7728  * @ctxt:  the XPath Parser context
7729  * @nargs:  the number of arguments
7730  *
7731  * Implement the substring() XPath function
7732  *    string substring(string, number, number?)
7733  * The substring function returns the substring of the first argument
7734  * starting at the position specified in the second argument with
7735  * length specified in the third argument. For example,
7736  * substring("12345",2,3) returns "234". If the third argument is not
7737  * specified, it returns the substring starting at the position specified
7738  * in the second argument and continuing to the end of the string. For
7739  * example, substring("12345",2) returns "2345".  More precisely, each
7740  * character in the string (see [3.6 Strings]) is considered to have a
7741  * numeric position: the position of the first character is 1, the position
7742  * of the second character is 2 and so on. The returned substring contains
7743  * those characters for which the position of the character is greater than
7744  * or equal to the second argument and, if the third argument is specified,
7745  * less than the sum of the second and third arguments; the comparisons
7746  * and addition used for the above follow the standard IEEE 754 rules. Thus:
7747  *  - substring("12345", 1.5, 2.6) returns "234"
7748  *  - substring("12345", 0, 3) returns "12"
7749  *  - substring("12345", 0 div 0, 3) returns ""
7750  *  - substring("12345", 1, 0 div 0) returns ""
7751  *  - substring("12345", -42, 1 div 0) returns "12345"
7752  *  - substring("12345", -1 div 0, 1 div 0) returns ""
7753  */
7754 void
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt,int nargs)7755 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7756     xmlXPathObjectPtr str, start, len;
7757     double le=0, in;
7758     int i = 1, j = INT_MAX;
7759 
7760     if (nargs < 2) {
7761 	CHECK_ARITY(2);
7762     }
7763     if (nargs > 3) {
7764 	CHECK_ARITY(3);
7765     }
7766     /*
7767      * take care of possible last (position) argument
7768     */
7769     if (nargs == 3) {
7770 	CAST_TO_NUMBER;
7771 	CHECK_TYPE(XPATH_NUMBER);
7772 	len = valuePop(ctxt);
7773 	le = len->floatval;
7774 	xmlXPathReleaseObject(ctxt->context, len);
7775     }
7776 
7777     CAST_TO_NUMBER;
7778     CHECK_TYPE(XPATH_NUMBER);
7779     start = valuePop(ctxt);
7780     in = start->floatval;
7781     xmlXPathReleaseObject(ctxt->context, start);
7782     CAST_TO_STRING;
7783     CHECK_TYPE(XPATH_STRING);
7784     str = valuePop(ctxt);
7785 
7786     if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
7787         i = INT_MAX;
7788     } else if (in >= 1.0) {
7789         i = (int)in;
7790         if (in - floor(in) >= 0.5)
7791             i += 1;
7792     }
7793 
7794     if (nargs == 3) {
7795         double rin, rle, end;
7796 
7797         rin = floor(in);
7798         if (in - rin >= 0.5)
7799             rin += 1.0;
7800 
7801         rle = floor(le);
7802         if (le - rle >= 0.5)
7803             rle += 1.0;
7804 
7805         end = rin + rle;
7806         if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
7807             j = 1;
7808         } else if (end < INT_MAX) {
7809             j = (int)end;
7810         }
7811     }
7812 
7813     i -= 1;
7814     j -= 1;
7815 
7816     if ((i < j) && (i < xmlUTF8Strlen(str->stringval))) {
7817         xmlChar *ret = xmlUTF8Strsub(str->stringval, i, j - i);
7818         if (ret == NULL)
7819             xmlXPathPErrMemory(ctxt);
7820 	valuePush(ctxt, xmlXPathCacheNewString(ctxt, ret));
7821 	xmlFree(ret);
7822     } else {
7823 	valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7824     }
7825 
7826     xmlXPathReleaseObject(ctxt->context, str);
7827 }
7828 
7829 /**
7830  * xmlXPathSubstringBeforeFunction:
7831  * @ctxt:  the XPath Parser context
7832  * @nargs:  the number of arguments
7833  *
7834  * Implement the substring-before() XPath function
7835  *    string substring-before(string, string)
7836  * The substring-before function returns the substring of the first
7837  * argument string that precedes the first occurrence of the second
7838  * argument string in the first argument string, or the empty string
7839  * if the first argument string does not contain the second argument
7840  * string. For example, substring-before("1999/04/01","/") returns 1999.
7841  */
7842 void
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt,int nargs)7843 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7844     xmlXPathObjectPtr str = NULL;
7845     xmlXPathObjectPtr find = NULL;
7846     const xmlChar *point;
7847     xmlChar *result;
7848 
7849     CHECK_ARITY(2);
7850     CAST_TO_STRING;
7851     find = valuePop(ctxt);
7852     CAST_TO_STRING;
7853     str = valuePop(ctxt);
7854     if (ctxt->error != 0)
7855         goto error;
7856 
7857     point = xmlStrstr(str->stringval, find->stringval);
7858     if (point == NULL) {
7859         result = xmlStrdup(BAD_CAST "");
7860     } else {
7861         result = xmlStrndup(str->stringval, point - str->stringval);
7862     }
7863     if (result == NULL) {
7864         xmlXPathPErrMemory(ctxt);
7865         goto error;
7866     }
7867     valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7868 
7869 error:
7870     xmlXPathReleaseObject(ctxt->context, str);
7871     xmlXPathReleaseObject(ctxt->context, find);
7872 }
7873 
7874 /**
7875  * xmlXPathSubstringAfterFunction:
7876  * @ctxt:  the XPath Parser context
7877  * @nargs:  the number of arguments
7878  *
7879  * Implement the substring-after() XPath function
7880  *    string substring-after(string, string)
7881  * The substring-after function returns the substring of the first
7882  * argument string that follows the first occurrence of the second
7883  * argument string in the first argument string, or the empty string
7884  * if the first argument string does not contain the second argument
7885  * string. For example, substring-after("1999/04/01","/") returns 04/01,
7886  * and substring-after("1999/04/01","19") returns 99/04/01.
7887  */
7888 void
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt,int nargs)7889 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7890     xmlXPathObjectPtr str = NULL;
7891     xmlXPathObjectPtr find = NULL;
7892     const xmlChar *point;
7893     xmlChar *result;
7894 
7895     CHECK_ARITY(2);
7896     CAST_TO_STRING;
7897     find = valuePop(ctxt);
7898     CAST_TO_STRING;
7899     str = valuePop(ctxt);
7900     if (ctxt->error != 0)
7901         goto error;
7902 
7903     point = xmlStrstr(str->stringval, find->stringval);
7904     if (point == NULL) {
7905         result = xmlStrdup(BAD_CAST "");
7906     } else {
7907         result = xmlStrdup(point + xmlStrlen(find->stringval));
7908     }
7909     if (result == NULL) {
7910         xmlXPathPErrMemory(ctxt);
7911         goto error;
7912     }
7913     valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7914 
7915 error:
7916     xmlXPathReleaseObject(ctxt->context, str);
7917     xmlXPathReleaseObject(ctxt->context, find);
7918 }
7919 
7920 /**
7921  * xmlXPathNormalizeFunction:
7922  * @ctxt:  the XPath Parser context
7923  * @nargs:  the number of arguments
7924  *
7925  * Implement the normalize-space() XPath function
7926  *    string normalize-space(string?)
7927  * The normalize-space function returns the argument string with white
7928  * space normalized by stripping leading and trailing whitespace
7929  * and replacing sequences of whitespace characters by a single
7930  * space. Whitespace characters are the same allowed by the S production
7931  * in XML. If the argument is omitted, it defaults to the context
7932  * node converted to a string, in other words the value of the context node.
7933  */
7934 void
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt,int nargs)7935 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7936     xmlChar *source, *target;
7937     int blank;
7938 
7939     if (ctxt == NULL) return;
7940     if (nargs == 0) {
7941         /* Use current context node */
7942         source = xmlXPathCastNodeToString(ctxt->context->node);
7943         if (source == NULL)
7944             xmlXPathPErrMemory(ctxt);
7945         valuePush(ctxt, xmlXPathCacheWrapString(ctxt, source));
7946         nargs = 1;
7947     }
7948 
7949     CHECK_ARITY(1);
7950     CAST_TO_STRING;
7951     CHECK_TYPE(XPATH_STRING);
7952     source = ctxt->value->stringval;
7953     if (source == NULL)
7954         return;
7955     target = source;
7956 
7957     /* Skip leading whitespaces */
7958     while (IS_BLANK_CH(*source))
7959         source++;
7960 
7961     /* Collapse intermediate whitespaces, and skip trailing whitespaces */
7962     blank = 0;
7963     while (*source) {
7964         if (IS_BLANK_CH(*source)) {
7965 	    blank = 1;
7966         } else {
7967             if (blank) {
7968                 *target++ = 0x20;
7969                 blank = 0;
7970             }
7971             *target++ = *source;
7972         }
7973         source++;
7974     }
7975     *target = 0;
7976 }
7977 
7978 /**
7979  * xmlXPathTranslateFunction:
7980  * @ctxt:  the XPath Parser context
7981  * @nargs:  the number of arguments
7982  *
7983  * Implement the translate() XPath function
7984  *    string translate(string, string, string)
7985  * The translate function returns the first argument string with
7986  * occurrences of characters in the second argument string replaced
7987  * by the character at the corresponding position in the third argument
7988  * string. For example, translate("bar","abc","ABC") returns the string
7989  * BAr. If there is a character in the second argument string with no
7990  * character at a corresponding position in the third argument string
7991  * (because the second argument string is longer than the third argument
7992  * string), then occurrences of that character in the first argument
7993  * string are removed. For example, translate("--aaa--","abc-","ABC")
7994  * returns "AAA". If a character occurs more than once in second
7995  * argument string, then the first occurrence determines the replacement
7996  * character. If the third argument string is longer than the second
7997  * argument string, then excess characters are ignored.
7998  */
7999 void
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt,int nargs)8000 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8001     xmlXPathObjectPtr str = NULL;
8002     xmlXPathObjectPtr from = NULL;
8003     xmlXPathObjectPtr to = NULL;
8004     xmlBufPtr target;
8005     int offset, max;
8006     int ch;
8007     const xmlChar *point;
8008     xmlChar *cptr, *content;
8009 
8010     CHECK_ARITY(3);
8011 
8012     CAST_TO_STRING;
8013     to = valuePop(ctxt);
8014     CAST_TO_STRING;
8015     from = valuePop(ctxt);
8016     CAST_TO_STRING;
8017     str = valuePop(ctxt);
8018     if (ctxt->error != 0)
8019         goto error;
8020 
8021     /*
8022      * Account for quadratic runtime
8023      */
8024     if (ctxt->context->opLimit != 0) {
8025         unsigned long f1 = xmlStrlen(from->stringval);
8026         unsigned long f2 = xmlStrlen(str->stringval);
8027 
8028         if ((f1 > 0) && (f2 > 0)) {
8029             unsigned long p;
8030 
8031             f1 = f1 / 10 + 1;
8032             f2 = f2 / 10 + 1;
8033             p = f1 > ULONG_MAX / f2 ? ULONG_MAX : f1 * f2;
8034             if (xmlXPathCheckOpLimit(ctxt, p) < 0)
8035                 goto error;
8036         }
8037     }
8038 
8039     target = xmlBufCreate(50);
8040     if (target == NULL) {
8041         xmlXPathPErrMemory(ctxt);
8042         goto error;
8043     }
8044 
8045     max = xmlUTF8Strlen(to->stringval);
8046     for (cptr = str->stringval; (ch=*cptr); ) {
8047         offset = xmlUTF8Strloc(from->stringval, cptr);
8048         if (offset >= 0) {
8049             if (offset < max) {
8050                 point = xmlUTF8Strpos(to->stringval, offset);
8051                 if (point)
8052                     xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
8053             }
8054         } else
8055             xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
8056 
8057         /* Step to next character in input */
8058         cptr++;
8059         if ( ch & 0x80 ) {
8060             /* if not simple ascii, verify proper format */
8061             if ( (ch & 0xc0) != 0xc0 ) {
8062                 xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
8063                 break;
8064             }
8065             /* then skip over remaining bytes for this char */
8066             while ( (ch <<= 1) & 0x80 )
8067                 if ( (*cptr++ & 0xc0) != 0x80 ) {
8068                     xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
8069                     break;
8070                 }
8071             if (ch & 0x80) /* must have had error encountered */
8072                 break;
8073         }
8074     }
8075 
8076     content = xmlBufDetach(target);
8077     if (content == NULL)
8078         xmlXPathPErrMemory(ctxt);
8079     else
8080         valuePush(ctxt, xmlXPathCacheWrapString(ctxt, content));
8081     xmlBufFree(target);
8082 error:
8083     xmlXPathReleaseObject(ctxt->context, str);
8084     xmlXPathReleaseObject(ctxt->context, from);
8085     xmlXPathReleaseObject(ctxt->context, to);
8086 }
8087 
8088 /**
8089  * xmlXPathBooleanFunction:
8090  * @ctxt:  the XPath Parser context
8091  * @nargs:  the number of arguments
8092  *
8093  * Implement the boolean() XPath function
8094  *    boolean boolean(object)
8095  * The boolean function converts its argument to a boolean as follows:
8096  *    - a number is true if and only if it is neither positive or
8097  *      negative zero nor NaN
8098  *    - a node-set is true if and only if it is non-empty
8099  *    - a string is true if and only if its length is non-zero
8100  */
8101 void
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt,int nargs)8102 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8103     xmlXPathObjectPtr cur;
8104 
8105     CHECK_ARITY(1);
8106     cur = valuePop(ctxt);
8107     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8108     if (cur->type != XPATH_BOOLEAN) {
8109         int boolval = xmlXPathCastToBoolean(cur);
8110 
8111         xmlXPathReleaseObject(ctxt->context, cur);
8112         cur = xmlXPathCacheNewBoolean(ctxt, boolval);
8113     }
8114     valuePush(ctxt, cur);
8115 }
8116 
8117 /**
8118  * xmlXPathNotFunction:
8119  * @ctxt:  the XPath Parser context
8120  * @nargs:  the number of arguments
8121  *
8122  * Implement the not() XPath function
8123  *    boolean not(boolean)
8124  * The not function returns true if its argument is false,
8125  * and false otherwise.
8126  */
8127 void
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt,int nargs)8128 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8129     CHECK_ARITY(1);
8130     CAST_TO_BOOLEAN;
8131     CHECK_TYPE(XPATH_BOOLEAN);
8132     ctxt->value->boolval = ! ctxt->value->boolval;
8133 }
8134 
8135 /**
8136  * xmlXPathTrueFunction:
8137  * @ctxt:  the XPath Parser context
8138  * @nargs:  the number of arguments
8139  *
8140  * Implement the true() XPath function
8141  *    boolean true()
8142  */
8143 void
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt,int nargs)8144 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8145     CHECK_ARITY(0);
8146     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
8147 }
8148 
8149 /**
8150  * xmlXPathFalseFunction:
8151  * @ctxt:  the XPath Parser context
8152  * @nargs:  the number of arguments
8153  *
8154  * Implement the false() XPath function
8155  *    boolean false()
8156  */
8157 void
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt,int nargs)8158 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8159     CHECK_ARITY(0);
8160     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
8161 }
8162 
8163 /**
8164  * xmlXPathLangFunction:
8165  * @ctxt:  the XPath Parser context
8166  * @nargs:  the number of arguments
8167  *
8168  * Implement the lang() XPath function
8169  *    boolean lang(string)
8170  * The lang function returns true or false depending on whether the
8171  * language of the context node as specified by xml:lang attributes
8172  * is the same as or is a sublanguage of the language specified by
8173  * the argument string. The language of the context node is determined
8174  * by the value of the xml:lang attribute on the context node, or, if
8175  * the context node has no xml:lang attribute, by the value of the
8176  * xml:lang attribute on the nearest ancestor of the context node that
8177  * has an xml:lang attribute. If there is no such attribute, then lang
8178  * returns false. If there is such an attribute, then lang returns
8179  * true if the attribute value is equal to the argument ignoring case,
8180  * or if there is some suffix starting with - such that the attribute
8181  * value is equal to the argument ignoring that suffix of the attribute
8182  * value and ignoring case.
8183  */
8184 void
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt,int nargs)8185 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8186     xmlXPathObjectPtr val;
8187     xmlNodePtr cur;
8188     xmlChar *theLang;
8189     const xmlChar *lang;
8190     int ret = 0;
8191     int i;
8192 
8193     CHECK_ARITY(1);
8194     CAST_TO_STRING;
8195     CHECK_TYPE(XPATH_STRING);
8196     val = valuePop(ctxt);
8197     lang = val->stringval;
8198     cur = ctxt->context->node;
8199     while (cur != NULL) {
8200         if (xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE,
8201                                 &theLang) < 0)
8202             xmlXPathPErrMemory(ctxt);
8203         if (theLang != NULL)
8204             break;
8205         cur = cur->parent;
8206     }
8207     if ((theLang != NULL) && (lang != NULL)) {
8208         for (i = 0;lang[i] != 0;i++)
8209             if (toupper(lang[i]) != toupper(theLang[i]))
8210                 goto not_equal;
8211         if ((theLang[i] == 0) || (theLang[i] == '-'))
8212             ret = 1;
8213     }
8214 not_equal:
8215     if (theLang != NULL)
8216 	xmlFree((void *)theLang);
8217 
8218     xmlXPathReleaseObject(ctxt->context, val);
8219     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
8220 }
8221 
8222 /**
8223  * xmlXPathNumberFunction:
8224  * @ctxt:  the XPath Parser context
8225  * @nargs:  the number of arguments
8226  *
8227  * Implement the number() XPath function
8228  *    number number(object?)
8229  */
8230 void
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt,int nargs)8231 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8232     xmlXPathObjectPtr cur;
8233     double res;
8234 
8235     if (ctxt == NULL) return;
8236     if (nargs == 0) {
8237 	if (ctxt->context->node == NULL) {
8238 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
8239 	} else {
8240 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
8241             if (content == NULL)
8242                 xmlXPathPErrMemory(ctxt);
8243 
8244 	    res = xmlXPathStringEvalNumber(content);
8245 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8246 	    xmlFree(content);
8247 	}
8248 	return;
8249     }
8250 
8251     CHECK_ARITY(1);
8252     cur = valuePop(ctxt);
8253     if (cur->type != XPATH_NUMBER) {
8254         double floatval;
8255 
8256         floatval = xmlXPathCastToNumberInternal(ctxt, cur);
8257         xmlXPathReleaseObject(ctxt->context, cur);
8258         cur = xmlXPathCacheNewFloat(ctxt, floatval);
8259     }
8260     valuePush(ctxt, cur);
8261 }
8262 
8263 /**
8264  * xmlXPathSumFunction:
8265  * @ctxt:  the XPath Parser context
8266  * @nargs:  the number of arguments
8267  *
8268  * Implement the sum() XPath function
8269  *    number sum(node-set)
8270  * The sum function returns the sum of the values of the nodes in
8271  * the argument node-set.
8272  */
8273 void
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt,int nargs)8274 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8275     xmlXPathObjectPtr cur;
8276     int i;
8277     double res = 0.0;
8278 
8279     CHECK_ARITY(1);
8280     if ((ctxt->value == NULL) ||
8281 	((ctxt->value->type != XPATH_NODESET) &&
8282 	 (ctxt->value->type != XPATH_XSLT_TREE)))
8283 	XP_ERROR(XPATH_INVALID_TYPE);
8284     cur = valuePop(ctxt);
8285 
8286     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
8287 	for (i = 0; i < cur->nodesetval->nodeNr; i++) {
8288 	    res += xmlXPathNodeToNumberInternal(ctxt,
8289                                                 cur->nodesetval->nodeTab[i]);
8290 	}
8291     }
8292     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8293     xmlXPathReleaseObject(ctxt->context, cur);
8294 }
8295 
8296 /**
8297  * xmlXPathFloorFunction:
8298  * @ctxt:  the XPath Parser context
8299  * @nargs:  the number of arguments
8300  *
8301  * Implement the floor() XPath function
8302  *    number floor(number)
8303  * The floor function returns the largest (closest to positive infinity)
8304  * number that is not greater than the argument and that is an integer.
8305  */
8306 void
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt,int nargs)8307 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8308     CHECK_ARITY(1);
8309     CAST_TO_NUMBER;
8310     CHECK_TYPE(XPATH_NUMBER);
8311 
8312     ctxt->value->floatval = floor(ctxt->value->floatval);
8313 }
8314 
8315 /**
8316  * xmlXPathCeilingFunction:
8317  * @ctxt:  the XPath Parser context
8318  * @nargs:  the number of arguments
8319  *
8320  * Implement the ceiling() XPath function
8321  *    number ceiling(number)
8322  * The ceiling function returns the smallest (closest to negative infinity)
8323  * number that is not less than the argument and that is an integer.
8324  */
8325 void
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt,int nargs)8326 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8327     CHECK_ARITY(1);
8328     CAST_TO_NUMBER;
8329     CHECK_TYPE(XPATH_NUMBER);
8330 
8331 #ifdef _AIX
8332     /* Work around buggy ceil() function on AIX */
8333     ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
8334 #else
8335     ctxt->value->floatval = ceil(ctxt->value->floatval);
8336 #endif
8337 }
8338 
8339 /**
8340  * xmlXPathRoundFunction:
8341  * @ctxt:  the XPath Parser context
8342  * @nargs:  the number of arguments
8343  *
8344  * Implement the round() XPath function
8345  *    number round(number)
8346  * The round function returns the number that is closest to the
8347  * argument and that is an integer. If there are two such numbers,
8348  * then the one that is closest to positive infinity is returned.
8349  */
8350 void
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt,int nargs)8351 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8352     double f;
8353 
8354     CHECK_ARITY(1);
8355     CAST_TO_NUMBER;
8356     CHECK_TYPE(XPATH_NUMBER);
8357 
8358     f = ctxt->value->floatval;
8359 
8360     if ((f >= -0.5) && (f < 0.5)) {
8361         /* Handles negative zero. */
8362         ctxt->value->floatval *= 0.0;
8363     }
8364     else {
8365         double rounded = floor(f);
8366         if (f - rounded >= 0.5)
8367             rounded += 1.0;
8368         ctxt->value->floatval = rounded;
8369     }
8370 }
8371 
8372 /************************************************************************
8373  *									*
8374  *			The Parser					*
8375  *									*
8376  ************************************************************************/
8377 
8378 /*
8379  * a few forward declarations since we use a recursive call based
8380  * implementation.
8381  */
8382 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
8383 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
8384 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
8385 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
8386 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
8387 	                                  int qualified);
8388 
8389 /**
8390  * xmlXPathCurrentChar:
8391  * @ctxt:  the XPath parser context
8392  * @cur:  pointer to the beginning of the char
8393  * @len:  pointer to the length of the char read
8394  *
8395  * The current char value, if using UTF-8 this may actually span multiple
8396  * bytes in the input buffer.
8397  *
8398  * Returns the current char value and its length
8399  */
8400 
8401 static int
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt,int * len)8402 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
8403     unsigned char c;
8404     unsigned int val;
8405     const xmlChar *cur;
8406 
8407     if (ctxt == NULL)
8408 	return(0);
8409     cur = ctxt->cur;
8410 
8411     /*
8412      * We are supposed to handle UTF8, check it's valid
8413      * From rfc2044: encoding of the Unicode values on UTF-8:
8414      *
8415      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
8416      * 0000 0000-0000 007F   0xxxxxxx
8417      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
8418      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
8419      *
8420      * Check for the 0x110000 limit too
8421      */
8422     c = *cur;
8423     if (c & 0x80) {
8424 	if ((cur[1] & 0xc0) != 0x80)
8425 	    goto encoding_error;
8426 	if ((c & 0xe0) == 0xe0) {
8427 
8428 	    if ((cur[2] & 0xc0) != 0x80)
8429 		goto encoding_error;
8430 	    if ((c & 0xf0) == 0xf0) {
8431 		if (((c & 0xf8) != 0xf0) ||
8432 		    ((cur[3] & 0xc0) != 0x80))
8433 		    goto encoding_error;
8434 		/* 4-byte code */
8435 		*len = 4;
8436 		val = (cur[0] & 0x7) << 18;
8437 		val |= (cur[1] & 0x3f) << 12;
8438 		val |= (cur[2] & 0x3f) << 6;
8439 		val |= cur[3] & 0x3f;
8440 	    } else {
8441 	      /* 3-byte code */
8442 		*len = 3;
8443 		val = (cur[0] & 0xf) << 12;
8444 		val |= (cur[1] & 0x3f) << 6;
8445 		val |= cur[2] & 0x3f;
8446 	    }
8447 	} else {
8448 	  /* 2-byte code */
8449 	    *len = 2;
8450 	    val = (cur[0] & 0x1f) << 6;
8451 	    val |= cur[1] & 0x3f;
8452 	}
8453 	if (!IS_CHAR(val)) {
8454 	    XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
8455 	}
8456 	return(val);
8457     } else {
8458 	/* 1-byte code */
8459 	*len = 1;
8460 	return(*cur);
8461     }
8462 encoding_error:
8463     /*
8464      * If we detect an UTF8 error that probably means that the
8465      * input encoding didn't get properly advertised in the
8466      * declaration header. Report the error and switch the encoding
8467      * to ISO-Latin-1 (if you don't like this policy, just declare the
8468      * encoding !)
8469      */
8470     *len = 0;
8471     XP_ERROR0(XPATH_ENCODING_ERROR);
8472 }
8473 
8474 /**
8475  * xmlXPathParseNCName:
8476  * @ctxt:  the XPath Parser context
8477  *
8478  * parse an XML namespace non qualified name.
8479  *
8480  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
8481  *
8482  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
8483  *                       CombiningChar | Extender
8484  *
8485  * Returns the namespace name or NULL
8486  */
8487 
8488 xmlChar *
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt)8489 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
8490     const xmlChar *in;
8491     xmlChar *ret;
8492     int count = 0;
8493 
8494     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8495     /*
8496      * Accelerator for simple ASCII names
8497      */
8498     in = ctxt->cur;
8499     if (((*in >= 0x61) && (*in <= 0x7A)) ||
8500 	((*in >= 0x41) && (*in <= 0x5A)) ||
8501 	(*in == '_')) {
8502 	in++;
8503 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
8504 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
8505 	       ((*in >= 0x30) && (*in <= 0x39)) ||
8506 	       (*in == '_') || (*in == '.') ||
8507 	       (*in == '-'))
8508 	    in++;
8509 	if ((*in == ' ') || (*in == '>') || (*in == '/') ||
8510             (*in == '[') || (*in == ']') || (*in == ':') ||
8511             (*in == '@') || (*in == '*')) {
8512 	    count = in - ctxt->cur;
8513 	    if (count == 0)
8514 		return(NULL);
8515 	    ret = xmlStrndup(ctxt->cur, count);
8516             if (ret == NULL)
8517                 xmlXPathPErrMemory(ctxt);
8518 	    ctxt->cur = in;
8519 	    return(ret);
8520 	}
8521     }
8522     return(xmlXPathParseNameComplex(ctxt, 0));
8523 }
8524 
8525 
8526 /**
8527  * xmlXPathParseQName:
8528  * @ctxt:  the XPath Parser context
8529  * @prefix:  a xmlChar **
8530  *
8531  * parse an XML qualified name
8532  *
8533  * [NS 5] QName ::= (Prefix ':')? LocalPart
8534  *
8535  * [NS 6] Prefix ::= NCName
8536  *
8537  * [NS 7] LocalPart ::= NCName
8538  *
8539  * Returns the function returns the local part, and prefix is updated
8540  *   to get the Prefix if any.
8541  */
8542 
8543 static xmlChar *
xmlXPathParseQName(xmlXPathParserContextPtr ctxt,xmlChar ** prefix)8544 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
8545     xmlChar *ret = NULL;
8546 
8547     *prefix = NULL;
8548     ret = xmlXPathParseNCName(ctxt);
8549     if (ret && CUR == ':') {
8550         *prefix = ret;
8551 	NEXT;
8552 	ret = xmlXPathParseNCName(ctxt);
8553     }
8554     return(ret);
8555 }
8556 
8557 /**
8558  * xmlXPathParseName:
8559  * @ctxt:  the XPath Parser context
8560  *
8561  * parse an XML name
8562  *
8563  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8564  *                  CombiningChar | Extender
8565  *
8566  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8567  *
8568  * Returns the namespace name or NULL
8569  */
8570 
8571 xmlChar *
xmlXPathParseName(xmlXPathParserContextPtr ctxt)8572 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
8573     const xmlChar *in;
8574     xmlChar *ret;
8575     size_t count = 0;
8576 
8577     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8578     /*
8579      * Accelerator for simple ASCII names
8580      */
8581     in = ctxt->cur;
8582     if (((*in >= 0x61) && (*in <= 0x7A)) ||
8583 	((*in >= 0x41) && (*in <= 0x5A)) ||
8584 	(*in == '_') || (*in == ':')) {
8585 	in++;
8586 	while (((*in >= 0x61) && (*in <= 0x7A)) ||
8587 	       ((*in >= 0x41) && (*in <= 0x5A)) ||
8588 	       ((*in >= 0x30) && (*in <= 0x39)) ||
8589 	       (*in == '_') || (*in == '-') ||
8590 	       (*in == ':') || (*in == '.'))
8591 	    in++;
8592 	if ((*in > 0) && (*in < 0x80)) {
8593 	    count = in - ctxt->cur;
8594             if (count > XML_MAX_NAME_LENGTH) {
8595                 ctxt->cur = in;
8596                 XP_ERRORNULL(XPATH_EXPR_ERROR);
8597             }
8598 	    ret = xmlStrndup(ctxt->cur, count);
8599             if (ret == NULL)
8600                 xmlXPathPErrMemory(ctxt);
8601 	    ctxt->cur = in;
8602 	    return(ret);
8603 	}
8604     }
8605     return(xmlXPathParseNameComplex(ctxt, 1));
8606 }
8607 
8608 static xmlChar *
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,int qualified)8609 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
8610     xmlChar *ret;
8611     xmlChar buf[XML_MAX_NAMELEN + 5];
8612     int len = 0, l;
8613     int c;
8614 
8615     /*
8616      * Handler for more complex cases
8617      */
8618     c = CUR_CHAR(l);
8619     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8620         (c == '[') || (c == ']') || (c == '@') || /* accelerators */
8621         (c == '*') || /* accelerators */
8622 	(!IS_LETTER(c) && (c != '_') &&
8623          ((!qualified) || (c != ':')))) {
8624 	return(NULL);
8625     }
8626 
8627     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8628 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8629             (c == '.') || (c == '-') ||
8630 	    (c == '_') || ((qualified) && (c == ':')) ||
8631 	    (IS_COMBINING(c)) ||
8632 	    (IS_EXTENDER(c)))) {
8633 	COPY_BUF(buf,len,c);
8634 	NEXTL(l);
8635 	c = CUR_CHAR(l);
8636 	if (len >= XML_MAX_NAMELEN) {
8637 	    /*
8638 	     * Okay someone managed to make a huge name, so he's ready to pay
8639 	     * for the processing speed.
8640 	     */
8641 	    xmlChar *buffer;
8642 	    int max = len * 2;
8643 
8644             if (len > XML_MAX_NAME_LENGTH) {
8645                 XP_ERRORNULL(XPATH_EXPR_ERROR);
8646             }
8647 	    buffer = xmlMalloc(max);
8648 	    if (buffer == NULL) {
8649                 xmlXPathPErrMemory(ctxt);
8650                 return(NULL);
8651 	    }
8652 	    memcpy(buffer, buf, len);
8653 	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
8654 		   (c == '.') || (c == '-') ||
8655 		   (c == '_') || ((qualified) && (c == ':')) ||
8656 		   (IS_COMBINING(c)) ||
8657 		   (IS_EXTENDER(c))) {
8658 		if (len + 10 > max) {
8659                     xmlChar *tmp;
8660                     if (max > XML_MAX_NAME_LENGTH) {
8661                         xmlFree(buffer);
8662                         XP_ERRORNULL(XPATH_EXPR_ERROR);
8663                     }
8664 		    max *= 2;
8665 		    tmp = (xmlChar *) xmlRealloc(buffer, max);
8666 		    if (tmp == NULL) {
8667                         xmlFree(buffer);
8668                         xmlXPathPErrMemory(ctxt);
8669                         return(NULL);
8670 		    }
8671                     buffer = tmp;
8672 		}
8673 		COPY_BUF(buffer,len,c);
8674 		NEXTL(l);
8675 		c = CUR_CHAR(l);
8676 	    }
8677 	    buffer[len] = 0;
8678 	    return(buffer);
8679 	}
8680     }
8681     if (len == 0)
8682 	return(NULL);
8683     ret = xmlStrndup(buf, len);
8684     if (ret == NULL)
8685         xmlXPathPErrMemory(ctxt);
8686     return(ret);
8687 }
8688 
8689 #define MAX_FRAC 20
8690 
8691 /**
8692  * xmlXPathStringEvalNumber:
8693  * @str:  A string to scan
8694  *
8695  *  [30a]  Float  ::= Number ('e' Digits?)?
8696  *
8697  *  [30]   Number ::=   Digits ('.' Digits?)?
8698  *                    | '.' Digits
8699  *  [31]   Digits ::=   [0-9]+
8700  *
8701  * Compile a Number in the string
8702  * In complement of the Number expression, this function also handles
8703  * negative values : '-' Number.
8704  *
8705  * Returns the double value.
8706  */
8707 double
xmlXPathStringEvalNumber(const xmlChar * str)8708 xmlXPathStringEvalNumber(const xmlChar *str) {
8709     const xmlChar *cur = str;
8710     double ret;
8711     int ok = 0;
8712     int isneg = 0;
8713     int exponent = 0;
8714     int is_exponent_negative = 0;
8715 #ifdef __GNUC__
8716     unsigned long tmp = 0;
8717     double temp;
8718 #endif
8719     if (cur == NULL) return(0);
8720     while (IS_BLANK_CH(*cur)) cur++;
8721     if (*cur == '-') {
8722 	isneg = 1;
8723 	cur++;
8724     }
8725     if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
8726         return(xmlXPathNAN);
8727     }
8728 
8729 #ifdef __GNUC__
8730     /*
8731      * tmp/temp is a workaround against a gcc compiler bug
8732      * http://veillard.com/gcc.bug
8733      */
8734     ret = 0;
8735     while ((*cur >= '0') && (*cur <= '9')) {
8736 	ret = ret * 10;
8737 	tmp = (*cur - '0');
8738 	ok = 1;
8739 	cur++;
8740 	temp = (double) tmp;
8741 	ret = ret + temp;
8742     }
8743 #else
8744     ret = 0;
8745     while ((*cur >= '0') && (*cur <= '9')) {
8746 	ret = ret * 10 + (*cur - '0');
8747 	ok = 1;
8748 	cur++;
8749     }
8750 #endif
8751 
8752     if (*cur == '.') {
8753 	int v, frac = 0, max;
8754 	double fraction = 0;
8755 
8756         cur++;
8757 	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
8758 	    return(xmlXPathNAN);
8759 	}
8760         while (*cur == '0') {
8761 	    frac = frac + 1;
8762 	    cur++;
8763         }
8764         max = frac + MAX_FRAC;
8765 	while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
8766 	    v = (*cur - '0');
8767 	    fraction = fraction * 10 + v;
8768 	    frac = frac + 1;
8769 	    cur++;
8770 	}
8771 	fraction /= pow(10.0, frac);
8772 	ret = ret + fraction;
8773 	while ((*cur >= '0') && (*cur <= '9'))
8774 	    cur++;
8775     }
8776     if ((*cur == 'e') || (*cur == 'E')) {
8777       cur++;
8778       if (*cur == '-') {
8779 	is_exponent_negative = 1;
8780 	cur++;
8781       } else if (*cur == '+') {
8782         cur++;
8783       }
8784       while ((*cur >= '0') && (*cur <= '9')) {
8785         if (exponent < 1000000)
8786 	  exponent = exponent * 10 + (*cur - '0');
8787 	cur++;
8788       }
8789     }
8790     while (IS_BLANK_CH(*cur)) cur++;
8791     if (*cur != 0) return(xmlXPathNAN);
8792     if (isneg) ret = -ret;
8793     if (is_exponent_negative) exponent = -exponent;
8794     ret *= pow(10.0, (double)exponent);
8795     return(ret);
8796 }
8797 
8798 /**
8799  * xmlXPathCompNumber:
8800  * @ctxt:  the XPath Parser context
8801  *
8802  *  [30]   Number ::=   Digits ('.' Digits?)?
8803  *                    | '.' Digits
8804  *  [31]   Digits ::=   [0-9]+
8805  *
8806  * Compile a Number, then push it on the stack
8807  *
8808  */
8809 static void
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)8810 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
8811 {
8812     double ret = 0.0;
8813     int ok = 0;
8814     int exponent = 0;
8815     int is_exponent_negative = 0;
8816     xmlXPathObjectPtr num;
8817 #ifdef __GNUC__
8818     unsigned long tmp = 0;
8819     double temp;
8820 #endif
8821 
8822     CHECK_ERROR;
8823     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
8824         XP_ERROR(XPATH_NUMBER_ERROR);
8825     }
8826 #ifdef __GNUC__
8827     /*
8828      * tmp/temp is a workaround against a gcc compiler bug
8829      * http://veillard.com/gcc.bug
8830      */
8831     ret = 0;
8832     while ((CUR >= '0') && (CUR <= '9')) {
8833 	ret = ret * 10;
8834 	tmp = (CUR - '0');
8835         ok = 1;
8836         NEXT;
8837 	temp = (double) tmp;
8838 	ret = ret + temp;
8839     }
8840 #else
8841     ret = 0;
8842     while ((CUR >= '0') && (CUR <= '9')) {
8843 	ret = ret * 10 + (CUR - '0');
8844 	ok = 1;
8845 	NEXT;
8846     }
8847 #endif
8848     if (CUR == '.') {
8849 	int v, frac = 0, max;
8850 	double fraction = 0;
8851 
8852         NEXT;
8853         if (((CUR < '0') || (CUR > '9')) && (!ok)) {
8854             XP_ERROR(XPATH_NUMBER_ERROR);
8855         }
8856         while (CUR == '0') {
8857             frac = frac + 1;
8858             NEXT;
8859         }
8860         max = frac + MAX_FRAC;
8861         while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
8862 	    v = (CUR - '0');
8863 	    fraction = fraction * 10 + v;
8864 	    frac = frac + 1;
8865             NEXT;
8866         }
8867         fraction /= pow(10.0, frac);
8868         ret = ret + fraction;
8869         while ((CUR >= '0') && (CUR <= '9'))
8870             NEXT;
8871     }
8872     if ((CUR == 'e') || (CUR == 'E')) {
8873         NEXT;
8874         if (CUR == '-') {
8875             is_exponent_negative = 1;
8876             NEXT;
8877         } else if (CUR == '+') {
8878 	    NEXT;
8879 	}
8880         while ((CUR >= '0') && (CUR <= '9')) {
8881             if (exponent < 1000000)
8882                 exponent = exponent * 10 + (CUR - '0');
8883             NEXT;
8884         }
8885         if (is_exponent_negative)
8886             exponent = -exponent;
8887         ret *= pow(10.0, (double) exponent);
8888     }
8889     num = xmlXPathCacheNewFloat(ctxt, ret);
8890     if (num == NULL) {
8891 	ctxt->error = XPATH_MEMORY_ERROR;
8892     } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
8893                               NULL) == -1) {
8894         xmlXPathReleaseObject(ctxt->context, num);
8895     }
8896 }
8897 
8898 /**
8899  * xmlXPathParseLiteral:
8900  * @ctxt:  the XPath Parser context
8901  *
8902  * Parse a Literal
8903  *
8904  *  [29]   Literal ::=   '"' [^"]* '"'
8905  *                    | "'" [^']* "'"
8906  *
8907  * Returns the value found or NULL in case of error
8908  */
8909 static xmlChar *
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt)8910 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
8911     const xmlChar *q;
8912     xmlChar *ret = NULL;
8913     int quote;
8914 
8915     if (CUR == '"') {
8916         quote = '"';
8917     } else if (CUR == '\'') {
8918         quote = '\'';
8919     } else {
8920 	XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
8921     }
8922 
8923     NEXT;
8924     q = CUR_PTR;
8925     while (CUR != quote) {
8926         int ch;
8927         int len = 4;
8928 
8929         if (CUR == 0)
8930             XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
8931         ch = xmlGetUTF8Char(CUR_PTR, &len);
8932         if ((ch < 0) || (IS_CHAR(ch) == 0))
8933             XP_ERRORNULL(XPATH_INVALID_CHAR_ERROR);
8934         CUR_PTR += len;
8935     }
8936     ret = xmlStrndup(q, CUR_PTR - q);
8937     if (ret == NULL)
8938         xmlXPathPErrMemory(ctxt);
8939     NEXT;
8940     return(ret);
8941 }
8942 
8943 /**
8944  * xmlXPathCompLiteral:
8945  * @ctxt:  the XPath Parser context
8946  *
8947  * Parse a Literal and push it on the stack.
8948  *
8949  *  [29]   Literal ::=   '"' [^"]* '"'
8950  *                    | "'" [^']* "'"
8951  *
8952  * TODO: xmlXPathCompLiteral memory allocation could be improved.
8953  */
8954 static void
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt)8955 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
8956     xmlChar *ret = NULL;
8957     xmlXPathObjectPtr lit;
8958 
8959     ret = xmlXPathParseLiteral(ctxt);
8960     if (ret == NULL)
8961         return;
8962     lit = xmlXPathCacheNewString(ctxt, ret);
8963     if (lit == NULL) {
8964         ctxt->error = XPATH_MEMORY_ERROR;
8965     } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
8966                               NULL) == -1) {
8967         xmlXPathReleaseObject(ctxt->context, lit);
8968     }
8969     xmlFree(ret);
8970 }
8971 
8972 /**
8973  * xmlXPathCompVariableReference:
8974  * @ctxt:  the XPath Parser context
8975  *
8976  * Parse a VariableReference, evaluate it and push it on the stack.
8977  *
8978  * The variable bindings consist of a mapping from variable names
8979  * to variable values. The value of a variable is an object, which can be
8980  * of any of the types that are possible for the value of an expression,
8981  * and may also be of additional types not specified here.
8982  *
8983  * Early evaluation is possible since:
8984  * The variable bindings [...] used to evaluate a subexpression are
8985  * always the same as those used to evaluate the containing expression.
8986  *
8987  *  [36]   VariableReference ::=   '$' QName
8988  */
8989 static void
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt)8990 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
8991     xmlChar *name;
8992     xmlChar *prefix;
8993 
8994     SKIP_BLANKS;
8995     if (CUR != '$') {
8996 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8997     }
8998     NEXT;
8999     name = xmlXPathParseQName(ctxt, &prefix);
9000     if (name == NULL) {
9001         xmlFree(prefix);
9002 	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9003     }
9004     ctxt->comp->last = -1;
9005     if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
9006         xmlFree(prefix);
9007         xmlFree(name);
9008     }
9009     SKIP_BLANKS;
9010     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
9011 	XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
9012     }
9013 }
9014 
9015 /**
9016  * xmlXPathIsNodeType:
9017  * @name:  a name string
9018  *
9019  * Is the name given a NodeType one.
9020  *
9021  *  [38]   NodeType ::=   'comment'
9022  *                    | 'text'
9023  *                    | 'processing-instruction'
9024  *                    | 'node'
9025  *
9026  * Returns 1 if true 0 otherwise
9027  */
9028 int
xmlXPathIsNodeType(const xmlChar * name)9029 xmlXPathIsNodeType(const xmlChar *name) {
9030     if (name == NULL)
9031 	return(0);
9032 
9033     if (xmlStrEqual(name, BAD_CAST "node"))
9034 	return(1);
9035     if (xmlStrEqual(name, BAD_CAST "text"))
9036 	return(1);
9037     if (xmlStrEqual(name, BAD_CAST "comment"))
9038 	return(1);
9039     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9040 	return(1);
9041     return(0);
9042 }
9043 
9044 /**
9045  * xmlXPathCompFunctionCall:
9046  * @ctxt:  the XPath Parser context
9047  *
9048  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
9049  *  [17]   Argument ::=   Expr
9050  *
9051  * Compile a function call, the evaluation of all arguments are
9052  * pushed on the stack
9053  */
9054 static void
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt)9055 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
9056     xmlChar *name;
9057     xmlChar *prefix;
9058     int nbargs = 0;
9059     int sort = 1;
9060 
9061     name = xmlXPathParseQName(ctxt, &prefix);
9062     if (name == NULL) {
9063 	xmlFree(prefix);
9064 	XP_ERROR(XPATH_EXPR_ERROR);
9065     }
9066     SKIP_BLANKS;
9067 
9068     if (CUR != '(') {
9069 	xmlFree(name);
9070 	xmlFree(prefix);
9071 	XP_ERROR(XPATH_EXPR_ERROR);
9072     }
9073     NEXT;
9074     SKIP_BLANKS;
9075 
9076     /*
9077     * Optimization for count(): we don't need the node-set to be sorted.
9078     */
9079     if ((prefix == NULL) && (name[0] == 'c') &&
9080 	xmlStrEqual(name, BAD_CAST "count"))
9081     {
9082 	sort = 0;
9083     }
9084     ctxt->comp->last = -1;
9085     if (CUR != ')') {
9086 	while (CUR != 0) {
9087 	    int op1 = ctxt->comp->last;
9088 	    ctxt->comp->last = -1;
9089 	    xmlXPathCompileExpr(ctxt, sort);
9090 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
9091 		xmlFree(name);
9092 		xmlFree(prefix);
9093 		return;
9094 	    }
9095 	    PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
9096 	    nbargs++;
9097 	    if (CUR == ')') break;
9098 	    if (CUR != ',') {
9099 		xmlFree(name);
9100 		xmlFree(prefix);
9101 		XP_ERROR(XPATH_EXPR_ERROR);
9102 	    }
9103 	    NEXT;
9104 	    SKIP_BLANKS;
9105 	}
9106     }
9107     if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
9108         xmlFree(prefix);
9109         xmlFree(name);
9110     }
9111     NEXT;
9112     SKIP_BLANKS;
9113 }
9114 
9115 /**
9116  * xmlXPathCompPrimaryExpr:
9117  * @ctxt:  the XPath Parser context
9118  *
9119  *  [15]   PrimaryExpr ::=   VariableReference
9120  *                | '(' Expr ')'
9121  *                | Literal
9122  *                | Number
9123  *                | FunctionCall
9124  *
9125  * Compile a primary expression.
9126  */
9127 static void
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt)9128 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
9129     SKIP_BLANKS;
9130     if (CUR == '$') xmlXPathCompVariableReference(ctxt);
9131     else if (CUR == '(') {
9132 	NEXT;
9133 	SKIP_BLANKS;
9134 	xmlXPathCompileExpr(ctxt, 1);
9135 	CHECK_ERROR;
9136 	if (CUR != ')') {
9137 	    XP_ERROR(XPATH_EXPR_ERROR);
9138 	}
9139 	NEXT;
9140 	SKIP_BLANKS;
9141     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9142 	xmlXPathCompNumber(ctxt);
9143     } else if ((CUR == '\'') || (CUR == '"')) {
9144 	xmlXPathCompLiteral(ctxt);
9145     } else {
9146 	xmlXPathCompFunctionCall(ctxt);
9147     }
9148     SKIP_BLANKS;
9149 }
9150 
9151 /**
9152  * xmlXPathCompFilterExpr:
9153  * @ctxt:  the XPath Parser context
9154  *
9155  *  [20]   FilterExpr ::=   PrimaryExpr
9156  *               | FilterExpr Predicate
9157  *
9158  * Compile a filter expression.
9159  * Square brackets are used to filter expressions in the same way that
9160  * they are used in location paths. It is an error if the expression to
9161  * be filtered does not evaluate to a node-set. The context node list
9162  * used for evaluating the expression in square brackets is the node-set
9163  * to be filtered listed in document order.
9164  */
9165 
9166 static void
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt)9167 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
9168     xmlXPathCompPrimaryExpr(ctxt);
9169     CHECK_ERROR;
9170     SKIP_BLANKS;
9171 
9172     while (CUR == '[') {
9173 	xmlXPathCompPredicate(ctxt, 1);
9174 	SKIP_BLANKS;
9175     }
9176 
9177 
9178 }
9179 
9180 /**
9181  * xmlXPathScanName:
9182  * @ctxt:  the XPath Parser context
9183  *
9184  * Trickery: parse an XML name but without consuming the input flow
9185  * Needed to avoid insanity in the parser state.
9186  *
9187  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9188  *                  CombiningChar | Extender
9189  *
9190  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9191  *
9192  * [6] Names ::= Name (S Name)*
9193  *
9194  * Returns the Name parsed or NULL
9195  */
9196 
9197 static xmlChar *
xmlXPathScanName(xmlXPathParserContextPtr ctxt)9198 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
9199     int l;
9200     int c;
9201     const xmlChar *cur;
9202     xmlChar *ret;
9203 
9204     cur = ctxt->cur;
9205 
9206     c = CUR_CHAR(l);
9207     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9208 	(!IS_LETTER(c) && (c != '_') &&
9209          (c != ':'))) {
9210 	return(NULL);
9211     }
9212 
9213     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9214 	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9215             (c == '.') || (c == '-') ||
9216 	    (c == '_') || (c == ':') ||
9217 	    (IS_COMBINING(c)) ||
9218 	    (IS_EXTENDER(c)))) {
9219 	NEXTL(l);
9220 	c = CUR_CHAR(l);
9221     }
9222     ret = xmlStrndup(cur, ctxt->cur - cur);
9223     if (ret == NULL)
9224         xmlXPathPErrMemory(ctxt);
9225     ctxt->cur = cur;
9226     return(ret);
9227 }
9228 
9229 /**
9230  * xmlXPathCompPathExpr:
9231  * @ctxt:  the XPath Parser context
9232  *
9233  *  [19]   PathExpr ::=   LocationPath
9234  *               | FilterExpr
9235  *               | FilterExpr '/' RelativeLocationPath
9236  *               | FilterExpr '//' RelativeLocationPath
9237  *
9238  * Compile a path expression.
9239  * The / operator and // operators combine an arbitrary expression
9240  * and a relative location path. It is an error if the expression
9241  * does not evaluate to a node-set.
9242  * The / operator does composition in the same way as when / is
9243  * used in a location path. As in location paths, // is short for
9244  * /descendant-or-self::node()/.
9245  */
9246 
9247 static void
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt)9248 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
9249     int lc = 1;           /* Should we branch to LocationPath ?         */
9250     xmlChar *name = NULL; /* we may have to preparse a name to find out */
9251 
9252     SKIP_BLANKS;
9253     if ((CUR == '$') || (CUR == '(') ||
9254 	(IS_ASCII_DIGIT(CUR)) ||
9255         (CUR == '\'') || (CUR == '"') ||
9256 	(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9257 	lc = 0;
9258     } else if (CUR == '*') {
9259 	/* relative or absolute location path */
9260 	lc = 1;
9261     } else if (CUR == '/') {
9262 	/* relative or absolute location path */
9263 	lc = 1;
9264     } else if (CUR == '@') {
9265 	/* relative abbreviated attribute location path */
9266 	lc = 1;
9267     } else if (CUR == '.') {
9268 	/* relative abbreviated attribute location path */
9269 	lc = 1;
9270     } else {
9271 	/*
9272 	 * Problem is finding if we have a name here whether it's:
9273 	 *   - a nodetype
9274 	 *   - a function call in which case it's followed by '('
9275 	 *   - an axis in which case it's followed by ':'
9276 	 *   - a element name
9277 	 * We do an a priori analysis here rather than having to
9278 	 * maintain parsed token content through the recursive function
9279 	 * calls. This looks uglier but makes the code easier to
9280 	 * read/write/debug.
9281 	 */
9282 	SKIP_BLANKS;
9283 	name = xmlXPathScanName(ctxt);
9284 	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
9285 	    lc = 1;
9286 	    xmlFree(name);
9287 	} else if (name != NULL) {
9288 	    int len =xmlStrlen(name);
9289 
9290 
9291 	    while (NXT(len) != 0) {
9292 		if (NXT(len) == '/') {
9293 		    /* element name */
9294 		    lc = 1;
9295 		    break;
9296 		} else if (IS_BLANK_CH(NXT(len))) {
9297 		    /* ignore blanks */
9298 		    ;
9299 		} else if (NXT(len) == ':') {
9300 		    lc = 1;
9301 		    break;
9302 		} else if ((NXT(len) == '(')) {
9303 		    /* Node Type or Function */
9304 		    if (xmlXPathIsNodeType(name)) {
9305 			lc = 1;
9306 		    } else {
9307 			lc = 0;
9308 		    }
9309                     break;
9310 		} else if ((NXT(len) == '[')) {
9311 		    /* element name */
9312 		    lc = 1;
9313 		    break;
9314 		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
9315 			   (NXT(len) == '=')) {
9316 		    lc = 1;
9317 		    break;
9318 		} else {
9319 		    lc = 1;
9320 		    break;
9321 		}
9322 		len++;
9323 	    }
9324 	    if (NXT(len) == 0) {
9325 		/* element name */
9326 		lc = 1;
9327 	    }
9328 	    xmlFree(name);
9329 	} else {
9330 	    /* make sure all cases are covered explicitly */
9331 	    XP_ERROR(XPATH_EXPR_ERROR);
9332 	}
9333     }
9334 
9335     if (lc) {
9336 	if (CUR == '/') {
9337 	    PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
9338 	} else {
9339 	    PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9340 	}
9341 	xmlXPathCompLocationPath(ctxt);
9342     } else {
9343 	xmlXPathCompFilterExpr(ctxt);
9344 	CHECK_ERROR;
9345 	if ((CUR == '/') && (NXT(1) == '/')) {
9346 	    SKIP(2);
9347 	    SKIP_BLANKS;
9348 
9349 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9350 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9351 
9352 	    xmlXPathCompRelativeLocationPath(ctxt);
9353 	} else if (CUR == '/') {
9354 	    xmlXPathCompRelativeLocationPath(ctxt);
9355 	}
9356     }
9357     SKIP_BLANKS;
9358 }
9359 
9360 /**
9361  * xmlXPathCompUnionExpr:
9362  * @ctxt:  the XPath Parser context
9363  *
9364  *  [18]   UnionExpr ::=   PathExpr
9365  *               | UnionExpr '|' PathExpr
9366  *
9367  * Compile an union expression.
9368  */
9369 
9370 static void
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt)9371 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
9372     xmlXPathCompPathExpr(ctxt);
9373     CHECK_ERROR;
9374     SKIP_BLANKS;
9375     while (CUR == '|') {
9376 	int op1 = ctxt->comp->last;
9377 	PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9378 
9379 	NEXT;
9380 	SKIP_BLANKS;
9381 	xmlXPathCompPathExpr(ctxt);
9382 
9383 	PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
9384 
9385 	SKIP_BLANKS;
9386     }
9387 }
9388 
9389 /**
9390  * xmlXPathCompUnaryExpr:
9391  * @ctxt:  the XPath Parser context
9392  *
9393  *  [27]   UnaryExpr ::=   UnionExpr
9394  *                   | '-' UnaryExpr
9395  *
9396  * Compile an unary expression.
9397  */
9398 
9399 static void
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt)9400 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
9401     int minus = 0;
9402     int found = 0;
9403 
9404     SKIP_BLANKS;
9405     while (CUR == '-') {
9406         minus = 1 - minus;
9407 	found = 1;
9408 	NEXT;
9409 	SKIP_BLANKS;
9410     }
9411 
9412     xmlXPathCompUnionExpr(ctxt);
9413     CHECK_ERROR;
9414     if (found) {
9415 	if (minus)
9416 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
9417 	else
9418 	    PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
9419     }
9420 }
9421 
9422 /**
9423  * xmlXPathCompMultiplicativeExpr:
9424  * @ctxt:  the XPath Parser context
9425  *
9426  *  [26]   MultiplicativeExpr ::=   UnaryExpr
9427  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
9428  *                   | MultiplicativeExpr 'div' UnaryExpr
9429  *                   | MultiplicativeExpr 'mod' UnaryExpr
9430  *  [34]   MultiplyOperator ::=   '*'
9431  *
9432  * Compile an Additive expression.
9433  */
9434 
9435 static void
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt)9436 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
9437     xmlXPathCompUnaryExpr(ctxt);
9438     CHECK_ERROR;
9439     SKIP_BLANKS;
9440     while ((CUR == '*') ||
9441            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
9442            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
9443 	int op = -1;
9444 	int op1 = ctxt->comp->last;
9445 
9446         if (CUR == '*') {
9447 	    op = 0;
9448 	    NEXT;
9449 	} else if (CUR == 'd') {
9450 	    op = 1;
9451 	    SKIP(3);
9452 	} else if (CUR == 'm') {
9453 	    op = 2;
9454 	    SKIP(3);
9455 	}
9456 	SKIP_BLANKS;
9457         xmlXPathCompUnaryExpr(ctxt);
9458 	CHECK_ERROR;
9459 	PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
9460 	SKIP_BLANKS;
9461     }
9462 }
9463 
9464 /**
9465  * xmlXPathCompAdditiveExpr:
9466  * @ctxt:  the XPath Parser context
9467  *
9468  *  [25]   AdditiveExpr ::=   MultiplicativeExpr
9469  *                   | AdditiveExpr '+' MultiplicativeExpr
9470  *                   | AdditiveExpr '-' MultiplicativeExpr
9471  *
9472  * Compile an Additive expression.
9473  */
9474 
9475 static void
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt)9476 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
9477 
9478     xmlXPathCompMultiplicativeExpr(ctxt);
9479     CHECK_ERROR;
9480     SKIP_BLANKS;
9481     while ((CUR == '+') || (CUR == '-')) {
9482 	int plus;
9483 	int op1 = ctxt->comp->last;
9484 
9485         if (CUR == '+') plus = 1;
9486 	else plus = 0;
9487 	NEXT;
9488 	SKIP_BLANKS;
9489         xmlXPathCompMultiplicativeExpr(ctxt);
9490 	CHECK_ERROR;
9491 	PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
9492 	SKIP_BLANKS;
9493     }
9494 }
9495 
9496 /**
9497  * xmlXPathCompRelationalExpr:
9498  * @ctxt:  the XPath Parser context
9499  *
9500  *  [24]   RelationalExpr ::=   AdditiveExpr
9501  *                 | RelationalExpr '<' AdditiveExpr
9502  *                 | RelationalExpr '>' AdditiveExpr
9503  *                 | RelationalExpr '<=' AdditiveExpr
9504  *                 | RelationalExpr '>=' AdditiveExpr
9505  *
9506  *  A <= B > C is allowed ? Answer from James, yes with
9507  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
9508  *  which is basically what got implemented.
9509  *
9510  * Compile a Relational expression, then push the result
9511  * on the stack
9512  */
9513 
9514 static void
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt)9515 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
9516     xmlXPathCompAdditiveExpr(ctxt);
9517     CHECK_ERROR;
9518     SKIP_BLANKS;
9519     while ((CUR == '<') || (CUR == '>')) {
9520 	int inf, strict;
9521 	int op1 = ctxt->comp->last;
9522 
9523         if (CUR == '<') inf = 1;
9524 	else inf = 0;
9525 	if (NXT(1) == '=') strict = 0;
9526 	else strict = 1;
9527 	NEXT;
9528 	if (!strict) NEXT;
9529 	SKIP_BLANKS;
9530         xmlXPathCompAdditiveExpr(ctxt);
9531 	CHECK_ERROR;
9532 	PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
9533 	SKIP_BLANKS;
9534     }
9535 }
9536 
9537 /**
9538  * xmlXPathCompEqualityExpr:
9539  * @ctxt:  the XPath Parser context
9540  *
9541  *  [23]   EqualityExpr ::=   RelationalExpr
9542  *                 | EqualityExpr '=' RelationalExpr
9543  *                 | EqualityExpr '!=' RelationalExpr
9544  *
9545  *  A != B != C is allowed ? Answer from James, yes with
9546  *  (RelationalExpr = RelationalExpr) = RelationalExpr
9547  *  (RelationalExpr != RelationalExpr) != RelationalExpr
9548  *  which is basically what got implemented.
9549  *
9550  * Compile an Equality expression.
9551  *
9552  */
9553 static void
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt)9554 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
9555     xmlXPathCompRelationalExpr(ctxt);
9556     CHECK_ERROR;
9557     SKIP_BLANKS;
9558     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
9559 	int eq;
9560 	int op1 = ctxt->comp->last;
9561 
9562         if (CUR == '=') eq = 1;
9563 	else eq = 0;
9564 	NEXT;
9565 	if (!eq) NEXT;
9566 	SKIP_BLANKS;
9567         xmlXPathCompRelationalExpr(ctxt);
9568 	CHECK_ERROR;
9569 	PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
9570 	SKIP_BLANKS;
9571     }
9572 }
9573 
9574 /**
9575  * xmlXPathCompAndExpr:
9576  * @ctxt:  the XPath Parser context
9577  *
9578  *  [22]   AndExpr ::=   EqualityExpr
9579  *                 | AndExpr 'and' EqualityExpr
9580  *
9581  * Compile an AND expression.
9582  *
9583  */
9584 static void
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt)9585 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
9586     xmlXPathCompEqualityExpr(ctxt);
9587     CHECK_ERROR;
9588     SKIP_BLANKS;
9589     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
9590 	int op1 = ctxt->comp->last;
9591         SKIP(3);
9592 	SKIP_BLANKS;
9593         xmlXPathCompEqualityExpr(ctxt);
9594 	CHECK_ERROR;
9595 	PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
9596 	SKIP_BLANKS;
9597     }
9598 }
9599 
9600 /**
9601  * xmlXPathCompileExpr:
9602  * @ctxt:  the XPath Parser context
9603  *
9604  *  [14]   Expr ::=   OrExpr
9605  *  [21]   OrExpr ::=   AndExpr
9606  *                 | OrExpr 'or' AndExpr
9607  *
9608  * Parse and compile an expression
9609  */
9610 static void
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt,int sort)9611 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
9612     xmlXPathContextPtr xpctxt = ctxt->context;
9613 
9614     if (xpctxt != NULL) {
9615         if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
9616             XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9617         /*
9618          * Parsing a single '(' pushes about 10 functions on the call stack
9619          * before recursing!
9620          */
9621         xpctxt->depth += 10;
9622     }
9623 
9624     xmlXPathCompAndExpr(ctxt);
9625     CHECK_ERROR;
9626     SKIP_BLANKS;
9627     while ((CUR == 'o') && (NXT(1) == 'r')) {
9628 	int op1 = ctxt->comp->last;
9629         SKIP(2);
9630 	SKIP_BLANKS;
9631         xmlXPathCompAndExpr(ctxt);
9632 	CHECK_ERROR;
9633 	PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
9634 	SKIP_BLANKS;
9635     }
9636     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
9637 	/* more ops could be optimized too */
9638 	/*
9639 	* This is the main place to eliminate sorting for
9640 	* operations which don't require a sorted node-set.
9641 	* E.g. count().
9642 	*/
9643 	PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
9644     }
9645 
9646     if (xpctxt != NULL)
9647         xpctxt->depth -= 10;
9648 }
9649 
9650 /**
9651  * xmlXPathCompPredicate:
9652  * @ctxt:  the XPath Parser context
9653  * @filter:  act as a filter
9654  *
9655  *  [8]   Predicate ::=   '[' PredicateExpr ']'
9656  *  [9]   PredicateExpr ::=   Expr
9657  *
9658  * Compile a predicate expression
9659  */
9660 static void
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt,int filter)9661 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
9662     int op1 = ctxt->comp->last;
9663 
9664     SKIP_BLANKS;
9665     if (CUR != '[') {
9666 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9667     }
9668     NEXT;
9669     SKIP_BLANKS;
9670 
9671     ctxt->comp->last = -1;
9672     /*
9673     * This call to xmlXPathCompileExpr() will deactivate sorting
9674     * of the predicate result.
9675     * TODO: Sorting is still activated for filters, since I'm not
9676     *  sure if needed. Normally sorting should not be needed, since
9677     *  a filter can only diminish the number of items in a sequence,
9678     *  but won't change its order; so if the initial sequence is sorted,
9679     *  subsequent sorting is not needed.
9680     */
9681     if (! filter)
9682 	xmlXPathCompileExpr(ctxt, 0);
9683     else
9684 	xmlXPathCompileExpr(ctxt, 1);
9685     CHECK_ERROR;
9686 
9687     if (CUR != ']') {
9688 	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9689     }
9690 
9691     if (filter)
9692 	PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
9693     else
9694 	PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
9695 
9696     NEXT;
9697     SKIP_BLANKS;
9698 }
9699 
9700 /**
9701  * xmlXPathCompNodeTest:
9702  * @ctxt:  the XPath Parser context
9703  * @test:  pointer to a xmlXPathTestVal
9704  * @type:  pointer to a xmlXPathTypeVal
9705  * @prefix:  placeholder for a possible name prefix
9706  *
9707  * [7] NodeTest ::=   NameTest
9708  *		    | NodeType '(' ')'
9709  *		    | 'processing-instruction' '(' Literal ')'
9710  *
9711  * [37] NameTest ::=  '*'
9712  *		    | NCName ':' '*'
9713  *		    | QName
9714  * [38] NodeType ::= 'comment'
9715  *		   | 'text'
9716  *		   | 'processing-instruction'
9717  *		   | 'node'
9718  *
9719  * Returns the name found and updates @test, @type and @prefix appropriately
9720  */
9721 static xmlChar *
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt,xmlXPathTestVal * test,xmlXPathTypeVal * type,xmlChar ** prefix,xmlChar * name)9722 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
9723 	             xmlXPathTypeVal *type, xmlChar **prefix,
9724 		     xmlChar *name) {
9725     int blanks;
9726 
9727     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
9728 	return(NULL);
9729     }
9730     *type = (xmlXPathTypeVal) 0;
9731     *test = (xmlXPathTestVal) 0;
9732     *prefix = NULL;
9733     SKIP_BLANKS;
9734 
9735     if ((name == NULL) && (CUR == '*')) {
9736 	/*
9737 	 * All elements
9738 	 */
9739 	NEXT;
9740 	*test = NODE_TEST_ALL;
9741 	return(NULL);
9742     }
9743 
9744     if (name == NULL)
9745 	name = xmlXPathParseNCName(ctxt);
9746     if (name == NULL) {
9747 	XP_ERRORNULL(XPATH_EXPR_ERROR);
9748     }
9749 
9750     blanks = IS_BLANK_CH(CUR);
9751     SKIP_BLANKS;
9752     if (CUR == '(') {
9753 	NEXT;
9754 	/*
9755 	 * NodeType or PI search
9756 	 */
9757 	if (xmlStrEqual(name, BAD_CAST "comment"))
9758 	    *type = NODE_TYPE_COMMENT;
9759 	else if (xmlStrEqual(name, BAD_CAST "node"))
9760 	    *type = NODE_TYPE_NODE;
9761 	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9762 	    *type = NODE_TYPE_PI;
9763 	else if (xmlStrEqual(name, BAD_CAST "text"))
9764 	    *type = NODE_TYPE_TEXT;
9765 	else {
9766 	    if (name != NULL)
9767 		xmlFree(name);
9768 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
9769 	}
9770 
9771 	*test = NODE_TEST_TYPE;
9772 
9773 	SKIP_BLANKS;
9774 	if (*type == NODE_TYPE_PI) {
9775 	    /*
9776 	     * Specific case: search a PI by name.
9777 	     */
9778 	    if (name != NULL)
9779 		xmlFree(name);
9780 	    name = NULL;
9781 	    if (CUR != ')') {
9782 		name = xmlXPathParseLiteral(ctxt);
9783 		*test = NODE_TEST_PI;
9784 		SKIP_BLANKS;
9785 	    }
9786 	}
9787 	if (CUR != ')') {
9788 	    if (name != NULL)
9789 		xmlFree(name);
9790 	    XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
9791 	}
9792 	NEXT;
9793 	return(name);
9794     }
9795     *test = NODE_TEST_NAME;
9796     if ((!blanks) && (CUR == ':')) {
9797 	NEXT;
9798 
9799 	/*
9800 	 * Since currently the parser context don't have a
9801 	 * namespace list associated:
9802 	 * The namespace name for this prefix can be computed
9803 	 * only at evaluation time. The compilation is done
9804 	 * outside of any context.
9805 	 */
9806 	*prefix = name;
9807 
9808 	if (CUR == '*') {
9809 	    /*
9810 	     * All elements
9811 	     */
9812 	    NEXT;
9813 	    *test = NODE_TEST_ALL;
9814 	    return(NULL);
9815 	}
9816 
9817 	name = xmlXPathParseNCName(ctxt);
9818 	if (name == NULL) {
9819 	    XP_ERRORNULL(XPATH_EXPR_ERROR);
9820 	}
9821     }
9822     return(name);
9823 }
9824 
9825 /**
9826  * xmlXPathIsAxisName:
9827  * @name:  a preparsed name token
9828  *
9829  * [6] AxisName ::=   'ancestor'
9830  *                  | 'ancestor-or-self'
9831  *                  | 'attribute'
9832  *                  | 'child'
9833  *                  | 'descendant'
9834  *                  | 'descendant-or-self'
9835  *                  | 'following'
9836  *                  | 'following-sibling'
9837  *                  | 'namespace'
9838  *                  | 'parent'
9839  *                  | 'preceding'
9840  *                  | 'preceding-sibling'
9841  *                  | 'self'
9842  *
9843  * Returns the axis or 0
9844  */
9845 static xmlXPathAxisVal
xmlXPathIsAxisName(const xmlChar * name)9846 xmlXPathIsAxisName(const xmlChar *name) {
9847     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
9848     switch (name[0]) {
9849 	case 'a':
9850 	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
9851 		ret = AXIS_ANCESTOR;
9852 	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
9853 		ret = AXIS_ANCESTOR_OR_SELF;
9854 	    if (xmlStrEqual(name, BAD_CAST "attribute"))
9855 		ret = AXIS_ATTRIBUTE;
9856 	    break;
9857 	case 'c':
9858 	    if (xmlStrEqual(name, BAD_CAST "child"))
9859 		ret = AXIS_CHILD;
9860 	    break;
9861 	case 'd':
9862 	    if (xmlStrEqual(name, BAD_CAST "descendant"))
9863 		ret = AXIS_DESCENDANT;
9864 	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
9865 		ret = AXIS_DESCENDANT_OR_SELF;
9866 	    break;
9867 	case 'f':
9868 	    if (xmlStrEqual(name, BAD_CAST "following"))
9869 		ret = AXIS_FOLLOWING;
9870 	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
9871 		ret = AXIS_FOLLOWING_SIBLING;
9872 	    break;
9873 	case 'n':
9874 	    if (xmlStrEqual(name, BAD_CAST "namespace"))
9875 		ret = AXIS_NAMESPACE;
9876 	    break;
9877 	case 'p':
9878 	    if (xmlStrEqual(name, BAD_CAST "parent"))
9879 		ret = AXIS_PARENT;
9880 	    if (xmlStrEqual(name, BAD_CAST "preceding"))
9881 		ret = AXIS_PRECEDING;
9882 	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
9883 		ret = AXIS_PRECEDING_SIBLING;
9884 	    break;
9885 	case 's':
9886 	    if (xmlStrEqual(name, BAD_CAST "self"))
9887 		ret = AXIS_SELF;
9888 	    break;
9889     }
9890     return(ret);
9891 }
9892 
9893 /**
9894  * xmlXPathCompStep:
9895  * @ctxt:  the XPath Parser context
9896  *
9897  * [4] Step ::=   AxisSpecifier NodeTest Predicate*
9898  *                  | AbbreviatedStep
9899  *
9900  * [12] AbbreviatedStep ::=   '.' | '..'
9901  *
9902  * [5] AxisSpecifier ::= AxisName '::'
9903  *                  | AbbreviatedAxisSpecifier
9904  *
9905  * [13] AbbreviatedAxisSpecifier ::= '@'?
9906  *
9907  * Modified for XPtr range support as:
9908  *
9909  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
9910  *                     | AbbreviatedStep
9911  *                     | 'range-to' '(' Expr ')' Predicate*
9912  *
9913  * Compile one step in a Location Path
9914  * A location step of . is short for self::node(). This is
9915  * particularly useful in conjunction with //. For example, the
9916  * location path .//para is short for
9917  * self::node()/descendant-or-self::node()/child::para
9918  * and so will select all para descendant elements of the context
9919  * node.
9920  * Similarly, a location step of .. is short for parent::node().
9921  * For example, ../title is short for parent::node()/child::title
9922  * and so will select the title children of the parent of the context
9923  * node.
9924  */
9925 static void
xmlXPathCompStep(xmlXPathParserContextPtr ctxt)9926 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
9927     SKIP_BLANKS;
9928     if ((CUR == '.') && (NXT(1) == '.')) {
9929 	SKIP(2);
9930 	SKIP_BLANKS;
9931 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
9932 		    NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9933     } else if (CUR == '.') {
9934 	NEXT;
9935 	SKIP_BLANKS;
9936     } else {
9937 	xmlChar *name = NULL;
9938 	xmlChar *prefix = NULL;
9939 	xmlXPathTestVal test = (xmlXPathTestVal) 0;
9940 	xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
9941 	xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
9942 	int op1;
9943 
9944 	if (CUR == '*') {
9945 	    axis = AXIS_CHILD;
9946 	} else {
9947 	    if (name == NULL)
9948 		name = xmlXPathParseNCName(ctxt);
9949 	    if (name != NULL) {
9950 		axis = xmlXPathIsAxisName(name);
9951 		if (axis != 0) {
9952 		    SKIP_BLANKS;
9953 		    if ((CUR == ':') && (NXT(1) == ':')) {
9954 			SKIP(2);
9955 			xmlFree(name);
9956 			name = NULL;
9957 		    } else {
9958 			/* an element name can conflict with an axis one :-\ */
9959 			axis = AXIS_CHILD;
9960 		    }
9961 		} else {
9962 		    axis = AXIS_CHILD;
9963 		}
9964 	    } else if (CUR == '@') {
9965 		NEXT;
9966 		axis = AXIS_ATTRIBUTE;
9967 	    } else {
9968 		axis = AXIS_CHILD;
9969 	    }
9970 	}
9971 
9972         if (ctxt->error != XPATH_EXPRESSION_OK) {
9973             xmlFree(name);
9974             return;
9975         }
9976 
9977 	name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
9978 	if (test == 0)
9979 	    return;
9980 
9981         if ((prefix != NULL) && (ctxt->context != NULL) &&
9982 	    (ctxt->context->flags & XML_XPATH_CHECKNS)) {
9983 	    if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
9984 		xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
9985 	    }
9986 	}
9987 
9988 	op1 = ctxt->comp->last;
9989 	ctxt->comp->last = -1;
9990 
9991 	SKIP_BLANKS;
9992 	while (CUR == '[') {
9993 	    xmlXPathCompPredicate(ctxt, 0);
9994 	}
9995 
9996         if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
9997                            test, type, (void *)prefix, (void *)name) == -1) {
9998             xmlFree(prefix);
9999             xmlFree(name);
10000         }
10001     }
10002 }
10003 
10004 /**
10005  * xmlXPathCompRelativeLocationPath:
10006  * @ctxt:  the XPath Parser context
10007  *
10008  *  [3]   RelativeLocationPath ::=   Step
10009  *                     | RelativeLocationPath '/' Step
10010  *                     | AbbreviatedRelativeLocationPath
10011  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
10012  *
10013  * Compile a relative location path.
10014  */
10015 static void
xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt)10016 xmlXPathCompRelativeLocationPath
10017 (xmlXPathParserContextPtr ctxt) {
10018     SKIP_BLANKS;
10019     if ((CUR == '/') && (NXT(1) == '/')) {
10020 	SKIP(2);
10021 	SKIP_BLANKS;
10022 	PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10023 		         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10024     } else if (CUR == '/') {
10025 	    NEXT;
10026 	SKIP_BLANKS;
10027     }
10028     xmlXPathCompStep(ctxt);
10029     CHECK_ERROR;
10030     SKIP_BLANKS;
10031     while (CUR == '/') {
10032 	if ((CUR == '/') && (NXT(1) == '/')) {
10033 	    SKIP(2);
10034 	    SKIP_BLANKS;
10035 	    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10036 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10037 	    xmlXPathCompStep(ctxt);
10038 	} else if (CUR == '/') {
10039 	    NEXT;
10040 	    SKIP_BLANKS;
10041 	    xmlXPathCompStep(ctxt);
10042 	}
10043 	SKIP_BLANKS;
10044     }
10045 }
10046 
10047 /**
10048  * xmlXPathCompLocationPath:
10049  * @ctxt:  the XPath Parser context
10050  *
10051  *  [1]   LocationPath ::=   RelativeLocationPath
10052  *                     | AbsoluteLocationPath
10053  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
10054  *                     | AbbreviatedAbsoluteLocationPath
10055  *  [10]   AbbreviatedAbsoluteLocationPath ::=
10056  *                           '//' RelativeLocationPath
10057  *
10058  * Compile a location path
10059  *
10060  * // is short for /descendant-or-self::node()/. For example,
10061  * //para is short for /descendant-or-self::node()/child::para and
10062  * so will select any para element in the document (even a para element
10063  * that is a document element will be selected by //para since the
10064  * document element node is a child of the root node); div//para is
10065  * short for div/descendant-or-self::node()/child::para and so will
10066  * select all para descendants of div children.
10067  */
10068 static void
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt)10069 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
10070     SKIP_BLANKS;
10071     if (CUR != '/') {
10072         xmlXPathCompRelativeLocationPath(ctxt);
10073     } else {
10074 	while (CUR == '/') {
10075 	    if ((CUR == '/') && (NXT(1) == '/')) {
10076 		SKIP(2);
10077 		SKIP_BLANKS;
10078 		PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10079 			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10080 		xmlXPathCompRelativeLocationPath(ctxt);
10081 	    } else if (CUR == '/') {
10082 		NEXT;
10083 		SKIP_BLANKS;
10084 		if ((CUR != 0 ) &&
10085 		    ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
10086 		     (CUR == '@') || (CUR == '*')))
10087 		    xmlXPathCompRelativeLocationPath(ctxt);
10088 	    }
10089 	    CHECK_ERROR;
10090 	}
10091     }
10092 }
10093 
10094 /************************************************************************
10095  *									*
10096  *		XPath precompiled expression evaluation			*
10097  *									*
10098  ************************************************************************/
10099 
10100 static int
10101 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
10102 
10103 /**
10104  * xmlXPathNodeSetFilter:
10105  * @ctxt:  the XPath Parser context
10106  * @set: the node set to filter
10107  * @filterOpIndex: the index of the predicate/filter op
10108  * @minPos: minimum position in the filtered set (1-based)
10109  * @maxPos: maximum position in the filtered set (1-based)
10110  * @hasNsNodes: true if the node set may contain namespace nodes
10111  *
10112  * Filter a node set, keeping only nodes for which the predicate expression
10113  * matches. Afterwards, keep only nodes between minPos and maxPos in the
10114  * filtered result.
10115  */
10116 static void
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,xmlNodeSetPtr set,int filterOpIndex,int minPos,int maxPos,int hasNsNodes)10117 xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
10118 		      xmlNodeSetPtr set,
10119 		      int filterOpIndex,
10120                       int minPos, int maxPos,
10121 		      int hasNsNodes)
10122 {
10123     xmlXPathContextPtr xpctxt;
10124     xmlNodePtr oldnode;
10125     xmlDocPtr olddoc;
10126     xmlXPathStepOpPtr filterOp;
10127     int oldcs, oldpp;
10128     int i, j, pos;
10129 
10130     if ((set == NULL) || (set->nodeNr == 0))
10131         return;
10132 
10133     /*
10134     * Check if the node set contains a sufficient number of nodes for
10135     * the requested range.
10136     */
10137     if (set->nodeNr < minPos) {
10138         xmlXPathNodeSetClear(set, hasNsNodes);
10139         return;
10140     }
10141 
10142     xpctxt = ctxt->context;
10143     oldnode = xpctxt->node;
10144     olddoc = xpctxt->doc;
10145     oldcs = xpctxt->contextSize;
10146     oldpp = xpctxt->proximityPosition;
10147     filterOp = &ctxt->comp->steps[filterOpIndex];
10148 
10149     xpctxt->contextSize = set->nodeNr;
10150 
10151     for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
10152         xmlNodePtr node = set->nodeTab[i];
10153         int res;
10154 
10155         xpctxt->node = node;
10156         xpctxt->proximityPosition = i + 1;
10157 
10158         /*
10159         * Also set the xpath document in case things like
10160         * key() are evaluated in the predicate.
10161         *
10162         * TODO: Get real doc for namespace nodes.
10163         */
10164         if ((node->type != XML_NAMESPACE_DECL) &&
10165             (node->doc != NULL))
10166             xpctxt->doc = node->doc;
10167 
10168         res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
10169 
10170         if (ctxt->error != XPATH_EXPRESSION_OK)
10171             break;
10172         if (res < 0) {
10173             /* Shouldn't happen */
10174             xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
10175             break;
10176         }
10177 
10178         if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
10179             if (i != j) {
10180                 set->nodeTab[j] = node;
10181                 set->nodeTab[i] = NULL;
10182             }
10183 
10184             j += 1;
10185         } else {
10186             /* Remove the entry from the initial node set. */
10187             set->nodeTab[i] = NULL;
10188             if (node->type == XML_NAMESPACE_DECL)
10189                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10190         }
10191 
10192         if (res != 0) {
10193             if (pos == maxPos) {
10194                 i += 1;
10195                 break;
10196             }
10197 
10198             pos += 1;
10199         }
10200     }
10201 
10202     /* Free remaining nodes. */
10203     if (hasNsNodes) {
10204         for (; i < set->nodeNr; i++) {
10205             xmlNodePtr node = set->nodeTab[i];
10206             if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
10207                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10208         }
10209     }
10210 
10211     set->nodeNr = j;
10212 
10213     /* If too many elements were removed, shrink table to preserve memory. */
10214     if ((set->nodeMax > XML_NODESET_DEFAULT) &&
10215         (set->nodeNr < set->nodeMax / 2)) {
10216         xmlNodePtr *tmp;
10217         int nodeMax = set->nodeNr;
10218 
10219         if (nodeMax < XML_NODESET_DEFAULT)
10220             nodeMax = XML_NODESET_DEFAULT;
10221         tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
10222                 nodeMax * sizeof(xmlNodePtr));
10223         if (tmp == NULL) {
10224             xmlXPathPErrMemory(ctxt);
10225         } else {
10226             set->nodeTab = tmp;
10227             set->nodeMax = nodeMax;
10228         }
10229     }
10230 
10231     xpctxt->node = oldnode;
10232     xpctxt->doc = olddoc;
10233     xpctxt->contextSize = oldcs;
10234     xpctxt->proximityPosition = oldpp;
10235 }
10236 
10237 /**
10238  * xmlXPathCompOpEvalPredicate:
10239  * @ctxt:  the XPath Parser context
10240  * @op: the predicate op
10241  * @set: the node set to filter
10242  * @minPos: minimum position in the filtered set (1-based)
10243  * @maxPos: maximum position in the filtered set (1-based)
10244  * @hasNsNodes: true if the node set may contain namespace nodes
10245  *
10246  * Filter a node set, keeping only nodes for which the sequence of predicate
10247  * expressions matches. Afterwards, keep only nodes between minPos and maxPos
10248  * in the filtered result.
10249  */
10250 static void
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int minPos,int maxPos,int hasNsNodes)10251 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
10252 			    xmlXPathStepOpPtr op,
10253 			    xmlNodeSetPtr set,
10254                             int minPos, int maxPos,
10255 			    int hasNsNodes)
10256 {
10257     if (op->ch1 != -1) {
10258 	xmlXPathCompExprPtr comp = ctxt->comp;
10259 	/*
10260 	* Process inner predicates first.
10261 	*/
10262 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
10263             XP_ERROR(XPATH_INVALID_OPERAND);
10264 	}
10265         if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10266             XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10267         ctxt->context->depth += 1;
10268 	xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
10269                                     1, set->nodeNr, hasNsNodes);
10270         ctxt->context->depth -= 1;
10271 	CHECK_ERROR;
10272     }
10273 
10274     if (op->ch2 != -1)
10275         xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
10276 }
10277 
10278 static int
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int * maxPos)10279 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
10280 			    xmlXPathStepOpPtr op,
10281 			    int *maxPos)
10282 {
10283 
10284     xmlXPathStepOpPtr exprOp;
10285 
10286     /*
10287     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
10288     */
10289 
10290     /*
10291     * If not -1, then ch1 will point to:
10292     * 1) For predicates (XPATH_OP_PREDICATE):
10293     *    - an inner predicate operator
10294     * 2) For filters (XPATH_OP_FILTER):
10295     *    - an inner filter operator OR
10296     *    - an expression selecting the node set.
10297     *      E.g. "key('a', 'b')" or "(//foo | //bar)".
10298     */
10299     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
10300 	return(0);
10301 
10302     if (op->ch2 != -1) {
10303 	exprOp = &ctxt->comp->steps[op->ch2];
10304     } else
10305 	return(0);
10306 
10307     if ((exprOp != NULL) &&
10308 	(exprOp->op == XPATH_OP_VALUE) &&
10309 	(exprOp->value4 != NULL) &&
10310 	(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
10311     {
10312         double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
10313 
10314 	/*
10315 	* We have a "[n]" predicate here.
10316 	* TODO: Unfortunately this simplistic test here is not
10317 	* able to detect a position() predicate in compound
10318 	* expressions like "[@attr = 'a" and position() = 1],
10319 	* and even not the usage of position() in
10320 	* "[position() = 1]"; thus - obviously - a position-range,
10321 	* like it "[position() < 5]", is also not detected.
10322 	* Maybe we could rewrite the AST to ease the optimization.
10323 	*/
10324 
10325         if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
10326 	    *maxPos = (int) floatval;
10327             if (floatval == (double) *maxPos)
10328                 return(1);
10329         }
10330     }
10331     return(0);
10332 }
10333 
10334 static int
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first,xmlNodePtr * last,int toBool)10335 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
10336                            xmlXPathStepOpPtr op,
10337 			   xmlNodePtr * first, xmlNodePtr * last,
10338 			   int toBool)
10339 {
10340 
10341 #define XP_TEST_HIT \
10342     if (hasAxisRange != 0) { \
10343 	if (++pos == maxPos) { \
10344 	    if (addNode(seq, cur) < 0) \
10345 	        xmlXPathPErrMemory(ctxt); \
10346 	    goto axis_range_end; } \
10347     } else { \
10348 	if (addNode(seq, cur) < 0) \
10349 	    xmlXPathPErrMemory(ctxt); \
10350 	if (breakOnFirstHit) goto first_hit; }
10351 
10352 #define XP_TEST_HIT_NS \
10353     if (hasAxisRange != 0) { \
10354 	if (++pos == maxPos) { \
10355 	    hasNsNodes = 1; \
10356 	    if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
10357 	        xmlXPathPErrMemory(ctxt); \
10358 	goto axis_range_end; } \
10359     } else { \
10360 	hasNsNodes = 1; \
10361 	if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
10362 	    xmlXPathPErrMemory(ctxt); \
10363 	if (breakOnFirstHit) goto first_hit; }
10364 
10365     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
10366     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
10367     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
10368     const xmlChar *prefix = op->value4;
10369     const xmlChar *name = op->value5;
10370     const xmlChar *URI = NULL;
10371 
10372     int total = 0, hasNsNodes = 0;
10373     /* The popped object holding the context nodes */
10374     xmlXPathObjectPtr obj;
10375     /* The set of context nodes for the node tests */
10376     xmlNodeSetPtr contextSeq;
10377     int contextIdx;
10378     xmlNodePtr contextNode;
10379     /* The final resulting node set wrt to all context nodes */
10380     xmlNodeSetPtr outSeq;
10381     /*
10382     * The temporary resulting node set wrt 1 context node.
10383     * Used to feed predicate evaluation.
10384     */
10385     xmlNodeSetPtr seq;
10386     xmlNodePtr cur;
10387     /* First predicate operator */
10388     xmlXPathStepOpPtr predOp;
10389     int maxPos; /* The requested position() (when a "[n]" predicate) */
10390     int hasPredicateRange, hasAxisRange, pos;
10391     int breakOnFirstHit;
10392 
10393     xmlXPathTraversalFunction next = NULL;
10394     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
10395     xmlXPathNodeSetMergeFunction mergeAndClear;
10396     xmlNodePtr oldContextNode;
10397     xmlXPathContextPtr xpctxt = ctxt->context;
10398 
10399 
10400     CHECK_TYPE0(XPATH_NODESET);
10401     obj = valuePop(ctxt);
10402     /*
10403     * Setup namespaces.
10404     */
10405     if (prefix != NULL) {
10406         URI = xmlXPathNsLookup(xpctxt, prefix);
10407         if (URI == NULL) {
10408 	    xmlXPathReleaseObject(xpctxt, obj);
10409             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10410 	}
10411     }
10412     /*
10413     * Setup axis.
10414     *
10415     * MAYBE FUTURE TODO: merging optimizations:
10416     * - If the nodes to be traversed wrt to the initial nodes and
10417     *   the current axis cannot overlap, then we could avoid searching
10418     *   for duplicates during the merge.
10419     *   But the question is how/when to evaluate if they cannot overlap.
10420     *   Example: if we know that for two initial nodes, the one is
10421     *   not in the ancestor-or-self axis of the other, then we could safely
10422     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
10423     *   the descendant-or-self axis.
10424     */
10425     mergeAndClear = xmlXPathNodeSetMergeAndClear;
10426     switch (axis) {
10427         case AXIS_ANCESTOR:
10428             first = NULL;
10429             next = xmlXPathNextAncestor;
10430             break;
10431         case AXIS_ANCESTOR_OR_SELF:
10432             first = NULL;
10433             next = xmlXPathNextAncestorOrSelf;
10434             break;
10435         case AXIS_ATTRIBUTE:
10436             first = NULL;
10437 	    last = NULL;
10438             next = xmlXPathNextAttribute;
10439 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10440             break;
10441         case AXIS_CHILD:
10442 	    last = NULL;
10443 	    if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
10444 		(type == NODE_TYPE_NODE))
10445 	    {
10446 		/*
10447 		* Optimization if an element node type is 'element'.
10448 		*/
10449 		next = xmlXPathNextChildElement;
10450 	    } else
10451 		next = xmlXPathNextChild;
10452 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10453             break;
10454         case AXIS_DESCENDANT:
10455 	    last = NULL;
10456             next = xmlXPathNextDescendant;
10457             break;
10458         case AXIS_DESCENDANT_OR_SELF:
10459 	    last = NULL;
10460             next = xmlXPathNextDescendantOrSelf;
10461             break;
10462         case AXIS_FOLLOWING:
10463 	    last = NULL;
10464             next = xmlXPathNextFollowing;
10465             break;
10466         case AXIS_FOLLOWING_SIBLING:
10467 	    last = NULL;
10468             next = xmlXPathNextFollowingSibling;
10469             break;
10470         case AXIS_NAMESPACE:
10471             first = NULL;
10472 	    last = NULL;
10473             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
10474 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10475             break;
10476         case AXIS_PARENT:
10477             first = NULL;
10478             next = xmlXPathNextParent;
10479             break;
10480         case AXIS_PRECEDING:
10481             first = NULL;
10482             next = xmlXPathNextPrecedingInternal;
10483             break;
10484         case AXIS_PRECEDING_SIBLING:
10485             first = NULL;
10486             next = xmlXPathNextPrecedingSibling;
10487             break;
10488         case AXIS_SELF:
10489             first = NULL;
10490 	    last = NULL;
10491             next = xmlXPathNextSelf;
10492 	    mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10493             break;
10494     }
10495 
10496     if (next == NULL) {
10497 	xmlXPathReleaseObject(xpctxt, obj);
10498         return(0);
10499     }
10500     contextSeq = obj->nodesetval;
10501     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
10502         valuePush(ctxt, obj);
10503         return(0);
10504     }
10505     /*
10506     * Predicate optimization ---------------------------------------------
10507     * If this step has a last predicate, which contains a position(),
10508     * then we'll optimize (although not exactly "position()", but only
10509     * the  short-hand form, i.e., "[n]".
10510     *
10511     * Example - expression "/foo[parent::bar][1]":
10512     *
10513     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
10514     *   ROOT                               -- op->ch1
10515     *   PREDICATE                          -- op->ch2 (predOp)
10516     *     PREDICATE                          -- predOp->ch1 = [parent::bar]
10517     *       SORT
10518     *         COLLECT  'parent' 'name' 'node' bar
10519     *           NODE
10520     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
10521     *
10522     */
10523     maxPos = 0;
10524     predOp = NULL;
10525     hasPredicateRange = 0;
10526     hasAxisRange = 0;
10527     if (op->ch2 != -1) {
10528 	/*
10529 	* There's at least one predicate. 16 == XPATH_OP_PREDICATE
10530 	*/
10531 	predOp = &ctxt->comp->steps[op->ch2];
10532 	if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
10533 	    if (predOp->ch1 != -1) {
10534 		/*
10535 		* Use the next inner predicate operator.
10536 		*/
10537 		predOp = &ctxt->comp->steps[predOp->ch1];
10538 		hasPredicateRange = 1;
10539 	    } else {
10540 		/*
10541 		* There's no other predicate than the [n] predicate.
10542 		*/
10543 		predOp = NULL;
10544 		hasAxisRange = 1;
10545 	    }
10546 	}
10547     }
10548     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
10549     /*
10550     * Axis traversal -----------------------------------------------------
10551     */
10552     /*
10553      * 2.3 Node Tests
10554      *  - For the attribute axis, the principal node type is attribute.
10555      *  - For the namespace axis, the principal node type is namespace.
10556      *  - For other axes, the principal node type is element.
10557      *
10558      * A node test * is true for any node of the
10559      * principal node type. For example, child::* will
10560      * select all element children of the context node
10561      */
10562     oldContextNode = xpctxt->node;
10563     addNode = xmlXPathNodeSetAddUnique;
10564     outSeq = NULL;
10565     seq = NULL;
10566     contextNode = NULL;
10567     contextIdx = 0;
10568 
10569 
10570     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
10571            (ctxt->error == XPATH_EXPRESSION_OK)) {
10572 	xpctxt->node = contextSeq->nodeTab[contextIdx++];
10573 
10574 	if (seq == NULL) {
10575 	    seq = xmlXPathNodeSetCreate(NULL);
10576 	    if (seq == NULL) {
10577                 xmlXPathPErrMemory(ctxt);
10578 		total = 0;
10579 		goto error;
10580 	    }
10581 	}
10582 	/*
10583 	* Traverse the axis and test the nodes.
10584 	*/
10585 	pos = 0;
10586 	cur = NULL;
10587 	hasNsNodes = 0;
10588         do {
10589             if (OP_LIMIT_EXCEEDED(ctxt, 1))
10590                 goto error;
10591 
10592             cur = next(ctxt, cur);
10593             if (cur == NULL)
10594                 break;
10595 
10596 	    /*
10597 	    * QUESTION TODO: What does the "first" and "last" stuff do?
10598 	    */
10599             if ((first != NULL) && (*first != NULL)) {
10600 		if (*first == cur)
10601 		    break;
10602 		if (((total % 256) == 0) &&
10603 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10604 		    (xmlXPathCmpNodesExt(*first, cur) >= 0))
10605 #else
10606 		    (xmlXPathCmpNodes(*first, cur) >= 0))
10607 #endif
10608 		{
10609 		    break;
10610 		}
10611 	    }
10612 	    if ((last != NULL) && (*last != NULL)) {
10613 		if (*last == cur)
10614 		    break;
10615 		if (((total % 256) == 0) &&
10616 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10617 		    (xmlXPathCmpNodesExt(cur, *last) >= 0))
10618 #else
10619 		    (xmlXPathCmpNodes(cur, *last) >= 0))
10620 #endif
10621 		{
10622 		    break;
10623 		}
10624 	    }
10625 
10626             total++;
10627 
10628 	    switch (test) {
10629                 case NODE_TEST_NONE:
10630 		    total = 0;
10631 		    goto error;
10632                 case NODE_TEST_TYPE:
10633 		    if (type == NODE_TYPE_NODE) {
10634 			switch (cur->type) {
10635 			    case XML_DOCUMENT_NODE:
10636 			    case XML_HTML_DOCUMENT_NODE:
10637 			    case XML_ELEMENT_NODE:
10638 			    case XML_ATTRIBUTE_NODE:
10639 			    case XML_PI_NODE:
10640 			    case XML_COMMENT_NODE:
10641 			    case XML_CDATA_SECTION_NODE:
10642 			    case XML_TEXT_NODE:
10643 				XP_TEST_HIT
10644 				break;
10645 			    case XML_NAMESPACE_DECL: {
10646 				if (axis == AXIS_NAMESPACE) {
10647 				    XP_TEST_HIT_NS
10648 				} else {
10649 	                            hasNsNodes = 1;
10650 				    XP_TEST_HIT
10651 				}
10652 				break;
10653                             }
10654 			    default:
10655 				break;
10656 			}
10657 		    } else if (cur->type == (xmlElementType) type) {
10658 			if (cur->type == XML_NAMESPACE_DECL)
10659 			    XP_TEST_HIT_NS
10660 			else
10661 			    XP_TEST_HIT
10662 		    } else if ((type == NODE_TYPE_TEXT) &&
10663 			 (cur->type == XML_CDATA_SECTION_NODE))
10664 		    {
10665 			XP_TEST_HIT
10666 		    }
10667 		    break;
10668                 case NODE_TEST_PI:
10669                     if ((cur->type == XML_PI_NODE) &&
10670                         ((name == NULL) || xmlStrEqual(name, cur->name)))
10671 		    {
10672 			XP_TEST_HIT
10673                     }
10674                     break;
10675                 case NODE_TEST_ALL:
10676                     if (axis == AXIS_ATTRIBUTE) {
10677                         if (cur->type == XML_ATTRIBUTE_NODE)
10678 			{
10679                             if (prefix == NULL)
10680 			    {
10681 				XP_TEST_HIT
10682                             } else if ((cur->ns != NULL) &&
10683 				(xmlStrEqual(URI, cur->ns->href)))
10684 			    {
10685 				XP_TEST_HIT
10686                             }
10687                         }
10688                     } else if (axis == AXIS_NAMESPACE) {
10689                         if (cur->type == XML_NAMESPACE_DECL)
10690 			{
10691 			    XP_TEST_HIT_NS
10692                         }
10693                     } else {
10694                         if (cur->type == XML_ELEMENT_NODE) {
10695                             if (prefix == NULL)
10696 			    {
10697 				XP_TEST_HIT
10698 
10699                             } else if ((cur->ns != NULL) &&
10700 				(xmlStrEqual(URI, cur->ns->href)))
10701 			    {
10702 				XP_TEST_HIT
10703                             }
10704                         }
10705                     }
10706                     break;
10707                 case NODE_TEST_NS:{
10708                         /* TODO */
10709                         break;
10710                     }
10711                 case NODE_TEST_NAME:
10712                     if (axis == AXIS_ATTRIBUTE) {
10713                         if (cur->type != XML_ATTRIBUTE_NODE)
10714 			    break;
10715 		    } else if (axis == AXIS_NAMESPACE) {
10716                         if (cur->type != XML_NAMESPACE_DECL)
10717 			    break;
10718 		    } else {
10719 		        if (cur->type != XML_ELEMENT_NODE)
10720 			    break;
10721 		    }
10722                     switch (cur->type) {
10723                         case XML_ELEMENT_NODE:
10724                             if (xmlStrEqual(name, cur->name)) {
10725                                 if (prefix == NULL) {
10726                                     if (cur->ns == NULL)
10727 				    {
10728 					XP_TEST_HIT
10729                                     }
10730                                 } else {
10731                                     if ((cur->ns != NULL) &&
10732                                         (xmlStrEqual(URI, cur->ns->href)))
10733 				    {
10734 					XP_TEST_HIT
10735                                     }
10736                                 }
10737                             }
10738                             break;
10739                         case XML_ATTRIBUTE_NODE:{
10740                                 xmlAttrPtr attr = (xmlAttrPtr) cur;
10741 
10742                                 if (xmlStrEqual(name, attr->name)) {
10743                                     if (prefix == NULL) {
10744                                         if ((attr->ns == NULL) ||
10745                                             (attr->ns->prefix == NULL))
10746 					{
10747 					    XP_TEST_HIT
10748                                         }
10749                                     } else {
10750                                         if ((attr->ns != NULL) &&
10751                                             (xmlStrEqual(URI,
10752 					      attr->ns->href)))
10753 					{
10754 					    XP_TEST_HIT
10755                                         }
10756                                     }
10757                                 }
10758                                 break;
10759                             }
10760                         case XML_NAMESPACE_DECL:
10761                             if (cur->type == XML_NAMESPACE_DECL) {
10762                                 xmlNsPtr ns = (xmlNsPtr) cur;
10763 
10764                                 if ((ns->prefix != NULL) && (name != NULL)
10765                                     && (xmlStrEqual(ns->prefix, name)))
10766 				{
10767 				    XP_TEST_HIT_NS
10768                                 }
10769                             }
10770                             break;
10771                         default:
10772                             break;
10773                     }
10774                     break;
10775 	    } /* switch(test) */
10776         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
10777 
10778 	goto apply_predicates;
10779 
10780 axis_range_end: /* ----------------------------------------------------- */
10781 	/*
10782 	* We have a "/foo[n]", and position() = n was reached.
10783 	* Note that we can have as well "/foo/::parent::foo[1]", so
10784 	* a duplicate-aware merge is still needed.
10785 	* Merge with the result.
10786 	*/
10787 	if (outSeq == NULL) {
10788 	    outSeq = seq;
10789 	    seq = NULL;
10790 	} else {
10791 	    outSeq = mergeAndClear(outSeq, seq);
10792             if (outSeq == NULL)
10793                 xmlXPathPErrMemory(ctxt);
10794         }
10795 	/*
10796 	* Break if only a true/false result was requested.
10797 	*/
10798 	if (toBool)
10799 	    break;
10800 	continue;
10801 
10802 first_hit: /* ---------------------------------------------------------- */
10803 	/*
10804 	* Break if only a true/false result was requested and
10805 	* no predicates existed and a node test succeeded.
10806 	*/
10807 	if (outSeq == NULL) {
10808 	    outSeq = seq;
10809 	    seq = NULL;
10810 	} else {
10811 	    outSeq = mergeAndClear(outSeq, seq);
10812             if (outSeq == NULL)
10813                 xmlXPathPErrMemory(ctxt);
10814         }
10815 	break;
10816 
10817 apply_predicates: /* --------------------------------------------------- */
10818         if (ctxt->error != XPATH_EXPRESSION_OK)
10819 	    goto error;
10820 
10821         /*
10822 	* Apply predicates.
10823 	*/
10824         if ((predOp != NULL) && (seq->nodeNr > 0)) {
10825 	    /*
10826 	    * E.g. when we have a "/foo[some expression][n]".
10827 	    */
10828 	    /*
10829 	    * QUESTION TODO: The old predicate evaluation took into
10830 	    *  account location-sets.
10831 	    *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
10832 	    *  Do we expect such a set here?
10833 	    *  All what I learned now from the evaluation semantics
10834 	    *  does not indicate that a location-set will be processed
10835 	    *  here, so this looks OK.
10836 	    */
10837 	    /*
10838 	    * Iterate over all predicates, starting with the outermost
10839 	    * predicate.
10840 	    * TODO: Problem: we cannot execute the inner predicates first
10841 	    *  since we cannot go back *up* the operator tree!
10842 	    *  Options we have:
10843 	    *  1) Use of recursive functions (like is it currently done
10844 	    *     via xmlXPathCompOpEval())
10845 	    *  2) Add a predicate evaluation information stack to the
10846 	    *     context struct
10847 	    *  3) Change the way the operators are linked; we need a
10848 	    *     "parent" field on xmlXPathStepOp
10849 	    *
10850 	    * For the moment, I'll try to solve this with a recursive
10851 	    * function: xmlXPathCompOpEvalPredicate().
10852 	    */
10853 	    if (hasPredicateRange != 0)
10854 		xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
10855 					    hasNsNodes);
10856 	    else
10857 		xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
10858 					    hasNsNodes);
10859 
10860 	    if (ctxt->error != XPATH_EXPRESSION_OK) {
10861 		total = 0;
10862 		goto error;
10863 	    }
10864         }
10865 
10866         if (seq->nodeNr > 0) {
10867 	    /*
10868 	    * Add to result set.
10869 	    */
10870 	    if (outSeq == NULL) {
10871 		outSeq = seq;
10872 		seq = NULL;
10873 	    } else {
10874 		outSeq = mergeAndClear(outSeq, seq);
10875                 if (outSeq == NULL)
10876                     xmlXPathPErrMemory(ctxt);
10877 	    }
10878 
10879             if (toBool)
10880                 break;
10881 	}
10882     }
10883 
10884 error:
10885     if ((obj->boolval) && (obj->user != NULL)) {
10886 	/*
10887 	* QUESTION TODO: What does this do and why?
10888 	* TODO: Do we have to do this also for the "error"
10889 	* cleanup further down?
10890 	*/
10891 	ctxt->value->boolval = 1;
10892 	ctxt->value->user = obj->user;
10893 	obj->user = NULL;
10894 	obj->boolval = 0;
10895     }
10896     xmlXPathReleaseObject(xpctxt, obj);
10897 
10898     /*
10899     * Ensure we return at least an empty set.
10900     */
10901     if (outSeq == NULL) {
10902 	if ((seq != NULL) && (seq->nodeNr == 0)) {
10903 	    outSeq = seq;
10904         } else {
10905 	    outSeq = xmlXPathNodeSetCreate(NULL);
10906             if (outSeq == NULL)
10907                 xmlXPathPErrMemory(ctxt);
10908         }
10909     }
10910     if ((seq != NULL) && (seq != outSeq)) {
10911 	 xmlXPathFreeNodeSet(seq);
10912     }
10913     /*
10914     * Hand over the result. Better to push the set also in
10915     * case of errors.
10916     */
10917     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, outSeq));
10918     /*
10919     * Reset the context node.
10920     */
10921     xpctxt->node = oldContextNode;
10922     /*
10923     * When traversing the namespace axis in "toBool" mode, it's
10924     * possible that tmpNsList wasn't freed.
10925     */
10926     if (xpctxt->tmpNsList != NULL) {
10927         xmlFree(xpctxt->tmpNsList);
10928         xpctxt->tmpNsList = NULL;
10929     }
10930 
10931     return(total);
10932 }
10933 
10934 static int
10935 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
10936 			      xmlXPathStepOpPtr op, xmlNodePtr * first);
10937 
10938 /**
10939  * xmlXPathCompOpEvalFirst:
10940  * @ctxt:  the XPath parser context with the compiled expression
10941  * @op:  an XPath compiled operation
10942  * @first:  the first elem found so far
10943  *
10944  * Evaluate the Precompiled XPath operation searching only the first
10945  * element in document order
10946  *
10947  * Returns the number of examined objects.
10948  */
10949 static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)10950 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
10951                         xmlXPathStepOpPtr op, xmlNodePtr * first)
10952 {
10953     int total = 0, cur;
10954     xmlXPathCompExprPtr comp;
10955     xmlXPathObjectPtr arg1, arg2;
10956 
10957     CHECK_ERROR0;
10958     if (OP_LIMIT_EXCEEDED(ctxt, 1))
10959         return(0);
10960     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10961         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10962     ctxt->context->depth += 1;
10963     comp = ctxt->comp;
10964     switch (op->op) {
10965         case XPATH_OP_END:
10966             break;
10967         case XPATH_OP_UNION:
10968             total =
10969                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10970                                         first);
10971 	    CHECK_ERROR0;
10972             if ((ctxt->value != NULL)
10973                 && (ctxt->value->type == XPATH_NODESET)
10974                 && (ctxt->value->nodesetval != NULL)
10975                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10976                 /*
10977                  * limit tree traversing to first node in the result
10978                  */
10979 		/*
10980 		* OPTIMIZE TODO: This implicitly sorts
10981 		*  the result, even if not needed. E.g. if the argument
10982 		*  of the count() function, no sorting is needed.
10983 		* OPTIMIZE TODO: How do we know if the node-list wasn't
10984 		*  already sorted?
10985 		*/
10986 		if (ctxt->value->nodesetval->nodeNr > 1)
10987 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
10988                 *first = ctxt->value->nodesetval->nodeTab[0];
10989             }
10990             cur =
10991                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
10992                                         first);
10993 	    CHECK_ERROR0;
10994 
10995             arg2 = valuePop(ctxt);
10996             arg1 = valuePop(ctxt);
10997             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10998                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10999 	        xmlXPathReleaseObject(ctxt->context, arg1);
11000 	        xmlXPathReleaseObject(ctxt->context, arg2);
11001                 XP_ERROR0(XPATH_INVALID_TYPE);
11002             }
11003             if ((ctxt->context->opLimit != 0) &&
11004                 (((arg1->nodesetval != NULL) &&
11005                   (xmlXPathCheckOpLimit(ctxt,
11006                                         arg1->nodesetval->nodeNr) < 0)) ||
11007                  ((arg2->nodesetval != NULL) &&
11008                   (xmlXPathCheckOpLimit(ctxt,
11009                                         arg2->nodesetval->nodeNr) < 0)))) {
11010 	        xmlXPathReleaseObject(ctxt->context, arg1);
11011 	        xmlXPathReleaseObject(ctxt->context, arg2);
11012                 break;
11013             }
11014 
11015             if ((arg2->nodesetval != NULL) &&
11016                 (arg2->nodesetval->nodeNr != 0)) {
11017                 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11018                                                         arg2->nodesetval);
11019                 if (arg1->nodesetval == NULL)
11020                     xmlXPathPErrMemory(ctxt);
11021             }
11022             valuePush(ctxt, arg1);
11023 	    xmlXPathReleaseObject(ctxt->context, arg2);
11024             total += cur;
11025             break;
11026         case XPATH_OP_ROOT:
11027             xmlXPathRoot(ctxt);
11028             break;
11029         case XPATH_OP_NODE:
11030             if (op->ch1 != -1)
11031                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11032 	    CHECK_ERROR0;
11033             if (op->ch2 != -1)
11034                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11035 	    CHECK_ERROR0;
11036 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11037 		ctxt->context->node));
11038             break;
11039         case XPATH_OP_COLLECT:{
11040                 if (op->ch1 == -1)
11041                     break;
11042 
11043                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11044 		CHECK_ERROR0;
11045 
11046                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
11047                 break;
11048             }
11049         case XPATH_OP_VALUE:
11050             valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11051             break;
11052         case XPATH_OP_SORT:
11053             if (op->ch1 != -1)
11054                 total +=
11055                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11056                                             first);
11057 	    CHECK_ERROR0;
11058             if ((ctxt->value != NULL)
11059                 && (ctxt->value->type == XPATH_NODESET)
11060                 && (ctxt->value->nodesetval != NULL)
11061 		&& (ctxt->value->nodesetval->nodeNr > 1))
11062                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11063             break;
11064 #ifdef XP_OPTIMIZED_FILTER_FIRST
11065 	case XPATH_OP_FILTER:
11066                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
11067             break;
11068 #endif
11069         default:
11070             total += xmlXPathCompOpEval(ctxt, op);
11071             break;
11072     }
11073 
11074     ctxt->context->depth -= 1;
11075     return(total);
11076 }
11077 
11078 /**
11079  * xmlXPathCompOpEvalLast:
11080  * @ctxt:  the XPath parser context with the compiled expression
11081  * @op:  an XPath compiled operation
11082  * @last:  the last elem found so far
11083  *
11084  * Evaluate the Precompiled XPath operation searching only the last
11085  * element in document order
11086  *
11087  * Returns the number of nodes traversed
11088  */
11089 static int
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * last)11090 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
11091                        xmlNodePtr * last)
11092 {
11093     int total = 0, cur;
11094     xmlXPathCompExprPtr comp;
11095     xmlXPathObjectPtr arg1, arg2;
11096 
11097     CHECK_ERROR0;
11098     if (OP_LIMIT_EXCEEDED(ctxt, 1))
11099         return(0);
11100     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11101         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11102     ctxt->context->depth += 1;
11103     comp = ctxt->comp;
11104     switch (op->op) {
11105         case XPATH_OP_END:
11106             break;
11107         case XPATH_OP_UNION:
11108             total =
11109                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
11110 	    CHECK_ERROR0;
11111             if ((ctxt->value != NULL)
11112                 && (ctxt->value->type == XPATH_NODESET)
11113                 && (ctxt->value->nodesetval != NULL)
11114                 && (ctxt->value->nodesetval->nodeNr >= 1)) {
11115                 /*
11116                  * limit tree traversing to first node in the result
11117                  */
11118 		if (ctxt->value->nodesetval->nodeNr > 1)
11119 		    xmlXPathNodeSetSort(ctxt->value->nodesetval);
11120                 *last =
11121                     ctxt->value->nodesetval->nodeTab[ctxt->value->
11122                                                      nodesetval->nodeNr -
11123                                                      1];
11124             }
11125             cur =
11126                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
11127 	    CHECK_ERROR0;
11128             if ((ctxt->value != NULL)
11129                 && (ctxt->value->type == XPATH_NODESET)
11130                 && (ctxt->value->nodesetval != NULL)
11131                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
11132             }
11133 
11134             arg2 = valuePop(ctxt);
11135             arg1 = valuePop(ctxt);
11136             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11137                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11138 	        xmlXPathReleaseObject(ctxt->context, arg1);
11139 	        xmlXPathReleaseObject(ctxt->context, arg2);
11140                 XP_ERROR0(XPATH_INVALID_TYPE);
11141             }
11142             if ((ctxt->context->opLimit != 0) &&
11143                 (((arg1->nodesetval != NULL) &&
11144                   (xmlXPathCheckOpLimit(ctxt,
11145                                         arg1->nodesetval->nodeNr) < 0)) ||
11146                  ((arg2->nodesetval != NULL) &&
11147                   (xmlXPathCheckOpLimit(ctxt,
11148                                         arg2->nodesetval->nodeNr) < 0)))) {
11149 	        xmlXPathReleaseObject(ctxt->context, arg1);
11150 	        xmlXPathReleaseObject(ctxt->context, arg2);
11151                 break;
11152             }
11153 
11154             if ((arg2->nodesetval != NULL) &&
11155                 (arg2->nodesetval->nodeNr != 0)) {
11156                 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11157                                                         arg2->nodesetval);
11158                 if (arg1->nodesetval == NULL)
11159                     xmlXPathPErrMemory(ctxt);
11160             }
11161             valuePush(ctxt, arg1);
11162 	    xmlXPathReleaseObject(ctxt->context, arg2);
11163             total += cur;
11164             break;
11165         case XPATH_OP_ROOT:
11166             xmlXPathRoot(ctxt);
11167             break;
11168         case XPATH_OP_NODE:
11169             if (op->ch1 != -1)
11170                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11171 	    CHECK_ERROR0;
11172             if (op->ch2 != -1)
11173                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11174 	    CHECK_ERROR0;
11175 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11176 		ctxt->context->node));
11177             break;
11178         case XPATH_OP_COLLECT:{
11179                 if (op->ch1 == -1)
11180                     break;
11181 
11182                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11183 		CHECK_ERROR0;
11184 
11185                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
11186                 break;
11187             }
11188         case XPATH_OP_VALUE:
11189             valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11190             break;
11191         case XPATH_OP_SORT:
11192             if (op->ch1 != -1)
11193                 total +=
11194                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
11195                                            last);
11196 	    CHECK_ERROR0;
11197             if ((ctxt->value != NULL)
11198                 && (ctxt->value->type == XPATH_NODESET)
11199                 && (ctxt->value->nodesetval != NULL)
11200 		&& (ctxt->value->nodesetval->nodeNr > 1))
11201                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11202             break;
11203         default:
11204             total += xmlXPathCompOpEval(ctxt, op);
11205             break;
11206     }
11207 
11208     ctxt->context->depth -= 1;
11209     return (total);
11210 }
11211 
11212 #ifdef XP_OPTIMIZED_FILTER_FIRST
11213 static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)11214 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11215 			      xmlXPathStepOpPtr op, xmlNodePtr * first)
11216 {
11217     int total = 0;
11218     xmlXPathCompExprPtr comp;
11219     xmlXPathObjectPtr obj;
11220     xmlNodeSetPtr set;
11221 
11222     CHECK_ERROR0;
11223     comp = ctxt->comp;
11224     /*
11225     * Optimization for ()[last()] selection i.e. the last elem
11226     */
11227     if ((op->ch1 != -1) && (op->ch2 != -1) &&
11228 	(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11229 	(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11230 	int f = comp->steps[op->ch2].ch1;
11231 
11232 	if ((f != -1) &&
11233 	    (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11234 	    (comp->steps[f].value5 == NULL) &&
11235 	    (comp->steps[f].value == 0) &&
11236 	    (comp->steps[f].value4 != NULL) &&
11237 	    (xmlStrEqual
11238 	    (comp->steps[f].value4, BAD_CAST "last"))) {
11239 	    xmlNodePtr last = NULL;
11240 
11241 	    total +=
11242 		xmlXPathCompOpEvalLast(ctxt,
11243 		    &comp->steps[op->ch1],
11244 		    &last);
11245 	    CHECK_ERROR0;
11246 	    /*
11247 	    * The nodeset should be in document order,
11248 	    * Keep only the last value
11249 	    */
11250 	    if ((ctxt->value != NULL) &&
11251 		(ctxt->value->type == XPATH_NODESET) &&
11252 		(ctxt->value->nodesetval != NULL) &&
11253 		(ctxt->value->nodesetval->nodeTab != NULL) &&
11254 		(ctxt->value->nodesetval->nodeNr > 1)) {
11255                 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11256 		*first = *(ctxt->value->nodesetval->nodeTab);
11257 	    }
11258 	    return (total);
11259 	}
11260     }
11261 
11262     if (op->ch1 != -1)
11263 	total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11264     CHECK_ERROR0;
11265     if (op->ch2 == -1)
11266 	return (total);
11267     if (ctxt->value == NULL)
11268 	return (total);
11269 
11270     /*
11271      * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
11272      * the stack. We have to temporarily remove the nodeset object from the
11273      * stack to avoid freeing it prematurely.
11274      */
11275     CHECK_TYPE0(XPATH_NODESET);
11276     obj = valuePop(ctxt);
11277     set = obj->nodesetval;
11278     if (set != NULL) {
11279         xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
11280         if (set->nodeNr > 0)
11281             *first = set->nodeTab[0];
11282     }
11283     valuePush(ctxt, obj);
11284 
11285     return (total);
11286 }
11287 #endif /* XP_OPTIMIZED_FILTER_FIRST */
11288 
11289 /**
11290  * xmlXPathCompOpEval:
11291  * @ctxt:  the XPath parser context with the compiled expression
11292  * @op:  an XPath compiled operation
11293  *
11294  * Evaluate the Precompiled XPath operation
11295  * Returns the number of nodes traversed
11296  */
11297 static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op)11298 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
11299 {
11300     int total = 0;
11301     int equal, ret;
11302     xmlXPathCompExprPtr comp;
11303     xmlXPathObjectPtr arg1, arg2;
11304 
11305     CHECK_ERROR0;
11306     if (OP_LIMIT_EXCEEDED(ctxt, 1))
11307         return(0);
11308     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11309         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11310     ctxt->context->depth += 1;
11311     comp = ctxt->comp;
11312     switch (op->op) {
11313         case XPATH_OP_END:
11314             break;
11315         case XPATH_OP_AND:
11316             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11317 	    CHECK_ERROR0;
11318             xmlXPathBooleanFunction(ctxt, 1);
11319             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
11320                 break;
11321             arg2 = valuePop(ctxt);
11322             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11323 	    if (ctxt->error) {
11324 		xmlXPathFreeObject(arg2);
11325 		break;
11326 	    }
11327             xmlXPathBooleanFunction(ctxt, 1);
11328             if (ctxt->value != NULL)
11329                 ctxt->value->boolval &= arg2->boolval;
11330 	    xmlXPathReleaseObject(ctxt->context, arg2);
11331             break;
11332         case XPATH_OP_OR:
11333             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11334 	    CHECK_ERROR0;
11335             xmlXPathBooleanFunction(ctxt, 1);
11336             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
11337                 break;
11338             arg2 = valuePop(ctxt);
11339             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11340 	    if (ctxt->error) {
11341 		xmlXPathFreeObject(arg2);
11342 		break;
11343 	    }
11344             xmlXPathBooleanFunction(ctxt, 1);
11345             if (ctxt->value != NULL)
11346                 ctxt->value->boolval |= arg2->boolval;
11347 	    xmlXPathReleaseObject(ctxt->context, arg2);
11348             break;
11349         case XPATH_OP_EQUAL:
11350             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11351 	    CHECK_ERROR0;
11352             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11353 	    CHECK_ERROR0;
11354 	    if (op->value)
11355 		equal = xmlXPathEqualValues(ctxt);
11356 	    else
11357 		equal = xmlXPathNotEqualValues(ctxt);
11358 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, equal));
11359             break;
11360         case XPATH_OP_CMP:
11361             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11362 	    CHECK_ERROR0;
11363             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11364 	    CHECK_ERROR0;
11365             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
11366 	    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
11367             break;
11368         case XPATH_OP_PLUS:
11369             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11370 	    CHECK_ERROR0;
11371             if (op->ch2 != -1) {
11372                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11373 	    }
11374 	    CHECK_ERROR0;
11375             if (op->value == 0)
11376                 xmlXPathSubValues(ctxt);
11377             else if (op->value == 1)
11378                 xmlXPathAddValues(ctxt);
11379             else if (op->value == 2)
11380                 xmlXPathValueFlipSign(ctxt);
11381             else if (op->value == 3) {
11382                 CAST_TO_NUMBER;
11383                 CHECK_TYPE0(XPATH_NUMBER);
11384             }
11385             break;
11386         case XPATH_OP_MULT:
11387             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11388 	    CHECK_ERROR0;
11389             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11390 	    CHECK_ERROR0;
11391             if (op->value == 0)
11392                 xmlXPathMultValues(ctxt);
11393             else if (op->value == 1)
11394                 xmlXPathDivValues(ctxt);
11395             else if (op->value == 2)
11396                 xmlXPathModValues(ctxt);
11397             break;
11398         case XPATH_OP_UNION:
11399             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11400 	    CHECK_ERROR0;
11401             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11402 	    CHECK_ERROR0;
11403 
11404             arg2 = valuePop(ctxt);
11405             arg1 = valuePop(ctxt);
11406             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11407                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11408 	        xmlXPathReleaseObject(ctxt->context, arg1);
11409 	        xmlXPathReleaseObject(ctxt->context, arg2);
11410                 XP_ERROR0(XPATH_INVALID_TYPE);
11411             }
11412             if ((ctxt->context->opLimit != 0) &&
11413                 (((arg1->nodesetval != NULL) &&
11414                   (xmlXPathCheckOpLimit(ctxt,
11415                                         arg1->nodesetval->nodeNr) < 0)) ||
11416                  ((arg2->nodesetval != NULL) &&
11417                   (xmlXPathCheckOpLimit(ctxt,
11418                                         arg2->nodesetval->nodeNr) < 0)))) {
11419 	        xmlXPathReleaseObject(ctxt->context, arg1);
11420 	        xmlXPathReleaseObject(ctxt->context, arg2);
11421                 break;
11422             }
11423 
11424 	    if (((arg2->nodesetval != NULL) &&
11425 		 (arg2->nodesetval->nodeNr != 0)))
11426 	    {
11427 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11428 							arg2->nodesetval);
11429                 if (arg1->nodesetval == NULL)
11430                     xmlXPathPErrMemory(ctxt);
11431 	    }
11432 
11433             valuePush(ctxt, arg1);
11434 	    xmlXPathReleaseObject(ctxt->context, arg2);
11435             break;
11436         case XPATH_OP_ROOT:
11437             xmlXPathRoot(ctxt);
11438             break;
11439         case XPATH_OP_NODE:
11440             if (op->ch1 != -1)
11441                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11442 	    CHECK_ERROR0;
11443             if (op->ch2 != -1)
11444                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11445 	    CHECK_ERROR0;
11446 	    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11447                                                     ctxt->context->node));
11448             break;
11449         case XPATH_OP_COLLECT:{
11450                 if (op->ch1 == -1)
11451                     break;
11452 
11453                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11454 		CHECK_ERROR0;
11455 
11456                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
11457                 break;
11458             }
11459         case XPATH_OP_VALUE:
11460             valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11461             break;
11462         case XPATH_OP_VARIABLE:{
11463 		xmlXPathObjectPtr val;
11464 
11465                 if (op->ch1 != -1)
11466                     total +=
11467                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11468                 if (op->value5 == NULL) {
11469 		    val = xmlXPathVariableLookup(ctxt->context, op->value4);
11470 		    if (val == NULL)
11471 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
11472                     valuePush(ctxt, val);
11473 		} else {
11474                     const xmlChar *URI;
11475 
11476                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
11477                     if (URI == NULL) {
11478                         XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11479                         break;
11480                     }
11481 		    val = xmlXPathVariableLookupNS(ctxt->context,
11482                                                        op->value4, URI);
11483 		    if (val == NULL)
11484 			XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
11485                     valuePush(ctxt, val);
11486                 }
11487                 break;
11488             }
11489         case XPATH_OP_FUNCTION:{
11490                 xmlXPathFunction func;
11491                 const xmlChar *oldFunc, *oldFuncURI;
11492 		int i;
11493                 int frame;
11494 
11495                 frame = ctxt->valueNr;
11496                 if (op->ch1 != -1) {
11497                     total +=
11498                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11499                     if (ctxt->error != XPATH_EXPRESSION_OK)
11500                         break;
11501                 }
11502 		if (ctxt->valueNr < frame + op->value)
11503 		    XP_ERROR0(XPATH_INVALID_OPERAND);
11504 		for (i = 0; i < op->value; i++) {
11505 		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL)
11506 			XP_ERROR0(XPATH_INVALID_OPERAND);
11507                 }
11508                 if (op->cache != NULL)
11509                     func = op->cache;
11510                 else {
11511                     const xmlChar *URI = NULL;
11512 
11513                     if (op->value5 == NULL)
11514                         func =
11515                             xmlXPathFunctionLookup(ctxt->context,
11516                                                    op->value4);
11517                     else {
11518                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
11519                         if (URI == NULL)
11520                             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11521                         func = xmlXPathFunctionLookupNS(ctxt->context,
11522                                                         op->value4, URI);
11523                     }
11524                     if (func == NULL)
11525                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
11526                     op->cache = func;
11527                     op->cacheURI = (void *) URI;
11528                 }
11529                 oldFunc = ctxt->context->function;
11530                 oldFuncURI = ctxt->context->functionURI;
11531                 ctxt->context->function = op->value4;
11532                 ctxt->context->functionURI = op->cacheURI;
11533                 func(ctxt, op->value);
11534                 ctxt->context->function = oldFunc;
11535                 ctxt->context->functionURI = oldFuncURI;
11536                 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
11537                     (ctxt->valueNr != frame + 1))
11538                     XP_ERROR0(XPATH_STACK_ERROR);
11539                 break;
11540             }
11541         case XPATH_OP_ARG:
11542             if (op->ch1 != -1) {
11543                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11544 	        CHECK_ERROR0;
11545             }
11546             if (op->ch2 != -1) {
11547                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11548 	        CHECK_ERROR0;
11549 	    }
11550             break;
11551         case XPATH_OP_PREDICATE:
11552         case XPATH_OP_FILTER:{
11553                 xmlXPathObjectPtr obj;
11554                 xmlNodeSetPtr set;
11555 
11556                 /*
11557                  * Optimization for ()[1] selection i.e. the first elem
11558                  */
11559                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
11560 #ifdef XP_OPTIMIZED_FILTER_FIRST
11561 		    /*
11562 		    * FILTER TODO: Can we assume that the inner processing
11563 		    *  will result in an ordered list if we have an
11564 		    *  XPATH_OP_FILTER?
11565 		    *  What about an additional field or flag on
11566 		    *  xmlXPathObject like @sorted ? This way we wouldn't need
11567 		    *  to assume anything, so it would be more robust and
11568 		    *  easier to optimize.
11569 		    */
11570                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
11571 		     (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
11572 #else
11573 		    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11574 #endif
11575                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
11576                     xmlXPathObjectPtr val;
11577 
11578                     val = comp->steps[op->ch2].value4;
11579                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&
11580                         (val->floatval == 1.0)) {
11581                         xmlNodePtr first = NULL;
11582 
11583                         total +=
11584                             xmlXPathCompOpEvalFirst(ctxt,
11585                                                     &comp->steps[op->ch1],
11586                                                     &first);
11587 			CHECK_ERROR0;
11588                         /*
11589                          * The nodeset should be in document order,
11590                          * Keep only the first value
11591                          */
11592                         if ((ctxt->value != NULL) &&
11593                             (ctxt->value->type == XPATH_NODESET) &&
11594                             (ctxt->value->nodesetval != NULL) &&
11595                             (ctxt->value->nodesetval->nodeNr > 1))
11596                             xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
11597                                                         1, 1);
11598                         break;
11599                     }
11600                 }
11601                 /*
11602                  * Optimization for ()[last()] selection i.e. the last elem
11603                  */
11604                 if ((op->ch1 != -1) && (op->ch2 != -1) &&
11605                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11606                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11607                     int f = comp->steps[op->ch2].ch1;
11608 
11609                     if ((f != -1) &&
11610                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11611                         (comp->steps[f].value5 == NULL) &&
11612                         (comp->steps[f].value == 0) &&
11613                         (comp->steps[f].value4 != NULL) &&
11614                         (xmlStrEqual
11615                          (comp->steps[f].value4, BAD_CAST "last"))) {
11616                         xmlNodePtr last = NULL;
11617 
11618                         total +=
11619                             xmlXPathCompOpEvalLast(ctxt,
11620                                                    &comp->steps[op->ch1],
11621                                                    &last);
11622 			CHECK_ERROR0;
11623                         /*
11624                          * The nodeset should be in document order,
11625                          * Keep only the last value
11626                          */
11627                         if ((ctxt->value != NULL) &&
11628                             (ctxt->value->type == XPATH_NODESET) &&
11629                             (ctxt->value->nodesetval != NULL) &&
11630                             (ctxt->value->nodesetval->nodeTab != NULL) &&
11631                             (ctxt->value->nodesetval->nodeNr > 1))
11632                             xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11633                         break;
11634                     }
11635                 }
11636 		/*
11637 		* Process inner predicates first.
11638 		* Example "index[parent::book][1]":
11639 		* ...
11640 		*   PREDICATE   <-- we are here "[1]"
11641 		*     PREDICATE <-- process "[parent::book]" first
11642 		*       SORT
11643 		*         COLLECT  'parent' 'name' 'node' book
11644 		*           NODE
11645 		*     ELEM Object is a number : 1
11646 		*/
11647                 if (op->ch1 != -1)
11648                     total +=
11649                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11650 		CHECK_ERROR0;
11651                 if (op->ch2 == -1)
11652                     break;
11653                 if (ctxt->value == NULL)
11654                     break;
11655 
11656                 /*
11657                  * In case of errors, xmlXPathNodeSetFilter can pop additional
11658                  * nodes from the stack. We have to temporarily remove the
11659                  * nodeset object from the stack to avoid freeing it
11660                  * prematurely.
11661                  */
11662                 CHECK_TYPE0(XPATH_NODESET);
11663                 obj = valuePop(ctxt);
11664                 set = obj->nodesetval;
11665                 if (set != NULL)
11666                     xmlXPathNodeSetFilter(ctxt, set, op->ch2,
11667                                           1, set->nodeNr, 1);
11668                 valuePush(ctxt, obj);
11669                 break;
11670             }
11671         case XPATH_OP_SORT:
11672             if (op->ch1 != -1)
11673                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11674 	    CHECK_ERROR0;
11675             if ((ctxt->value != NULL) &&
11676                 (ctxt->value->type == XPATH_NODESET) &&
11677                 (ctxt->value->nodesetval != NULL) &&
11678 		(ctxt->value->nodesetval->nodeNr > 1))
11679 	    {
11680                 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11681 	    }
11682             break;
11683         default:
11684             XP_ERROR0(XPATH_INVALID_OPERAND);
11685             break;
11686     }
11687 
11688     ctxt->context->depth -= 1;
11689     return (total);
11690 }
11691 
11692 /**
11693  * xmlXPathCompOpEvalToBoolean:
11694  * @ctxt:  the XPath parser context
11695  *
11696  * Evaluates if the expression evaluates to true.
11697  *
11698  * Returns 1 if true, 0 if false and -1 on API or internal errors.
11699  */
11700 static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int isPredicate)11701 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
11702 			    xmlXPathStepOpPtr op,
11703 			    int isPredicate)
11704 {
11705     xmlXPathObjectPtr resObj = NULL;
11706 
11707 start:
11708     if (OP_LIMIT_EXCEEDED(ctxt, 1))
11709         return(0);
11710     /* comp = ctxt->comp; */
11711     switch (op->op) {
11712         case XPATH_OP_END:
11713             return (0);
11714 	case XPATH_OP_VALUE:
11715 	    resObj = (xmlXPathObjectPtr) op->value4;
11716 	    if (isPredicate)
11717 		return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
11718 	    return(xmlXPathCastToBoolean(resObj));
11719 	case XPATH_OP_SORT:
11720 	    /*
11721 	    * We don't need sorting for boolean results. Skip this one.
11722 	    */
11723             if (op->ch1 != -1) {
11724 		op = &ctxt->comp->steps[op->ch1];
11725 		goto start;
11726 	    }
11727 	    return(0);
11728 	case XPATH_OP_COLLECT:
11729 	    if (op->ch1 == -1)
11730 		return(0);
11731 
11732             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
11733 	    if (ctxt->error != XPATH_EXPRESSION_OK)
11734 		return(-1);
11735 
11736             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
11737 	    if (ctxt->error != XPATH_EXPRESSION_OK)
11738 		return(-1);
11739 
11740 	    resObj = valuePop(ctxt);
11741 	    if (resObj == NULL)
11742 		return(-1);
11743 	    break;
11744 	default:
11745 	    /*
11746 	    * Fallback to call xmlXPathCompOpEval().
11747 	    */
11748 	    xmlXPathCompOpEval(ctxt, op);
11749 	    if (ctxt->error != XPATH_EXPRESSION_OK)
11750 		return(-1);
11751 
11752 	    resObj = valuePop(ctxt);
11753 	    if (resObj == NULL)
11754 		return(-1);
11755 	    break;
11756     }
11757 
11758     if (resObj) {
11759 	int res;
11760 
11761 	if (resObj->type == XPATH_BOOLEAN) {
11762 	    res = resObj->boolval;
11763 	} else if (isPredicate) {
11764 	    /*
11765 	    * For predicates a result of type "number" is handled
11766 	    * differently:
11767 	    * SPEC XPath 1.0:
11768 	    * "If the result is a number, the result will be converted
11769 	    *  to true if the number is equal to the context position
11770 	    *  and will be converted to false otherwise;"
11771 	    */
11772 	    res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
11773 	} else {
11774 	    res = xmlXPathCastToBoolean(resObj);
11775 	}
11776 	xmlXPathReleaseObject(ctxt->context, resObj);
11777 	return(res);
11778     }
11779 
11780     return(0);
11781 }
11782 
11783 #ifdef XPATH_STREAMING
11784 /**
11785  * xmlXPathRunStreamEval:
11786  * @pctxt:  the XPath parser context with the compiled expression
11787  *
11788  * Evaluate the Precompiled Streamable XPath expression in the given context.
11789  */
11790 static int
xmlXPathRunStreamEval(xmlXPathParserContextPtr pctxt,xmlPatternPtr comp,xmlXPathObjectPtr * resultSeq,int toBool)11791 xmlXPathRunStreamEval(xmlXPathParserContextPtr pctxt, xmlPatternPtr comp,
11792 		      xmlXPathObjectPtr *resultSeq, int toBool)
11793 {
11794     int max_depth, min_depth;
11795     int from_root;
11796     int ret, depth;
11797     int eval_all_nodes;
11798     xmlNodePtr cur = NULL, limit = NULL;
11799     xmlStreamCtxtPtr patstream = NULL;
11800     xmlXPathContextPtr ctxt = pctxt->context;
11801 
11802     if ((ctxt == NULL) || (comp == NULL))
11803         return(-1);
11804     max_depth = xmlPatternMaxDepth(comp);
11805     if (max_depth == -1)
11806         return(-1);
11807     if (max_depth == -2)
11808         max_depth = 10000;
11809     min_depth = xmlPatternMinDepth(comp);
11810     if (min_depth == -1)
11811         return(-1);
11812     from_root = xmlPatternFromRoot(comp);
11813     if (from_root < 0)
11814         return(-1);
11815 
11816     if (! toBool) {
11817 	if (resultSeq == NULL)
11818 	    return(-1);
11819 	*resultSeq = xmlXPathCacheNewNodeSet(pctxt, NULL);
11820 	if (*resultSeq == NULL)
11821 	    return(-1);
11822     }
11823 
11824     /*
11825      * handle the special cases of "/" amd "." being matched
11826      */
11827     if (min_depth == 0) {
11828         int res;
11829 
11830 	if (from_root) {
11831 	    /* Select "/" */
11832 	    if (toBool)
11833 		return(1);
11834             res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
11835                                            (xmlNodePtr) ctxt->doc);
11836 	} else {
11837 	    /* Select "self::node()" */
11838 	    if (toBool)
11839 		return(1);
11840             res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
11841                                            ctxt->node);
11842 	}
11843 
11844         if (res < 0)
11845             xmlXPathPErrMemory(pctxt);
11846     }
11847     if (max_depth == 0) {
11848 	return(0);
11849     }
11850 
11851     if (from_root) {
11852         cur = (xmlNodePtr)ctxt->doc;
11853     } else if (ctxt->node != NULL) {
11854         switch (ctxt->node->type) {
11855             case XML_ELEMENT_NODE:
11856             case XML_DOCUMENT_NODE:
11857             case XML_DOCUMENT_FRAG_NODE:
11858             case XML_HTML_DOCUMENT_NODE:
11859 	        cur = ctxt->node;
11860 		break;
11861             case XML_ATTRIBUTE_NODE:
11862             case XML_TEXT_NODE:
11863             case XML_CDATA_SECTION_NODE:
11864             case XML_ENTITY_REF_NODE:
11865             case XML_ENTITY_NODE:
11866             case XML_PI_NODE:
11867             case XML_COMMENT_NODE:
11868             case XML_NOTATION_NODE:
11869             case XML_DTD_NODE:
11870             case XML_DOCUMENT_TYPE_NODE:
11871             case XML_ELEMENT_DECL:
11872             case XML_ATTRIBUTE_DECL:
11873             case XML_ENTITY_DECL:
11874             case XML_NAMESPACE_DECL:
11875             case XML_XINCLUDE_START:
11876             case XML_XINCLUDE_END:
11877 		break;
11878 	}
11879 	limit = cur;
11880     }
11881     if (cur == NULL) {
11882         return(0);
11883     }
11884 
11885     patstream = xmlPatternGetStreamCtxt(comp);
11886     if (patstream == NULL) {
11887         xmlXPathPErrMemory(pctxt);
11888 	return(-1);
11889     }
11890 
11891     eval_all_nodes = xmlStreamWantsAnyNode(patstream);
11892 
11893     if (from_root) {
11894 	ret = xmlStreamPush(patstream, NULL, NULL);
11895 	if (ret < 0) {
11896 	} else if (ret == 1) {
11897 	    if (toBool)
11898 		goto return_1;
11899 	    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) < 0)
11900                 xmlXPathPErrMemory(pctxt);
11901 	}
11902     }
11903     depth = 0;
11904     goto scan_children;
11905 next_node:
11906     do {
11907         if (ctxt->opLimit != 0) {
11908             if (ctxt->opCount >= ctxt->opLimit) {
11909                 xmlXPathErr(ctxt, XPATH_RECURSION_LIMIT_EXCEEDED);
11910                 xmlFreeStreamCtxt(patstream);
11911                 return(-1);
11912             }
11913             ctxt->opCount++;
11914         }
11915 
11916 	switch (cur->type) {
11917 	    case XML_ELEMENT_NODE:
11918 	    case XML_TEXT_NODE:
11919 	    case XML_CDATA_SECTION_NODE:
11920 	    case XML_COMMENT_NODE:
11921 	    case XML_PI_NODE:
11922 		if (cur->type == XML_ELEMENT_NODE) {
11923 		    ret = xmlStreamPush(patstream, cur->name,
11924 				(cur->ns ? cur->ns->href : NULL));
11925 		} else if (eval_all_nodes)
11926 		    ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
11927 		else
11928 		    break;
11929 
11930 		if (ret < 0) {
11931 		    xmlXPathPErrMemory(pctxt);
11932 		} else if (ret == 1) {
11933 		    if (toBool)
11934 			goto return_1;
11935 		    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
11936                                                  cur) < 0)
11937                         xmlXPathPErrMemory(pctxt);
11938 		}
11939 		if ((cur->children == NULL) || (depth >= max_depth)) {
11940 		    ret = xmlStreamPop(patstream);
11941 		    while (cur->next != NULL) {
11942 			cur = cur->next;
11943 			if ((cur->type != XML_ENTITY_DECL) &&
11944 			    (cur->type != XML_DTD_NODE))
11945 			    goto next_node;
11946 		    }
11947 		}
11948 	    default:
11949 		break;
11950 	}
11951 
11952 scan_children:
11953 	if (cur->type == XML_NAMESPACE_DECL) break;
11954 	if ((cur->children != NULL) && (depth < max_depth)) {
11955 	    /*
11956 	     * Do not descend on entities declarations
11957 	     */
11958 	    if (cur->children->type != XML_ENTITY_DECL) {
11959 		cur = cur->children;
11960 		depth++;
11961 		/*
11962 		 * Skip DTDs
11963 		 */
11964 		if (cur->type != XML_DTD_NODE)
11965 		    continue;
11966 	    }
11967 	}
11968 
11969 	if (cur == limit)
11970 	    break;
11971 
11972 	while (cur->next != NULL) {
11973 	    cur = cur->next;
11974 	    if ((cur->type != XML_ENTITY_DECL) &&
11975 		(cur->type != XML_DTD_NODE))
11976 		goto next_node;
11977 	}
11978 
11979 	do {
11980 	    cur = cur->parent;
11981 	    depth--;
11982 	    if ((cur == NULL) || (cur == limit) ||
11983                 (cur->type == XML_DOCUMENT_NODE))
11984 	        goto done;
11985 	    if (cur->type == XML_ELEMENT_NODE) {
11986 		ret = xmlStreamPop(patstream);
11987 	    } else if ((eval_all_nodes) &&
11988 		((cur->type == XML_TEXT_NODE) ||
11989 		 (cur->type == XML_CDATA_SECTION_NODE) ||
11990 		 (cur->type == XML_COMMENT_NODE) ||
11991 		 (cur->type == XML_PI_NODE)))
11992 	    {
11993 		ret = xmlStreamPop(patstream);
11994 	    }
11995 	    if (cur->next != NULL) {
11996 		cur = cur->next;
11997 		break;
11998 	    }
11999 	} while (cur != NULL);
12000 
12001     } while ((cur != NULL) && (depth >= 0));
12002 
12003 done:
12004 
12005     if (patstream)
12006 	xmlFreeStreamCtxt(patstream);
12007     return(0);
12008 
12009 return_1:
12010     if (patstream)
12011 	xmlFreeStreamCtxt(patstream);
12012     return(1);
12013 }
12014 #endif /* XPATH_STREAMING */
12015 
12016 /**
12017  * xmlXPathRunEval:
12018  * @ctxt:  the XPath parser context with the compiled expression
12019  * @toBool:  evaluate to a boolean result
12020  *
12021  * Evaluate the Precompiled XPath expression in the given context.
12022  */
12023 static int
xmlXPathRunEval(xmlXPathParserContextPtr ctxt,int toBool)12024 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
12025 {
12026     xmlXPathCompExprPtr comp;
12027     int oldDepth;
12028 
12029     if ((ctxt == NULL) || (ctxt->comp == NULL))
12030 	return(-1);
12031 
12032     if (ctxt->valueTab == NULL) {
12033 	/* Allocate the value stack */
12034 	ctxt->valueTab = (xmlXPathObjectPtr *)
12035 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
12036 	if (ctxt->valueTab == NULL) {
12037 	    xmlXPathPErrMemory(ctxt);
12038 	    return(-1);
12039 	}
12040 	ctxt->valueNr = 0;
12041 	ctxt->valueMax = 10;
12042 	ctxt->value = NULL;
12043     }
12044 #ifdef XPATH_STREAMING
12045     if (ctxt->comp->stream) {
12046 	int res;
12047 
12048 	if (toBool) {
12049 	    /*
12050 	    * Evaluation to boolean result.
12051 	    */
12052 	    res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, NULL, 1);
12053 	    if (res != -1)
12054 		return(res);
12055 	} else {
12056 	    xmlXPathObjectPtr resObj = NULL;
12057 
12058 	    /*
12059 	    * Evaluation to a sequence.
12060 	    */
12061 	    res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, &resObj, 0);
12062 
12063 	    if ((res != -1) && (resObj != NULL)) {
12064 		valuePush(ctxt, resObj);
12065 		return(0);
12066 	    }
12067 	    if (resObj != NULL)
12068 		xmlXPathReleaseObject(ctxt->context, resObj);
12069 	}
12070 	/*
12071 	* QUESTION TODO: This falls back to normal XPath evaluation
12072 	* if res == -1. Is this intended?
12073 	*/
12074     }
12075 #endif
12076     comp = ctxt->comp;
12077     if (comp->last < 0) {
12078         xmlXPathErr(ctxt, XPATH_STACK_ERROR);
12079 	return(-1);
12080     }
12081     oldDepth = ctxt->context->depth;
12082     if (toBool)
12083 	return(xmlXPathCompOpEvalToBoolean(ctxt,
12084 	    &comp->steps[comp->last], 0));
12085     else
12086 	xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
12087     ctxt->context->depth = oldDepth;
12088 
12089     return(0);
12090 }
12091 
12092 /************************************************************************
12093  *									*
12094  *			Public interfaces				*
12095  *									*
12096  ************************************************************************/
12097 
12098 /**
12099  * xmlXPathEvalPredicate:
12100  * @ctxt:  the XPath context
12101  * @res:  the Predicate Expression evaluation result
12102  *
12103  * Evaluate a predicate result for the current node.
12104  * A PredicateExpr is evaluated by evaluating the Expr and converting
12105  * the result to a boolean. If the result is a number, the result will
12106  * be converted to true if the number is equal to the position of the
12107  * context node in the context node list (as returned by the position
12108  * function) and will be converted to false otherwise; if the result
12109  * is not a number, then the result will be converted as if by a call
12110  * to the boolean function.
12111  *
12112  * Returns 1 if predicate is true, 0 otherwise
12113  */
12114 int
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt,xmlXPathObjectPtr res)12115 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
12116     if ((ctxt == NULL) || (res == NULL)) return(0);
12117     switch (res->type) {
12118         case XPATH_BOOLEAN:
12119 	    return(res->boolval);
12120         case XPATH_NUMBER:
12121 	    return(res->floatval == ctxt->proximityPosition);
12122         case XPATH_NODESET:
12123         case XPATH_XSLT_TREE:
12124 	    if (res->nodesetval == NULL)
12125 		return(0);
12126 	    return(res->nodesetval->nodeNr != 0);
12127         case XPATH_STRING:
12128 	    return((res->stringval != NULL) &&
12129 	           (xmlStrlen(res->stringval) != 0));
12130         default:
12131 	    break;
12132     }
12133     return(0);
12134 }
12135 
12136 /**
12137  * xmlXPathEvaluatePredicateResult:
12138  * @ctxt:  the XPath Parser context
12139  * @res:  the Predicate Expression evaluation result
12140  *
12141  * Evaluate a predicate result for the current node.
12142  * A PredicateExpr is evaluated by evaluating the Expr and converting
12143  * the result to a boolean. If the result is a number, the result will
12144  * be converted to true if the number is equal to the position of the
12145  * context node in the context node list (as returned by the position
12146  * function) and will be converted to false otherwise; if the result
12147  * is not a number, then the result will be converted as if by a call
12148  * to the boolean function.
12149  *
12150  * Returns 1 if predicate is true, 0 otherwise
12151  */
12152 int
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr res)12153 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
12154                                 xmlXPathObjectPtr res) {
12155     if ((ctxt == NULL) || (res == NULL)) return(0);
12156     switch (res->type) {
12157         case XPATH_BOOLEAN:
12158 	    return(res->boolval);
12159         case XPATH_NUMBER:
12160 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
12161 	    return((res->floatval == ctxt->context->proximityPosition) &&
12162 	           (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
12163 #else
12164 	    return(res->floatval == ctxt->context->proximityPosition);
12165 #endif
12166         case XPATH_NODESET:
12167         case XPATH_XSLT_TREE:
12168 	    if (res->nodesetval == NULL)
12169 		return(0);
12170 	    return(res->nodesetval->nodeNr != 0);
12171         case XPATH_STRING:
12172 	    return((res->stringval != NULL) && (res->stringval[0] != 0));
12173         default:
12174 	    break;
12175     }
12176     return(0);
12177 }
12178 
12179 #ifdef XPATH_STREAMING
12180 /**
12181  * xmlXPathTryStreamCompile:
12182  * @ctxt: an XPath context
12183  * @str:  the XPath expression
12184  *
12185  * Try to compile the XPath expression as a streamable subset.
12186  *
12187  * Returns the compiled expression or NULL if failed to compile.
12188  */
12189 static xmlXPathCompExprPtr
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt,const xmlChar * str)12190 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
12191     /*
12192      * Optimization: use streaming patterns when the XPath expression can
12193      * be compiled to a stream lookup
12194      */
12195     xmlPatternPtr stream;
12196     xmlXPathCompExprPtr comp;
12197     xmlDictPtr dict = NULL;
12198     const xmlChar **namespaces = NULL;
12199     xmlNsPtr ns;
12200     int i, j;
12201 
12202     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
12203         (!xmlStrchr(str, '@'))) {
12204 	const xmlChar *tmp;
12205         int res;
12206 
12207 	/*
12208 	 * We don't try to handle expressions using the verbose axis
12209 	 * specifiers ("::"), just the simplified form at this point.
12210 	 * Additionally, if there is no list of namespaces available and
12211 	 *  there's a ":" in the expression, indicating a prefixed QName,
12212 	 *  then we won't try to compile either. xmlPatterncompile() needs
12213 	 *  to have a list of namespaces at compilation time in order to
12214 	 *  compile prefixed name tests.
12215 	 */
12216 	tmp = xmlStrchr(str, ':');
12217 	if ((tmp != NULL) &&
12218 	    ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
12219 	    return(NULL);
12220 
12221 	if (ctxt != NULL) {
12222 	    dict = ctxt->dict;
12223 	    if (ctxt->nsNr > 0) {
12224 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
12225 		if (namespaces == NULL) {
12226 		    xmlXPathErrMemory(ctxt);
12227 		    return(NULL);
12228 		}
12229 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
12230 		    ns = ctxt->namespaces[j];
12231 		    namespaces[i++] = ns->href;
12232 		    namespaces[i++] = ns->prefix;
12233 		}
12234 		namespaces[i++] = NULL;
12235 		namespaces[i] = NULL;
12236 	    }
12237 	}
12238 
12239 	res = xmlPatternCompileSafe(str, dict, XML_PATTERN_XPATH, namespaces,
12240                                     &stream);
12241 	if (namespaces != NULL) {
12242 	    xmlFree((xmlChar **)namespaces);
12243 	}
12244         if (res < 0) {
12245             xmlXPathErrMemory(ctxt);
12246             return(NULL);
12247         }
12248 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
12249 	    comp = xmlXPathNewCompExpr();
12250 	    if (comp == NULL) {
12251 		xmlXPathErrMemory(ctxt);
12252 	        xmlFreePattern(stream);
12253 		return(NULL);
12254 	    }
12255 	    comp->stream = stream;
12256 	    comp->dict = dict;
12257 	    if (comp->dict)
12258 		xmlDictReference(comp->dict);
12259 	    return(comp);
12260 	}
12261 	xmlFreePattern(stream);
12262     }
12263     return(NULL);
12264 }
12265 #endif /* XPATH_STREAMING */
12266 
12267 static void
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,xmlXPathStepOpPtr op)12268 xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
12269                            xmlXPathStepOpPtr op)
12270 {
12271     xmlXPathCompExprPtr comp = pctxt->comp;
12272     xmlXPathContextPtr ctxt;
12273 
12274     /*
12275     * Try to rewrite "descendant-or-self::node()/foo" to an optimized
12276     * internal representation.
12277     */
12278 
12279     if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
12280         (op->ch1 != -1) &&
12281         (op->ch2 == -1 /* no predicate */))
12282     {
12283         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
12284 
12285         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
12286             ((xmlXPathAxisVal) prevop->value ==
12287                 AXIS_DESCENDANT_OR_SELF) &&
12288             (prevop->ch2 == -1) &&
12289             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
12290             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
12291         {
12292             /*
12293             * This is a "descendant-or-self::node()" without predicates.
12294             * Try to eliminate it.
12295             */
12296 
12297             switch ((xmlXPathAxisVal) op->value) {
12298                 case AXIS_CHILD:
12299                 case AXIS_DESCENDANT:
12300                     /*
12301                     * Convert "descendant-or-self::node()/child::" or
12302                     * "descendant-or-self::node()/descendant::" to
12303                     * "descendant::"
12304                     */
12305                     op->ch1   = prevop->ch1;
12306                     op->value = AXIS_DESCENDANT;
12307                     break;
12308                 case AXIS_SELF:
12309                 case AXIS_DESCENDANT_OR_SELF:
12310                     /*
12311                     * Convert "descendant-or-self::node()/self::" or
12312                     * "descendant-or-self::node()/descendant-or-self::" to
12313                     * to "descendant-or-self::"
12314                     */
12315                     op->ch1   = prevop->ch1;
12316                     op->value = AXIS_DESCENDANT_OR_SELF;
12317                     break;
12318                 default:
12319                     break;
12320             }
12321 	}
12322     }
12323 
12324     /* OP_VALUE has invalid ch1. */
12325     if (op->op == XPATH_OP_VALUE)
12326         return;
12327 
12328     /* Recurse */
12329     ctxt = pctxt->context;
12330     if (ctxt != NULL) {
12331         if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
12332             return;
12333         ctxt->depth += 1;
12334     }
12335     if (op->ch1 != -1)
12336         xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
12337     if (op->ch2 != -1)
12338 	xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
12339     if (ctxt != NULL)
12340         ctxt->depth -= 1;
12341 }
12342 
12343 /**
12344  * xmlXPathCtxtCompile:
12345  * @ctxt: an XPath context
12346  * @str:  the XPath expression
12347  *
12348  * Compile an XPath expression
12349  *
12350  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
12351  *         the caller has to free the object.
12352  */
12353 xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt,const xmlChar * str)12354 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
12355     xmlXPathParserContextPtr pctxt;
12356     xmlXPathContextPtr tmpctxt = NULL;
12357     xmlXPathCompExprPtr comp;
12358     int oldDepth = 0;
12359 
12360 #ifdef XPATH_STREAMING
12361     comp = xmlXPathTryStreamCompile(ctxt, str);
12362     if (comp != NULL)
12363         return(comp);
12364 #endif
12365 
12366     xmlInitParser();
12367 
12368     /*
12369      * We need an xmlXPathContext for the depth check.
12370      */
12371     if (ctxt == NULL) {
12372         tmpctxt = xmlXPathNewContext(NULL);
12373         if (tmpctxt == NULL)
12374             return(NULL);
12375         ctxt = tmpctxt;
12376     }
12377 
12378     pctxt = xmlXPathNewParserContext(str, ctxt);
12379     if (pctxt == NULL) {
12380         if (tmpctxt != NULL)
12381             xmlXPathFreeContext(tmpctxt);
12382         return NULL;
12383     }
12384 
12385     oldDepth = ctxt->depth;
12386     xmlXPathCompileExpr(pctxt, 1);
12387     ctxt->depth = oldDepth;
12388 
12389     if( pctxt->error != XPATH_EXPRESSION_OK )
12390     {
12391         xmlXPathFreeParserContext(pctxt);
12392         if (tmpctxt != NULL)
12393             xmlXPathFreeContext(tmpctxt);
12394         return(NULL);
12395     }
12396 
12397     if (*pctxt->cur != 0) {
12398 	/*
12399 	 * aleksey: in some cases this line prints *second* error message
12400 	 * (see bug #78858) and probably this should be fixed.
12401 	 * However, we are not sure that all error messages are printed
12402 	 * out in other places. It's not critical so we leave it as-is for now
12403 	 */
12404 	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
12405 	comp = NULL;
12406     } else {
12407 	comp = pctxt->comp;
12408 	if ((comp->nbStep > 1) && (comp->last >= 0)) {
12409             if (ctxt != NULL)
12410                 oldDepth = ctxt->depth;
12411 	    xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
12412             if (ctxt != NULL)
12413                 ctxt->depth = oldDepth;
12414 	}
12415 	pctxt->comp = NULL;
12416     }
12417     xmlXPathFreeParserContext(pctxt);
12418     if (tmpctxt != NULL)
12419         xmlXPathFreeContext(tmpctxt);
12420 
12421     if (comp != NULL) {
12422 	comp->expr = xmlStrdup(str);
12423     }
12424     return(comp);
12425 }
12426 
12427 /**
12428  * xmlXPathCompile:
12429  * @str:  the XPath expression
12430  *
12431  * Compile an XPath expression
12432  *
12433  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
12434  *         the caller has to free the object.
12435  */
12436 xmlXPathCompExprPtr
xmlXPathCompile(const xmlChar * str)12437 xmlXPathCompile(const xmlChar *str) {
12438     return(xmlXPathCtxtCompile(NULL, str));
12439 }
12440 
12441 /**
12442  * xmlXPathCompiledEvalInternal:
12443  * @comp:  the compiled XPath expression
12444  * @ctxt:  the XPath context
12445  * @resObj: the resulting XPath object or NULL
12446  * @toBool: 1 if only a boolean result is requested
12447  *
12448  * Evaluate the Precompiled XPath expression in the given context.
12449  * The caller has to free @resObj.
12450  *
12451  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12452  *         the caller has to free the object.
12453  */
12454 static int
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt,xmlXPathObjectPtr * resObjPtr,int toBool)12455 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
12456 			     xmlXPathContextPtr ctxt,
12457 			     xmlXPathObjectPtr *resObjPtr,
12458 			     int toBool)
12459 {
12460     xmlXPathParserContextPtr pctxt;
12461     xmlXPathObjectPtr resObj = NULL;
12462     int res;
12463 
12464     if (comp == NULL)
12465 	return(-1);
12466     xmlInitParser();
12467 
12468     xmlResetError(&ctxt->lastError);
12469 
12470     pctxt = xmlXPathCompParserContext(comp, ctxt);
12471     if (pctxt == NULL)
12472         return(-1);
12473     res = xmlXPathRunEval(pctxt, toBool);
12474 
12475     if (pctxt->error == XPATH_EXPRESSION_OK) {
12476         if (pctxt->valueNr != ((toBool) ? 0 : 1))
12477             xmlXPathErr(pctxt, XPATH_STACK_ERROR);
12478         else if (!toBool)
12479             resObj = valuePop(pctxt);
12480     }
12481 
12482     if (resObjPtr)
12483         *resObjPtr = resObj;
12484     else
12485         xmlXPathReleaseObject(ctxt, resObj);
12486 
12487     pctxt->comp = NULL;
12488     xmlXPathFreeParserContext(pctxt);
12489 
12490     return(res);
12491 }
12492 
12493 /**
12494  * xmlXPathCompiledEval:
12495  * @comp:  the compiled XPath expression
12496  * @ctx:  the XPath context
12497  *
12498  * Evaluate the Precompiled XPath expression in the given context.
12499  *
12500  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12501  *         the caller has to free the object.
12502  */
12503 xmlXPathObjectPtr
xmlXPathCompiledEval(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctx)12504 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
12505 {
12506     xmlXPathObjectPtr res = NULL;
12507 
12508     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
12509     return(res);
12510 }
12511 
12512 /**
12513  * xmlXPathCompiledEvalToBoolean:
12514  * @comp:  the compiled XPath expression
12515  * @ctxt:  the XPath context
12516  *
12517  * Applies the XPath boolean() function on the result of the given
12518  * compiled expression.
12519  *
12520  * Returns 1 if the expression evaluated to true, 0 if to false and
12521  *         -1 in API and internal errors.
12522  */
12523 int
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)12524 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
12525 			      xmlXPathContextPtr ctxt)
12526 {
12527     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
12528 }
12529 
12530 /**
12531  * xmlXPathEvalExpr:
12532  * @ctxt:  the XPath Parser context
12533  *
12534  * DEPRECATED: Internal function, don't use.
12535  *
12536  * Parse and evaluate an XPath expression in the given context,
12537  * then push the result on the context stack
12538  */
12539 void
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt)12540 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
12541 #ifdef XPATH_STREAMING
12542     xmlXPathCompExprPtr comp;
12543 #endif
12544     int oldDepth = 0;
12545 
12546     if ((ctxt == NULL) || (ctxt->context == NULL))
12547         return;
12548     if (ctxt->context->lastError.code != 0)
12549         return;
12550 
12551 #ifdef XPATH_STREAMING
12552     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
12553     if ((comp == NULL) &&
12554         (ctxt->context->lastError.code == XML_ERR_NO_MEMORY)) {
12555         xmlXPathPErrMemory(ctxt);
12556         return;
12557     }
12558     if (comp != NULL) {
12559         if (ctxt->comp != NULL)
12560 	    xmlXPathFreeCompExpr(ctxt->comp);
12561         ctxt->comp = comp;
12562     } else
12563 #endif
12564     {
12565         if (ctxt->context != NULL)
12566             oldDepth = ctxt->context->depth;
12567 	xmlXPathCompileExpr(ctxt, 1);
12568         if (ctxt->context != NULL)
12569             ctxt->context->depth = oldDepth;
12570         CHECK_ERROR;
12571 
12572         /* Check for trailing characters. */
12573         if (*ctxt->cur != 0)
12574             XP_ERROR(XPATH_EXPR_ERROR);
12575 
12576 	if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
12577             if (ctxt->context != NULL)
12578                 oldDepth = ctxt->context->depth;
12579 	    xmlXPathOptimizeExpression(ctxt,
12580 		&ctxt->comp->steps[ctxt->comp->last]);
12581             if (ctxt->context != NULL)
12582                 ctxt->context->depth = oldDepth;
12583         }
12584     }
12585 
12586     xmlXPathRunEval(ctxt, 0);
12587 }
12588 
12589 /**
12590  * xmlXPathEval:
12591  * @str:  the XPath expression
12592  * @ctx:  the XPath context
12593  *
12594  * Evaluate the XPath Location Path in the given context.
12595  *
12596  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12597  *         the caller has to free the object.
12598  */
12599 xmlXPathObjectPtr
xmlXPathEval(const xmlChar * str,xmlXPathContextPtr ctx)12600 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
12601     xmlXPathParserContextPtr ctxt;
12602     xmlXPathObjectPtr res;
12603 
12604     if (ctx == NULL)
12605         return(NULL);
12606 
12607     xmlInitParser();
12608 
12609     xmlResetError(&ctx->lastError);
12610 
12611     ctxt = xmlXPathNewParserContext(str, ctx);
12612     if (ctxt == NULL)
12613         return NULL;
12614     xmlXPathEvalExpr(ctxt);
12615 
12616     if (ctxt->error != XPATH_EXPRESSION_OK) {
12617 	res = NULL;
12618     } else if (ctxt->valueNr != 1) {
12619         xmlXPathErr(ctxt, XPATH_STACK_ERROR);
12620 	res = NULL;
12621     } else {
12622 	res = valuePop(ctxt);
12623     }
12624 
12625     xmlXPathFreeParserContext(ctxt);
12626     return(res);
12627 }
12628 
12629 /**
12630  * xmlXPathSetContextNode:
12631  * @node: the node to to use as the context node
12632  * @ctx:  the XPath context
12633  *
12634  * Sets 'node' as the context node. The node must be in the same
12635  * document as that associated with the context.
12636  *
12637  * Returns -1 in case of error or 0 if successful
12638  */
12639 int
xmlXPathSetContextNode(xmlNodePtr node,xmlXPathContextPtr ctx)12640 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
12641     if ((node == NULL) || (ctx == NULL))
12642         return(-1);
12643 
12644     if (node->doc == ctx->doc) {
12645         ctx->node = node;
12646 	return(0);
12647     }
12648     return(-1);
12649 }
12650 
12651 /**
12652  * xmlXPathNodeEval:
12653  * @node: the node to to use as the context node
12654  * @str:  the XPath expression
12655  * @ctx:  the XPath context
12656  *
12657  * Evaluate the XPath Location Path in the given context. The node 'node'
12658  * is set as the context node. The context node is not restored.
12659  *
12660  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12661  *         the caller has to free the object.
12662  */
12663 xmlXPathObjectPtr
xmlXPathNodeEval(xmlNodePtr node,const xmlChar * str,xmlXPathContextPtr ctx)12664 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
12665     if (str == NULL)
12666         return(NULL);
12667     if (xmlXPathSetContextNode(node, ctx) < 0)
12668         return(NULL);
12669     return(xmlXPathEval(str, ctx));
12670 }
12671 
12672 /**
12673  * xmlXPathEvalExpression:
12674  * @str:  the XPath expression
12675  * @ctxt:  the XPath context
12676  *
12677  * Alias for xmlXPathEval().
12678  *
12679  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12680  *         the caller has to free the object.
12681  */
12682 xmlXPathObjectPtr
xmlXPathEvalExpression(const xmlChar * str,xmlXPathContextPtr ctxt)12683 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
12684     return(xmlXPathEval(str, ctxt));
12685 }
12686 
12687 /************************************************************************
12688  *									*
12689  *	Extra functions not pertaining to the XPath spec		*
12690  *									*
12691  ************************************************************************/
12692 /**
12693  * xmlXPathEscapeUriFunction:
12694  * @ctxt:  the XPath Parser context
12695  * @nargs:  the number of arguments
12696  *
12697  * Implement the escape-uri() XPath function
12698  *    string escape-uri(string $str, bool $escape-reserved)
12699  *
12700  * This function applies the URI escaping rules defined in section 2 of [RFC
12701  * 2396] to the string supplied as $uri-part, which typically represents all
12702  * or part of a URI. The effect of the function is to replace any special
12703  * character in the string by an escape sequence of the form %xx%yy...,
12704  * where xxyy... is the hexadecimal representation of the octets used to
12705  * represent the character in UTF-8.
12706  *
12707  * The set of characters that are escaped depends on the setting of the
12708  * boolean argument $escape-reserved.
12709  *
12710  * If $escape-reserved is true, all characters are escaped other than lower
12711  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
12712  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
12713  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
12714  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
12715  * A-F).
12716  *
12717  * If $escape-reserved is false, the behavior differs in that characters
12718  * referred to in [RFC 2396] as reserved characters are not escaped. These
12719  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
12720  *
12721  * [RFC 2396] does not define whether escaped URIs should use lower case or
12722  * upper case for hexadecimal digits. To ensure that escaped URIs can be
12723  * compared using string comparison functions, this function must always use
12724  * the upper-case letters A-F.
12725  *
12726  * Generally, $escape-reserved should be set to true when escaping a string
12727  * that is to form a single part of a URI, and to false when escaping an
12728  * entire URI or URI reference.
12729  *
12730  * In the case of non-ascii characters, the string is encoded according to
12731  * utf-8 and then converted according to RFC 2396.
12732  *
12733  * Examples
12734  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
12735  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
12736  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
12737  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
12738  *
12739  */
12740 static void
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt,int nargs)12741 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
12742     xmlXPathObjectPtr str;
12743     int escape_reserved;
12744     xmlBufPtr target;
12745     xmlChar *cptr;
12746     xmlChar escape[4];
12747 
12748     CHECK_ARITY(2);
12749 
12750     escape_reserved = xmlXPathPopBoolean(ctxt);
12751 
12752     CAST_TO_STRING;
12753     str = valuePop(ctxt);
12754 
12755     target = xmlBufCreate(50);
12756 
12757     escape[0] = '%';
12758     escape[3] = 0;
12759 
12760     if (target) {
12761 	for (cptr = str->stringval; *cptr; cptr++) {
12762 	    if ((*cptr >= 'A' && *cptr <= 'Z') ||
12763 		(*cptr >= 'a' && *cptr <= 'z') ||
12764 		(*cptr >= '0' && *cptr <= '9') ||
12765 		*cptr == '-' || *cptr == '_' || *cptr == '.' ||
12766 		*cptr == '!' || *cptr == '~' || *cptr == '*' ||
12767 		*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
12768 		(*cptr == '%' &&
12769 		 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
12770 		  (cptr[1] >= 'a' && cptr[1] <= 'f') ||
12771 		  (cptr[1] >= '0' && cptr[1] <= '9')) &&
12772 		 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
12773 		  (cptr[2] >= 'a' && cptr[2] <= 'f') ||
12774 		  (cptr[2] >= '0' && cptr[2] <= '9'))) ||
12775 		(!escape_reserved &&
12776 		 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
12777 		  *cptr == ':' || *cptr == '@' || *cptr == '&' ||
12778 		  *cptr == '=' || *cptr == '+' || *cptr == '$' ||
12779 		  *cptr == ','))) {
12780 		xmlBufAdd(target, cptr, 1);
12781 	    } else {
12782 		if ((*cptr >> 4) < 10)
12783 		    escape[1] = '0' + (*cptr >> 4);
12784 		else
12785 		    escape[1] = 'A' - 10 + (*cptr >> 4);
12786 		if ((*cptr & 0xF) < 10)
12787 		    escape[2] = '0' + (*cptr & 0xF);
12788 		else
12789 		    escape[2] = 'A' - 10 + (*cptr & 0xF);
12790 
12791 		xmlBufAdd(target, &escape[0], 3);
12792 	    }
12793 	}
12794     }
12795     valuePush(ctxt, xmlXPathCacheNewString(ctxt, xmlBufContent(target)));
12796     xmlBufFree(target);
12797     xmlXPathReleaseObject(ctxt->context, str);
12798 }
12799 
12800 /**
12801  * xmlXPathRegisterAllFunctions:
12802  * @ctxt:  the XPath context
12803  *
12804  * Registers all default XPath functions in this context
12805  */
12806 void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)12807 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
12808 {
12809     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
12810                          xmlXPathBooleanFunction);
12811     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
12812                          xmlXPathCeilingFunction);
12813     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
12814                          xmlXPathCountFunction);
12815     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
12816                          xmlXPathConcatFunction);
12817     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
12818                          xmlXPathContainsFunction);
12819     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
12820                          xmlXPathIdFunction);
12821     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
12822                          xmlXPathFalseFunction);
12823     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
12824                          xmlXPathFloorFunction);
12825     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
12826                          xmlXPathLastFunction);
12827     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
12828                          xmlXPathLangFunction);
12829     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
12830                          xmlXPathLocalNameFunction);
12831     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
12832                          xmlXPathNotFunction);
12833     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
12834                          xmlXPathNameFunction);
12835     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
12836                          xmlXPathNamespaceURIFunction);
12837     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
12838                          xmlXPathNormalizeFunction);
12839     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
12840                          xmlXPathNumberFunction);
12841     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
12842                          xmlXPathPositionFunction);
12843     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
12844                          xmlXPathRoundFunction);
12845     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
12846                          xmlXPathStringFunction);
12847     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
12848                          xmlXPathStringLengthFunction);
12849     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
12850                          xmlXPathStartsWithFunction);
12851     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
12852                          xmlXPathSubstringFunction);
12853     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
12854                          xmlXPathSubstringBeforeFunction);
12855     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
12856                          xmlXPathSubstringAfterFunction);
12857     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
12858                          xmlXPathSumFunction);
12859     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
12860                          xmlXPathTrueFunction);
12861     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
12862                          xmlXPathTranslateFunction);
12863 
12864     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
12865 	 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
12866                          xmlXPathEscapeUriFunction);
12867 }
12868 
12869 #endif /* LIBXML_XPATH_ENABLED */
12870