VirtualBox

source: vbox/trunk/src/libs/libxml2-2.13.2/xpath.c@ 105770

Last change on this file since 105770 was 105420, checked in by vboxsync, 4 months ago

libxml2-2.12.6: Applied and adjusted our libxml2 changes to 2.12.6. bugref:10730

  • Property svn:eol-style set to native
File size: 365.6 KB
Line 
1/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
11 * See Copyright for the status of this software
12 *
13 * Author: daniel@veillard.com
14 *
15 */
16
17/* To avoid EBCDIC trouble when parsing on zOS */
18#if defined(__MVS__)
19#pragma convert("ISO8859-1")
20#endif
21
22#define IN_LIBXML
23#include "libxml.h"
24
25#include <limits.h>
26#include <string.h>
27#include <stddef.h>
28#include <math.h>
29#include <float.h>
30#include <ctype.h>
31
32#include <libxml/xmlmemory.h>
33#include <libxml/tree.h>
34#include <libxml/xpath.h>
35#include <libxml/xpathInternals.h>
36#include <libxml/parserInternals.h>
37#include <libxml/hash.h>
38#ifdef LIBXML_XPTR_LOCS_ENABLED
39#include <libxml/xpointer.h>
40#endif
41#ifdef LIBXML_DEBUG_ENABLED
42#include <libxml/debugXML.h>
43#endif
44#include <libxml/xmlerror.h>
45#include <libxml/threads.h>
46#ifdef LIBXML_PATTERN_ENABLED
47#include <libxml/pattern.h>
48#endif
49
50#include "private/buf.h"
51#include "private/error.h"
52#include "private/xpath.h"
53
54/* Disabled for now */
55#if 0
56#ifdef LIBXML_PATTERN_ENABLED
57#define XPATH_STREAMING
58#endif
59#endif
60
61/**
62 * WITH_TIM_SORT:
63 *
64 * Use the Timsort algorithm provided in timsort.h to sort
65 * nodeset as this is a great improvement over the old Shell sort
66 * used in xmlXPathNodeSetSort()
67 */
68#define WITH_TIM_SORT
69
70/*
71* XP_OPTIMIZED_NON_ELEM_COMPARISON:
72* If defined, this will use xmlXPathCmpNodesExt() instead of
73* xmlXPathCmpNodes(). The new function is optimized comparison of
74* non-element nodes; actually it will speed up comparison only if
75* xmlXPathOrderDocElems() was called in order to index the elements of
76* a tree in document order; Libxslt does such an indexing, thus it will
77* benefit from this optimization.
78*/
79#define XP_OPTIMIZED_NON_ELEM_COMPARISON
80
81/*
82* XP_OPTIMIZED_FILTER_FIRST:
83* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
84* in a way, that it stop evaluation at the first node.
85*/
86#define XP_OPTIMIZED_FILTER_FIRST
87
88/*
89 * XPATH_MAX_STEPS:
90 * when compiling an XPath expression we arbitrary limit the maximum
91 * number of step operation in the compiled expression. 1000000 is
92 * an insanely large value which should never be reached under normal
93 * circumstances
94 */
95#define XPATH_MAX_STEPS 1000000
96
97/*
98 * XPATH_MAX_STACK_DEPTH:
99 * when evaluating an XPath expression we arbitrary limit the maximum
100 * number of object allowed to be pushed on the stack. 1000000 is
101 * an insanely large value which should never be reached under normal
102 * circumstances
103 */
104#define XPATH_MAX_STACK_DEPTH 1000000
105
106/*
107 * XPATH_MAX_NODESET_LENGTH:
108 * when evaluating an XPath expression nodesets are created and we
109 * arbitrary limit the maximum length of those node set. 10000000 is
110 * an insanely large value which should never be reached under normal
111 * circumstances, one would first need to construct an in memory tree
112 * with more than 10 millions nodes.
113 */
114#define XPATH_MAX_NODESET_LENGTH 10000000
115
116/*
117 * XPATH_MAX_RECRUSION_DEPTH:
118 * Maximum amount of nested functions calls when parsing or evaluating
119 * expressions
120 */
121#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
122#define XPATH_MAX_RECURSION_DEPTH 500
123#elif defined(_WIN32)
124/* Windows typically limits stack size to 1MB. */
125#define XPATH_MAX_RECURSION_DEPTH 1000
126#else
127#define XPATH_MAX_RECURSION_DEPTH 5000
128#endif
129
130/*
131 * TODO:
132 * There are a few spots where some tests are done which depend upon ascii
133 * data. These should be enhanced for full UTF8 support (see particularly
134 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
135 */
136
137#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
138
139/************************************************************************
140 * *
141 * Floating point stuff *
142 * *
143 ************************************************************************/
144
145double xmlXPathNAN = 0.0;
146double xmlXPathPINF = 0.0;
147double xmlXPathNINF = 0.0;
148
149/**
150 * xmlXPathInit:
151 *
152 * DEPRECATED: Alias for xmlInitParser.
153 */
154void
155xmlXPathInit(void) {
156 xmlInitParser();
157}
158
159/**
160 * xmlInitXPathInternal:
161 *
162 * Initialize the XPath environment
163 */
164ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
165void
166xmlInitXPathInternal(void) {
167#if defined(NAN) && defined(INFINITY) && !defined(VBOX)
168 xmlXPathNAN = NAN;
169 xmlXPathPINF = INFINITY;
170 xmlXPathNINF = -INFINITY;
171#else
172 /* MSVC doesn't allow division by zero in constant expressions. */
173 double zero = 0.0;
174 xmlXPathNAN = 0.0 / zero;
175 xmlXPathPINF = 1.0 / zero;
176 xmlXPathNINF = -xmlXPathPINF;
177#endif
178}
179
180/**
181 * xmlXPathIsNaN:
182 * @val: a double value
183 *
184 * Checks whether a double is a NaN.
185 *
186 * Returns 1 if the value is a NaN, 0 otherwise
187 */
188int
189xmlXPathIsNaN(double val) {
190#ifdef isnan
191 return isnan(val);
192#else
193 return !(val == val);
194#endif
195}
196
197/**
198 * xmlXPathIsInf:
199 * @val: a double value
200 *
201 * Checks whether a double is an infinity.
202 *
203 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
204 */
205int
206xmlXPathIsInf(double val) {
207#ifdef isinf
208 return isinf(val) ? (val > 0 ? 1 : -1) : 0;
209#else
210 if (val >= xmlXPathPINF)
211 return 1;
212 if (val <= -xmlXPathPINF)
213 return -1;
214 return 0;
215#endif
216}
217
218#endif /* SCHEMAS or XPATH */
219
220#ifdef LIBXML_XPATH_ENABLED
221
222/*
223 * TODO: when compatibility allows remove all "fake node libxslt" strings
224 * the test should just be name[0] = ' '
225 */
226
227static const xmlNs xmlXPathXMLNamespaceStruct = {
228 NULL,
229 XML_NAMESPACE_DECL,
230 XML_XML_NAMESPACE,
231 BAD_CAST "xml",
232 NULL,
233 NULL
234};
235static const xmlNs *const xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
236#ifndef LIBXML_THREAD_ENABLED
237/*
238 * Optimizer is disabled only when threaded apps are detected while
239 * the library ain't compiled for thread safety.
240 */
241static int xmlXPathDisableOptimizer = 0;
242#endif
243
244static void
245xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes);
246
247#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
248/**
249 * xmlXPathCmpNodesExt:
250 * @node1: the first node
251 * @node2: the second node
252 *
253 * Compare two nodes w.r.t document order.
254 * This one is optimized for handling of non-element nodes.
255 *
256 * Returns -2 in case of error 1 if first point < second point, 0 if
257 * it's the same node, -1 otherwise
258 */
259static int
260xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
261 int depth1, depth2;
262 int misc = 0, precedence1 = 0, precedence2 = 0;
263 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
264 xmlNodePtr cur, root;
265 ptrdiff_t l1, l2;
266
267 if ((node1 == NULL) || (node2 == NULL))
268 return(-2);
269
270 if (node1 == node2)
271 return(0);
272
273 /*
274 * a couple of optimizations which will avoid computations in most cases
275 */
276 switch (node1->type) {
277 case XML_ELEMENT_NODE:
278 if (node2->type == XML_ELEMENT_NODE) {
279 if ((0 > (ptrdiff_t) node1->content) &&
280 (0 > (ptrdiff_t) node2->content) &&
281 (node1->doc == node2->doc))
282 {
283 l1 = -((ptrdiff_t) node1->content);
284 l2 = -((ptrdiff_t) node2->content);
285 if (l1 < l2)
286 return(1);
287 if (l1 > l2)
288 return(-1);
289 } else
290 goto turtle_comparison;
291 }
292 break;
293 case XML_ATTRIBUTE_NODE:
294 precedence1 = 1; /* element is owner */
295 miscNode1 = node1;
296 node1 = node1->parent;
297 misc = 1;
298 break;
299 case XML_TEXT_NODE:
300 case XML_CDATA_SECTION_NODE:
301 case XML_COMMENT_NODE:
302 case XML_PI_NODE: {
303 miscNode1 = node1;
304 /*
305 * Find nearest element node.
306 */
307 if (node1->prev != NULL) {
308 do {
309 node1 = node1->prev;
310 if (node1->type == XML_ELEMENT_NODE) {
311 precedence1 = 3; /* element in prev-sibl axis */
312 break;
313 }
314 if (node1->prev == NULL) {
315 precedence1 = 2; /* element is parent */
316 /*
317 * URGENT TODO: Are there any cases, where the
318 * parent of such a node is not an element node?
319 */
320 node1 = node1->parent;
321 break;
322 }
323 } while (1);
324 } else {
325 precedence1 = 2; /* element is parent */
326 node1 = node1->parent;
327 }
328 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
329 (0 <= (ptrdiff_t) node1->content)) {
330 /*
331 * Fallback for whatever case.
332 */
333 node1 = miscNode1;
334 precedence1 = 0;
335 } else
336 misc = 1;
337 }
338 break;
339 case XML_NAMESPACE_DECL:
340 /*
341 * TODO: why do we return 1 for namespace nodes?
342 */
343 return(1);
344 default:
345 break;
346 }
347 switch (node2->type) {
348 case XML_ELEMENT_NODE:
349 break;
350 case XML_ATTRIBUTE_NODE:
351 precedence2 = 1; /* element is owner */
352 miscNode2 = node2;
353 node2 = node2->parent;
354 misc = 1;
355 break;
356 case XML_TEXT_NODE:
357 case XML_CDATA_SECTION_NODE:
358 case XML_COMMENT_NODE:
359 case XML_PI_NODE: {
360 miscNode2 = node2;
361 if (node2->prev != NULL) {
362 do {
363 node2 = node2->prev;
364 if (node2->type == XML_ELEMENT_NODE) {
365 precedence2 = 3; /* element in prev-sibl axis */
366 break;
367 }
368 if (node2->prev == NULL) {
369 precedence2 = 2; /* element is parent */
370 node2 = node2->parent;
371 break;
372 }
373 } while (1);
374 } else {
375 precedence2 = 2; /* element is parent */
376 node2 = node2->parent;
377 }
378 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
379 (0 <= (ptrdiff_t) node2->content))
380 {
381 node2 = miscNode2;
382 precedence2 = 0;
383 } else
384 misc = 1;
385 }
386 break;
387 case XML_NAMESPACE_DECL:
388 return(1);
389 default:
390 break;
391 }
392 if (misc) {
393 if (node1 == node2) {
394 if (precedence1 == precedence2) {
395 /*
396 * The ugly case; but normally there aren't many
397 * adjacent non-element nodes around.
398 */
399 cur = miscNode2->prev;
400 while (cur != NULL) {
401 if (cur == miscNode1)
402 return(1);
403 if (cur->type == XML_ELEMENT_NODE)
404 return(-1);
405 cur = cur->prev;
406 }
407 return (-1);
408 } else {
409 /*
410 * Evaluate based on higher precedence wrt to the element.
411 * TODO: This assumes attributes are sorted before content.
412 * Is this 100% correct?
413 */
414 if (precedence1 < precedence2)
415 return(1);
416 else
417 return(-1);
418 }
419 }
420 /*
421 * Special case: One of the helper-elements is contained by the other.
422 * <foo>
423 * <node2>
424 * <node1>Text-1(precedence1 == 2)</node1>
425 * </node2>
426 * Text-6(precedence2 == 3)
427 * </foo>
428 */
429 if ((precedence2 == 3) && (precedence1 > 1)) {
430 cur = node1->parent;
431 while (cur) {
432 if (cur == node2)
433 return(1);
434 cur = cur->parent;
435 }
436 }
437 if ((precedence1 == 3) && (precedence2 > 1)) {
438 cur = node2->parent;
439 while (cur) {
440 if (cur == node1)
441 return(-1);
442 cur = cur->parent;
443 }
444 }
445 }
446
447 /*
448 * Speedup using document order if available.
449 */
450 if ((node1->type == XML_ELEMENT_NODE) &&
451 (node2->type == XML_ELEMENT_NODE) &&
452 (0 > (ptrdiff_t) node1->content) &&
453 (0 > (ptrdiff_t) node2->content) &&
454 (node1->doc == node2->doc)) {
455
456 l1 = -((ptrdiff_t) node1->content);
457 l2 = -((ptrdiff_t) node2->content);
458 if (l1 < l2)
459 return(1);
460 if (l1 > l2)
461 return(-1);
462 }
463
464turtle_comparison:
465
466 if (node1 == node2->prev)
467 return(1);
468 if (node1 == node2->next)
469 return(-1);
470 /*
471 * compute depth to root
472 */
473 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
474 if (cur->parent == node1)
475 return(1);
476 depth2++;
477 }
478 root = cur;
479 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
480 if (cur->parent == node2)
481 return(-1);
482 depth1++;
483 }
484 /*
485 * Distinct document (or distinct entities :-( ) case.
486 */
487 if (root != cur) {
488 return(-2);
489 }
490 /*
491 * get the nearest common ancestor.
492 */
493 while (depth1 > depth2) {
494 depth1--;
495 node1 = node1->parent;
496 }
497 while (depth2 > depth1) {
498 depth2--;
499 node2 = node2->parent;
500 }
501 while (node1->parent != node2->parent) {
502 node1 = node1->parent;
503 node2 = node2->parent;
504 /* should not happen but just in case ... */
505 if ((node1 == NULL) || (node2 == NULL))
506 return(-2);
507 }
508 /*
509 * Find who's first.
510 */
511 if (node1 == node2->prev)
512 return(1);
513 if (node1 == node2->next)
514 return(-1);
515 /*
516 * Speedup using document order if available.
517 */
518 if ((node1->type == XML_ELEMENT_NODE) &&
519 (node2->type == XML_ELEMENT_NODE) &&
520 (0 > (ptrdiff_t) node1->content) &&
521 (0 > (ptrdiff_t) node2->content) &&
522 (node1->doc == node2->doc)) {
523
524 l1 = -((ptrdiff_t) node1->content);
525 l2 = -((ptrdiff_t) node2->content);
526 if (l1 < l2)
527 return(1);
528 if (l1 > l2)
529 return(-1);
530 }
531
532 for (cur = node1->next;cur != NULL;cur = cur->next)
533 if (cur == node2)
534 return(1);
535 return(-1); /* assume there is no sibling list corruption */
536}
537#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
538
539/*
540 * Wrapper for the Timsort algorithm from timsort.h
541 */
542#ifdef WITH_TIM_SORT
543#define SORT_NAME libxml_domnode
544#define SORT_TYPE xmlNodePtr
545/**
546 * wrap_cmp:
547 * @x: a node
548 * @y: another node
549 *
550 * Comparison function for the Timsort implementation
551 *
552 * Returns -2 in case of error -1 if first point < second point, 0 if
553 * it's the same node, +1 otherwise
554 */
555static
556int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
557#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
558 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
559 {
560 int res = xmlXPathCmpNodesExt(x, y);
561 return res == -2 ? res : -res;
562 }
563#else
564 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
565 {
566 int res = xmlXPathCmpNodes(x, y);
567 return res == -2 ? res : -res;
568 }
569#endif
570#define SORT_CMP(x, y) (wrap_cmp(x, y))
571#include "timsort.h"
572#endif /* WITH_TIM_SORT */
573
574/************************************************************************
575 * *
576 * Error handling routines *
577 * *
578 ************************************************************************/
579
580/**
581 * XP_ERRORNULL:
582 * @X: the error code
583 *
584 * Macro to raise an XPath error and return NULL.
585 */
586#define XP_ERRORNULL(X) \
587 { xmlXPathErr(ctxt, X); return(NULL); }
588
589/*
590 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
591 */
592static const char* const xmlXPathErrorMessages[] = {
593 "Ok\n",
594 "Number encoding\n",
595 "Unfinished literal\n",
596 "Start of literal\n",
597 "Expected $ for variable reference\n",
598 "Undefined variable\n",
599 "Invalid predicate\n",
600 "Invalid expression\n",
601 "Missing closing curly brace\n",
602 "Unregistered function\n",
603 "Invalid operand\n",
604 "Invalid type\n",
605 "Invalid number of arguments\n",
606 "Invalid context size\n",
607 "Invalid context position\n",
608 "Memory allocation error\n",
609 "Syntax error\n",
610 "Resource error\n",
611 "Sub resource error\n",
612 "Undefined namespace prefix\n",
613 "Encoding error\n",
614 "Char out of XML range\n",
615 "Invalid or incomplete context\n",
616 "Stack usage error\n",
617 "Forbidden variable\n",
618 "Operation limit exceeded\n",
619 "Recursion limit exceeded\n",
620 "?? Unknown error ??\n" /* Must be last in the list! */
621};
622#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
623 sizeof(xmlXPathErrorMessages[0])) - 1)
624/**
625 * xmlXPathErrMemory:
626 * @ctxt: an XPath context
627 *
628 * Handle a memory allocation failure.
629 */
630void
631xmlXPathErrMemory(xmlXPathContextPtr ctxt)
632{
633 if (ctxt == NULL)
634 return;
635 xmlRaiseMemoryError(ctxt->error, NULL, ctxt->userData, XML_FROM_XPATH,
636 &ctxt->lastError);
637}
638
639/**
640 * xmlXPathPErrMemory:
641 * @ctxt: an XPath parser context
642 *
643 * Handle a memory allocation failure.
644 */
645void
646xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt)
647{
648 if (ctxt == NULL)
649 return;
650 ctxt->error = XPATH_MEMORY_ERROR;
651 xmlXPathErrMemory(ctxt->context);
652}
653
654/**
655 * xmlXPathErr:
656 * @ctxt: a XPath parser context
657 * @code: the error code
658 *
659 * Handle an XPath error
660 */
661void
662xmlXPathErr(xmlXPathParserContextPtr ctxt, int code)
663{
664 xmlStructuredErrorFunc schannel = NULL;
665 xmlGenericErrorFunc channel = NULL;
666 void *data = NULL;
667 xmlNodePtr node = NULL;
668 int res;
669
670 if (ctxt == NULL)
671 return;
672 if ((code < 0) || (code > MAXERRNO))
673 code = MAXERRNO;
674 /* Only report the first error */
675 if (ctxt->error != 0)
676 return;
677
678 ctxt->error = code;
679
680 if (ctxt->context != NULL) {
681 xmlErrorPtr err = &ctxt->context->lastError;
682
683 /* Don't overwrite memory error. */
684 if (err->code == XML_ERR_NO_MEMORY)
685 return;
686
687 /* cleanup current last error */
688 xmlResetError(err);
689
690 err->domain = XML_FROM_XPATH;
691 err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK;
692 err->level = XML_ERR_ERROR;
693 if (ctxt->base != NULL) {
694 err->str1 = (char *) xmlStrdup(ctxt->base);
695 if (err->str1 == NULL) {
696 xmlXPathPErrMemory(ctxt);
697 return;
698 }
699 }
700 err->int1 = ctxt->cur - ctxt->base;
701 err->node = ctxt->context->debugNode;
702
703 schannel = ctxt->context->error;
704 data = ctxt->context->userData;
705 node = ctxt->context->debugNode;
706 }
707
708 if (schannel == NULL) {
709 channel = xmlGenericError;
710 data = xmlGenericErrorContext;
711 }
712
713 res = __xmlRaiseError(schannel, channel, data, NULL, node, XML_FROM_XPATH,
714 code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
715 XML_ERR_ERROR, NULL, 0,
716 (const char *) ctxt->base, NULL, NULL,
717 ctxt->cur - ctxt->base, 0,
718 "%s", xmlXPathErrorMessages[code]);
719 if (res < 0)
720 xmlXPathPErrMemory(ctxt);
721}
722
723/**
724 * xmlXPatherror:
725 * @ctxt: the XPath Parser context
726 * @file: the file name
727 * @line: the line number
728 * @no: the error number
729 *
730 * Formats an error message.
731 */
732void
733xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
734 int line ATTRIBUTE_UNUSED, int no) {
735 xmlXPathErr(ctxt, no);
736}
737
738/**
739 * xmlXPathCheckOpLimit:
740 * @ctxt: the XPath Parser context
741 * @opCount: the number of operations to be added
742 *
743 * Adds opCount to the running total of operations and returns -1 if the
744 * operation limit is exceeded. Returns 0 otherwise.
745 */
746static int
747xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
748 xmlXPathContextPtr xpctxt = ctxt->context;
749
750 if ((opCount > xpctxt->opLimit) ||
751 (xpctxt->opCount > xpctxt->opLimit - opCount)) {
752 xpctxt->opCount = xpctxt->opLimit;
753 xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
754 return(-1);
755 }
756
757 xpctxt->opCount += opCount;
758 return(0);
759}
760
761#define OP_LIMIT_EXCEEDED(ctxt, n) \
762 ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
763
764/************************************************************************
765 * *
766 * Parser Types *
767 * *
768 ************************************************************************/
769
770/*
771 * Types are private:
772 */
773
774typedef enum {
775 XPATH_OP_END=0,
776 XPATH_OP_AND,
777 XPATH_OP_OR,
778 XPATH_OP_EQUAL,
779 XPATH_OP_CMP,
780 XPATH_OP_PLUS,
781 XPATH_OP_MULT,
782 XPATH_OP_UNION,
783 XPATH_OP_ROOT,
784 XPATH_OP_NODE,
785 XPATH_OP_COLLECT,
786 XPATH_OP_VALUE, /* 11 */
787 XPATH_OP_VARIABLE,
788 XPATH_OP_FUNCTION,
789 XPATH_OP_ARG,
790 XPATH_OP_PREDICATE,
791 XPATH_OP_FILTER, /* 16 */
792 XPATH_OP_SORT /* 17 */
793#ifdef LIBXML_XPTR_LOCS_ENABLED
794 ,XPATH_OP_RANGETO
795#endif
796} xmlXPathOp;
797
798typedef enum {
799 AXIS_ANCESTOR = 1,
800 AXIS_ANCESTOR_OR_SELF,
801 AXIS_ATTRIBUTE,
802 AXIS_CHILD,
803 AXIS_DESCENDANT,
804 AXIS_DESCENDANT_OR_SELF,
805 AXIS_FOLLOWING,
806 AXIS_FOLLOWING_SIBLING,
807 AXIS_NAMESPACE,
808 AXIS_PARENT,
809 AXIS_PRECEDING,
810 AXIS_PRECEDING_SIBLING,
811 AXIS_SELF
812} xmlXPathAxisVal;
813
814typedef enum {
815 NODE_TEST_NONE = 0,
816 NODE_TEST_TYPE = 1,
817 NODE_TEST_PI = 2,
818 NODE_TEST_ALL = 3,
819 NODE_TEST_NS = 4,
820 NODE_TEST_NAME = 5
821} xmlXPathTestVal;
822
823typedef enum {
824 NODE_TYPE_NODE = 0,
825 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
826 NODE_TYPE_TEXT = XML_TEXT_NODE,
827 NODE_TYPE_PI = XML_PI_NODE
828} xmlXPathTypeVal;
829
830typedef struct _xmlXPathStepOp xmlXPathStepOp;
831typedef xmlXPathStepOp *xmlXPathStepOpPtr;
832struct _xmlXPathStepOp {
833 xmlXPathOp op; /* The identifier of the operation */
834 int ch1; /* First child */
835 int ch2; /* Second child */
836 int value;
837 int value2;
838 int value3;
839 void *value4;
840 void *value5;
841 xmlXPathFunction cache;
842 void *cacheURI;
843};
844
845struct _xmlXPathCompExpr {
846 int nbStep; /* Number of steps in this expression */
847 int maxStep; /* Maximum number of steps allocated */
848 xmlXPathStepOp *steps; /* ops for computation of this expression */
849 int last; /* index of last step in expression */
850 xmlChar *expr; /* the expression being computed */
851 xmlDictPtr dict; /* the dictionary to use if any */
852#ifdef XPATH_STREAMING
853 xmlPatternPtr stream;
854#endif
855};
856
857/************************************************************************
858 * *
859 * Forward declarations *
860 * *
861 ************************************************************************/
862
863static void
864xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
865static int
866xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
867 xmlXPathStepOpPtr op, xmlNodePtr *first);
868static int
869xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
870 xmlXPathStepOpPtr op,
871 int isPredicate);
872static void
873xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
874
875/************************************************************************
876 * *
877 * Parser Type functions *
878 * *
879 ************************************************************************/
880
881/**
882 * xmlXPathNewCompExpr:
883 *
884 * Create a new Xpath component
885 *
886 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
887 */
888static xmlXPathCompExprPtr
889xmlXPathNewCompExpr(void) {
890 xmlXPathCompExprPtr cur;
891
892 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
893 if (cur == NULL)
894 return(NULL);
895 memset(cur, 0, sizeof(xmlXPathCompExpr));
896 cur->maxStep = 10;
897 cur->nbStep = 0;
898 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
899 sizeof(xmlXPathStepOp));
900 if (cur->steps == NULL) {
901 xmlFree(cur);
902 return(NULL);
903 }
904 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
905 cur->last = -1;
906 return(cur);
907}
908
909/**
910 * xmlXPathFreeCompExpr:
911 * @comp: an XPATH comp
912 *
913 * Free up the memory allocated by @comp
914 */
915void
916xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
917{
918 xmlXPathStepOpPtr op;
919 int i;
920
921 if (comp == NULL)
922 return;
923 if (comp->dict == NULL) {
924 for (i = 0; i < comp->nbStep; i++) {
925 op = &comp->steps[i];
926 if (op->value4 != NULL) {
927 if (op->op == XPATH_OP_VALUE)
928 xmlXPathFreeObject(op->value4);
929 else
930 xmlFree(op->value4);
931 }
932 if (op->value5 != NULL)
933 xmlFree(op->value5);
934 }
935 } else {
936 for (i = 0; i < comp->nbStep; i++) {
937 op = &comp->steps[i];
938 if (op->value4 != NULL) {
939 if (op->op == XPATH_OP_VALUE)
940 xmlXPathFreeObject(op->value4);
941 }
942 }
943 xmlDictFree(comp->dict);
944 }
945 if (comp->steps != NULL) {
946 xmlFree(comp->steps);
947 }
948#ifdef XPATH_STREAMING
949 if (comp->stream != NULL) {
950 xmlFreePatternList(comp->stream);
951 }
952#endif
953 if (comp->expr != NULL) {
954 xmlFree(comp->expr);
955 }
956
957 xmlFree(comp);
958}
959
960/**
961 * xmlXPathCompExprAdd:
962 * @comp: the compiled expression
963 * @ch1: first child index
964 * @ch2: second child index
965 * @op: an op
966 * @value: the first int value
967 * @value2: the second int value
968 * @value3: the third int value
969 * @value4: the first string value
970 * @value5: the second string value
971 *
972 * Add a step to an XPath Compiled Expression
973 *
974 * Returns -1 in case of failure, the index otherwise
975 */
976static int
977xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
978 xmlXPathOp op, int value,
979 int value2, int value3, void *value4, void *value5) {
980 xmlXPathCompExprPtr comp = ctxt->comp;
981 if (comp->nbStep >= comp->maxStep) {
982 xmlXPathStepOp *real;
983
984 if (comp->maxStep >= XPATH_MAX_STEPS) {
985 xmlXPathPErrMemory(ctxt);
986 return(-1);
987 }
988 comp->maxStep *= 2;
989 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
990 comp->maxStep * sizeof(xmlXPathStepOp));
991 if (real == NULL) {
992 comp->maxStep /= 2;
993 xmlXPathPErrMemory(ctxt);
994 return(-1);
995 }
996 comp->steps = real;
997 }
998 comp->last = comp->nbStep;
999 comp->steps[comp->nbStep].ch1 = ch1;
1000 comp->steps[comp->nbStep].ch2 = ch2;
1001 comp->steps[comp->nbStep].op = op;
1002 comp->steps[comp->nbStep].value = value;
1003 comp->steps[comp->nbStep].value2 = value2;
1004 comp->steps[comp->nbStep].value3 = value3;
1005 if ((comp->dict != NULL) &&
1006 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1007 (op == XPATH_OP_COLLECT))) {
1008 if (value4 != NULL) {
1009 comp->steps[comp->nbStep].value4 = (xmlChar *)
1010 (void *)xmlDictLookup(comp->dict, value4, -1);
1011 xmlFree(value4);
1012 } else
1013 comp->steps[comp->nbStep].value4 = NULL;
1014 if (value5 != NULL) {
1015 comp->steps[comp->nbStep].value5 = (xmlChar *)
1016 (void *)xmlDictLookup(comp->dict, value5, -1);
1017 xmlFree(value5);
1018 } else
1019 comp->steps[comp->nbStep].value5 = NULL;
1020 } else {
1021 comp->steps[comp->nbStep].value4 = value4;
1022 comp->steps[comp->nbStep].value5 = value5;
1023 }
1024 comp->steps[comp->nbStep].cache = NULL;
1025 return(comp->nbStep++);
1026}
1027
1028/**
1029 * xmlXPathCompSwap:
1030 * @comp: the compiled expression
1031 * @op: operation index
1032 *
1033 * Swaps 2 operations in the compiled expression
1034 */
1035static void
1036xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1037 int tmp;
1038
1039#ifndef LIBXML_THREAD_ENABLED
1040 /*
1041 * Since this manipulates possibly shared variables, this is
1042 * disabled if one detects that the library is used in a multithreaded
1043 * application
1044 */
1045 if (xmlXPathDisableOptimizer)
1046 return;
1047#endif
1048
1049 tmp = op->ch1;
1050 op->ch1 = op->ch2;
1051 op->ch2 = tmp;
1052}
1053
1054#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1055 xmlXPathCompExprAdd(ctxt, (op1), (op2), \
1056 (op), (val), (val2), (val3), (val4), (val5))
1057#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1058 xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \
1059 (op), (val), (val2), (val3), (val4), (val5))
1060
1061#define PUSH_LEAVE_EXPR(op, val, val2) \
1062xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1063
1064#define PUSH_UNARY_EXPR(op, ch, val, val2) \
1065xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1066
1067#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1068xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
1069 (val), (val2), 0 ,NULL ,NULL)
1070
1071/************************************************************************
1072 * *
1073 * XPath object cache structures *
1074 * *
1075 ************************************************************************/
1076
1077/* #define XP_DEFAULT_CACHE_ON */
1078
1079typedef struct _xmlXPathContextCache xmlXPathContextCache;
1080typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1081struct _xmlXPathContextCache {
1082 xmlXPathObjectPtr nodesetObjs; /* stringval points to next */
1083 xmlXPathObjectPtr miscObjs; /* stringval points to next */
1084 int numNodeset;
1085 int maxNodeset;
1086 int numMisc;
1087 int maxMisc;
1088};
1089
1090/************************************************************************
1091 * *
1092 * Debugging related functions *
1093 * *
1094 ************************************************************************/
1095
1096#ifdef LIBXML_DEBUG_ENABLED
1097static void
1098xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1099 int i;
1100 char shift[100];
1101
1102 for (i = 0;((i < depth) && (i < 25));i++)
1103 shift[2 * i] = shift[2 * i + 1] = ' ';
1104 shift[2 * i] = shift[2 * i + 1] = 0;
1105 if (cur == NULL) {
1106 fprintf(output, "%s", shift);
1107 fprintf(output, "Node is NULL !\n");
1108 return;
1109
1110 }
1111
1112 if ((cur->type == XML_DOCUMENT_NODE) ||
1113 (cur->type == XML_HTML_DOCUMENT_NODE)) {
1114 fprintf(output, "%s", shift);
1115 fprintf(output, " /\n");
1116 } else if (cur->type == XML_ATTRIBUTE_NODE)
1117 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1118 else
1119 xmlDebugDumpOneNode(output, cur, depth);
1120}
1121static void
1122xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1123 xmlNodePtr tmp;
1124 int i;
1125 char shift[100];
1126
1127 for (i = 0;((i < depth) && (i < 25));i++)
1128 shift[2 * i] = shift[2 * i + 1] = ' ';
1129 shift[2 * i] = shift[2 * i + 1] = 0;
1130 if (cur == NULL) {
1131 fprintf(output, "%s", shift);
1132 fprintf(output, "Node is NULL !\n");
1133 return;
1134
1135 }
1136
1137 while (cur != NULL) {
1138 tmp = cur;
1139 cur = cur->next;
1140 xmlDebugDumpOneNode(output, tmp, depth);
1141 }
1142}
1143
1144static void
1145xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1146 int i;
1147 char shift[100];
1148
1149 for (i = 0;((i < depth) && (i < 25));i++)
1150 shift[2 * i] = shift[2 * i + 1] = ' ';
1151 shift[2 * i] = shift[2 * i + 1] = 0;
1152
1153 if (cur == NULL) {
1154 fprintf(output, "%s", shift);
1155 fprintf(output, "NodeSet is NULL !\n");
1156 return;
1157
1158 }
1159
1160 if (cur != NULL) {
1161 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1162 for (i = 0;i < cur->nodeNr;i++) {
1163 fprintf(output, "%s", shift);
1164 fprintf(output, "%d", i + 1);
1165 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1166 }
1167 }
1168}
1169
1170static void
1171xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1172 int i;
1173 char shift[100];
1174
1175 for (i = 0;((i < depth) && (i < 25));i++)
1176 shift[2 * i] = shift[2 * i + 1] = ' ';
1177 shift[2 * i] = shift[2 * i + 1] = 0;
1178
1179 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1180 fprintf(output, "%s", shift);
1181 fprintf(output, "Value Tree is NULL !\n");
1182 return;
1183
1184 }
1185
1186 fprintf(output, "%s", shift);
1187 fprintf(output, "%d", i + 1);
1188 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1189}
1190#if defined(LIBXML_XPTR_LOCS_ENABLED)
1191static void
1192xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1193 int i;
1194 char shift[100];
1195
1196 for (i = 0;((i < depth) && (i < 25));i++)
1197 shift[2 * i] = shift[2 * i + 1] = ' ';
1198 shift[2 * i] = shift[2 * i + 1] = 0;
1199
1200 if (cur == NULL) {
1201 fprintf(output, "%s", shift);
1202 fprintf(output, "LocationSet is NULL !\n");
1203 return;
1204
1205 }
1206
1207 for (i = 0;i < cur->locNr;i++) {
1208 fprintf(output, "%s", shift);
1209 fprintf(output, "%d : ", i + 1);
1210 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1211 }
1212}
1213#endif /* LIBXML_XPTR_LOCS_ENABLED */
1214
1215/**
1216 * xmlXPathDebugDumpObject:
1217 * @output: the FILE * to dump the output
1218 * @cur: the object to inspect
1219 * @depth: indentation level
1220 *
1221 * Dump the content of the object for debugging purposes
1222 */
1223void
1224xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1225 int i;
1226 char shift[100];
1227
1228 if (output == NULL) return;
1229
1230 for (i = 0;((i < depth) && (i < 25));i++)
1231 shift[2 * i] = shift[2 * i + 1] = ' ';
1232 shift[2 * i] = shift[2 * i + 1] = 0;
1233
1234
1235 fprintf(output, "%s", shift);
1236
1237 if (cur == NULL) {
1238 fprintf(output, "Object is empty (NULL)\n");
1239 return;
1240 }
1241 switch(cur->type) {
1242 case XPATH_UNDEFINED:
1243 fprintf(output, "Object is uninitialized\n");
1244 break;
1245 case XPATH_NODESET:
1246 fprintf(output, "Object is a Node Set :\n");
1247 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1248 break;
1249 case XPATH_XSLT_TREE:
1250 fprintf(output, "Object is an XSLT value tree :\n");
1251 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1252 break;
1253 case XPATH_BOOLEAN:
1254 fprintf(output, "Object is a Boolean : ");
1255 if (cur->boolval) fprintf(output, "true\n");
1256 else fprintf(output, "false\n");
1257 break;
1258 case XPATH_NUMBER:
1259 switch (xmlXPathIsInf(cur->floatval)) {
1260 case 1:
1261 fprintf(output, "Object is a number : Infinity\n");
1262 break;
1263 case -1:
1264 fprintf(output, "Object is a number : -Infinity\n");
1265 break;
1266 default:
1267 if (xmlXPathIsNaN(cur->floatval)) {
1268 fprintf(output, "Object is a number : NaN\n");
1269 } else if (cur->floatval == 0) {
1270 /* Omit sign for negative zero. */
1271 fprintf(output, "Object is a number : 0\n");
1272 } else {
1273 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1274 }
1275 }
1276 break;
1277 case XPATH_STRING:
1278 fprintf(output, "Object is a string : ");
1279 xmlDebugDumpString(output, cur->stringval);
1280 fprintf(output, "\n");
1281 break;
1282#ifdef LIBXML_XPTR_LOCS_ENABLED
1283 case XPATH_POINT:
1284 fprintf(output, "Object is a point : index %d in node", cur->index);
1285 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1286 fprintf(output, "\n");
1287 break;
1288 case XPATH_RANGE:
1289 if ((cur->user2 == NULL) ||
1290 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1291 fprintf(output, "Object is a collapsed range :\n");
1292 fprintf(output, "%s", shift);
1293 if (cur->index >= 0)
1294 fprintf(output, "index %d in ", cur->index);
1295 fprintf(output, "node\n");
1296 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1297 depth + 1);
1298 } else {
1299 fprintf(output, "Object is a range :\n");
1300 fprintf(output, "%s", shift);
1301 fprintf(output, "From ");
1302 if (cur->index >= 0)
1303 fprintf(output, "index %d in ", cur->index);
1304 fprintf(output, "node\n");
1305 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1306 depth + 1);
1307 fprintf(output, "%s", shift);
1308 fprintf(output, "To ");
1309 if (cur->index2 >= 0)
1310 fprintf(output, "index %d in ", cur->index2);
1311 fprintf(output, "node\n");
1312 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1313 depth + 1);
1314 fprintf(output, "\n");
1315 }
1316 break;
1317 case XPATH_LOCATIONSET:
1318 fprintf(output, "Object is a Location Set:\n");
1319 xmlXPathDebugDumpLocationSet(output,
1320 (xmlLocationSetPtr) cur->user, depth);
1321 break;
1322#endif /* LIBXML_XPTR_LOCS_ENABLED */
1323 case XPATH_USERS:
1324 fprintf(output, "Object is user defined\n");
1325 break;
1326 }
1327}
1328
1329static void
1330xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1331 xmlXPathStepOpPtr op, int depth) {
1332 int i;
1333 char shift[100];
1334
1335 for (i = 0;((i < depth) && (i < 25));i++)
1336 shift[2 * i] = shift[2 * i + 1] = ' ';
1337 shift[2 * i] = shift[2 * i + 1] = 0;
1338
1339 fprintf(output, "%s", shift);
1340 if (op == NULL) {
1341 fprintf(output, "Step is NULL\n");
1342 return;
1343 }
1344 switch (op->op) {
1345 case XPATH_OP_END:
1346 fprintf(output, "END"); break;
1347 case XPATH_OP_AND:
1348 fprintf(output, "AND"); break;
1349 case XPATH_OP_OR:
1350 fprintf(output, "OR"); break;
1351 case XPATH_OP_EQUAL:
1352 if (op->value)
1353 fprintf(output, "EQUAL =");
1354 else
1355 fprintf(output, "EQUAL !=");
1356 break;
1357 case XPATH_OP_CMP:
1358 if (op->value)
1359 fprintf(output, "CMP <");
1360 else
1361 fprintf(output, "CMP >");
1362 if (!op->value2)
1363 fprintf(output, "=");
1364 break;
1365 case XPATH_OP_PLUS:
1366 if (op->value == 0)
1367 fprintf(output, "PLUS -");
1368 else if (op->value == 1)
1369 fprintf(output, "PLUS +");
1370 else if (op->value == 2)
1371 fprintf(output, "PLUS unary -");
1372 else if (op->value == 3)
1373 fprintf(output, "PLUS unary - -");
1374 break;
1375 case XPATH_OP_MULT:
1376 if (op->value == 0)
1377 fprintf(output, "MULT *");
1378 else if (op->value == 1)
1379 fprintf(output, "MULT div");
1380 else
1381 fprintf(output, "MULT mod");
1382 break;
1383 case XPATH_OP_UNION:
1384 fprintf(output, "UNION"); break;
1385 case XPATH_OP_ROOT:
1386 fprintf(output, "ROOT"); break;
1387 case XPATH_OP_NODE:
1388 fprintf(output, "NODE"); break;
1389 case XPATH_OP_SORT:
1390 fprintf(output, "SORT"); break;
1391 case XPATH_OP_COLLECT: {
1392 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1393 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1394 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1395 const xmlChar *prefix = op->value4;
1396 const xmlChar *name = op->value5;
1397
1398 fprintf(output, "COLLECT ");
1399 switch (axis) {
1400 case AXIS_ANCESTOR:
1401 fprintf(output, " 'ancestors' "); break;
1402 case AXIS_ANCESTOR_OR_SELF:
1403 fprintf(output, " 'ancestors-or-self' "); break;
1404 case AXIS_ATTRIBUTE:
1405 fprintf(output, " 'attributes' "); break;
1406 case AXIS_CHILD:
1407 fprintf(output, " 'child' "); break;
1408 case AXIS_DESCENDANT:
1409 fprintf(output, " 'descendant' "); break;
1410 case AXIS_DESCENDANT_OR_SELF:
1411 fprintf(output, " 'descendant-or-self' "); break;
1412 case AXIS_FOLLOWING:
1413 fprintf(output, " 'following' "); break;
1414 case AXIS_FOLLOWING_SIBLING:
1415 fprintf(output, " 'following-siblings' "); break;
1416 case AXIS_NAMESPACE:
1417 fprintf(output, " 'namespace' "); break;
1418 case AXIS_PARENT:
1419 fprintf(output, " 'parent' "); break;
1420 case AXIS_PRECEDING:
1421 fprintf(output, " 'preceding' "); break;
1422 case AXIS_PRECEDING_SIBLING:
1423 fprintf(output, " 'preceding-sibling' "); break;
1424 case AXIS_SELF:
1425 fprintf(output, " 'self' "); break;
1426 }
1427 switch (test) {
1428 case NODE_TEST_NONE:
1429 fprintf(output, "'none' "); break;
1430 case NODE_TEST_TYPE:
1431 fprintf(output, "'type' "); break;
1432 case NODE_TEST_PI:
1433 fprintf(output, "'PI' "); break;
1434 case NODE_TEST_ALL:
1435 fprintf(output, "'all' "); break;
1436 case NODE_TEST_NS:
1437 fprintf(output, "'namespace' "); break;
1438 case NODE_TEST_NAME:
1439 fprintf(output, "'name' "); break;
1440 }
1441 switch (type) {
1442 case NODE_TYPE_NODE:
1443 fprintf(output, "'node' "); break;
1444 case NODE_TYPE_COMMENT:
1445 fprintf(output, "'comment' "); break;
1446 case NODE_TYPE_TEXT:
1447 fprintf(output, "'text' "); break;
1448 case NODE_TYPE_PI:
1449 fprintf(output, "'PI' "); break;
1450 }
1451 if (prefix != NULL)
1452 fprintf(output, "%s:", prefix);
1453 if (name != NULL)
1454 fprintf(output, "%s", (const char *) name);
1455 break;
1456
1457 }
1458 case XPATH_OP_VALUE: {
1459 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1460
1461 fprintf(output, "ELEM ");
1462 xmlXPathDebugDumpObject(output, object, 0);
1463 goto finish;
1464 }
1465 case XPATH_OP_VARIABLE: {
1466 const xmlChar *prefix = op->value5;
1467 const xmlChar *name = op->value4;
1468
1469 if (prefix != NULL)
1470 fprintf(output, "VARIABLE %s:%s", prefix, name);
1471 else
1472 fprintf(output, "VARIABLE %s", name);
1473 break;
1474 }
1475 case XPATH_OP_FUNCTION: {
1476 int nbargs = op->value;
1477 const xmlChar *prefix = op->value5;
1478 const xmlChar *name = op->value4;
1479
1480 if (prefix != NULL)
1481 fprintf(output, "FUNCTION %s:%s(%d args)",
1482 prefix, name, nbargs);
1483 else
1484 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1485 break;
1486 }
1487 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1488 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1489 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1490#ifdef LIBXML_XPTR_LOCS_ENABLED
1491 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1492#endif
1493 default:
1494 fprintf(output, "UNKNOWN %d\n", op->op); return;
1495 }
1496 fprintf(output, "\n");
1497finish:
1498 if (op->ch1 >= 0)
1499 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1500 if (op->ch2 >= 0)
1501 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1502}
1503
1504/**
1505 * xmlXPathDebugDumpCompExpr:
1506 * @output: the FILE * for the output
1507 * @comp: the precompiled XPath expression
1508 * @depth: the indentation level.
1509 *
1510 * Dumps the tree of the compiled XPath expression.
1511 */
1512void
1513xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1514 int depth) {
1515 int i;
1516 char shift[100];
1517
1518 if ((output == NULL) || (comp == NULL)) return;
1519
1520 for (i = 0;((i < depth) && (i < 25));i++)
1521 shift[2 * i] = shift[2 * i + 1] = ' ';
1522 shift[2 * i] = shift[2 * i + 1] = 0;
1523
1524 fprintf(output, "%s", shift);
1525
1526#ifdef XPATH_STREAMING
1527 if (comp->stream) {
1528 fprintf(output, "Streaming Expression\n");
1529 } else
1530#endif
1531 {
1532 fprintf(output, "Compiled Expression : %d elements\n",
1533 comp->nbStep);
1534 i = comp->last;
1535 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1536 }
1537}
1538
1539#endif /* LIBXML_DEBUG_ENABLED */
1540
1541/************************************************************************
1542 * *
1543 * XPath object caching *
1544 * *
1545 ************************************************************************/
1546
1547/**
1548 * xmlXPathNewCache:
1549 *
1550 * Create a new object cache
1551 *
1552 * Returns the xmlXPathCache just allocated.
1553 */
1554static xmlXPathContextCachePtr
1555xmlXPathNewCache(void)
1556{
1557 xmlXPathContextCachePtr ret;
1558
1559 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1560 if (ret == NULL)
1561 return(NULL);
1562 memset(ret, 0 , sizeof(xmlXPathContextCache));
1563 ret->maxNodeset = 100;
1564 ret->maxMisc = 100;
1565 return(ret);
1566}
1567
1568static void
1569xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)
1570{
1571 while (list != NULL) {
1572 xmlXPathObjectPtr next;
1573
1574 next = (void *) list->stringval;
1575
1576 if (list->nodesetval != NULL) {
1577 if (list->nodesetval->nodeTab != NULL)
1578 xmlFree(list->nodesetval->nodeTab);
1579 xmlFree(list->nodesetval);
1580 }
1581 xmlFree(list);
1582
1583 list = next;
1584 }
1585}
1586
1587static void
1588xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1589{
1590 if (cache == NULL)
1591 return;
1592 if (cache->nodesetObjs)
1593 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1594 if (cache->miscObjs)
1595 xmlXPathCacheFreeObjectList(cache->miscObjs);
1596 xmlFree(cache);
1597}
1598
1599/**
1600 * xmlXPathContextSetCache:
1601 *
1602 * @ctxt: the XPath context
1603 * @active: enables/disables (creates/frees) the cache
1604 * @value: a value with semantics dependent on @options
1605 * @options: options (currently only the value 0 is used)
1606 *
1607 * Creates/frees an object cache on the XPath context.
1608 * If activates XPath objects (xmlXPathObject) will be cached internally
1609 * to be reused.
1610 * @options:
1611 * 0: This will set the XPath object caching:
1612 * @value:
1613 * This will set the maximum number of XPath objects
1614 * to be cached per slot
1615 * There are two slots for node-set and misc objects.
1616 * Use <0 for the default number (100).
1617 * Other values for @options have currently no effect.
1618 *
1619 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1620 */
1621int
1622xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1623 int active,
1624 int value,
1625 int options)
1626{
1627 if (ctxt == NULL)
1628 return(-1);
1629 if (active) {
1630 xmlXPathContextCachePtr cache;
1631
1632 if (ctxt->cache == NULL) {
1633 ctxt->cache = xmlXPathNewCache();
1634 if (ctxt->cache == NULL) {
1635 xmlXPathErrMemory(ctxt);
1636 return(-1);
1637 }
1638 }
1639 cache = (xmlXPathContextCachePtr) ctxt->cache;
1640 if (options == 0) {
1641 if (value < 0)
1642 value = 100;
1643 cache->maxNodeset = value;
1644 cache->maxMisc = value;
1645 }
1646 } else if (ctxt->cache != NULL) {
1647 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1648 ctxt->cache = NULL;
1649 }
1650 return(0);
1651}
1652
1653/**
1654 * xmlXPathCacheWrapNodeSet:
1655 * @pctxt: the XPath context
1656 * @val: the NodePtr value
1657 *
1658 * This is the cached version of xmlXPathWrapNodeSet().
1659 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1660 *
1661 * Returns the created or reused object.
1662 *
1663 * In case of error the node set is destroyed and NULL is returned.
1664 */
1665static xmlXPathObjectPtr
1666xmlXPathCacheWrapNodeSet(xmlXPathParserContextPtr pctxt, xmlNodeSetPtr val)
1667{
1668 xmlXPathObjectPtr ret;
1669 xmlXPathContextPtr ctxt = pctxt->context;
1670
1671 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1672 xmlXPathContextCachePtr cache =
1673 (xmlXPathContextCachePtr) ctxt->cache;
1674
1675 if (cache->miscObjs != NULL) {
1676 ret = cache->miscObjs;
1677 cache->miscObjs = (void *) ret->stringval;
1678 cache->numMisc -= 1;
1679 ret->stringval = NULL;
1680 ret->type = XPATH_NODESET;
1681 ret->nodesetval = val;
1682 return(ret);
1683 }
1684 }
1685
1686 ret = xmlXPathWrapNodeSet(val);
1687 if (ret == NULL)
1688 xmlXPathPErrMemory(pctxt);
1689 return(ret);
1690}
1691
1692/**
1693 * xmlXPathCacheWrapString:
1694 * @pctxt the XPath context
1695 * @val: the xmlChar * value
1696 *
1697 * This is the cached version of xmlXPathWrapString().
1698 * Wraps the @val string into an XPath object.
1699 *
1700 * Returns the created or reused object.
1701 */
1702static xmlXPathObjectPtr
1703xmlXPathCacheWrapString(xmlXPathParserContextPtr pctxt, xmlChar *val)
1704{
1705 xmlXPathObjectPtr ret;
1706 xmlXPathContextPtr ctxt = pctxt->context;
1707
1708 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1709 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1710
1711 if (cache->miscObjs != NULL) {
1712 ret = cache->miscObjs;
1713 cache->miscObjs = (void *) ret->stringval;
1714 cache->numMisc -= 1;
1715 ret->type = XPATH_STRING;
1716 ret->stringval = val;
1717 return(ret);
1718 }
1719 }
1720
1721 ret = xmlXPathWrapString(val);
1722 if (ret == NULL)
1723 xmlXPathPErrMemory(pctxt);
1724 return(ret);
1725}
1726
1727/**
1728 * xmlXPathCacheNewNodeSet:
1729 * @pctxt the XPath context
1730 * @val: the NodePtr value
1731 *
1732 * This is the cached version of xmlXPathNewNodeSet().
1733 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
1734 * it with the single Node @val
1735 *
1736 * Returns the created or reused object.
1737 */
1738static xmlXPathObjectPtr
1739xmlXPathCacheNewNodeSet(xmlXPathParserContextPtr pctxt, xmlNodePtr val)
1740{
1741 xmlXPathObjectPtr ret;
1742 xmlXPathContextPtr ctxt = pctxt->context;
1743
1744 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1745 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1746
1747 if (cache->nodesetObjs != NULL) {
1748 /*
1749 * Use the nodeset-cache.
1750 */
1751 ret = cache->nodesetObjs;
1752 cache->nodesetObjs = (void *) ret->stringval;
1753 cache->numNodeset -= 1;
1754 ret->stringval = NULL;
1755 ret->type = XPATH_NODESET;
1756 ret->boolval = 0;
1757 if (val) {
1758 if ((ret->nodesetval->nodeMax == 0) ||
1759 (val->type == XML_NAMESPACE_DECL))
1760 {
1761 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val) < 0)
1762 xmlXPathPErrMemory(pctxt);
1763 } else {
1764 ret->nodesetval->nodeTab[0] = val;
1765 ret->nodesetval->nodeNr = 1;
1766 }
1767 }
1768 return(ret);
1769 } else if (cache->miscObjs != NULL) {
1770 xmlNodeSetPtr set;
1771 /*
1772 * Fallback to misc-cache.
1773 */
1774
1775 set = xmlXPathNodeSetCreate(val);
1776 if (set == NULL) {
1777 xmlXPathPErrMemory(pctxt);
1778 return(NULL);
1779 }
1780
1781 ret = cache->miscObjs;
1782 cache->miscObjs = (void *) ret->stringval;
1783 cache->numMisc -= 1;
1784 ret->stringval = NULL;
1785 ret->type = XPATH_NODESET;
1786 ret->boolval = 0;
1787 ret->nodesetval = set;
1788 return(ret);
1789 }
1790 }
1791 ret = xmlXPathNewNodeSet(val);
1792 if (ret == NULL)
1793 xmlXPathPErrMemory(pctxt);
1794 return(ret);
1795}
1796
1797/**
1798 * xmlXPathCacheNewString:
1799 * @pctxt the XPath context
1800 * @val: the xmlChar * value
1801 *
1802 * This is the cached version of xmlXPathNewString().
1803 * Acquire an xmlXPathObjectPtr of type string and of value @val
1804 *
1805 * Returns the created or reused object.
1806 */
1807static xmlXPathObjectPtr
1808xmlXPathCacheNewString(xmlXPathParserContextPtr pctxt, const xmlChar *val)
1809{
1810 xmlXPathObjectPtr ret;
1811 xmlXPathContextPtr ctxt = pctxt->context;
1812
1813 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1814 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1815
1816 if (cache->miscObjs != NULL) {
1817 xmlChar *copy;
1818
1819 if (val == NULL)
1820 val = BAD_CAST "";
1821 copy = xmlStrdup(val);
1822 if (copy == NULL) {
1823 xmlXPathPErrMemory(pctxt);
1824 return(NULL);
1825 }
1826
1827 ret = cache->miscObjs;
1828 cache->miscObjs = (void *) ret->stringval;
1829 cache->numMisc -= 1;
1830 ret->type = XPATH_STRING;
1831 ret->stringval = copy;
1832 return(ret);
1833 }
1834 }
1835
1836 ret = xmlXPathNewString(val);
1837 if (ret == NULL)
1838 xmlXPathPErrMemory(pctxt);
1839 return(ret);
1840}
1841
1842/**
1843 * xmlXPathCacheNewCString:
1844 * @pctxt the XPath context
1845 * @val: the char * value
1846 *
1847 * This is the cached version of xmlXPathNewCString().
1848 * Acquire an xmlXPathObjectPtr of type string and of value @val
1849 *
1850 * Returns the created or reused object.
1851 */
1852static xmlXPathObjectPtr
1853xmlXPathCacheNewCString(xmlXPathParserContextPtr pctxt, const char *val)
1854{
1855 return xmlXPathCacheNewString(pctxt, BAD_CAST val);
1856}
1857
1858/**
1859 * xmlXPathCacheNewBoolean:
1860 * @pctxt the XPath context
1861 * @val: the boolean value
1862 *
1863 * This is the cached version of xmlXPathNewBoolean().
1864 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
1865 *
1866 * Returns the created or reused object.
1867 */
1868static xmlXPathObjectPtr
1869xmlXPathCacheNewBoolean(xmlXPathParserContextPtr pctxt, int val)
1870{
1871 xmlXPathObjectPtr ret;
1872 xmlXPathContextPtr ctxt = pctxt->context;
1873
1874 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1875 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1876
1877 if (cache->miscObjs != NULL) {
1878 ret = cache->miscObjs;
1879 cache->miscObjs = (void *) ret->stringval;
1880 cache->numMisc -= 1;
1881 ret->stringval = NULL;
1882 ret->type = XPATH_BOOLEAN;
1883 ret->boolval = (val != 0);
1884 return(ret);
1885 }
1886 }
1887
1888 ret = xmlXPathNewBoolean(val);
1889 if (ret == NULL)
1890 xmlXPathPErrMemory(pctxt);
1891 return(ret);
1892}
1893
1894/**
1895 * xmlXPathCacheNewFloat:
1896 * @pctxt the XPath context
1897 * @val: the double value
1898 *
1899 * This is the cached version of xmlXPathNewFloat().
1900 * Acquires an xmlXPathObjectPtr of type double and of value @val
1901 *
1902 * Returns the created or reused object.
1903 */
1904static xmlXPathObjectPtr
1905xmlXPathCacheNewFloat(xmlXPathParserContextPtr pctxt, double val)
1906{
1907 xmlXPathObjectPtr ret;
1908 xmlXPathContextPtr ctxt = pctxt->context;
1909
1910 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1911 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1912
1913 if (cache->miscObjs != NULL) {
1914 ret = cache->miscObjs;
1915 cache->miscObjs = (void *) ret->stringval;
1916 cache->numMisc -= 1;
1917 ret->stringval = NULL;
1918 ret->type = XPATH_NUMBER;
1919 ret->floatval = val;
1920 return(ret);
1921 }
1922 }
1923
1924 ret = xmlXPathNewFloat(val);
1925 if (ret == NULL)
1926 xmlXPathPErrMemory(pctxt);
1927 return(ret);
1928}
1929
1930/**
1931 * xmlXPathCacheObjectCopy:
1932 * @pctxt the XPath context
1933 * @val: the original object
1934 *
1935 * This is the cached version of xmlXPathObjectCopy().
1936 * Acquire a copy of a given object
1937 *
1938 * Returns a created or reused created object.
1939 */
1940static xmlXPathObjectPtr
1941xmlXPathCacheObjectCopy(xmlXPathParserContextPtr pctxt, xmlXPathObjectPtr val)
1942{
1943 xmlXPathObjectPtr ret;
1944 xmlXPathContextPtr ctxt = pctxt->context;
1945
1946 if (val == NULL)
1947 return(NULL);
1948
1949 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1950 switch (val->type) {
1951 case XPATH_NODESET: {
1952 xmlNodeSetPtr set;
1953
1954 set = xmlXPathNodeSetMerge(NULL, val->nodesetval);
1955 if (set == NULL) {
1956 xmlXPathPErrMemory(pctxt);
1957 return(NULL);
1958 }
1959 return(xmlXPathCacheWrapNodeSet(pctxt, set));
1960 }
1961 case XPATH_STRING:
1962 return(xmlXPathCacheNewString(pctxt, val->stringval));
1963 case XPATH_BOOLEAN:
1964 return(xmlXPathCacheNewBoolean(pctxt, val->boolval));
1965 case XPATH_NUMBER:
1966 return(xmlXPathCacheNewFloat(pctxt, val->floatval));
1967 default:
1968 break;
1969 }
1970 }
1971 ret = xmlXPathObjectCopy(val);
1972 if (ret == NULL)
1973 xmlXPathPErrMemory(pctxt);
1974 return(ret);
1975}
1976
1977/************************************************************************
1978 * *
1979 * Parser stacks related functions and macros *
1980 * *
1981 ************************************************************************/
1982
1983/**
1984 * xmlXPathCastToNumberInternal:
1985 * @ctxt: parser context
1986 * @val: an XPath object
1987 *
1988 * Converts an XPath object to its number value
1989 *
1990 * Returns the number value
1991 */
1992static double
1993xmlXPathCastToNumberInternal(xmlXPathParserContextPtr ctxt,
1994 xmlXPathObjectPtr val) {
1995 double ret = 0.0;
1996
1997 if (val == NULL)
1998 return(xmlXPathNAN);
1999 switch (val->type) {
2000 case XPATH_UNDEFINED:
2001 ret = xmlXPathNAN;
2002 break;
2003 case XPATH_NODESET:
2004 case XPATH_XSLT_TREE: {
2005 xmlChar *str;
2006
2007 str = xmlXPathCastNodeSetToString(val->nodesetval);
2008 if (str == NULL) {
2009 xmlXPathPErrMemory(ctxt);
2010 ret = xmlXPathNAN;
2011 } else {
2012 ret = xmlXPathCastStringToNumber(str);
2013 xmlFree(str);
2014 }
2015 break;
2016 }
2017 case XPATH_STRING:
2018 ret = xmlXPathCastStringToNumber(val->stringval);
2019 break;
2020 case XPATH_NUMBER:
2021 ret = val->floatval;
2022 break;
2023 case XPATH_BOOLEAN:
2024 ret = xmlXPathCastBooleanToNumber(val->boolval);
2025 break;
2026 case XPATH_USERS:
2027#ifdef LIBXML_XPTR_LOCS_ENABLED
2028 case XPATH_POINT:
2029 case XPATH_RANGE:
2030 case XPATH_LOCATIONSET:
2031#endif /* LIBXML_XPTR_LOCS_ENABLED */
2032 /* TODO */
2033 ret = xmlXPathNAN;
2034 break;
2035 }
2036 return(ret);
2037}
2038
2039/**
2040 * valuePop:
2041 * @ctxt: an XPath evaluation context
2042 *
2043 * Pops the top XPath object from the value stack
2044 *
2045 * Returns the XPath object just removed
2046 */
2047xmlXPathObjectPtr
2048valuePop(xmlXPathParserContextPtr ctxt)
2049{
2050 xmlXPathObjectPtr ret;
2051
2052 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2053 return (NULL);
2054
2055 ctxt->valueNr--;
2056 if (ctxt->valueNr > 0)
2057 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2058 else
2059 ctxt->value = NULL;
2060 ret = ctxt->valueTab[ctxt->valueNr];
2061 ctxt->valueTab[ctxt->valueNr] = NULL;
2062 return (ret);
2063}
2064/**
2065 * valuePush:
2066 * @ctxt: an XPath evaluation context
2067 * @value: the XPath object
2068 *
2069 * Pushes a new XPath object on top of the value stack. If value is NULL,
2070 * a memory error is recorded in the parser context.
2071 *
2072 * Returns the number of items on the value stack, or -1 in case of error.
2073 *
2074 * The object is destroyed in case of error.
2075 */
2076int
2077valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2078{
2079 if (ctxt == NULL) return(-1);
2080 if (value == NULL) {
2081 /*
2082 * A NULL value typically indicates that a memory allocation failed.
2083 */
2084 xmlXPathPErrMemory(ctxt);
2085 return(-1);
2086 }
2087 if (ctxt->valueNr >= ctxt->valueMax) {
2088 xmlXPathObjectPtr *tmp;
2089
2090 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2091 xmlXPathPErrMemory(ctxt);
2092 xmlXPathFreeObject(value);
2093 return (-1);
2094 }
2095 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2096 2 * ctxt->valueMax *
2097 sizeof(ctxt->valueTab[0]));
2098 if (tmp == NULL) {
2099 xmlXPathPErrMemory(ctxt);
2100 xmlXPathFreeObject(value);
2101 return (-1);
2102 }
2103 ctxt->valueMax *= 2;
2104 ctxt->valueTab = tmp;
2105 }
2106 ctxt->valueTab[ctxt->valueNr] = value;
2107 ctxt->value = value;
2108 return (ctxt->valueNr++);
2109}
2110
2111/**
2112 * xmlXPathPopBoolean:
2113 * @ctxt: an XPath parser context
2114 *
2115 * Pops a boolean from the stack, handling conversion if needed.
2116 * Check error with #xmlXPathCheckError.
2117 *
2118 * Returns the boolean
2119 */
2120int
2121xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2122 xmlXPathObjectPtr obj;
2123 int ret;
2124
2125 obj = valuePop(ctxt);
2126 if (obj == NULL) {
2127 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2128 return(0);
2129 }
2130 if (obj->type != XPATH_BOOLEAN)
2131 ret = xmlXPathCastToBoolean(obj);
2132 else
2133 ret = obj->boolval;
2134 xmlXPathReleaseObject(ctxt->context, obj);
2135 return(ret);
2136}
2137
2138/**
2139 * xmlXPathPopNumber:
2140 * @ctxt: an XPath parser context
2141 *
2142 * Pops a number from the stack, handling conversion if needed.
2143 * Check error with #xmlXPathCheckError.
2144 *
2145 * Returns the number
2146 */
2147double
2148xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2149 xmlXPathObjectPtr obj;
2150 double ret;
2151
2152 obj = valuePop(ctxt);
2153 if (obj == NULL) {
2154 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2155 return(0);
2156 }
2157 if (obj->type != XPATH_NUMBER)
2158 ret = xmlXPathCastToNumberInternal(ctxt, obj);
2159 else
2160 ret = obj->floatval;
2161 xmlXPathReleaseObject(ctxt->context, obj);
2162 return(ret);
2163}
2164
2165/**
2166 * xmlXPathPopString:
2167 * @ctxt: an XPath parser context
2168 *
2169 * Pops a string from the stack, handling conversion if needed.
2170 * Check error with #xmlXPathCheckError.
2171 *
2172 * Returns the string
2173 */
2174xmlChar *
2175xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2176 xmlXPathObjectPtr obj;
2177 xmlChar * ret;
2178
2179 obj = valuePop(ctxt);
2180 if (obj == NULL) {
2181 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2182 return(NULL);
2183 }
2184 ret = xmlXPathCastToString(obj);
2185 if (ret == NULL)
2186 xmlXPathPErrMemory(ctxt);
2187 xmlXPathReleaseObject(ctxt->context, obj);
2188 return(ret);
2189}
2190
2191/**
2192 * xmlXPathPopNodeSet:
2193 * @ctxt: an XPath parser context
2194 *
2195 * Pops a node-set from the stack, handling conversion if needed.
2196 * Check error with #xmlXPathCheckError.
2197 *
2198 * Returns the node-set
2199 */
2200xmlNodeSetPtr
2201xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2202 xmlXPathObjectPtr obj;
2203 xmlNodeSetPtr ret;
2204
2205 if (ctxt == NULL) return(NULL);
2206 if (ctxt->value == NULL) {
2207 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2208 return(NULL);
2209 }
2210 if (!xmlXPathStackIsNodeSet(ctxt)) {
2211 xmlXPathSetTypeError(ctxt);
2212 return(NULL);
2213 }
2214 obj = valuePop(ctxt);
2215 ret = obj->nodesetval;
2216#if 0
2217 /* to fix memory leak of not clearing obj->user */
2218 if (obj->boolval && obj->user != NULL)
2219 xmlFreeNodeList((xmlNodePtr) obj->user);
2220#endif
2221 obj->nodesetval = NULL;
2222 xmlXPathReleaseObject(ctxt->context, obj);
2223 return(ret);
2224}
2225
2226/**
2227 * xmlXPathPopExternal:
2228 * @ctxt: an XPath parser context
2229 *
2230 * Pops an external object from the stack, handling conversion if needed.
2231 * Check error with #xmlXPathCheckError.
2232 *
2233 * Returns the object
2234 */
2235void *
2236xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2237 xmlXPathObjectPtr obj;
2238 void * ret;
2239
2240 if ((ctxt == NULL) || (ctxt->value == NULL)) {
2241 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2242 return(NULL);
2243 }
2244 if (ctxt->value->type != XPATH_USERS) {
2245 xmlXPathSetTypeError(ctxt);
2246 return(NULL);
2247 }
2248 obj = valuePop(ctxt);
2249 ret = obj->user;
2250 obj->user = NULL;
2251 xmlXPathReleaseObject(ctxt->context, obj);
2252 return(ret);
2253}
2254
2255/*
2256 * Macros for accessing the content. Those should be used only by the parser,
2257 * and not exported.
2258 *
2259 * Dirty macros, i.e. one need to make assumption on the context to use them
2260 *
2261 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2262 * CUR returns the current xmlChar value, i.e. a 8 bit value
2263 * in ISO-Latin or UTF-8.
2264 * This should be used internally by the parser
2265 * only to compare to ASCII values otherwise it would break when
2266 * running with UTF-8 encoding.
2267 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2268 * to compare on ASCII based substring.
2269 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2270 * strings within the parser.
2271 * CURRENT Returns the current char value, with the full decoding of
2272 * UTF-8 if we are using this mode. It returns an int.
2273 * NEXT Skip to the next character, this does the proper decoding
2274 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2275 * It returns the pointer to the current xmlChar.
2276 */
2277
2278#define CUR (*ctxt->cur)
2279#define SKIP(val) ctxt->cur += (val)
2280#define NXT(val) ctxt->cur[(val)]
2281#define CUR_PTR ctxt->cur
2282#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2283
2284#define COPY_BUF(l,b,i,v) \
2285 if (l == 1) b[i++] = v; \
2286 else i += xmlCopyChar(l,&b[i],v)
2287
2288#define NEXTL(l) ctxt->cur += l
2289
2290#define SKIP_BLANKS \
2291 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2292
2293#define CURRENT (*ctxt->cur)
2294#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2295
2296
2297#ifndef DBL_DIG
2298#define DBL_DIG 16
2299#endif
2300#ifndef DBL_EPSILON
2301#define DBL_EPSILON 1E-9
2302#endif
2303
2304#define UPPER_DOUBLE 1E9
2305#define LOWER_DOUBLE 1E-5
2306#define LOWER_DOUBLE_EXP 5
2307
2308#define INTEGER_DIGITS DBL_DIG
2309#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2310#define EXPONENT_DIGITS (3 + 2)
2311
2312/**
2313 * xmlXPathFormatNumber:
2314 * @number: number to format
2315 * @buffer: output buffer
2316 * @buffersize: size of output buffer
2317 *
2318 * Convert the number into a string representation.
2319 */
2320static void
2321xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2322{
2323 switch (xmlXPathIsInf(number)) {
2324 case 1:
2325 if (buffersize > (int)sizeof("Infinity"))
2326 snprintf(buffer, buffersize, "Infinity");
2327 break;
2328 case -1:
2329 if (buffersize > (int)sizeof("-Infinity"))
2330 snprintf(buffer, buffersize, "-Infinity");
2331 break;
2332 default:
2333 if (xmlXPathIsNaN(number)) {
2334 if (buffersize > (int)sizeof("NaN"))
2335 snprintf(buffer, buffersize, "NaN");
2336 } else if (number == 0) {
2337 /* Omit sign for negative zero. */
2338 snprintf(buffer, buffersize, "0");
2339 } else if ((number > INT_MIN) && (number < INT_MAX) &&
2340 (number == (int) number)) {
2341 char work[30];
2342 char *ptr, *cur;
2343 int value = (int) number;
2344
2345 ptr = &buffer[0];
2346 if (value == 0) {
2347 *ptr++ = '0';
2348 } else {
2349 snprintf(work, 29, "%d", value);
2350 cur = &work[0];
2351 while ((*cur) && (ptr - buffer < buffersize)) {
2352 *ptr++ = *cur++;
2353 }
2354 }
2355 if (ptr - buffer < buffersize) {
2356 *ptr = 0;
2357 } else if (buffersize > 0) {
2358 ptr--;
2359 *ptr = 0;
2360 }
2361 } else {
2362 /*
2363 For the dimension of work,
2364 DBL_DIG is number of significant digits
2365 EXPONENT is only needed for "scientific notation"
2366 3 is sign, decimal point, and terminating zero
2367 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2368 Note that this dimension is slightly (a few characters)
2369 larger than actually necessary.
2370 */
2371 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2372 int integer_place, fraction_place;
2373 char *ptr;
2374 char *after_fraction;
2375 double absolute_value;
2376 int size;
2377
2378 absolute_value = fabs(number);
2379
2380 /*
2381 * First choose format - scientific or regular floating point.
2382 * In either case, result is in work, and after_fraction points
2383 * just past the fractional part.
2384 */
2385 if ( ((absolute_value > UPPER_DOUBLE) ||
2386 (absolute_value < LOWER_DOUBLE)) &&
2387 (absolute_value != 0.0) ) {
2388 /* Use scientific notation */
2389 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2390 fraction_place = DBL_DIG - 1;
2391 size = snprintf(work, sizeof(work),"%*.*e",
2392 integer_place, fraction_place, number);
2393 while ((size > 0) && (work[size] != 'e')) size--;
2394
2395 }
2396 else {
2397 /* Use regular notation */
2398 if (absolute_value > 0.0) {
2399 integer_place = (int)log10(absolute_value);
2400 if (integer_place > 0)
2401 fraction_place = DBL_DIG - integer_place - 1;
2402 else
2403 fraction_place = DBL_DIG - integer_place;
2404 } else {
2405 fraction_place = 1;
2406 }
2407 size = snprintf(work, sizeof(work), "%0.*f",
2408 fraction_place, number);
2409 }
2410
2411 /* Remove leading spaces sometimes inserted by snprintf */
2412 while (work[0] == ' ') {
2413 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2414 size--;
2415 }
2416
2417 /* Remove fractional trailing zeroes */
2418 after_fraction = work + size;
2419 ptr = after_fraction;
2420 while (*(--ptr) == '0')
2421 ;
2422 if (*ptr != '.')
2423 ptr++;
2424 while ((*ptr++ = *after_fraction++) != 0);
2425
2426 /* Finally copy result back to caller */
2427 size = strlen(work) + 1;
2428 if (size > buffersize) {
2429 work[buffersize - 1] = 0;
2430 size = buffersize;
2431 }
2432 memmove(buffer, work, size);
2433 }
2434 break;
2435 }
2436}
2437
2438
2439/************************************************************************
2440 * *
2441 * Routines to handle NodeSets *
2442 * *
2443 ************************************************************************/
2444
2445/**
2446 * xmlXPathOrderDocElems:
2447 * @doc: an input document
2448 *
2449 * Call this routine to speed up XPath computation on static documents.
2450 * This stamps all the element nodes with the document order
2451 * Like for line information, the order is kept in the element->content
2452 * field, the value stored is actually - the node number (starting at -1)
2453 * to be able to differentiate from line numbers.
2454 *
2455 * Returns the number of elements found in the document or -1 in case
2456 * of error.
2457 */
2458long
2459xmlXPathOrderDocElems(xmlDocPtr doc) {
2460 ptrdiff_t count = 0;
2461 xmlNodePtr cur;
2462
2463 if (doc == NULL)
2464 return(-1);
2465 cur = doc->children;
2466 while (cur != NULL) {
2467 if (cur->type == XML_ELEMENT_NODE) {
2468 cur->content = (void *) (-(++count));
2469 if (cur->children != NULL) {
2470 cur = cur->children;
2471 continue;
2472 }
2473 }
2474 if (cur->next != NULL) {
2475 cur = cur->next;
2476 continue;
2477 }
2478 do {
2479 cur = cur->parent;
2480 if (cur == NULL)
2481 break;
2482 if (cur == (xmlNodePtr) doc) {
2483 cur = NULL;
2484 break;
2485 }
2486 if (cur->next != NULL) {
2487 cur = cur->next;
2488 break;
2489 }
2490 } while (cur != NULL);
2491 }
2492 return(count);
2493}
2494
2495/**
2496 * xmlXPathCmpNodes:
2497 * @node1: the first node
2498 * @node2: the second node
2499 *
2500 * Compare two nodes w.r.t document order
2501 *
2502 * Returns -2 in case of error 1 if first point < second point, 0 if
2503 * it's the same node, -1 otherwise
2504 */
2505int
2506xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2507 int depth1, depth2;
2508 int attr1 = 0, attr2 = 0;
2509 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2510 xmlNodePtr cur, root;
2511
2512 if ((node1 == NULL) || (node2 == NULL))
2513 return(-2);
2514 /*
2515 * a couple of optimizations which will avoid computations in most cases
2516 */
2517 if (node1 == node2) /* trivial case */
2518 return(0);
2519 if (node1->type == XML_ATTRIBUTE_NODE) {
2520 attr1 = 1;
2521 attrNode1 = node1;
2522 node1 = node1->parent;
2523 }
2524 if (node2->type == XML_ATTRIBUTE_NODE) {
2525 attr2 = 1;
2526 attrNode2 = node2;
2527 node2 = node2->parent;
2528 }
2529 if (node1 == node2) {
2530 if (attr1 == attr2) {
2531 /* not required, but we keep attributes in order */
2532 if (attr1 != 0) {
2533 cur = attrNode2->prev;
2534 while (cur != NULL) {
2535 if (cur == attrNode1)
2536 return (1);
2537 cur = cur->prev;
2538 }
2539 return (-1);
2540 }
2541 return(0);
2542 }
2543 if (attr2 == 1)
2544 return(1);
2545 return(-1);
2546 }
2547 if ((node1->type == XML_NAMESPACE_DECL) ||
2548 (node2->type == XML_NAMESPACE_DECL))
2549 return(1);
2550 if (node1 == node2->prev)
2551 return(1);
2552 if (node1 == node2->next)
2553 return(-1);
2554
2555 /*
2556 * Speedup using document order if available.
2557 */
2558 if ((node1->type == XML_ELEMENT_NODE) &&
2559 (node2->type == XML_ELEMENT_NODE) &&
2560 (0 > (ptrdiff_t) node1->content) &&
2561 (0 > (ptrdiff_t) node2->content) &&
2562 (node1->doc == node2->doc)) {
2563 ptrdiff_t l1, l2;
2564
2565 l1 = -((ptrdiff_t) node1->content);
2566 l2 = -((ptrdiff_t) node2->content);
2567 if (l1 < l2)
2568 return(1);
2569 if (l1 > l2)
2570 return(-1);
2571 }
2572
2573 /*
2574 * compute depth to root
2575 */
2576 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2577 if (cur->parent == node1)
2578 return(1);
2579 depth2++;
2580 }
2581 root = cur;
2582 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2583 if (cur->parent == node2)
2584 return(-1);
2585 depth1++;
2586 }
2587 /*
2588 * Distinct document (or distinct entities :-( ) case.
2589 */
2590 if (root != cur) {
2591 return(-2);
2592 }
2593 /*
2594 * get the nearest common ancestor.
2595 */
2596 while (depth1 > depth2) {
2597 depth1--;
2598 node1 = node1->parent;
2599 }
2600 while (depth2 > depth1) {
2601 depth2--;
2602 node2 = node2->parent;
2603 }
2604 while (node1->parent != node2->parent) {
2605 node1 = node1->parent;
2606 node2 = node2->parent;
2607 /* should not happen but just in case ... */
2608 if ((node1 == NULL) || (node2 == NULL))
2609 return(-2);
2610 }
2611 /*
2612 * Find who's first.
2613 */
2614 if (node1 == node2->prev)
2615 return(1);
2616 if (node1 == node2->next)
2617 return(-1);
2618 /*
2619 * Speedup using document order if available.
2620 */
2621 if ((node1->type == XML_ELEMENT_NODE) &&
2622 (node2->type == XML_ELEMENT_NODE) &&
2623 (0 > (ptrdiff_t) node1->content) &&
2624 (0 > (ptrdiff_t) node2->content) &&
2625 (node1->doc == node2->doc)) {
2626 ptrdiff_t l1, l2;
2627
2628 l1 = -((ptrdiff_t) node1->content);
2629 l2 = -((ptrdiff_t) node2->content);
2630 if (l1 < l2)
2631 return(1);
2632 if (l1 > l2)
2633 return(-1);
2634 }
2635
2636 for (cur = node1->next;cur != NULL;cur = cur->next)
2637 if (cur == node2)
2638 return(1);
2639 return(-1); /* assume there is no sibling list corruption */
2640}
2641
2642/**
2643 * xmlXPathNodeSetSort:
2644 * @set: the node set
2645 *
2646 * Sort the node set in document order
2647 */
2648void
2649xmlXPathNodeSetSort(xmlNodeSetPtr set) {
2650#ifndef WITH_TIM_SORT
2651 int i, j, incr, len;
2652 xmlNodePtr tmp;
2653#endif
2654
2655 if (set == NULL)
2656 return;
2657
2658#ifndef WITH_TIM_SORT
2659 /*
2660 * Use the old Shell's sort implementation to sort the node-set
2661 * Timsort ought to be quite faster
2662 */
2663 len = set->nodeNr;
2664 for (incr = len / 2; incr > 0; incr /= 2) {
2665 for (i = incr; i < len; i++) {
2666 j = i - incr;
2667 while (j >= 0) {
2668#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2669 if (xmlXPathCmpNodesExt(set->nodeTab[j],
2670 set->nodeTab[j + incr]) == -1)
2671#else
2672 if (xmlXPathCmpNodes(set->nodeTab[j],
2673 set->nodeTab[j + incr]) == -1)
2674#endif
2675 {
2676 tmp = set->nodeTab[j];
2677 set->nodeTab[j] = set->nodeTab[j + incr];
2678 set->nodeTab[j + incr] = tmp;
2679 j -= incr;
2680 } else
2681 break;
2682 }
2683 }
2684 }
2685#else /* WITH_TIM_SORT */
2686 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2687#endif /* WITH_TIM_SORT */
2688}
2689
2690#define XML_NODESET_DEFAULT 10
2691/**
2692 * xmlXPathNodeSetDupNs:
2693 * @node: the parent node of the namespace XPath node
2694 * @ns: the libxml namespace declaration node.
2695 *
2696 * Namespace node in libxml don't match the XPath semantic. In a node set
2697 * the namespace nodes are duplicated and the next pointer is set to the
2698 * parent node in the XPath semantic.
2699 *
2700 * Returns the newly created object.
2701 */
2702static xmlNodePtr
2703xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2704 xmlNsPtr cur;
2705
2706 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2707 return(NULL);
2708 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
2709 return((xmlNodePtr) ns);
2710
2711 /*
2712 * Allocate a new Namespace and fill the fields.
2713 */
2714 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2715 if (cur == NULL)
2716 return(NULL);
2717 memset(cur, 0, sizeof(xmlNs));
2718 cur->type = XML_NAMESPACE_DECL;
2719 if (ns->href != NULL) {
2720 cur->href = xmlStrdup(ns->href);
2721 if (cur->href == NULL) {
2722 xmlFree(cur);
2723 return(NULL);
2724 }
2725 }
2726 if (ns->prefix != NULL) {
2727 cur->prefix = xmlStrdup(ns->prefix);
2728 if (cur->prefix == NULL) {
2729 xmlFree((xmlChar *) cur->href);
2730 xmlFree(cur);
2731 return(NULL);
2732 }
2733 }
2734 cur->next = (xmlNsPtr) node;
2735 return((xmlNodePtr) cur);
2736}
2737
2738/**
2739 * xmlXPathNodeSetFreeNs:
2740 * @ns: the XPath namespace node found in a nodeset.
2741 *
2742 * Namespace nodes in libxml don't match the XPath semantic. In a node set
2743 * the namespace nodes are duplicated and the next pointer is set to the
2744 * parent node in the XPath semantic. Check if such a node needs to be freed
2745 */
2746void
2747xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
2748 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2749 return;
2750
2751 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2752 if (ns->href != NULL)
2753 xmlFree((xmlChar *)ns->href);
2754 if (ns->prefix != NULL)
2755 xmlFree((xmlChar *)ns->prefix);
2756 xmlFree(ns);
2757 }
2758}
2759
2760/**
2761 * xmlXPathNodeSetCreate:
2762 * @val: an initial xmlNodePtr, or NULL
2763 *
2764 * Create a new xmlNodeSetPtr of type double and of value @val
2765 *
2766 * Returns the newly created object.
2767 */
2768xmlNodeSetPtr
2769xmlXPathNodeSetCreate(xmlNodePtr val) {
2770 xmlNodeSetPtr ret;
2771
2772 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2773 if (ret == NULL)
2774 return(NULL);
2775 memset(ret, 0 , sizeof(xmlNodeSet));
2776 if (val != NULL) {
2777 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2778 sizeof(xmlNodePtr));
2779 if (ret->nodeTab == NULL) {
2780 xmlFree(ret);
2781 return(NULL);
2782 }
2783 memset(ret->nodeTab, 0 ,
2784 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2785 ret->nodeMax = XML_NODESET_DEFAULT;
2786 if (val->type == XML_NAMESPACE_DECL) {
2787 xmlNsPtr ns = (xmlNsPtr) val;
2788 xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2789
2790 if (nsNode == NULL) {
2791 xmlXPathFreeNodeSet(ret);
2792 return(NULL);
2793 }
2794 ret->nodeTab[ret->nodeNr++] = nsNode;
2795 } else
2796 ret->nodeTab[ret->nodeNr++] = val;
2797 }
2798 return(ret);
2799}
2800
2801/**
2802 * xmlXPathNodeSetContains:
2803 * @cur: the node-set
2804 * @val: the node
2805 *
2806 * checks whether @cur contains @val
2807 *
2808 * Returns true (1) if @cur contains @val, false (0) otherwise
2809 */
2810int
2811xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
2812 int i;
2813
2814 if ((cur == NULL) || (val == NULL)) return(0);
2815 if (val->type == XML_NAMESPACE_DECL) {
2816 for (i = 0; i < cur->nodeNr; i++) {
2817 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2818 xmlNsPtr ns1, ns2;
2819
2820 ns1 = (xmlNsPtr) val;
2821 ns2 = (xmlNsPtr) cur->nodeTab[i];
2822 if (ns1 == ns2)
2823 return(1);
2824 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
2825 (xmlStrEqual(ns1->prefix, ns2->prefix)))
2826 return(1);
2827 }
2828 }
2829 } else {
2830 for (i = 0; i < cur->nodeNr; i++) {
2831 if (cur->nodeTab[i] == val)
2832 return(1);
2833 }
2834 }
2835 return(0);
2836}
2837
2838/**
2839 * xmlXPathNodeSetAddNs:
2840 * @cur: the initial node set
2841 * @node: the hosting node
2842 * @ns: a the namespace node
2843 *
2844 * add a new namespace node to an existing NodeSet
2845 *
2846 * Returns 0 in case of success and -1 in case of error
2847 */
2848int
2849xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
2850 int i;
2851 xmlNodePtr nsNode;
2852
2853 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
2854 (ns->type != XML_NAMESPACE_DECL) ||
2855 (node->type != XML_ELEMENT_NODE))
2856 return(-1);
2857
2858 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2859 /*
2860 * prevent duplicates
2861 */
2862 for (i = 0;i < cur->nodeNr;i++) {
2863 if ((cur->nodeTab[i] != NULL) &&
2864 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
2865 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
2866 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
2867 return(0);
2868 }
2869
2870 /*
2871 * grow the nodeTab if needed
2872 */
2873 if (cur->nodeMax == 0) {
2874 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2875 sizeof(xmlNodePtr));
2876 if (cur->nodeTab == NULL)
2877 return(-1);
2878 memset(cur->nodeTab, 0 ,
2879 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2880 cur->nodeMax = XML_NODESET_DEFAULT;
2881 } else if (cur->nodeNr == cur->nodeMax) {
2882 xmlNodePtr *temp;
2883
2884 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2885 return(-1);
2886 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2887 sizeof(xmlNodePtr));
2888 if (temp == NULL)
2889 return(-1);
2890 cur->nodeMax *= 2;
2891 cur->nodeTab = temp;
2892 }
2893 nsNode = xmlXPathNodeSetDupNs(node, ns);
2894 if(nsNode == NULL)
2895 return(-1);
2896 cur->nodeTab[cur->nodeNr++] = nsNode;
2897 return(0);
2898}
2899
2900/**
2901 * xmlXPathNodeSetAdd:
2902 * @cur: the initial node set
2903 * @val: a new xmlNodePtr
2904 *
2905 * add a new xmlNodePtr to an existing NodeSet
2906 *
2907 * Returns 0 in case of success, and -1 in case of error
2908 */
2909int
2910xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
2911 int i;
2912
2913 if ((cur == NULL) || (val == NULL)) return(-1);
2914
2915 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2916 /*
2917 * prevent duplicates
2918 */
2919 for (i = 0;i < cur->nodeNr;i++)
2920 if (cur->nodeTab[i] == val) return(0);
2921
2922 /*
2923 * grow the nodeTab if needed
2924 */
2925 if (cur->nodeMax == 0) {
2926 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2927 sizeof(xmlNodePtr));
2928 if (cur->nodeTab == NULL)
2929 return(-1);
2930 memset(cur->nodeTab, 0 ,
2931 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2932 cur->nodeMax = XML_NODESET_DEFAULT;
2933 } else if (cur->nodeNr == cur->nodeMax) {
2934 xmlNodePtr *temp;
2935
2936 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2937 return(-1);
2938 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2939 sizeof(xmlNodePtr));
2940 if (temp == NULL)
2941 return(-1);
2942 cur->nodeMax *= 2;
2943 cur->nodeTab = temp;
2944 }
2945 if (val->type == XML_NAMESPACE_DECL) {
2946 xmlNsPtr ns = (xmlNsPtr) val;
2947 xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2948
2949 if (nsNode == NULL)
2950 return(-1);
2951 cur->nodeTab[cur->nodeNr++] = nsNode;
2952 } else
2953 cur->nodeTab[cur->nodeNr++] = val;
2954 return(0);
2955}
2956
2957/**
2958 * xmlXPathNodeSetAddUnique:
2959 * @cur: the initial node set
2960 * @val: a new xmlNodePtr
2961 *
2962 * add a new xmlNodePtr to an existing NodeSet, optimized version
2963 * when we are sure the node is not already in the set.
2964 *
2965 * Returns 0 in case of success and -1 in case of failure
2966 */
2967int
2968xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
2969 if ((cur == NULL) || (val == NULL)) return(-1);
2970
2971 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2972 /*
2973 * grow the nodeTab if needed
2974 */
2975 if (cur->nodeMax == 0) {
2976 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2977 sizeof(xmlNodePtr));
2978 if (cur->nodeTab == NULL)
2979 return(-1);
2980 memset(cur->nodeTab, 0 ,
2981 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2982 cur->nodeMax = XML_NODESET_DEFAULT;
2983 } else if (cur->nodeNr == cur->nodeMax) {
2984 xmlNodePtr *temp;
2985
2986 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2987 return(-1);
2988 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2989 sizeof(xmlNodePtr));
2990 if (temp == NULL)
2991 return(-1);
2992 cur->nodeTab = temp;
2993 cur->nodeMax *= 2;
2994 }
2995 if (val->type == XML_NAMESPACE_DECL) {
2996 xmlNsPtr ns = (xmlNsPtr) val;
2997 xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2998
2999 if (nsNode == NULL)
3000 return(-1);
3001 cur->nodeTab[cur->nodeNr++] = nsNode;
3002 } else
3003 cur->nodeTab[cur->nodeNr++] = val;
3004 return(0);
3005}
3006
3007/**
3008 * xmlXPathNodeSetMerge:
3009 * @val1: the first NodeSet or NULL
3010 * @val2: the second NodeSet
3011 *
3012 * Merges two nodesets, all nodes from @val2 are added to @val1
3013 * if @val1 is NULL, a new set is created and copied from @val2
3014 *
3015 * Returns @val1 once extended or NULL in case of error.
3016 *
3017 * Frees @val1 in case of error.
3018 */
3019xmlNodeSetPtr
3020xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3021 int i, j, initNr, skip;
3022 xmlNodePtr n1, n2;
3023
3024 if (val1 == NULL) {
3025 val1 = xmlXPathNodeSetCreate(NULL);
3026 if (val1 == NULL)
3027 return (NULL);
3028 }
3029 if (val2 == NULL)
3030 return(val1);
3031
3032 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3033 initNr = val1->nodeNr;
3034
3035 for (i = 0;i < val2->nodeNr;i++) {
3036 n2 = val2->nodeTab[i];
3037 /*
3038 * check against duplicates
3039 */
3040 skip = 0;
3041 for (j = 0; j < initNr; j++) {
3042 n1 = val1->nodeTab[j];
3043 if (n1 == n2) {
3044 skip = 1;
3045 break;
3046 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3047 (n2->type == XML_NAMESPACE_DECL)) {
3048 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3049 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3050 ((xmlNsPtr) n2)->prefix)))
3051 {
3052 skip = 1;
3053 break;
3054 }
3055 }
3056 }
3057 if (skip)
3058 continue;
3059
3060 /*
3061 * grow the nodeTab if needed
3062 */
3063 if (val1->nodeMax == 0) {
3064 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3065 sizeof(xmlNodePtr));
3066 if (val1->nodeTab == NULL)
3067 goto error;
3068 memset(val1->nodeTab, 0 ,
3069 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3070 val1->nodeMax = XML_NODESET_DEFAULT;
3071 } else if (val1->nodeNr == val1->nodeMax) {
3072 xmlNodePtr *temp;
3073
3074 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
3075 goto error;
3076 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3077 sizeof(xmlNodePtr));
3078 if (temp == NULL)
3079 goto error;
3080 val1->nodeTab = temp;
3081 val1->nodeMax *= 2;
3082 }
3083 if (n2->type == XML_NAMESPACE_DECL) {
3084 xmlNsPtr ns = (xmlNsPtr) n2;
3085 xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3086
3087 if (nsNode == NULL)
3088 goto error;
3089 val1->nodeTab[val1->nodeNr++] = nsNode;
3090 } else
3091 val1->nodeTab[val1->nodeNr++] = n2;
3092 }
3093
3094 return(val1);
3095
3096error:
3097 xmlXPathFreeNodeSet(val1);
3098 return(NULL);
3099}
3100
3101
3102/**
3103 * xmlXPathNodeSetMergeAndClear:
3104 * @set1: the first NodeSet or NULL
3105 * @set2: the second NodeSet
3106 *
3107 * Merges two nodesets, all nodes from @set2 are added to @set1.
3108 * Checks for duplicate nodes. Clears set2.
3109 *
3110 * Returns @set1 once extended or NULL in case of error.
3111 *
3112 * Frees @set1 in case of error.
3113 */
3114static xmlNodeSetPtr
3115xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3116{
3117 {
3118 int i, j, initNbSet1;
3119 xmlNodePtr n1, n2;
3120
3121 initNbSet1 = set1->nodeNr;
3122 for (i = 0;i < set2->nodeNr;i++) {
3123 n2 = set2->nodeTab[i];
3124 /*
3125 * Skip duplicates.
3126 */
3127 for (j = 0; j < initNbSet1; j++) {
3128 n1 = set1->nodeTab[j];
3129 if (n1 == n2) {
3130 goto skip_node;
3131 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3132 (n2->type == XML_NAMESPACE_DECL))
3133 {
3134 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3135 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3136 ((xmlNsPtr) n2)->prefix)))
3137 {
3138 /*
3139 * Free the namespace node.
3140 */
3141 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3142 goto skip_node;
3143 }
3144 }
3145 }
3146 /*
3147 * grow the nodeTab if needed
3148 */
3149 if (set1->nodeMax == 0) {
3150 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3151 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3152 if (set1->nodeTab == NULL)
3153 goto error;
3154 memset(set1->nodeTab, 0,
3155 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3156 set1->nodeMax = XML_NODESET_DEFAULT;
3157 } else if (set1->nodeNr >= set1->nodeMax) {
3158 xmlNodePtr *temp;
3159
3160 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
3161 goto error;
3162 temp = (xmlNodePtr *) xmlRealloc(
3163 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3164 if (temp == NULL)
3165 goto error;
3166 set1->nodeTab = temp;
3167 set1->nodeMax *= 2;
3168 }
3169 set1->nodeTab[set1->nodeNr++] = n2;
3170skip_node:
3171 set2->nodeTab[i] = NULL;
3172 }
3173 }
3174 set2->nodeNr = 0;
3175 return(set1);
3176
3177error:
3178 xmlXPathFreeNodeSet(set1);
3179 xmlXPathNodeSetClear(set2, 1);
3180 return(NULL);
3181}
3182
3183/**
3184 * xmlXPathNodeSetMergeAndClearNoDupls:
3185 * @set1: the first NodeSet or NULL
3186 * @set2: the second NodeSet
3187 *
3188 * Merges two nodesets, all nodes from @set2 are added to @set1.
3189 * Doesn't check for duplicate nodes. Clears set2.
3190 *
3191 * Returns @set1 once extended or NULL in case of error.
3192 *
3193 * Frees @set1 in case of error.
3194 */
3195static xmlNodeSetPtr
3196xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3197{
3198 {
3199 int i;
3200 xmlNodePtr n2;
3201
3202 for (i = 0;i < set2->nodeNr;i++) {
3203 n2 = set2->nodeTab[i];
3204 if (set1->nodeMax == 0) {
3205 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3206 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3207 if (set1->nodeTab == NULL)
3208 goto error;
3209 memset(set1->nodeTab, 0,
3210 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3211 set1->nodeMax = XML_NODESET_DEFAULT;
3212 } else if (set1->nodeNr >= set1->nodeMax) {
3213 xmlNodePtr *temp;
3214
3215 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
3216 goto error;
3217 temp = (xmlNodePtr *) xmlRealloc(
3218 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3219 if (temp == NULL)
3220 goto error;
3221 set1->nodeTab = temp;
3222 set1->nodeMax *= 2;
3223 }
3224 set1->nodeTab[set1->nodeNr++] = n2;
3225 set2->nodeTab[i] = NULL;
3226 }
3227 }
3228 set2->nodeNr = 0;
3229 return(set1);
3230
3231error:
3232 xmlXPathFreeNodeSet(set1);
3233 xmlXPathNodeSetClear(set2, 1);
3234 return(NULL);
3235}
3236
3237/**
3238 * xmlXPathNodeSetDel:
3239 * @cur: the initial node set
3240 * @val: an xmlNodePtr
3241 *
3242 * Removes an xmlNodePtr from an existing NodeSet
3243 */
3244void
3245xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3246 int i;
3247
3248 if (cur == NULL) return;
3249 if (val == NULL) return;
3250
3251 /*
3252 * find node in nodeTab
3253 */
3254 for (i = 0;i < cur->nodeNr;i++)
3255 if (cur->nodeTab[i] == val) break;
3256
3257 if (i >= cur->nodeNr) { /* not found */
3258 return;
3259 }
3260 if ((cur->nodeTab[i] != NULL) &&
3261 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
3262 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
3263 cur->nodeNr--;
3264 for (;i < cur->nodeNr;i++)
3265 cur->nodeTab[i] = cur->nodeTab[i + 1];
3266 cur->nodeTab[cur->nodeNr] = NULL;
3267}
3268
3269/**
3270 * xmlXPathNodeSetRemove:
3271 * @cur: the initial node set
3272 * @val: the index to remove
3273 *
3274 * Removes an entry from an existing NodeSet list.
3275 */
3276void
3277xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
3278 if (cur == NULL) return;
3279 if (val >= cur->nodeNr) return;
3280 if ((cur->nodeTab[val] != NULL) &&
3281 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
3282 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
3283 cur->nodeNr--;
3284 for (;val < cur->nodeNr;val++)
3285 cur->nodeTab[val] = cur->nodeTab[val + 1];
3286 cur->nodeTab[cur->nodeNr] = NULL;
3287}
3288
3289/**
3290 * xmlXPathFreeNodeSet:
3291 * @obj: the xmlNodeSetPtr to free
3292 *
3293 * Free the NodeSet compound (not the actual nodes !).
3294 */
3295void
3296xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
3297 if (obj == NULL) return;
3298 if (obj->nodeTab != NULL) {
3299 int i;
3300
3301 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3302 for (i = 0;i < obj->nodeNr;i++)
3303 if ((obj->nodeTab[i] != NULL) &&
3304 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3305 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3306 xmlFree(obj->nodeTab);
3307 }
3308 xmlFree(obj);
3309}
3310
3311/**
3312 * xmlXPathNodeSetClearFromPos:
3313 * @set: the node set to be cleared
3314 * @pos: the start position to clear from
3315 *
3316 * Clears the list from temporary XPath objects (e.g. namespace nodes
3317 * are feed) starting with the entry at @pos, but does *not* free the list
3318 * itself. Sets the length of the list to @pos.
3319 */
3320static void
3321xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
3322{
3323 if ((set == NULL) || (pos >= set->nodeNr))
3324 return;
3325 else if ((hasNsNodes)) {
3326 int i;
3327 xmlNodePtr node;
3328
3329 for (i = pos; i < set->nodeNr; i++) {
3330 node = set->nodeTab[i];
3331 if ((node != NULL) &&
3332 (node->type == XML_NAMESPACE_DECL))
3333 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3334 }
3335 }
3336 set->nodeNr = pos;
3337}
3338
3339/**
3340 * xmlXPathNodeSetClear:
3341 * @set: the node set to clear
3342 *
3343 * Clears the list from all temporary XPath objects (e.g. namespace nodes
3344 * are feed), but does *not* free the list itself. Sets the length of the
3345 * list to 0.
3346 */
3347static void
3348xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
3349{
3350 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3351}
3352
3353/**
3354 * xmlXPathNodeSetKeepLast:
3355 * @set: the node set to be cleared
3356 *
3357 * Move the last node to the first position and clear temporary XPath objects
3358 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
3359 * to 1.
3360 */
3361static void
3362xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
3363{
3364 int i;
3365 xmlNodePtr node;
3366
3367 if ((set == NULL) || (set->nodeNr <= 1))
3368 return;
3369 for (i = 0; i < set->nodeNr - 1; i++) {
3370 node = set->nodeTab[i];
3371 if ((node != NULL) &&
3372 (node->type == XML_NAMESPACE_DECL))
3373 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3374 }
3375 set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
3376 set->nodeNr = 1;
3377}
3378
3379/**
3380 * xmlXPathNewNodeSet:
3381 * @val: the NodePtr value
3382 *
3383 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3384 * it with the single Node @val
3385 *
3386 * Returns the newly created object.
3387 */
3388xmlXPathObjectPtr
3389xmlXPathNewNodeSet(xmlNodePtr val) {
3390 xmlXPathObjectPtr ret;
3391
3392 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3393 if (ret == NULL)
3394 return(NULL);
3395 memset(ret, 0 , sizeof(xmlXPathObject));
3396 ret->type = XPATH_NODESET;
3397 ret->boolval = 0;
3398 ret->nodesetval = xmlXPathNodeSetCreate(val);
3399 if (ret->nodesetval == NULL) {
3400 xmlFree(ret);
3401 return(NULL);
3402 }
3403 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3404 return(ret);
3405}
3406
3407/**
3408 * xmlXPathNewValueTree:
3409 * @val: the NodePtr value
3410 *
3411 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
3412 * it with the tree root @val
3413 *
3414 * Returns the newly created object.
3415 */
3416xmlXPathObjectPtr
3417xmlXPathNewValueTree(xmlNodePtr val) {
3418 xmlXPathObjectPtr ret;
3419
3420 ret = xmlXPathNewNodeSet(val);
3421 if (ret == NULL)
3422 return(NULL);
3423 ret->type = XPATH_XSLT_TREE;
3424
3425 return(ret);
3426}
3427
3428/**
3429 * xmlXPathNewNodeSetList:
3430 * @val: an existing NodeSet
3431 *
3432 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3433 * it with the Nodeset @val
3434 *
3435 * Returns the newly created object.
3436 */
3437xmlXPathObjectPtr
3438xmlXPathNewNodeSetList(xmlNodeSetPtr val)
3439{
3440 xmlXPathObjectPtr ret;
3441
3442 if (val == NULL)
3443 ret = NULL;
3444 else if (val->nodeTab == NULL)
3445 ret = xmlXPathNewNodeSet(NULL);
3446 else {
3447 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
3448 if (ret) {
3449 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val);
3450 if (ret->nodesetval == NULL) {
3451 xmlFree(ret);
3452 return(NULL);
3453 }
3454 }
3455 }
3456
3457 return (ret);
3458}
3459
3460/**
3461 * xmlXPathWrapNodeSet:
3462 * @val: the NodePtr value
3463 *
3464 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
3465 *
3466 * Returns the newly created object.
3467 *
3468 * In case of error the node set is destroyed and NULL is returned.
3469 */
3470xmlXPathObjectPtr
3471xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
3472 xmlXPathObjectPtr ret;
3473
3474 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3475 if (ret == NULL) {
3476 xmlXPathFreeNodeSet(val);
3477 return(NULL);
3478 }
3479 memset(ret, 0 , sizeof(xmlXPathObject));
3480 ret->type = XPATH_NODESET;
3481 ret->nodesetval = val;
3482 return(ret);
3483}
3484
3485/**
3486 * xmlXPathFreeNodeSetList:
3487 * @obj: an existing NodeSetList object
3488 *
3489 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
3490 * the list contrary to xmlXPathFreeObject().
3491 */
3492void
3493xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
3494 if (obj == NULL) return;
3495 xmlFree(obj);
3496}
3497
3498/**
3499 * xmlXPathDifference:
3500 * @nodes1: a node-set
3501 * @nodes2: a node-set
3502 *
3503 * Implements the EXSLT - Sets difference() function:
3504 * node-set set:difference (node-set, node-set)
3505 *
3506 * Returns the difference between the two node sets, or nodes1 if
3507 * nodes2 is empty
3508 */
3509xmlNodeSetPtr
3510xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3511 xmlNodeSetPtr ret;
3512 int i, l1;
3513 xmlNodePtr cur;
3514
3515 if (xmlXPathNodeSetIsEmpty(nodes2))
3516 return(nodes1);
3517
3518 ret = xmlXPathNodeSetCreate(NULL);
3519 if (ret == NULL)
3520 return(NULL);
3521 if (xmlXPathNodeSetIsEmpty(nodes1))
3522 return(ret);
3523
3524 l1 = xmlXPathNodeSetGetLength(nodes1);
3525
3526 for (i = 0; i < l1; i++) {
3527 cur = xmlXPathNodeSetItem(nodes1, i);
3528 if (!xmlXPathNodeSetContains(nodes2, cur)) {
3529 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3530 xmlXPathFreeNodeSet(ret);
3531 return(NULL);
3532 }
3533 }
3534 }
3535 return(ret);
3536}
3537
3538/**
3539 * xmlXPathIntersection:
3540 * @nodes1: a node-set
3541 * @nodes2: a node-set
3542 *
3543 * Implements the EXSLT - Sets intersection() function:
3544 * node-set set:intersection (node-set, node-set)
3545 *
3546 * Returns a node set comprising the nodes that are within both the
3547 * node sets passed as arguments
3548 */
3549xmlNodeSetPtr
3550xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3551 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
3552 int i, l1;
3553 xmlNodePtr cur;
3554
3555 if (ret == NULL)
3556 return(ret);
3557 if (xmlXPathNodeSetIsEmpty(nodes1))
3558 return(ret);
3559 if (xmlXPathNodeSetIsEmpty(nodes2))
3560 return(ret);
3561
3562 l1 = xmlXPathNodeSetGetLength(nodes1);
3563
3564 for (i = 0; i < l1; i++) {
3565 cur = xmlXPathNodeSetItem(nodes1, i);
3566 if (xmlXPathNodeSetContains(nodes2, cur)) {
3567 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3568 xmlXPathFreeNodeSet(ret);
3569 return(NULL);
3570 }
3571 }
3572 }
3573 return(ret);
3574}
3575
3576/**
3577 * xmlXPathDistinctSorted:
3578 * @nodes: a node-set, sorted by document order
3579 *
3580 * Implements the EXSLT - Sets distinct() function:
3581 * node-set set:distinct (node-set)
3582 *
3583 * Returns a subset of the nodes contained in @nodes, or @nodes if
3584 * it is empty
3585 */
3586xmlNodeSetPtr
3587xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
3588 xmlNodeSetPtr ret;
3589 xmlHashTablePtr hash;
3590 int i, l;
3591 xmlChar * strval;
3592 xmlNodePtr cur;
3593
3594 if (xmlXPathNodeSetIsEmpty(nodes))
3595 return(nodes);
3596
3597 ret = xmlXPathNodeSetCreate(NULL);
3598 if (ret == NULL)
3599 return(ret);
3600 l = xmlXPathNodeSetGetLength(nodes);
3601 hash = xmlHashCreate (l);
3602 for (i = 0; i < l; i++) {
3603 cur = xmlXPathNodeSetItem(nodes, i);
3604 strval = xmlXPathCastNodeToString(cur);
3605 if (xmlHashLookup(hash, strval) == NULL) {
3606 if (xmlHashAddEntry(hash, strval, strval) < 0) {
3607 xmlFree(strval);
3608 goto error;
3609 }
3610 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3611 goto error;
3612 } else {
3613 xmlFree(strval);
3614 }
3615 }
3616 xmlHashFree(hash, xmlHashDefaultDeallocator);
3617 return(ret);
3618
3619error:
3620 xmlHashFree(hash, xmlHashDefaultDeallocator);
3621 xmlXPathFreeNodeSet(ret);
3622 return(NULL);
3623}
3624
3625/**
3626 * xmlXPathDistinct:
3627 * @nodes: a node-set
3628 *
3629 * Implements the EXSLT - Sets distinct() function:
3630 * node-set set:distinct (node-set)
3631 * @nodes is sorted by document order, then #exslSetsDistinctSorted
3632 * is called with the sorted node-set
3633 *
3634 * Returns a subset of the nodes contained in @nodes, or @nodes if
3635 * it is empty
3636 */
3637xmlNodeSetPtr
3638xmlXPathDistinct (xmlNodeSetPtr nodes) {
3639 if (xmlXPathNodeSetIsEmpty(nodes))
3640 return(nodes);
3641
3642 xmlXPathNodeSetSort(nodes);
3643 return(xmlXPathDistinctSorted(nodes));
3644}
3645
3646/**
3647 * xmlXPathHasSameNodes:
3648 * @nodes1: a node-set
3649 * @nodes2: a node-set
3650 *
3651 * Implements the EXSLT - Sets has-same-nodes function:
3652 * boolean set:has-same-node(node-set, node-set)
3653 *
3654 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
3655 * otherwise
3656 */
3657int
3658xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3659 int i, l;
3660 xmlNodePtr cur;
3661
3662 if (xmlXPathNodeSetIsEmpty(nodes1) ||
3663 xmlXPathNodeSetIsEmpty(nodes2))
3664 return(0);
3665
3666 l = xmlXPathNodeSetGetLength(nodes1);
3667 for (i = 0; i < l; i++) {
3668 cur = xmlXPathNodeSetItem(nodes1, i);
3669 if (xmlXPathNodeSetContains(nodes2, cur))
3670 return(1);
3671 }
3672 return(0);
3673}
3674
3675/**
3676 * xmlXPathNodeLeadingSorted:
3677 * @nodes: a node-set, sorted by document order
3678 * @node: a node
3679 *
3680 * Implements the EXSLT - Sets leading() function:
3681 * node-set set:leading (node-set, node-set)
3682 *
3683 * Returns the nodes in @nodes that precede @node in document order,
3684 * @nodes if @node is NULL or an empty node-set if @nodes
3685 * doesn't contain @node
3686 */
3687xmlNodeSetPtr
3688xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3689 int i, l;
3690 xmlNodePtr cur;
3691 xmlNodeSetPtr ret;
3692
3693 if (node == NULL)
3694 return(nodes);
3695
3696 ret = xmlXPathNodeSetCreate(NULL);
3697 if (ret == NULL)
3698 return(ret);
3699 if (xmlXPathNodeSetIsEmpty(nodes) ||
3700 (!xmlXPathNodeSetContains(nodes, node)))
3701 return(ret);
3702
3703 l = xmlXPathNodeSetGetLength(nodes);
3704 for (i = 0; i < l; i++) {
3705 cur = xmlXPathNodeSetItem(nodes, i);
3706 if (cur == node)
3707 break;
3708 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3709 xmlXPathFreeNodeSet(ret);
3710 return(NULL);
3711 }
3712 }
3713 return(ret);
3714}
3715
3716/**
3717 * xmlXPathNodeLeading:
3718 * @nodes: a node-set
3719 * @node: a node
3720 *
3721 * Implements the EXSLT - Sets leading() function:
3722 * node-set set:leading (node-set, node-set)
3723 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
3724 * is called.
3725 *
3726 * Returns the nodes in @nodes that precede @node in document order,
3727 * @nodes if @node is NULL or an empty node-set if @nodes
3728 * doesn't contain @node
3729 */
3730xmlNodeSetPtr
3731xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
3732 xmlXPathNodeSetSort(nodes);
3733 return(xmlXPathNodeLeadingSorted(nodes, node));
3734}
3735
3736/**
3737 * xmlXPathLeadingSorted:
3738 * @nodes1: a node-set, sorted by document order
3739 * @nodes2: a node-set, sorted by document order
3740 *
3741 * Implements the EXSLT - Sets leading() function:
3742 * node-set set:leading (node-set, node-set)
3743 *
3744 * Returns the nodes in @nodes1 that precede the first node in @nodes2
3745 * in document order, @nodes1 if @nodes2 is NULL or empty or
3746 * an empty node-set if @nodes1 doesn't contain @nodes2
3747 */
3748xmlNodeSetPtr
3749xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3750 if (xmlXPathNodeSetIsEmpty(nodes2))
3751 return(nodes1);
3752 return(xmlXPathNodeLeadingSorted(nodes1,
3753 xmlXPathNodeSetItem(nodes2, 1)));
3754}
3755
3756/**
3757 * xmlXPathLeading:
3758 * @nodes1: a node-set
3759 * @nodes2: a node-set
3760 *
3761 * Implements the EXSLT - Sets leading() function:
3762 * node-set set:leading (node-set, node-set)
3763 * @nodes1 and @nodes2 are sorted by document order, then
3764 * #exslSetsLeadingSorted is called.
3765 *
3766 * Returns the nodes in @nodes1 that precede the first node in @nodes2
3767 * in document order, @nodes1 if @nodes2 is NULL or empty or
3768 * an empty node-set if @nodes1 doesn't contain @nodes2
3769 */
3770xmlNodeSetPtr
3771xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3772 if (xmlXPathNodeSetIsEmpty(nodes2))
3773 return(nodes1);
3774 if (xmlXPathNodeSetIsEmpty(nodes1))
3775 return(xmlXPathNodeSetCreate(NULL));
3776 xmlXPathNodeSetSort(nodes1);
3777 xmlXPathNodeSetSort(nodes2);
3778 return(xmlXPathNodeLeadingSorted(nodes1,
3779 xmlXPathNodeSetItem(nodes2, 1)));
3780}
3781
3782/**
3783 * xmlXPathNodeTrailingSorted:
3784 * @nodes: a node-set, sorted by document order
3785 * @node: a node
3786 *
3787 * Implements the EXSLT - Sets trailing() function:
3788 * node-set set:trailing (node-set, node-set)
3789 *
3790 * Returns the nodes in @nodes that follow @node in document order,
3791 * @nodes if @node is NULL or an empty node-set if @nodes
3792 * doesn't contain @node
3793 */
3794xmlNodeSetPtr
3795xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3796 int i, l;
3797 xmlNodePtr cur;
3798 xmlNodeSetPtr ret;
3799
3800 if (node == NULL)
3801 return(nodes);
3802
3803 ret = xmlXPathNodeSetCreate(NULL);
3804 if (ret == NULL)
3805 return(ret);
3806 if (xmlXPathNodeSetIsEmpty(nodes) ||
3807 (!xmlXPathNodeSetContains(nodes, node)))
3808 return(ret);
3809
3810 l = xmlXPathNodeSetGetLength(nodes);
3811 for (i = l - 1; i >= 0; i--) {
3812 cur = xmlXPathNodeSetItem(nodes, i);
3813 if (cur == node)
3814 break;
3815 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3816 xmlXPathFreeNodeSet(ret);
3817 return(NULL);
3818 }
3819 }
3820 xmlXPathNodeSetSort(ret); /* bug 413451 */
3821 return(ret);
3822}
3823
3824/**
3825 * xmlXPathNodeTrailing:
3826 * @nodes: a node-set
3827 * @node: a node
3828 *
3829 * Implements the EXSLT - Sets trailing() function:
3830 * node-set set:trailing (node-set, node-set)
3831 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
3832 * is called.
3833 *
3834 * Returns the nodes in @nodes that follow @node in document order,
3835 * @nodes if @node is NULL or an empty node-set if @nodes
3836 * doesn't contain @node
3837 */
3838xmlNodeSetPtr
3839xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
3840 xmlXPathNodeSetSort(nodes);
3841 return(xmlXPathNodeTrailingSorted(nodes, node));
3842}
3843
3844/**
3845 * xmlXPathTrailingSorted:
3846 * @nodes1: a node-set, sorted by document order
3847 * @nodes2: a node-set, sorted by document order
3848 *
3849 * Implements the EXSLT - Sets trailing() function:
3850 * node-set set:trailing (node-set, node-set)
3851 *
3852 * Returns the nodes in @nodes1 that follow the first node in @nodes2
3853 * in document order, @nodes1 if @nodes2 is NULL or empty or
3854 * an empty node-set if @nodes1 doesn't contain @nodes2
3855 */
3856xmlNodeSetPtr
3857xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3858 if (xmlXPathNodeSetIsEmpty(nodes2))
3859 return(nodes1);
3860 return(xmlXPathNodeTrailingSorted(nodes1,
3861 xmlXPathNodeSetItem(nodes2, 0)));
3862}
3863
3864/**
3865 * xmlXPathTrailing:
3866 * @nodes1: a node-set
3867 * @nodes2: a node-set
3868 *
3869 * Implements the EXSLT - Sets trailing() function:
3870 * node-set set:trailing (node-set, node-set)
3871 * @nodes1 and @nodes2 are sorted by document order, then
3872 * #xmlXPathTrailingSorted is called.
3873 *
3874 * Returns the nodes in @nodes1 that follow the first node in @nodes2
3875 * in document order, @nodes1 if @nodes2 is NULL or empty or
3876 * an empty node-set if @nodes1 doesn't contain @nodes2
3877 */
3878xmlNodeSetPtr
3879xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3880 if (xmlXPathNodeSetIsEmpty(nodes2))
3881 return(nodes1);
3882 if (xmlXPathNodeSetIsEmpty(nodes1))
3883 return(xmlXPathNodeSetCreate(NULL));
3884 xmlXPathNodeSetSort(nodes1);
3885 xmlXPathNodeSetSort(nodes2);
3886 return(xmlXPathNodeTrailingSorted(nodes1,
3887 xmlXPathNodeSetItem(nodes2, 0)));
3888}
3889
3890/************************************************************************
3891 * *
3892 * Routines to handle extra functions *
3893 * *
3894 ************************************************************************/
3895
3896/**
3897 * xmlXPathRegisterFunc:
3898 * @ctxt: the XPath context
3899 * @name: the function name
3900 * @f: the function implementation or NULL
3901 *
3902 * Register a new function. If @f is NULL it unregisters the function
3903 *
3904 * Returns 0 in case of success, -1 in case of error
3905 */
3906int
3907xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
3908 xmlXPathFunction f) {
3909 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
3910}
3911
3912/**
3913 * xmlXPathRegisterFuncNS:
3914 * @ctxt: the XPath context
3915 * @name: the function name
3916 * @ns_uri: the function namespace URI
3917 * @f: the function implementation or NULL
3918 *
3919 * Register a new function. If @f is NULL it unregisters the function
3920 *
3921 * Returns 0 in case of success, -1 in case of error
3922 */
3923int
3924xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3925 const xmlChar *ns_uri, xmlXPathFunction f) {
3926 int ret;
3927
3928 if (ctxt == NULL)
3929 return(-1);
3930 if (name == NULL)
3931 return(-1);
3932
3933 if (ctxt->funcHash == NULL)
3934 ctxt->funcHash = xmlHashCreate(0);
3935 if (ctxt->funcHash == NULL) {
3936 xmlXPathErrMemory(ctxt);
3937 return(-1);
3938 }
3939 if (f == NULL)
3940 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
3941XML_IGNORE_FPTR_CAST_WARNINGS
3942 ret = xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f);
3943XML_POP_WARNINGS
3944 if (ret < 0) {
3945 xmlXPathErrMemory(ctxt);
3946 return(-1);
3947 }
3948
3949 return(0);
3950}
3951
3952/**
3953 * xmlXPathRegisterFuncLookup:
3954 * @ctxt: the XPath context
3955 * @f: the lookup function
3956 * @funcCtxt: the lookup data
3957 *
3958 * Registers an external mechanism to do function lookup.
3959 */
3960void
3961xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
3962 xmlXPathFuncLookupFunc f,
3963 void *funcCtxt) {
3964 if (ctxt == NULL)
3965 return;
3966 ctxt->funcLookupFunc = f;
3967 ctxt->funcLookupData = funcCtxt;
3968}
3969
3970/**
3971 * xmlXPathFunctionLookup:
3972 * @ctxt: the XPath context
3973 * @name: the function name
3974 *
3975 * Search in the Function array of the context for the given
3976 * function.
3977 *
3978 * Returns the xmlXPathFunction or NULL if not found
3979 */
3980xmlXPathFunction
3981xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
3982 if (ctxt == NULL)
3983 return (NULL);
3984
3985 if (ctxt->funcLookupFunc != NULL) {
3986 xmlXPathFunction ret;
3987 xmlXPathFuncLookupFunc f;
3988
3989 f = ctxt->funcLookupFunc;
3990 ret = f(ctxt->funcLookupData, name, NULL);
3991 if (ret != NULL)
3992 return(ret);
3993 }
3994 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
3995}
3996
3997/**
3998 * xmlXPathFunctionLookupNS:
3999 * @ctxt: the XPath context
4000 * @name: the function name
4001 * @ns_uri: the function namespace URI
4002 *
4003 * Search in the Function array of the context for the given
4004 * function.
4005 *
4006 * Returns the xmlXPathFunction or NULL if not found
4007 */
4008xmlXPathFunction
4009xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4010 const xmlChar *ns_uri) {
4011 xmlXPathFunction ret;
4012
4013 if (ctxt == NULL)
4014 return(NULL);
4015 if (name == NULL)
4016 return(NULL);
4017
4018 if (ctxt->funcLookupFunc != NULL) {
4019 xmlXPathFuncLookupFunc f;
4020
4021 f = ctxt->funcLookupFunc;
4022 ret = f(ctxt->funcLookupData, name, ns_uri);
4023 if (ret != NULL)
4024 return(ret);
4025 }
4026
4027 if (ctxt->funcHash == NULL)
4028 return(NULL);
4029
4030XML_IGNORE_FPTR_CAST_WARNINGS
4031 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4032XML_POP_WARNINGS
4033 return(ret);
4034}
4035
4036/**
4037 * xmlXPathRegisteredFuncsCleanup:
4038 * @ctxt: the XPath context
4039 *
4040 * Cleanup the XPath context data associated to registered functions
4041 */
4042void
4043xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4044 if (ctxt == NULL)
4045 return;
4046
4047 xmlHashFree(ctxt->funcHash, NULL);
4048 ctxt->funcHash = NULL;
4049}
4050
4051/************************************************************************
4052 * *
4053 * Routines to handle Variables *
4054 * *
4055 ************************************************************************/
4056
4057/**
4058 * xmlXPathRegisterVariable:
4059 * @ctxt: the XPath context
4060 * @name: the variable name
4061 * @value: the variable value or NULL
4062 *
4063 * Register a new variable value. If @value is NULL it unregisters
4064 * the variable
4065 *
4066 * Returns 0 in case of success, -1 in case of error
4067 */
4068int
4069xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4070 xmlXPathObjectPtr value) {
4071 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4072}
4073
4074/**
4075 * xmlXPathRegisterVariableNS:
4076 * @ctxt: the XPath context
4077 * @name: the variable name
4078 * @ns_uri: the variable namespace URI
4079 * @value: the variable value or NULL
4080 *
4081 * Register a new variable value. If @value is NULL it unregisters
4082 * the variable
4083 *
4084 * Returns 0 in case of success, -1 in case of error
4085 */
4086int
4087xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4088 const xmlChar *ns_uri,
4089 xmlXPathObjectPtr value) {
4090 if (ctxt == NULL)
4091 return(-1);
4092 if (name == NULL)
4093 return(-1);
4094
4095 if (ctxt->varHash == NULL)
4096 ctxt->varHash = xmlHashCreate(0);
4097 if (ctxt->varHash == NULL)
4098 return(-1);
4099 if (value == NULL)
4100 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4101 xmlXPathFreeObjectEntry));
4102 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4103 (void *) value, xmlXPathFreeObjectEntry));
4104}
4105
4106/**
4107 * xmlXPathRegisterVariableLookup:
4108 * @ctxt: the XPath context
4109 * @f: the lookup function
4110 * @data: the lookup data
4111 *
4112 * register an external mechanism to do variable lookup
4113 */
4114void
4115xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4116 xmlXPathVariableLookupFunc f, void *data) {
4117 if (ctxt == NULL)
4118 return;
4119 ctxt->varLookupFunc = f;
4120 ctxt->varLookupData = data;
4121}
4122
4123/**
4124 * xmlXPathVariableLookup:
4125 * @ctxt: the XPath context
4126 * @name: the variable name
4127 *
4128 * Search in the Variable array of the context for the given
4129 * variable value.
4130 *
4131 * Returns a copy of the value or NULL if not found
4132 */
4133xmlXPathObjectPtr
4134xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4135 if (ctxt == NULL)
4136 return(NULL);
4137
4138 if (ctxt->varLookupFunc != NULL) {
4139 xmlXPathObjectPtr ret;
4140
4141 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4142 (ctxt->varLookupData, name, NULL);
4143 return(ret);
4144 }
4145 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4146}
4147
4148/**
4149 * xmlXPathVariableLookupNS:
4150 * @ctxt: the XPath context
4151 * @name: the variable name
4152 * @ns_uri: the variable namespace URI
4153 *
4154 * Search in the Variable array of the context for the given
4155 * variable value.
4156 *
4157 * Returns the a copy of the value or NULL if not found
4158 */
4159xmlXPathObjectPtr
4160xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4161 const xmlChar *ns_uri) {
4162 if (ctxt == NULL)
4163 return(NULL);
4164
4165 if (ctxt->varLookupFunc != NULL) {
4166 xmlXPathObjectPtr ret;
4167
4168 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4169 (ctxt->varLookupData, name, ns_uri);
4170 if (ret != NULL) return(ret);
4171 }
4172
4173 if (ctxt->varHash == NULL)
4174 return(NULL);
4175 if (name == NULL)
4176 return(NULL);
4177
4178 return(xmlXPathObjectCopy(xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4179}
4180
4181/**
4182 * xmlXPathRegisteredVariablesCleanup:
4183 * @ctxt: the XPath context
4184 *
4185 * Cleanup the XPath context data associated to registered variables
4186 */
4187void
4188xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4189 if (ctxt == NULL)
4190 return;
4191
4192 xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
4193 ctxt->varHash = NULL;
4194}
4195
4196/**
4197 * xmlXPathRegisterNs:
4198 * @ctxt: the XPath context
4199 * @prefix: the namespace prefix cannot be NULL or empty string
4200 * @ns_uri: the namespace name
4201 *
4202 * Register a new namespace. If @ns_uri is NULL it unregisters
4203 * the namespace
4204 *
4205 * Returns 0 in case of success, -1 in case of error
4206 */
4207int
4208xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4209 const xmlChar *ns_uri) {
4210 xmlChar *copy;
4211
4212 if (ctxt == NULL)
4213 return(-1);
4214 if (prefix == NULL)
4215 return(-1);
4216 if (prefix[0] == 0)
4217 return(-1);
4218
4219 if (ctxt->nsHash == NULL)
4220 ctxt->nsHash = xmlHashCreate(10);
4221 if (ctxt->nsHash == NULL) {
4222 xmlXPathErrMemory(ctxt);
4223 return(-1);
4224 }
4225 if (ns_uri == NULL)
4226 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
4227 xmlHashDefaultDeallocator));
4228
4229 copy = xmlStrdup(ns_uri);
4230 if (copy == NULL) {
4231 xmlXPathErrMemory(ctxt);
4232 return(-1);
4233 }
4234 if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
4235 xmlHashDefaultDeallocator) < 0) {
4236 xmlXPathErrMemory(ctxt);
4237 xmlFree(copy);
4238 return(-1);
4239 }
4240
4241 return(0);
4242}
4243
4244/**
4245 * xmlXPathNsLookup:
4246 * @ctxt: the XPath context
4247 * @prefix: the namespace prefix value
4248 *
4249 * Search in the namespace declaration array of the context for the given
4250 * namespace name associated to the given prefix
4251 *
4252 * Returns the value or NULL if not found
4253 */
4254const xmlChar *
4255xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
4256 if (ctxt == NULL)
4257 return(NULL);
4258 if (prefix == NULL)
4259 return(NULL);
4260
4261 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4262 return(XML_XML_NAMESPACE);
4263
4264 if (ctxt->namespaces != NULL) {
4265 int i;
4266
4267 for (i = 0;i < ctxt->nsNr;i++) {
4268 if ((ctxt->namespaces[i] != NULL) &&
4269 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4270 return(ctxt->namespaces[i]->href);
4271 }
4272 }
4273
4274 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4275}
4276
4277/**
4278 * xmlXPathRegisteredNsCleanup:
4279 * @ctxt: the XPath context
4280 *
4281 * Cleanup the XPath context data associated to registered variables
4282 */
4283void
4284xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
4285 if (ctxt == NULL)
4286 return;
4287
4288 xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4289 ctxt->nsHash = NULL;
4290}
4291
4292/************************************************************************
4293 * *
4294 * Routines to handle Values *
4295 * *
4296 ************************************************************************/
4297
4298/* Allocations are terrible, one needs to optimize all this !!! */
4299
4300/**
4301 * xmlXPathNewFloat:
4302 * @val: the double value
4303 *
4304 * Create a new xmlXPathObjectPtr of type double and of value @val
4305 *
4306 * Returns the newly created object.
4307 */
4308xmlXPathObjectPtr
4309xmlXPathNewFloat(double val) {
4310 xmlXPathObjectPtr ret;
4311
4312 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4313 if (ret == NULL)
4314 return(NULL);
4315 memset(ret, 0 , sizeof(xmlXPathObject));
4316 ret->type = XPATH_NUMBER;
4317 ret->floatval = val;
4318 return(ret);
4319}
4320
4321/**
4322 * xmlXPathNewBoolean:
4323 * @val: the boolean value
4324 *
4325 * Create a new xmlXPathObjectPtr of type boolean and of value @val
4326 *
4327 * Returns the newly created object.
4328 */
4329xmlXPathObjectPtr
4330xmlXPathNewBoolean(int val) {
4331 xmlXPathObjectPtr ret;
4332
4333 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4334 if (ret == NULL)
4335 return(NULL);
4336 memset(ret, 0 , sizeof(xmlXPathObject));
4337 ret->type = XPATH_BOOLEAN;
4338 ret->boolval = (val != 0);
4339 return(ret);
4340}
4341
4342/**
4343 * xmlXPathNewString:
4344 * @val: the xmlChar * value
4345 *
4346 * Create a new xmlXPathObjectPtr of type string and of value @val
4347 *
4348 * Returns the newly created object.
4349 */
4350xmlXPathObjectPtr
4351xmlXPathNewString(const xmlChar *val) {
4352 xmlXPathObjectPtr ret;
4353
4354 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4355 if (ret == NULL)
4356 return(NULL);
4357 memset(ret, 0 , sizeof(xmlXPathObject));
4358 ret->type = XPATH_STRING;
4359 if (val == NULL)
4360 val = BAD_CAST "";
4361 ret->stringval = xmlStrdup(val);
4362 if (ret->stringval == NULL) {
4363 xmlFree(ret);
4364 return(NULL);
4365 }
4366 return(ret);
4367}
4368
4369/**
4370 * xmlXPathWrapString:
4371 * @val: the xmlChar * value
4372 *
4373 * Wraps the @val string into an XPath object.
4374 *
4375 * Returns the newly created object.
4376 *
4377 * Frees @val in case of error.
4378 */
4379xmlXPathObjectPtr
4380xmlXPathWrapString (xmlChar *val) {
4381 xmlXPathObjectPtr ret;
4382
4383 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4384 if (ret == NULL) {
4385 xmlFree(val);
4386 return(NULL);
4387 }
4388 memset(ret, 0 , sizeof(xmlXPathObject));
4389 ret->type = XPATH_STRING;
4390 ret->stringval = val;
4391 return(ret);
4392}
4393
4394/**
4395 * xmlXPathNewCString:
4396 * @val: the char * value
4397 *
4398 * Create a new xmlXPathObjectPtr of type string and of value @val
4399 *
4400 * Returns the newly created object.
4401 */
4402xmlXPathObjectPtr
4403xmlXPathNewCString(const char *val) {
4404 return(xmlXPathNewString(BAD_CAST val));
4405}
4406
4407/**
4408 * xmlXPathWrapCString:
4409 * @val: the char * value
4410 *
4411 * Wraps a string into an XPath object.
4412 *
4413 * Returns the newly created object.
4414 */
4415xmlXPathObjectPtr
4416xmlXPathWrapCString (char * val) {
4417 return(xmlXPathWrapString((xmlChar *)(val)));
4418}
4419
4420/**
4421 * xmlXPathWrapExternal:
4422 * @val: the user data
4423 *
4424 * Wraps the @val data into an XPath object.
4425 *
4426 * Returns the newly created object.
4427 */
4428xmlXPathObjectPtr
4429xmlXPathWrapExternal (void *val) {
4430 xmlXPathObjectPtr ret;
4431
4432 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4433 if (ret == NULL)
4434 return(NULL);
4435 memset(ret, 0 , sizeof(xmlXPathObject));
4436 ret->type = XPATH_USERS;
4437 ret->user = val;
4438 return(ret);
4439}
4440
4441/**
4442 * xmlXPathObjectCopy:
4443 * @val: the original object
4444 *
4445 * allocate a new copy of a given object
4446 *
4447 * Returns the newly created object.
4448 */
4449xmlXPathObjectPtr
4450xmlXPathObjectCopy(xmlXPathObjectPtr val) {
4451 xmlXPathObjectPtr ret;
4452
4453 if (val == NULL)
4454 return(NULL);
4455
4456 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4457 if (ret == NULL)
4458 return(NULL);
4459 memcpy(ret, val , sizeof(xmlXPathObject));
4460 switch (val->type) {
4461 case XPATH_BOOLEAN:
4462 case XPATH_NUMBER:
4463#ifdef LIBXML_XPTR_LOCS_ENABLED
4464 case XPATH_POINT:
4465 case XPATH_RANGE:
4466#endif /* LIBXML_XPTR_LOCS_ENABLED */
4467 break;
4468 case XPATH_STRING:
4469 ret->stringval = xmlStrdup(val->stringval);
4470 if (ret->stringval == NULL) {
4471 xmlFree(ret);
4472 return(NULL);
4473 }
4474 break;
4475 case XPATH_XSLT_TREE:
4476#if 0
4477/*
4478 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
4479 this previous handling is no longer correct, and can cause some serious
4480 problems (ref. bug 145547)
4481*/
4482 if ((val->nodesetval != NULL) &&
4483 (val->nodesetval->nodeTab != NULL)) {
4484 xmlNodePtr cur, tmp;
4485 xmlDocPtr top;
4486
4487 ret->boolval = 1;
4488 top = xmlNewDoc(NULL);
4489 top->name = (char *)
4490 xmlStrdup(val->nodesetval->nodeTab[0]->name);
4491 ret->user = top;
4492 if (top != NULL) {
4493 top->doc = top;
4494 cur = val->nodesetval->nodeTab[0]->children;
4495 while (cur != NULL) {
4496 tmp = xmlDocCopyNode(cur, top, 1);
4497 xmlAddChild((xmlNodePtr) top, tmp);
4498 cur = cur->next;
4499 }
4500 }
4501
4502 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
4503 } else
4504 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
4505 /* Deallocate the copied tree value */
4506 break;
4507#endif
4508 case XPATH_NODESET:
4509 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
4510 if (ret->nodesetval == NULL) {
4511 xmlFree(ret);
4512 return(NULL);
4513 }
4514 /* Do not deallocate the copied tree value */
4515 ret->boolval = 0;
4516 break;
4517#ifdef LIBXML_XPTR_LOCS_ENABLED
4518 case XPATH_LOCATIONSET:
4519 {
4520 xmlLocationSetPtr loc = val->user;
4521 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
4522 break;
4523 }
4524#endif
4525 case XPATH_USERS:
4526 ret->user = val->user;
4527 break;
4528 default:
4529 xmlFree(ret);
4530 ret = NULL;
4531 break;
4532 }
4533 return(ret);
4534}
4535
4536/**
4537 * xmlXPathFreeObject:
4538 * @obj: the object to free
4539 *
4540 * Free up an xmlXPathObjectPtr object.
4541 */
4542void
4543xmlXPathFreeObject(xmlXPathObjectPtr obj) {
4544 if (obj == NULL) return;
4545 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4546 if (obj->nodesetval != NULL)
4547 xmlXPathFreeNodeSet(obj->nodesetval);
4548#ifdef LIBXML_XPTR_LOCS_ENABLED
4549 } else if (obj->type == XPATH_LOCATIONSET) {
4550 if (obj->user != NULL)
4551 xmlXPtrFreeLocationSet(obj->user);
4552#endif
4553 } else if (obj->type == XPATH_STRING) {
4554 if (obj->stringval != NULL)
4555 xmlFree(obj->stringval);
4556 }
4557 xmlFree(obj);
4558}
4559
4560static void
4561xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
4562 xmlXPathFreeObject((xmlXPathObjectPtr) obj);
4563}
4564
4565/**
4566 * xmlXPathReleaseObject:
4567 * @obj: the xmlXPathObjectPtr to free or to cache
4568 *
4569 * Depending on the state of the cache this frees the given
4570 * XPath object or stores it in the cache.
4571 */
4572static void
4573xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
4574{
4575 if (obj == NULL)
4576 return;
4577 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4578 xmlXPathFreeObject(obj);
4579 } else {
4580 xmlXPathContextCachePtr cache =
4581 (xmlXPathContextCachePtr) ctxt->cache;
4582
4583 switch (obj->type) {
4584 case XPATH_NODESET:
4585 case XPATH_XSLT_TREE:
4586 if (obj->nodesetval != NULL) {
4587 if ((obj->nodesetval->nodeMax <= 40) &&
4588 (cache->numNodeset < cache->maxNodeset)) {
4589 obj->stringval = (void *) cache->nodesetObjs;
4590 cache->nodesetObjs = obj;
4591 cache->numNodeset += 1;
4592 goto obj_cached;
4593 } else {
4594 xmlXPathFreeNodeSet(obj->nodesetval);
4595 obj->nodesetval = NULL;
4596 }
4597 }
4598 break;
4599 case XPATH_STRING:
4600 if (obj->stringval != NULL)
4601 xmlFree(obj->stringval);
4602 obj->stringval = NULL;
4603 break;
4604 case XPATH_BOOLEAN:
4605 case XPATH_NUMBER:
4606 break;
4607#ifdef LIBXML_XPTR_LOCS_ENABLED
4608 case XPATH_LOCATIONSET:
4609 if (obj->user != NULL) {
4610 xmlXPtrFreeLocationSet(obj->user);
4611 }
4612 goto free_obj;
4613#endif
4614 default:
4615 goto free_obj;
4616 }
4617
4618 /*
4619 * Fallback to adding to the misc-objects slot.
4620 */
4621 if (cache->numMisc >= cache->maxMisc)
4622 goto free_obj;
4623 obj->stringval = (void *) cache->miscObjs;
4624 cache->miscObjs = obj;
4625 cache->numMisc += 1;
4626
4627obj_cached:
4628 obj->boolval = 0;
4629 if (obj->nodesetval != NULL) {
4630 xmlNodeSetPtr tmpset = obj->nodesetval;
4631
4632 /*
4633 * Due to those nasty ns-nodes, we need to traverse
4634 * the list and free the ns-nodes.
4635 */
4636 if (tmpset->nodeNr > 0) {
4637 int i;
4638 xmlNodePtr node;
4639
4640 for (i = 0; i < tmpset->nodeNr; i++) {
4641 node = tmpset->nodeTab[i];
4642 if ((node != NULL) &&
4643 (node->type == XML_NAMESPACE_DECL))
4644 {
4645 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4646 }
4647 }
4648 }
4649 tmpset->nodeNr = 0;
4650 }
4651
4652 return;
4653
4654free_obj:
4655 /*
4656 * Cache is full; free the object.
4657 */
4658 if (obj->nodesetval != NULL)
4659 xmlXPathFreeNodeSet(obj->nodesetval);
4660 xmlFree(obj);
4661 }
4662 return;
4663}
4664
4665
4666/************************************************************************
4667 * *
4668 * Type Casting Routines *
4669 * *
4670 ************************************************************************/
4671
4672/**
4673 * xmlXPathCastBooleanToString:
4674 * @val: a boolean
4675 *
4676 * Converts a boolean to its string value.
4677 *
4678 * Returns a newly allocated string.
4679 */
4680xmlChar *
4681xmlXPathCastBooleanToString (int val) {
4682 xmlChar *ret;
4683 if (val)
4684 ret = xmlStrdup((const xmlChar *) "true");
4685 else
4686 ret = xmlStrdup((const xmlChar *) "false");
4687 return(ret);
4688}
4689
4690/**
4691 * xmlXPathCastNumberToString:
4692 * @val: a number
4693 *
4694 * Converts a number to its string value.
4695 *
4696 * Returns a newly allocated string.
4697 */
4698xmlChar *
4699xmlXPathCastNumberToString (double val) {
4700 xmlChar *ret;
4701 switch (xmlXPathIsInf(val)) {
4702 case 1:
4703 ret = xmlStrdup((const xmlChar *) "Infinity");
4704 break;
4705 case -1:
4706 ret = xmlStrdup((const xmlChar *) "-Infinity");
4707 break;
4708 default:
4709 if (xmlXPathIsNaN(val)) {
4710 ret = xmlStrdup((const xmlChar *) "NaN");
4711 } else if (val == 0) {
4712 /* Omit sign for negative zero. */
4713 ret = xmlStrdup((const xmlChar *) "0");
4714 } else {
4715 /* could be improved */
4716 char buf[100];
4717 xmlXPathFormatNumber(val, buf, 99);
4718 buf[99] = 0;
4719 ret = xmlStrdup((const xmlChar *) buf);
4720 }
4721 }
4722 return(ret);
4723}
4724
4725/**
4726 * xmlXPathCastNodeToString:
4727 * @node: a node
4728 *
4729 * Converts a node to its string value.
4730 *
4731 * Returns a newly allocated string.
4732 */
4733xmlChar *
4734xmlXPathCastNodeToString (xmlNodePtr node) {
4735 return(xmlNodeGetContent(node));
4736}
4737
4738/**
4739 * xmlXPathCastNodeSetToString:
4740 * @ns: a node-set
4741 *
4742 * Converts a node-set to its string value.
4743 *
4744 * Returns a newly allocated string.
4745 */
4746xmlChar *
4747xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
4748 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
4749 return(xmlStrdup((const xmlChar *) ""));
4750
4751 if (ns->nodeNr > 1)
4752 xmlXPathNodeSetSort(ns);
4753 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
4754}
4755
4756/**
4757 * xmlXPathCastToString:
4758 * @val: an XPath object
4759 *
4760 * Converts an existing object to its string() equivalent
4761 *
4762 * Returns the allocated string value of the object, NULL in case of error.
4763 * It's up to the caller to free the string memory with xmlFree().
4764 */
4765xmlChar *
4766xmlXPathCastToString(xmlXPathObjectPtr val) {
4767 xmlChar *ret = NULL;
4768
4769 if (val == NULL)
4770 return(xmlStrdup((const xmlChar *) ""));
4771 switch (val->type) {
4772 case XPATH_UNDEFINED:
4773 ret = xmlStrdup((const xmlChar *) "");
4774 break;
4775 case XPATH_NODESET:
4776 case XPATH_XSLT_TREE:
4777 ret = xmlXPathCastNodeSetToString(val->nodesetval);
4778 break;
4779 case XPATH_STRING:
4780 return(xmlStrdup(val->stringval));
4781 case XPATH_BOOLEAN:
4782 ret = xmlXPathCastBooleanToString(val->boolval);
4783 break;
4784 case XPATH_NUMBER: {
4785 ret = xmlXPathCastNumberToString(val->floatval);
4786 break;
4787 }
4788 case XPATH_USERS:
4789#ifdef LIBXML_XPTR_LOCS_ENABLED
4790 case XPATH_POINT:
4791 case XPATH_RANGE:
4792 case XPATH_LOCATIONSET:
4793#endif /* LIBXML_XPTR_LOCS_ENABLED */
4794 /* TODO */
4795 ret = xmlStrdup((const xmlChar *) "");
4796 break;
4797 }
4798 return(ret);
4799}
4800
4801/**
4802 * xmlXPathConvertString:
4803 * @val: an XPath object
4804 *
4805 * Converts an existing object to its string() equivalent
4806 *
4807 * Returns the new object, the old one is freed (or the operation
4808 * is done directly on @val)
4809 */
4810xmlXPathObjectPtr
4811xmlXPathConvertString(xmlXPathObjectPtr val) {
4812 xmlChar *res = NULL;
4813
4814 if (val == NULL)
4815 return(xmlXPathNewCString(""));
4816
4817 switch (val->type) {
4818 case XPATH_UNDEFINED:
4819 break;
4820 case XPATH_NODESET:
4821 case XPATH_XSLT_TREE:
4822 res = xmlXPathCastNodeSetToString(val->nodesetval);
4823 break;
4824 case XPATH_STRING:
4825 return(val);
4826 case XPATH_BOOLEAN:
4827 res = xmlXPathCastBooleanToString(val->boolval);
4828 break;
4829 case XPATH_NUMBER:
4830 res = xmlXPathCastNumberToString(val->floatval);
4831 break;
4832 case XPATH_USERS:
4833#ifdef LIBXML_XPTR_LOCS_ENABLED
4834 case XPATH_POINT:
4835 case XPATH_RANGE:
4836 case XPATH_LOCATIONSET:
4837#endif /* LIBXML_XPTR_LOCS_ENABLED */
4838 /* TODO */
4839 break;
4840 }
4841 xmlXPathFreeObject(val);
4842 if (res == NULL)
4843 return(xmlXPathNewCString(""));
4844 return(xmlXPathWrapString(res));
4845}
4846
4847/**
4848 * xmlXPathCastBooleanToNumber:
4849 * @val: a boolean
4850 *
4851 * Converts a boolean to its number value
4852 *
4853 * Returns the number value
4854 */
4855double
4856xmlXPathCastBooleanToNumber(int val) {
4857 if (val)
4858 return(1.0);
4859 return(0.0);
4860}
4861
4862/**
4863 * xmlXPathCastStringToNumber:
4864 * @val: a string
4865 *
4866 * Converts a string to its number value
4867 *
4868 * Returns the number value
4869 */
4870double
4871xmlXPathCastStringToNumber(const xmlChar * val) {
4872 return(xmlXPathStringEvalNumber(val));
4873}
4874
4875/**
4876 * xmlXPathNodeToNumberInternal:
4877 * @node: a node
4878 *
4879 * Converts a node to its number value
4880 *
4881 * Returns the number value
4882 */
4883static double
4884xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt, xmlNodePtr node) {
4885 xmlChar *strval;
4886 double ret;
4887
4888 if (node == NULL)
4889 return(xmlXPathNAN);
4890 strval = xmlXPathCastNodeToString(node);
4891 if (strval == NULL) {
4892 xmlXPathPErrMemory(ctxt);
4893 return(xmlXPathNAN);
4894 }
4895 ret = xmlXPathCastStringToNumber(strval);
4896 xmlFree(strval);
4897
4898 return(ret);
4899}
4900
4901/**
4902 * xmlXPathCastNodeToNumber:
4903 * @node: a node
4904 *
4905 * Converts a node to its number value
4906 *
4907 * Returns the number value
4908 */
4909double
4910xmlXPathCastNodeToNumber (xmlNodePtr node) {
4911 return(xmlXPathNodeToNumberInternal(NULL, node));
4912}
4913
4914/**
4915 * xmlXPathCastNodeSetToNumber:
4916 * @ns: a node-set
4917 *
4918 * Converts a node-set to its number value
4919 *
4920 * Returns the number value
4921 */
4922double
4923xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
4924 xmlChar *str;
4925 double ret;
4926
4927 if (ns == NULL)
4928 return(xmlXPathNAN);
4929 str = xmlXPathCastNodeSetToString(ns);
4930 ret = xmlXPathCastStringToNumber(str);
4931 xmlFree(str);
4932 return(ret);
4933}
4934
4935/**
4936 * xmlXPathCastToNumber:
4937 * @val: an XPath object
4938 *
4939 * Converts an XPath object to its number value
4940 *
4941 * Returns the number value
4942 */
4943double
4944xmlXPathCastToNumber(xmlXPathObjectPtr val) {
4945 return(xmlXPathCastToNumberInternal(NULL, val));
4946}
4947
4948/**
4949 * xmlXPathConvertNumber:
4950 * @val: an XPath object
4951 *
4952 * Converts an existing object to its number() equivalent
4953 *
4954 * Returns the new object, the old one is freed (or the operation
4955 * is done directly on @val)
4956 */
4957xmlXPathObjectPtr
4958xmlXPathConvertNumber(xmlXPathObjectPtr val) {
4959 xmlXPathObjectPtr ret;
4960
4961 if (val == NULL)
4962 return(xmlXPathNewFloat(0.0));
4963 if (val->type == XPATH_NUMBER)
4964 return(val);
4965 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
4966 xmlXPathFreeObject(val);
4967 return(ret);
4968}
4969
4970/**
4971 * xmlXPathCastNumberToBoolean:
4972 * @val: a number
4973 *
4974 * Converts a number to its boolean value
4975 *
4976 * Returns the boolean value
4977 */
4978int
4979xmlXPathCastNumberToBoolean (double val) {
4980 if (xmlXPathIsNaN(val) || (val == 0.0))
4981 return(0);
4982 return(1);
4983}
4984
4985/**
4986 * xmlXPathCastStringToBoolean:
4987 * @val: a string
4988 *
4989 * Converts a string to its boolean value
4990 *
4991 * Returns the boolean value
4992 */
4993int
4994xmlXPathCastStringToBoolean (const xmlChar *val) {
4995 if ((val == NULL) || (xmlStrlen(val) == 0))
4996 return(0);
4997 return(1);
4998}
4999
5000/**
5001 * xmlXPathCastNodeSetToBoolean:
5002 * @ns: a node-set
5003 *
5004 * Converts a node-set to its boolean value
5005 *
5006 * Returns the boolean value
5007 */
5008int
5009xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5010 if ((ns == NULL) || (ns->nodeNr == 0))
5011 return(0);
5012 return(1);
5013}
5014
5015/**
5016 * xmlXPathCastToBoolean:
5017 * @val: an XPath object
5018 *
5019 * Converts an XPath object to its boolean value
5020 *
5021 * Returns the boolean value
5022 */
5023int
5024xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5025 int ret = 0;
5026
5027 if (val == NULL)
5028 return(0);
5029 switch (val->type) {
5030 case XPATH_UNDEFINED:
5031 ret = 0;
5032 break;
5033 case XPATH_NODESET:
5034 case XPATH_XSLT_TREE:
5035 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5036 break;
5037 case XPATH_STRING:
5038 ret = xmlXPathCastStringToBoolean(val->stringval);
5039 break;
5040 case XPATH_NUMBER:
5041 ret = xmlXPathCastNumberToBoolean(val->floatval);
5042 break;
5043 case XPATH_BOOLEAN:
5044 ret = val->boolval;
5045 break;
5046 case XPATH_USERS:
5047#ifdef LIBXML_XPTR_LOCS_ENABLED
5048 case XPATH_POINT:
5049 case XPATH_RANGE:
5050 case XPATH_LOCATIONSET:
5051#endif /* LIBXML_XPTR_LOCS_ENABLED */
5052 /* TODO */
5053 ret = 0;
5054 break;
5055 }
5056 return(ret);
5057}
5058
5059
5060/**
5061 * xmlXPathConvertBoolean:
5062 * @val: an XPath object
5063 *
5064 * Converts an existing object to its boolean() equivalent
5065 *
5066 * Returns the new object, the old one is freed (or the operation
5067 * is done directly on @val)
5068 */
5069xmlXPathObjectPtr
5070xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5071 xmlXPathObjectPtr ret;
5072
5073 if (val == NULL)
5074 return(xmlXPathNewBoolean(0));
5075 if (val->type == XPATH_BOOLEAN)
5076 return(val);
5077 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5078 xmlXPathFreeObject(val);
5079 return(ret);
5080}
5081
5082/************************************************************************
5083 * *
5084 * Routines to handle XPath contexts *
5085 * *
5086 ************************************************************************/
5087
5088/**
5089 * xmlXPathNewContext:
5090 * @doc: the XML document
5091 *
5092 * Create a new xmlXPathContext
5093 *
5094 * Returns the xmlXPathContext just allocated. The caller will need to free it.
5095 */
5096xmlXPathContextPtr
5097xmlXPathNewContext(xmlDocPtr doc) {
5098 xmlXPathContextPtr ret;
5099
5100 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5101 if (ret == NULL)
5102 return(NULL);
5103 memset(ret, 0 , sizeof(xmlXPathContext));
5104 ret->doc = doc;
5105 ret->node = NULL;
5106
5107 ret->varHash = NULL;
5108
5109 ret->nb_types = 0;
5110 ret->max_types = 0;
5111 ret->types = NULL;
5112
5113 ret->nb_axis = 0;
5114 ret->max_axis = 0;
5115 ret->axis = NULL;
5116
5117 ret->nsHash = NULL;
5118 ret->user = NULL;
5119
5120 ret->contextSize = -1;
5121 ret->proximityPosition = -1;
5122
5123#ifdef XP_DEFAULT_CACHE_ON
5124 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
5125 xmlXPathFreeContext(ret);
5126 return(NULL);
5127 }
5128#endif
5129
5130 xmlXPathRegisterAllFunctions(ret);
5131
5132 if (ret->lastError.code != XML_ERR_OK) {
5133 xmlXPathFreeContext(ret);
5134 return(NULL);
5135 }
5136
5137 return(ret);
5138}
5139
5140/**
5141 * xmlXPathFreeContext:
5142 * @ctxt: the context to free
5143 *
5144 * Free up an xmlXPathContext
5145 */
5146void
5147xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
5148 if (ctxt == NULL) return;
5149
5150 if (ctxt->cache != NULL)
5151 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
5152 xmlXPathRegisteredNsCleanup(ctxt);
5153 xmlXPathRegisteredFuncsCleanup(ctxt);
5154 xmlXPathRegisteredVariablesCleanup(ctxt);
5155 xmlResetError(&ctxt->lastError);
5156 xmlFree(ctxt);
5157}
5158
5159/**
5160 * xmlXPathSetErrorHandler:
5161 * @ctxt: the XPath context
5162 * @handler: error handler
5163 * @data: user data which will be passed to the handler
5164 *
5165 * Register a callback function that will be called on errors and
5166 * warnings. If handler is NULL, the error handler will be deactivated.
5167 *
5168 * Available since 2.13.0.
5169 */
5170void
5171xmlXPathSetErrorHandler(xmlXPathContextPtr ctxt,
5172 xmlStructuredErrorFunc handler, void *data) {
5173 if (ctxt == NULL)
5174 return;
5175
5176 ctxt->error = handler;
5177 ctxt->userData = data;
5178}
5179
5180/************************************************************************
5181 * *
5182 * Routines to handle XPath parser contexts *
5183 * *
5184 ************************************************************************/
5185
5186/**
5187 * xmlXPathNewParserContext:
5188 * @str: the XPath expression
5189 * @ctxt: the XPath context
5190 *
5191 * Create a new xmlXPathParserContext
5192 *
5193 * Returns the xmlXPathParserContext just allocated.
5194 */
5195xmlXPathParserContextPtr
5196xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
5197 xmlXPathParserContextPtr ret;
5198
5199 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5200 if (ret == NULL) {
5201 xmlXPathErrMemory(ctxt);
5202 return(NULL);
5203 }
5204 memset(ret, 0 , sizeof(xmlXPathParserContext));
5205 ret->cur = ret->base = str;
5206 ret->context = ctxt;
5207
5208 ret->comp = xmlXPathNewCompExpr();
5209 if (ret->comp == NULL) {
5210 xmlXPathErrMemory(ctxt);
5211 xmlFree(ret->valueTab);
5212 xmlFree(ret);
5213 return(NULL);
5214 }
5215 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
5216 ret->comp->dict = ctxt->dict;
5217 xmlDictReference(ret->comp->dict);
5218 }
5219
5220 return(ret);
5221}
5222
5223/**
5224 * xmlXPathCompParserContext:
5225 * @comp: the XPath compiled expression
5226 * @ctxt: the XPath context
5227 *
5228 * Create a new xmlXPathParserContext when processing a compiled expression
5229 *
5230 * Returns the xmlXPathParserContext just allocated.
5231 */
5232static xmlXPathParserContextPtr
5233xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
5234 xmlXPathParserContextPtr ret;
5235
5236 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5237 if (ret == NULL) {
5238 xmlXPathErrMemory(ctxt);
5239 return(NULL);
5240 }
5241 memset(ret, 0 , sizeof(xmlXPathParserContext));
5242
5243 /* Allocate the value stack */
5244 ret->valueTab = (xmlXPathObjectPtr *)
5245 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
5246 if (ret->valueTab == NULL) {
5247 xmlFree(ret);
5248 xmlXPathErrMemory(ctxt);
5249 return(NULL);
5250 }
5251 ret->valueNr = 0;
5252 ret->valueMax = 10;
5253 ret->value = NULL;
5254
5255 ret->context = ctxt;
5256 ret->comp = comp;
5257
5258 return(ret);
5259}
5260
5261/**
5262 * xmlXPathFreeParserContext:
5263 * @ctxt: the context to free
5264 *
5265 * Free up an xmlXPathParserContext
5266 */
5267void
5268xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
5269 int i;
5270
5271 if (ctxt->valueTab != NULL) {
5272 for (i = 0; i < ctxt->valueNr; i++) {
5273 if (ctxt->context)
5274 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
5275 else
5276 xmlXPathFreeObject(ctxt->valueTab[i]);
5277 }
5278 xmlFree(ctxt->valueTab);
5279 }
5280 if (ctxt->comp != NULL) {
5281#ifdef XPATH_STREAMING
5282 if (ctxt->comp->stream != NULL) {
5283 xmlFreePatternList(ctxt->comp->stream);
5284 ctxt->comp->stream = NULL;
5285 }
5286#endif
5287 xmlXPathFreeCompExpr(ctxt->comp);
5288 }
5289 xmlFree(ctxt);
5290}
5291
5292/************************************************************************
5293 * *
5294 * The implicit core function library *
5295 * *
5296 ************************************************************************/
5297
5298/**
5299 * xmlXPathNodeValHash:
5300 * @node: a node pointer
5301 *
5302 * Function computing the beginning of the string value of the node,
5303 * used to speed up comparisons
5304 *
5305 * Returns an int usable as a hash
5306 */
5307static unsigned int
5308xmlXPathNodeValHash(xmlNodePtr node) {
5309 int len = 2;
5310 const xmlChar * string = NULL;
5311 xmlNodePtr tmp = NULL;
5312 unsigned int ret = 0;
5313
5314 if (node == NULL)
5315 return(0);
5316
5317 if (node->type == XML_DOCUMENT_NODE) {
5318 tmp = xmlDocGetRootElement((xmlDocPtr) node);
5319 if (tmp == NULL)
5320 node = node->children;
5321 else
5322 node = tmp;
5323
5324 if (node == NULL)
5325 return(0);
5326 }
5327
5328 switch (node->type) {
5329 case XML_COMMENT_NODE:
5330 case XML_PI_NODE:
5331 case XML_CDATA_SECTION_NODE:
5332 case XML_TEXT_NODE:
5333 string = node->content;
5334 if (string == NULL)
5335 return(0);
5336 if (string[0] == 0)
5337 return(0);
5338 return(string[0] + (string[1] << 8));
5339 case XML_NAMESPACE_DECL:
5340 string = ((xmlNsPtr)node)->href;
5341 if (string == NULL)
5342 return(0);
5343 if (string[0] == 0)
5344 return(0);
5345 return(string[0] + (string[1] << 8));
5346 case XML_ATTRIBUTE_NODE:
5347 tmp = ((xmlAttrPtr) node)->children;
5348 break;
5349 case XML_ELEMENT_NODE:
5350 tmp = node->children;
5351 break;
5352 default:
5353 return(0);
5354 }
5355 while (tmp != NULL) {
5356 switch (tmp->type) {
5357 case XML_CDATA_SECTION_NODE:
5358 case XML_TEXT_NODE:
5359 string = tmp->content;
5360 break;
5361 default:
5362 string = NULL;
5363 break;
5364 }
5365 if ((string != NULL) && (string[0] != 0)) {
5366 if (len == 1) {
5367 return(ret + (string[0] << 8));
5368 }
5369 if (string[1] == 0) {
5370 len = 1;
5371 ret = string[0];
5372 } else {
5373 return(string[0] + (string[1] << 8));
5374 }
5375 }
5376 /*
5377 * Skip to next node
5378 */
5379 if ((tmp->children != NULL) &&
5380 (tmp->type != XML_DTD_NODE) &&
5381 (tmp->type != XML_ENTITY_REF_NODE) &&
5382 (tmp->children->type != XML_ENTITY_DECL)) {
5383 tmp = tmp->children;
5384 continue;
5385 }
5386 if (tmp == node)
5387 break;
5388
5389 if (tmp->next != NULL) {
5390 tmp = tmp->next;
5391 continue;
5392 }
5393
5394 do {
5395 tmp = tmp->parent;
5396 if (tmp == NULL)
5397 break;
5398 if (tmp == node) {
5399 tmp = NULL;
5400 break;
5401 }
5402 if (tmp->next != NULL) {
5403 tmp = tmp->next;
5404 break;
5405 }
5406 } while (tmp != NULL);
5407 }
5408 return(ret);
5409}
5410
5411/**
5412 * xmlXPathStringHash:
5413 * @string: a string
5414 *
5415 * Function computing the beginning of the string value of the node,
5416 * used to speed up comparisons
5417 *
5418 * Returns an int usable as a hash
5419 */
5420static unsigned int
5421xmlXPathStringHash(const xmlChar * string) {
5422 if (string == NULL)
5423 return(0);
5424 if (string[0] == 0)
5425 return(0);
5426 return(string[0] + (string[1] << 8));
5427}
5428
5429/**
5430 * xmlXPathCompareNodeSetFloat:
5431 * @ctxt: the XPath Parser context
5432 * @inf: less than (1) or greater than (0)
5433 * @strict: is the comparison strict
5434 * @arg: the node set
5435 * @f: the value
5436 *
5437 * Implement the compare operation between a nodeset and a number
5438 * @ns < @val (1, 1, ...
5439 * @ns <= @val (1, 0, ...
5440 * @ns > @val (0, 1, ...
5441 * @ns >= @val (0, 0, ...
5442 *
5443 * If one object to be compared is a node-set and the other is a number,
5444 * then the comparison will be true if and only if there is a node in the
5445 * node-set such that the result of performing the comparison on the number
5446 * to be compared and on the result of converting the string-value of that
5447 * node to a number using the number function is true.
5448 *
5449 * Returns 0 or 1 depending on the results of the test.
5450 */
5451static int
5452xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
5453 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5454 int i, ret = 0;
5455 xmlNodeSetPtr ns;
5456 xmlChar *str2;
5457
5458 if ((f == NULL) || (arg == NULL) ||
5459 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5460 xmlXPathReleaseObject(ctxt->context, arg);
5461 xmlXPathReleaseObject(ctxt->context, f);
5462 return(0);
5463 }
5464 ns = arg->nodesetval;
5465 if (ns != NULL) {
5466 for (i = 0;i < ns->nodeNr;i++) {
5467 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5468 if (str2 != NULL) {
5469 valuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5470 xmlFree(str2);
5471 xmlXPathNumberFunction(ctxt, 1);
5472 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, f));
5473 ret = xmlXPathCompareValues(ctxt, inf, strict);
5474 if (ret)
5475 break;
5476 } else {
5477 xmlXPathPErrMemory(ctxt);
5478 }
5479 }
5480 }
5481 xmlXPathReleaseObject(ctxt->context, arg);
5482 xmlXPathReleaseObject(ctxt->context, f);
5483 return(ret);
5484}
5485
5486/**
5487 * xmlXPathCompareNodeSetString:
5488 * @ctxt: the XPath Parser context
5489 * @inf: less than (1) or greater than (0)
5490 * @strict: is the comparison strict
5491 * @arg: the node set
5492 * @s: the value
5493 *
5494 * Implement the compare operation between a nodeset and a string
5495 * @ns < @val (1, 1, ...
5496 * @ns <= @val (1, 0, ...
5497 * @ns > @val (0, 1, ...
5498 * @ns >= @val (0, 0, ...
5499 *
5500 * If one object to be compared is a node-set and the other is a string,
5501 * then the comparison will be true if and only if there is a node in
5502 * the node-set such that the result of performing the comparison on the
5503 * string-value of the node and the other string is true.
5504 *
5505 * Returns 0 or 1 depending on the results of the test.
5506 */
5507static int
5508xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
5509 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5510 int i, ret = 0;
5511 xmlNodeSetPtr ns;
5512 xmlChar *str2;
5513
5514 if ((s == NULL) || (arg == NULL) ||
5515 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5516 xmlXPathReleaseObject(ctxt->context, arg);
5517 xmlXPathReleaseObject(ctxt->context, s);
5518 return(0);
5519 }
5520 ns = arg->nodesetval;
5521 if (ns != NULL) {
5522 for (i = 0;i < ns->nodeNr;i++) {
5523 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5524 if (str2 != NULL) {
5525 valuePush(ctxt,
5526 xmlXPathCacheNewString(ctxt, str2));
5527 xmlFree(str2);
5528 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, s));
5529 ret = xmlXPathCompareValues(ctxt, inf, strict);
5530 if (ret)
5531 break;
5532 } else {
5533 xmlXPathPErrMemory(ctxt);
5534 }
5535 }
5536 }
5537 xmlXPathReleaseObject(ctxt->context, arg);
5538 xmlXPathReleaseObject(ctxt->context, s);
5539 return(ret);
5540}
5541
5542/**
5543 * xmlXPathCompareNodeSets:
5544 * @inf: less than (1) or greater than (0)
5545 * @strict: is the comparison strict
5546 * @arg1: the first node set object
5547 * @arg2: the second node set object
5548 *
5549 * Implement the compare operation on nodesets:
5550 *
5551 * If both objects to be compared are node-sets, then the comparison
5552 * will be true if and only if there is a node in the first node-set
5553 * and a node in the second node-set such that the result of performing
5554 * the comparison on the string-values of the two nodes is true.
5555 * ....
5556 * When neither object to be compared is a node-set and the operator
5557 * is <=, <, >= or >, then the objects are compared by converting both
5558 * objects to numbers and comparing the numbers according to IEEE 754.
5559 * ....
5560 * The number function converts its argument to a number as follows:
5561 * - a string that consists of optional whitespace followed by an
5562 * optional minus sign followed by a Number followed by whitespace
5563 * is converted to the IEEE 754 number that is nearest (according
5564 * to the IEEE 754 round-to-nearest rule) to the mathematical value
5565 * represented by the string; any other string is converted to NaN
5566 *
5567 * Conclusion all nodes need to be converted first to their string value
5568 * and then the comparison must be done when possible
5569 */
5570static int
5571xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt, int inf, int strict,
5572 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5573 int i, j, init = 0;
5574 double val1;
5575 double *values2;
5576 int ret = 0;
5577 xmlNodeSetPtr ns1;
5578 xmlNodeSetPtr ns2;
5579
5580 if ((arg1 == NULL) ||
5581 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5582 xmlXPathFreeObject(arg2);
5583 return(0);
5584 }
5585 if ((arg2 == NULL) ||
5586 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
5587 xmlXPathFreeObject(arg1);
5588 xmlXPathFreeObject(arg2);
5589 return(0);
5590 }
5591
5592 ns1 = arg1->nodesetval;
5593 ns2 = arg2->nodesetval;
5594
5595 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5596 xmlXPathFreeObject(arg1);
5597 xmlXPathFreeObject(arg2);
5598 return(0);
5599 }
5600 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5601 xmlXPathFreeObject(arg1);
5602 xmlXPathFreeObject(arg2);
5603 return(0);
5604 }
5605
5606 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5607 if (values2 == NULL) {
5608 xmlXPathPErrMemory(ctxt);
5609 xmlXPathFreeObject(arg1);
5610 xmlXPathFreeObject(arg2);
5611 return(0);
5612 }
5613 for (i = 0;i < ns1->nodeNr;i++) {
5614 val1 = xmlXPathNodeToNumberInternal(ctxt, ns1->nodeTab[i]);
5615 if (xmlXPathIsNaN(val1))
5616 continue;
5617 for (j = 0;j < ns2->nodeNr;j++) {
5618 if (init == 0) {
5619 values2[j] = xmlXPathNodeToNumberInternal(ctxt,
5620 ns2->nodeTab[j]);
5621 }
5622 if (xmlXPathIsNaN(values2[j]))
5623 continue;
5624 if (inf && strict)
5625 ret = (val1 < values2[j]);
5626 else if (inf && !strict)
5627 ret = (val1 <= values2[j]);
5628 else if (!inf && strict)
5629 ret = (val1 > values2[j]);
5630 else if (!inf && !strict)
5631 ret = (val1 >= values2[j]);
5632 if (ret)
5633 break;
5634 }
5635 if (ret)
5636 break;
5637 init = 1;
5638 }
5639 xmlFree(values2);
5640 xmlXPathFreeObject(arg1);
5641 xmlXPathFreeObject(arg2);
5642 return(ret);
5643}
5644
5645/**
5646 * xmlXPathCompareNodeSetValue:
5647 * @ctxt: the XPath Parser context
5648 * @inf: less than (1) or greater than (0)
5649 * @strict: is the comparison strict
5650 * @arg: the node set
5651 * @val: the value
5652 *
5653 * Implement the compare operation between a nodeset and a value
5654 * @ns < @val (1, 1, ...
5655 * @ns <= @val (1, 0, ...
5656 * @ns > @val (0, 1, ...
5657 * @ns >= @val (0, 0, ...
5658 *
5659 * If one object to be compared is a node-set and the other is a boolean,
5660 * then the comparison will be true if and only if the result of performing
5661 * the comparison on the boolean and on the result of converting
5662 * the node-set to a boolean using the boolean function is true.
5663 *
5664 * Returns 0 or 1 depending on the results of the test.
5665 */
5666static int
5667xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
5668 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
5669 if ((val == NULL) || (arg == NULL) ||
5670 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5671 return(0);
5672
5673 switch(val->type) {
5674 case XPATH_NUMBER:
5675 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
5676 case XPATH_NODESET:
5677 case XPATH_XSLT_TREE:
5678 return(xmlXPathCompareNodeSets(ctxt, inf, strict, arg, val));
5679 case XPATH_STRING:
5680 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
5681 case XPATH_BOOLEAN:
5682 valuePush(ctxt, arg);
5683 xmlXPathBooleanFunction(ctxt, 1);
5684 valuePush(ctxt, val);
5685 return(xmlXPathCompareValues(ctxt, inf, strict));
5686 default:
5687 xmlXPathReleaseObject(ctxt->context, arg);
5688 xmlXPathReleaseObject(ctxt->context, val);
5689 XP_ERROR0(XPATH_INVALID_TYPE);
5690 }
5691 return(0);
5692}
5693
5694/**
5695 * xmlXPathEqualNodeSetString:
5696 * @arg: the nodeset object argument
5697 * @str: the string to compare to.
5698 * @neq: flag to show whether for '=' (0) or '!=' (1)
5699 *
5700 * Implement the equal operation on XPath objects content: @arg1 == @arg2
5701 * If one object to be compared is a node-set and the other is a string,
5702 * then the comparison will be true if and only if there is a node in
5703 * the node-set such that the result of performing the comparison on the
5704 * string-value of the node and the other string is true.
5705 *
5706 * Returns 0 or 1 depending on the results of the test.
5707 */
5708static int
5709xmlXPathEqualNodeSetString(xmlXPathParserContextPtr ctxt,
5710 xmlXPathObjectPtr arg, const xmlChar * str, int neq)
5711{
5712 int i;
5713 xmlNodeSetPtr ns;
5714 xmlChar *str2;
5715 unsigned int hash;
5716
5717 if ((str == NULL) || (arg == NULL) ||
5718 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5719 return (0);
5720 ns = arg->nodesetval;
5721 /*
5722 * A NULL nodeset compared with a string is always false
5723 * (since there is no node equal, and no node not equal)
5724 */
5725 if ((ns == NULL) || (ns->nodeNr <= 0) )
5726 return (0);
5727 hash = xmlXPathStringHash(str);
5728 for (i = 0; i < ns->nodeNr; i++) {
5729 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
5730 str2 = xmlNodeGetContent(ns->nodeTab[i]);
5731 if (str2 == NULL) {
5732 xmlXPathPErrMemory(ctxt);
5733 return(0);
5734 }
5735 if (xmlStrEqual(str, str2)) {
5736 xmlFree(str2);
5737 if (neq)
5738 continue;
5739 return (1);
5740 } else if (neq) {
5741 xmlFree(str2);
5742 return (1);
5743 }
5744 xmlFree(str2);
5745 } else if (neq)
5746 return (1);
5747 }
5748 return (0);
5749}
5750
5751/**
5752 * xmlXPathEqualNodeSetFloat:
5753 * @arg: the nodeset object argument
5754 * @f: the float to compare to
5755 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
5756 *
5757 * Implement the equal operation on XPath objects content: @arg1 == @arg2
5758 * If one object to be compared is a node-set and the other is a number,
5759 * then the comparison will be true if and only if there is a node in
5760 * the node-set such that the result of performing the comparison on the
5761 * number to be compared and on the result of converting the string-value
5762 * of that node to a number using the number function is true.
5763 *
5764 * Returns 0 or 1 depending on the results of the test.
5765 */
5766static int
5767xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
5768 xmlXPathObjectPtr arg, double f, int neq) {
5769 int i, ret=0;
5770 xmlNodeSetPtr ns;
5771 xmlChar *str2;
5772 xmlXPathObjectPtr val;
5773 double v;
5774
5775 if ((arg == NULL) ||
5776 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5777 return(0);
5778
5779 ns = arg->nodesetval;
5780 if (ns != NULL) {
5781 for (i=0;i<ns->nodeNr;i++) {
5782 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5783 if (str2 != NULL) {
5784 valuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5785 xmlFree(str2);
5786 xmlXPathNumberFunction(ctxt, 1);
5787 CHECK_ERROR0;
5788 val = valuePop(ctxt);
5789 v = val->floatval;
5790 xmlXPathReleaseObject(ctxt->context, val);
5791 if (!xmlXPathIsNaN(v)) {
5792 if ((!neq) && (v==f)) {
5793 ret = 1;
5794 break;
5795 } else if ((neq) && (v!=f)) {
5796 ret = 1;
5797 break;
5798 }
5799 } else { /* NaN is unequal to any value */
5800 if (neq)
5801 ret = 1;
5802 }
5803 } else {
5804 xmlXPathPErrMemory(ctxt);
5805 }
5806 }
5807 }
5808
5809 return(ret);
5810}
5811
5812
5813/**
5814 * xmlXPathEqualNodeSets:
5815 * @arg1: first nodeset object argument
5816 * @arg2: second nodeset object argument
5817 * @neq: flag to show whether to test '=' (0) or '!=' (1)
5818 *
5819 * Implement the equal / not equal operation on XPath nodesets:
5820 * @arg1 == @arg2 or @arg1 != @arg2
5821 * If both objects to be compared are node-sets, then the comparison
5822 * will be true if and only if there is a node in the first node-set and
5823 * a node in the second node-set such that the result of performing the
5824 * comparison on the string-values of the two nodes is true.
5825 *
5826 * (needless to say, this is a costly operation)
5827 *
5828 * Returns 0 or 1 depending on the results of the test.
5829 */
5830static int
5831xmlXPathEqualNodeSets(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr arg1,
5832 xmlXPathObjectPtr arg2, int neq) {
5833 int i, j;
5834 unsigned int *hashs1;
5835 unsigned int *hashs2;
5836 xmlChar **values1;
5837 xmlChar **values2;
5838 int ret = 0;
5839 xmlNodeSetPtr ns1;
5840 xmlNodeSetPtr ns2;
5841
5842 if ((arg1 == NULL) ||
5843 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
5844 return(0);
5845 if ((arg2 == NULL) ||
5846 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
5847 return(0);
5848
5849 ns1 = arg1->nodesetval;
5850 ns2 = arg2->nodesetval;
5851
5852 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
5853 return(0);
5854 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
5855 return(0);
5856
5857 /*
5858 * for equal, check if there is a node pertaining to both sets
5859 */
5860 if (neq == 0)
5861 for (i = 0;i < ns1->nodeNr;i++)
5862 for (j = 0;j < ns2->nodeNr;j++)
5863 if (ns1->nodeTab[i] == ns2->nodeTab[j])
5864 return(1);
5865
5866 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
5867 if (values1 == NULL) {
5868 xmlXPathPErrMemory(ctxt);
5869 return(0);
5870 }
5871 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
5872 if (hashs1 == NULL) {
5873 xmlXPathPErrMemory(ctxt);
5874 xmlFree(values1);
5875 return(0);
5876 }
5877 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
5878 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
5879 if (values2 == NULL) {
5880 xmlXPathPErrMemory(ctxt);
5881 xmlFree(hashs1);
5882 xmlFree(values1);
5883 return(0);
5884 }
5885 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
5886 if (hashs2 == NULL) {
5887 xmlXPathPErrMemory(ctxt);
5888 xmlFree(hashs1);
5889 xmlFree(values1);
5890 xmlFree(values2);
5891 return(0);
5892 }
5893 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
5894 for (i = 0;i < ns1->nodeNr;i++) {
5895 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
5896 for (j = 0;j < ns2->nodeNr;j++) {
5897 if (i == 0)
5898 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
5899 if (hashs1[i] != hashs2[j]) {
5900 if (neq) {
5901 ret = 1;
5902 break;
5903 }
5904 }
5905 else {
5906 if (values1[i] == NULL) {
5907 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
5908 if (values1[i] == NULL)
5909 xmlXPathPErrMemory(ctxt);
5910 }
5911 if (values2[j] == NULL) {
5912 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
5913 if (values2[j] == NULL)
5914 xmlXPathPErrMemory(ctxt);
5915 }
5916 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
5917 if (ret)
5918 break;
5919 }
5920 }
5921 if (ret)
5922 break;
5923 }
5924 for (i = 0;i < ns1->nodeNr;i++)
5925 if (values1[i] != NULL)
5926 xmlFree(values1[i]);
5927 for (j = 0;j < ns2->nodeNr;j++)
5928 if (values2[j] != NULL)
5929 xmlFree(values2[j]);
5930 xmlFree(values1);
5931 xmlFree(values2);
5932 xmlFree(hashs1);
5933 xmlFree(hashs2);
5934 return(ret);
5935}
5936
5937static int
5938xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
5939 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5940 int ret = 0;
5941 /*
5942 *At this point we are assured neither arg1 nor arg2
5943 *is a nodeset, so we can just pick the appropriate routine.
5944 */
5945 switch (arg1->type) {
5946 case XPATH_UNDEFINED:
5947 break;
5948 case XPATH_BOOLEAN:
5949 switch (arg2->type) {
5950 case XPATH_UNDEFINED:
5951 break;
5952 case XPATH_BOOLEAN:
5953 ret = (arg1->boolval == arg2->boolval);
5954 break;
5955 case XPATH_NUMBER:
5956 ret = (arg1->boolval ==
5957 xmlXPathCastNumberToBoolean(arg2->floatval));
5958 break;
5959 case XPATH_STRING:
5960 if ((arg2->stringval == NULL) ||
5961 (arg2->stringval[0] == 0)) ret = 0;
5962 else
5963 ret = 1;
5964 ret = (arg1->boolval == ret);
5965 break;
5966 case XPATH_USERS:
5967#ifdef LIBXML_XPTR_LOCS_ENABLED
5968 case XPATH_POINT:
5969 case XPATH_RANGE:
5970 case XPATH_LOCATIONSET:
5971#endif /* LIBXML_XPTR_LOCS_ENABLED */
5972 /* TODO */
5973 break;
5974 case XPATH_NODESET:
5975 case XPATH_XSLT_TREE:
5976 break;
5977 }
5978 break;
5979 case XPATH_NUMBER:
5980 switch (arg2->type) {
5981 case XPATH_UNDEFINED:
5982 break;
5983 case XPATH_BOOLEAN:
5984 ret = (arg2->boolval==
5985 xmlXPathCastNumberToBoolean(arg1->floatval));
5986 break;
5987 case XPATH_STRING:
5988 valuePush(ctxt, arg2);
5989 xmlXPathNumberFunction(ctxt, 1);
5990 arg2 = valuePop(ctxt);
5991 if (ctxt->error)
5992 break;
5993 /* Falls through. */
5994 case XPATH_NUMBER:
5995 /* Hand check NaN and Infinity equalities */
5996 if (xmlXPathIsNaN(arg1->floatval) ||
5997 xmlXPathIsNaN(arg2->floatval)) {
5998 ret = 0;
5999 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6000 if (xmlXPathIsInf(arg2->floatval) == 1)
6001 ret = 1;
6002 else
6003 ret = 0;
6004 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6005 if (xmlXPathIsInf(arg2->floatval) == -1)
6006 ret = 1;
6007 else
6008 ret = 0;
6009 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6010 if (xmlXPathIsInf(arg1->floatval) == 1)
6011 ret = 1;
6012 else
6013 ret = 0;
6014 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6015 if (xmlXPathIsInf(arg1->floatval) == -1)
6016 ret = 1;
6017 else
6018 ret = 0;
6019 } else {
6020 ret = (arg1->floatval == arg2->floatval);
6021 }
6022 break;
6023 case XPATH_USERS:
6024#ifdef LIBXML_XPTR_LOCS_ENABLED
6025 case XPATH_POINT:
6026 case XPATH_RANGE:
6027 case XPATH_LOCATIONSET:
6028#endif /* LIBXML_XPTR_LOCS_ENABLED */
6029 /* TODO */
6030 break;
6031 case XPATH_NODESET:
6032 case XPATH_XSLT_TREE:
6033 break;
6034 }
6035 break;
6036 case XPATH_STRING:
6037 switch (arg2->type) {
6038 case XPATH_UNDEFINED:
6039 break;
6040 case XPATH_BOOLEAN:
6041 if ((arg1->stringval == NULL) ||
6042 (arg1->stringval[0] == 0)) ret = 0;
6043 else
6044 ret = 1;
6045 ret = (arg2->boolval == ret);
6046 break;
6047 case XPATH_STRING:
6048 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6049 break;
6050 case XPATH_NUMBER:
6051 valuePush(ctxt, arg1);
6052 xmlXPathNumberFunction(ctxt, 1);
6053 arg1 = valuePop(ctxt);
6054 if (ctxt->error)
6055 break;
6056 /* Hand check NaN and Infinity equalities */
6057 if (xmlXPathIsNaN(arg1->floatval) ||
6058 xmlXPathIsNaN(arg2->floatval)) {
6059 ret = 0;
6060 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6061 if (xmlXPathIsInf(arg2->floatval) == 1)
6062 ret = 1;
6063 else
6064 ret = 0;
6065 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6066 if (xmlXPathIsInf(arg2->floatval) == -1)
6067 ret = 1;
6068 else
6069 ret = 0;
6070 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6071 if (xmlXPathIsInf(arg1->floatval) == 1)
6072 ret = 1;
6073 else
6074 ret = 0;
6075 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6076 if (xmlXPathIsInf(arg1->floatval) == -1)
6077 ret = 1;
6078 else
6079 ret = 0;
6080 } else {
6081 ret = (arg1->floatval == arg2->floatval);
6082 }
6083 break;
6084 case XPATH_USERS:
6085#ifdef LIBXML_XPTR_LOCS_ENABLED
6086 case XPATH_POINT:
6087 case XPATH_RANGE:
6088 case XPATH_LOCATIONSET:
6089#endif /* LIBXML_XPTR_LOCS_ENABLED */
6090 /* TODO */
6091 break;
6092 case XPATH_NODESET:
6093 case XPATH_XSLT_TREE:
6094 break;
6095 }
6096 break;
6097 case XPATH_USERS:
6098#ifdef LIBXML_XPTR_LOCS_ENABLED
6099 case XPATH_POINT:
6100 case XPATH_RANGE:
6101 case XPATH_LOCATIONSET:
6102#endif /* LIBXML_XPTR_LOCS_ENABLED */
6103 /* TODO */
6104 break;
6105 case XPATH_NODESET:
6106 case XPATH_XSLT_TREE:
6107 break;
6108 }
6109 xmlXPathReleaseObject(ctxt->context, arg1);
6110 xmlXPathReleaseObject(ctxt->context, arg2);
6111 return(ret);
6112}
6113
6114/**
6115 * xmlXPathEqualValues:
6116 * @ctxt: the XPath Parser context
6117 *
6118 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6119 *
6120 * Returns 0 or 1 depending on the results of the test.
6121 */
6122int
6123xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
6124 xmlXPathObjectPtr arg1, arg2, argtmp;
6125 int ret = 0;
6126
6127 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6128 arg2 = valuePop(ctxt);
6129 arg1 = valuePop(ctxt);
6130 if ((arg1 == NULL) || (arg2 == NULL)) {
6131 if (arg1 != NULL)
6132 xmlXPathReleaseObject(ctxt->context, arg1);
6133 else
6134 xmlXPathReleaseObject(ctxt->context, arg2);
6135 XP_ERROR0(XPATH_INVALID_OPERAND);
6136 }
6137
6138 if (arg1 == arg2) {
6139 xmlXPathFreeObject(arg1);
6140 return(1);
6141 }
6142
6143 /*
6144 *If either argument is a nodeset, it's a 'special case'
6145 */
6146 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6147 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6148 /*
6149 *Hack it to assure arg1 is the nodeset
6150 */
6151 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6152 argtmp = arg2;
6153 arg2 = arg1;
6154 arg1 = argtmp;
6155 }
6156 switch (arg2->type) {
6157 case XPATH_UNDEFINED:
6158 break;
6159 case XPATH_NODESET:
6160 case XPATH_XSLT_TREE:
6161 ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 0);
6162 break;
6163 case XPATH_BOOLEAN:
6164 if ((arg1->nodesetval == NULL) ||
6165 (arg1->nodesetval->nodeNr == 0)) ret = 0;
6166 else
6167 ret = 1;
6168 ret = (ret == arg2->boolval);
6169 break;
6170 case XPATH_NUMBER:
6171 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
6172 break;
6173 case XPATH_STRING:
6174 ret = xmlXPathEqualNodeSetString(ctxt, arg1,
6175 arg2->stringval, 0);
6176 break;
6177 case XPATH_USERS:
6178#ifdef LIBXML_XPTR_LOCS_ENABLED
6179 case XPATH_POINT:
6180 case XPATH_RANGE:
6181 case XPATH_LOCATIONSET:
6182#endif /* LIBXML_XPTR_LOCS_ENABLED */
6183 /* TODO */
6184 break;
6185 }
6186 xmlXPathReleaseObject(ctxt->context, arg1);
6187 xmlXPathReleaseObject(ctxt->context, arg2);
6188 return(ret);
6189 }
6190
6191 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6192}
6193
6194/**
6195 * xmlXPathNotEqualValues:
6196 * @ctxt: the XPath Parser context
6197 *
6198 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6199 *
6200 * Returns 0 or 1 depending on the results of the test.
6201 */
6202int
6203xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
6204 xmlXPathObjectPtr arg1, arg2, argtmp;
6205 int ret = 0;
6206
6207 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6208 arg2 = valuePop(ctxt);
6209 arg1 = valuePop(ctxt);
6210 if ((arg1 == NULL) || (arg2 == NULL)) {
6211 if (arg1 != NULL)
6212 xmlXPathReleaseObject(ctxt->context, arg1);
6213 else
6214 xmlXPathReleaseObject(ctxt->context, arg2);
6215 XP_ERROR0(XPATH_INVALID_OPERAND);
6216 }
6217
6218 if (arg1 == arg2) {
6219 xmlXPathReleaseObject(ctxt->context, arg1);
6220 return(0);
6221 }
6222
6223 /*
6224 *If either argument is a nodeset, it's a 'special case'
6225 */
6226 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6227 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6228 /*
6229 *Hack it to assure arg1 is the nodeset
6230 */
6231 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6232 argtmp = arg2;
6233 arg2 = arg1;
6234 arg1 = argtmp;
6235 }
6236 switch (arg2->type) {
6237 case XPATH_UNDEFINED:
6238 break;
6239 case XPATH_NODESET:
6240 case XPATH_XSLT_TREE:
6241 ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 1);
6242 break;
6243 case XPATH_BOOLEAN:
6244 if ((arg1->nodesetval == NULL) ||
6245 (arg1->nodesetval->nodeNr == 0)) ret = 0;
6246 else
6247 ret = 1;
6248 ret = (ret != arg2->boolval);
6249 break;
6250 case XPATH_NUMBER:
6251 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
6252 break;
6253 case XPATH_STRING:
6254 ret = xmlXPathEqualNodeSetString(ctxt, arg1,
6255 arg2->stringval, 1);
6256 break;
6257 case XPATH_USERS:
6258#ifdef LIBXML_XPTR_LOCS_ENABLED
6259 case XPATH_POINT:
6260 case XPATH_RANGE:
6261 case XPATH_LOCATIONSET:
6262#endif /* LIBXML_XPTR_LOCS_ENABLED */
6263 /* TODO */
6264 break;
6265 }
6266 xmlXPathReleaseObject(ctxt->context, arg1);
6267 xmlXPathReleaseObject(ctxt->context, arg2);
6268 return(ret);
6269 }
6270
6271 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6272}
6273
6274/**
6275 * xmlXPathCompareValues:
6276 * @ctxt: the XPath Parser context
6277 * @inf: less than (1) or greater than (0)
6278 * @strict: is the comparison strict
6279 *
6280 * Implement the compare operation on XPath objects:
6281 * @arg1 < @arg2 (1, 1, ...
6282 * @arg1 <= @arg2 (1, 0, ...
6283 * @arg1 > @arg2 (0, 1, ...
6284 * @arg1 >= @arg2 (0, 0, ...
6285 *
6286 * When neither object to be compared is a node-set and the operator is
6287 * <=, <, >=, >, then the objects are compared by converted both objects
6288 * to numbers and comparing the numbers according to IEEE 754. The <
6289 * comparison will be true if and only if the first number is less than the
6290 * second number. The <= comparison will be true if and only if the first
6291 * number is less than or equal to the second number. The > comparison
6292 * will be true if and only if the first number is greater than the second
6293 * number. The >= comparison will be true if and only if the first number
6294 * is greater than or equal to the second number.
6295 *
6296 * Returns 1 if the comparison succeeded, 0 if it failed
6297 */
6298int
6299xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
6300 int ret = 0, arg1i = 0, arg2i = 0;
6301 xmlXPathObjectPtr arg1, arg2;
6302
6303 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6304 arg2 = valuePop(ctxt);
6305 arg1 = valuePop(ctxt);
6306 if ((arg1 == NULL) || (arg2 == NULL)) {
6307 if (arg1 != NULL)
6308 xmlXPathReleaseObject(ctxt->context, arg1);
6309 else
6310 xmlXPathReleaseObject(ctxt->context, arg2);
6311 XP_ERROR0(XPATH_INVALID_OPERAND);
6312 }
6313
6314 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6315 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6316 /*
6317 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
6318 * are not freed from within this routine; they will be freed from the
6319 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
6320 */
6321 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
6322 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
6323 ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
6324 } else {
6325 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6326 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
6327 arg1, arg2);
6328 } else {
6329 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
6330 arg2, arg1);
6331 }
6332 }
6333 return(ret);
6334 }
6335
6336 if (arg1->type != XPATH_NUMBER) {
6337 valuePush(ctxt, arg1);
6338 xmlXPathNumberFunction(ctxt, 1);
6339 arg1 = valuePop(ctxt);
6340 }
6341 if (arg2->type != XPATH_NUMBER) {
6342 valuePush(ctxt, arg2);
6343 xmlXPathNumberFunction(ctxt, 1);
6344 arg2 = valuePop(ctxt);
6345 }
6346 if (ctxt->error)
6347 goto error;
6348 /*
6349 * Add tests for infinity and nan
6350 * => feedback on 3.4 for Inf and NaN
6351 */
6352 /* Hand check NaN and Infinity comparisons */
6353 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
6354 ret=0;
6355 } else {
6356 arg1i=xmlXPathIsInf(arg1->floatval);
6357 arg2i=xmlXPathIsInf(arg2->floatval);
6358 if (inf && strict) {
6359 if ((arg1i == -1 && arg2i != -1) ||
6360 (arg2i == 1 && arg1i != 1)) {
6361 ret = 1;
6362 } else if (arg1i == 0 && arg2i == 0) {
6363 ret = (arg1->floatval < arg2->floatval);
6364 } else {
6365 ret = 0;
6366 }
6367 }
6368 else if (inf && !strict) {
6369 if (arg1i == -1 || arg2i == 1) {
6370 ret = 1;
6371 } else if (arg1i == 0 && arg2i == 0) {
6372 ret = (arg1->floatval <= arg2->floatval);
6373 } else {
6374 ret = 0;
6375 }
6376 }
6377 else if (!inf && strict) {
6378 if ((arg1i == 1 && arg2i != 1) ||
6379 (arg2i == -1 && arg1i != -1)) {
6380 ret = 1;
6381 } else if (arg1i == 0 && arg2i == 0) {
6382 ret = (arg1->floatval > arg2->floatval);
6383 } else {
6384 ret = 0;
6385 }
6386 }
6387 else if (!inf && !strict) {
6388 if (arg1i == 1 || arg2i == -1) {
6389 ret = 1;
6390 } else if (arg1i == 0 && arg2i == 0) {
6391 ret = (arg1->floatval >= arg2->floatval);
6392 } else {
6393 ret = 0;
6394 }
6395 }
6396 }
6397error:
6398 xmlXPathReleaseObject(ctxt->context, arg1);
6399 xmlXPathReleaseObject(ctxt->context, arg2);
6400 return(ret);
6401}
6402
6403/**
6404 * xmlXPathValueFlipSign:
6405 * @ctxt: the XPath Parser context
6406 *
6407 * Implement the unary - operation on an XPath object
6408 * The numeric operators convert their operands to numbers as if
6409 * by calling the number function.
6410 */
6411void
6412xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
6413 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
6414 CAST_TO_NUMBER;
6415 CHECK_TYPE(XPATH_NUMBER);
6416 ctxt->value->floatval = -ctxt->value->floatval;
6417}
6418
6419/**
6420 * xmlXPathAddValues:
6421 * @ctxt: the XPath Parser context
6422 *
6423 * Implement the add operation on XPath objects:
6424 * The numeric operators convert their operands to numbers as if
6425 * by calling the number function.
6426 */
6427void
6428xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
6429 xmlXPathObjectPtr arg;
6430 double val;
6431
6432 arg = valuePop(ctxt);
6433 if (arg == NULL)
6434 XP_ERROR(XPATH_INVALID_OPERAND);
6435 val = xmlXPathCastToNumberInternal(ctxt, arg);
6436 xmlXPathReleaseObject(ctxt->context, arg);
6437 CAST_TO_NUMBER;
6438 CHECK_TYPE(XPATH_NUMBER);
6439 ctxt->value->floatval += val;
6440}
6441
6442/**
6443 * xmlXPathSubValues:
6444 * @ctxt: the XPath Parser context
6445 *
6446 * Implement the subtraction operation on XPath objects:
6447 * The numeric operators convert their operands to numbers as if
6448 * by calling the number function.
6449 */
6450void
6451xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
6452 xmlXPathObjectPtr arg;
6453 double val;
6454
6455 arg = valuePop(ctxt);
6456 if (arg == NULL)
6457 XP_ERROR(XPATH_INVALID_OPERAND);
6458 val = xmlXPathCastToNumberInternal(ctxt, arg);
6459 xmlXPathReleaseObject(ctxt->context, arg);
6460 CAST_TO_NUMBER;
6461 CHECK_TYPE(XPATH_NUMBER);
6462 ctxt->value->floatval -= val;
6463}
6464
6465/**
6466 * xmlXPathMultValues:
6467 * @ctxt: the XPath Parser context
6468 *
6469 * Implement the multiply operation on XPath objects:
6470 * The numeric operators convert their operands to numbers as if
6471 * by calling the number function.
6472 */
6473void
6474xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
6475 xmlXPathObjectPtr arg;
6476 double val;
6477
6478 arg = valuePop(ctxt);
6479 if (arg == NULL)
6480 XP_ERROR(XPATH_INVALID_OPERAND);
6481 val = xmlXPathCastToNumberInternal(ctxt, arg);
6482 xmlXPathReleaseObject(ctxt->context, arg);
6483 CAST_TO_NUMBER;
6484 CHECK_TYPE(XPATH_NUMBER);
6485 ctxt->value->floatval *= val;
6486}
6487
6488/**
6489 * xmlXPathDivValues:
6490 * @ctxt: the XPath Parser context
6491 *
6492 * Implement the div operation on XPath objects @arg1 / @arg2:
6493 * The numeric operators convert their operands to numbers as if
6494 * by calling the number function.
6495 */
6496ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
6497void
6498xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
6499 xmlXPathObjectPtr arg;
6500 double val;
6501
6502 arg = valuePop(ctxt);
6503 if (arg == NULL)
6504 XP_ERROR(XPATH_INVALID_OPERAND);
6505 val = xmlXPathCastToNumberInternal(ctxt, arg);
6506 xmlXPathReleaseObject(ctxt->context, arg);
6507 CAST_TO_NUMBER;
6508 CHECK_TYPE(XPATH_NUMBER);
6509 ctxt->value->floatval /= val;
6510}
6511
6512/**
6513 * xmlXPathModValues:
6514 * @ctxt: the XPath Parser context
6515 *
6516 * Implement the mod operation on XPath objects: @arg1 / @arg2
6517 * The numeric operators convert their operands to numbers as if
6518 * by calling the number function.
6519 */
6520void
6521xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
6522 xmlXPathObjectPtr arg;
6523 double arg1, arg2;
6524
6525 arg = valuePop(ctxt);
6526 if (arg == NULL)
6527 XP_ERROR(XPATH_INVALID_OPERAND);
6528 arg2 = xmlXPathCastToNumberInternal(ctxt, arg);
6529 xmlXPathReleaseObject(ctxt->context, arg);
6530 CAST_TO_NUMBER;
6531 CHECK_TYPE(XPATH_NUMBER);
6532 arg1 = ctxt->value->floatval;
6533 if (arg2 == 0)
6534 ctxt->value->floatval = xmlXPathNAN;
6535 else {
6536 ctxt->value->floatval = fmod(arg1, arg2);
6537 }
6538}
6539
6540/************************************************************************
6541 * *
6542 * The traversal functions *
6543 * *
6544 ************************************************************************/
6545
6546/*
6547 * A traversal function enumerates nodes along an axis.
6548 * Initially it must be called with NULL, and it indicates
6549 * termination on the axis by returning NULL.
6550 */
6551typedef xmlNodePtr (*xmlXPathTraversalFunction)
6552 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
6553
6554/*
6555 * xmlXPathTraversalFunctionExt:
6556 * A traversal function enumerates nodes along an axis.
6557 * Initially it must be called with NULL, and it indicates
6558 * termination on the axis by returning NULL.
6559 * The context node of the traversal is specified via @contextNode.
6560 */
6561typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
6562 (xmlNodePtr cur, xmlNodePtr contextNode);
6563
6564/*
6565 * xmlXPathNodeSetMergeFunction:
6566 * Used for merging node sets in xmlXPathCollectAndTest().
6567 */
6568typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
6569 (xmlNodeSetPtr, xmlNodeSetPtr);
6570
6571
6572/**
6573 * xmlXPathNextSelf:
6574 * @ctxt: the XPath Parser context
6575 * @cur: the current node in the traversal
6576 *
6577 * Traversal function for the "self" direction
6578 * The self axis contains just the context node itself
6579 *
6580 * Returns the next element following that axis
6581 */
6582xmlNodePtr
6583xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6584 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6585 if (cur == NULL)
6586 return(ctxt->context->node);
6587 return(NULL);
6588}
6589
6590/**
6591 * xmlXPathNextChild:
6592 * @ctxt: the XPath Parser context
6593 * @cur: the current node in the traversal
6594 *
6595 * Traversal function for the "child" direction
6596 * The child axis contains the children of the context node in document order.
6597 *
6598 * Returns the next element following that axis
6599 */
6600xmlNodePtr
6601xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6602 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6603 if (cur == NULL) {
6604 if (ctxt->context->node == NULL) return(NULL);
6605 switch (ctxt->context->node->type) {
6606 case XML_ELEMENT_NODE:
6607 case XML_TEXT_NODE:
6608 case XML_CDATA_SECTION_NODE:
6609 case XML_ENTITY_REF_NODE:
6610 case XML_ENTITY_NODE:
6611 case XML_PI_NODE:
6612 case XML_COMMENT_NODE:
6613 case XML_NOTATION_NODE:
6614 case XML_DTD_NODE:
6615 return(ctxt->context->node->children);
6616 case XML_DOCUMENT_NODE:
6617 case XML_DOCUMENT_TYPE_NODE:
6618 case XML_DOCUMENT_FRAG_NODE:
6619 case XML_HTML_DOCUMENT_NODE:
6620 return(((xmlDocPtr) ctxt->context->node)->children);
6621 case XML_ELEMENT_DECL:
6622 case XML_ATTRIBUTE_DECL:
6623 case XML_ENTITY_DECL:
6624 case XML_ATTRIBUTE_NODE:
6625 case XML_NAMESPACE_DECL:
6626 case XML_XINCLUDE_START:
6627 case XML_XINCLUDE_END:
6628 return(NULL);
6629 }
6630 return(NULL);
6631 }
6632 if ((cur->type == XML_DOCUMENT_NODE) ||
6633 (cur->type == XML_HTML_DOCUMENT_NODE))
6634 return(NULL);
6635 return(cur->next);
6636}
6637
6638/**
6639 * xmlXPathNextChildElement:
6640 * @ctxt: the XPath Parser context
6641 * @cur: the current node in the traversal
6642 *
6643 * Traversal function for the "child" direction and nodes of type element.
6644 * The child axis contains the children of the context node in document order.
6645 *
6646 * Returns the next element following that axis
6647 */
6648static xmlNodePtr
6649xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6650 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6651 if (cur == NULL) {
6652 cur = ctxt->context->node;
6653 if (cur == NULL) return(NULL);
6654 /*
6655 * Get the first element child.
6656 */
6657 switch (cur->type) {
6658 case XML_ELEMENT_NODE:
6659 case XML_DOCUMENT_FRAG_NODE:
6660 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
6661 case XML_ENTITY_NODE:
6662 cur = cur->children;
6663 if (cur != NULL) {
6664 if (cur->type == XML_ELEMENT_NODE)
6665 return(cur);
6666 do {
6667 cur = cur->next;
6668 } while ((cur != NULL) &&
6669 (cur->type != XML_ELEMENT_NODE));
6670 return(cur);
6671 }
6672 return(NULL);
6673 case XML_DOCUMENT_NODE:
6674 case XML_HTML_DOCUMENT_NODE:
6675 return(xmlDocGetRootElement((xmlDocPtr) cur));
6676 default:
6677 return(NULL);
6678 }
6679 return(NULL);
6680 }
6681 /*
6682 * Get the next sibling element node.
6683 */
6684 switch (cur->type) {
6685 case XML_ELEMENT_NODE:
6686 case XML_TEXT_NODE:
6687 case XML_ENTITY_REF_NODE:
6688 case XML_ENTITY_NODE:
6689 case XML_CDATA_SECTION_NODE:
6690 case XML_PI_NODE:
6691 case XML_COMMENT_NODE:
6692 case XML_XINCLUDE_END:
6693 break;
6694 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
6695 default:
6696 return(NULL);
6697 }
6698 if (cur->next != NULL) {
6699 if (cur->next->type == XML_ELEMENT_NODE)
6700 return(cur->next);
6701 cur = cur->next;
6702 do {
6703 cur = cur->next;
6704 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
6705 return(cur);
6706 }
6707 return(NULL);
6708}
6709
6710#if 0
6711/**
6712 * xmlXPathNextDescendantOrSelfElemParent:
6713 * @ctxt: the XPath Parser context
6714 * @cur: the current node in the traversal
6715 *
6716 * Traversal function for the "descendant-or-self" axis.
6717 * Additionally it returns only nodes which can be parents of
6718 * element nodes.
6719 *
6720 *
6721 * Returns the next element following that axis
6722 */
6723static xmlNodePtr
6724xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
6725 xmlNodePtr contextNode)
6726{
6727 if (cur == NULL) {
6728 if (contextNode == NULL)
6729 return(NULL);
6730 switch (contextNode->type) {
6731 case XML_ELEMENT_NODE:
6732 case XML_XINCLUDE_START:
6733 case XML_DOCUMENT_FRAG_NODE:
6734 case XML_DOCUMENT_NODE:
6735 case XML_HTML_DOCUMENT_NODE:
6736 return(contextNode);
6737 default:
6738 return(NULL);
6739 }
6740 return(NULL);
6741 } else {
6742 xmlNodePtr start = cur;
6743
6744 while (cur != NULL) {
6745 switch (cur->type) {
6746 case XML_ELEMENT_NODE:
6747 /* TODO: OK to have XInclude here? */
6748 case XML_XINCLUDE_START:
6749 case XML_DOCUMENT_FRAG_NODE:
6750 if (cur != start)
6751 return(cur);
6752 if (cur->children != NULL) {
6753 cur = cur->children;
6754 continue;
6755 }
6756 break;
6757 /* Not sure if we need those here. */
6758 case XML_DOCUMENT_NODE:
6759 case XML_HTML_DOCUMENT_NODE:
6760 if (cur != start)
6761 return(cur);
6762 return(xmlDocGetRootElement((xmlDocPtr) cur));
6763 default:
6764 break;
6765 }
6766
6767next_sibling:
6768 if ((cur == NULL) || (cur == contextNode))
6769 return(NULL);
6770 if (cur->next != NULL) {
6771 cur = cur->next;
6772 } else {
6773 cur = cur->parent;
6774 goto next_sibling;
6775 }
6776 }
6777 }
6778 return(NULL);
6779}
6780#endif
6781
6782/**
6783 * xmlXPathNextDescendant:
6784 * @ctxt: the XPath Parser context
6785 * @cur: the current node in the traversal
6786 *
6787 * Traversal function for the "descendant" direction
6788 * the descendant axis contains the descendants of the context node in document
6789 * order; a descendant is a child or a child of a child and so on.
6790 *
6791 * Returns the next element following that axis
6792 */
6793xmlNodePtr
6794xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6795 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6796 if (cur == NULL) {
6797 if (ctxt->context->node == NULL)
6798 return(NULL);
6799 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6800 (ctxt->context->node->type == XML_NAMESPACE_DECL))
6801 return(NULL);
6802
6803 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6804 return(ctxt->context->doc->children);
6805 return(ctxt->context->node->children);
6806 }
6807
6808 if (cur->type == XML_NAMESPACE_DECL)
6809 return(NULL);
6810 if (cur->children != NULL) {
6811 /*
6812 * Do not descend on entities declarations
6813 */
6814 if (cur->children->type != XML_ENTITY_DECL) {
6815 cur = cur->children;
6816 /*
6817 * Skip DTDs
6818 */
6819 if (cur->type != XML_DTD_NODE)
6820 return(cur);
6821 }
6822 }
6823
6824 if (cur == ctxt->context->node) return(NULL);
6825
6826 while (cur->next != NULL) {
6827 cur = cur->next;
6828 if ((cur->type != XML_ENTITY_DECL) &&
6829 (cur->type != XML_DTD_NODE))
6830 return(cur);
6831 }
6832
6833 do {
6834 cur = cur->parent;
6835 if (cur == NULL) break;
6836 if (cur == ctxt->context->node) return(NULL);
6837 if (cur->next != NULL) {
6838 cur = cur->next;
6839 return(cur);
6840 }
6841 } while (cur != NULL);
6842 return(cur);
6843}
6844
6845/**
6846 * xmlXPathNextDescendantOrSelf:
6847 * @ctxt: the XPath Parser context
6848 * @cur: the current node in the traversal
6849 *
6850 * Traversal function for the "descendant-or-self" direction
6851 * the descendant-or-self axis contains the context node and the descendants
6852 * of the context node in document order; thus the context node is the first
6853 * node on the axis, and the first child of the context node is the second node
6854 * on the axis
6855 *
6856 * Returns the next element following that axis
6857 */
6858xmlNodePtr
6859xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6860 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6861 if (cur == NULL)
6862 return(ctxt->context->node);
6863
6864 if (ctxt->context->node == NULL)
6865 return(NULL);
6866 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6867 (ctxt->context->node->type == XML_NAMESPACE_DECL))
6868 return(NULL);
6869
6870 return(xmlXPathNextDescendant(ctxt, cur));
6871}
6872
6873/**
6874 * xmlXPathNextParent:
6875 * @ctxt: the XPath Parser context
6876 * @cur: the current node in the traversal
6877 *
6878 * Traversal function for the "parent" direction
6879 * The parent axis contains the parent of the context node, if there is one.
6880 *
6881 * Returns the next element following that axis
6882 */
6883xmlNodePtr
6884xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6885 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6886 /*
6887 * the parent of an attribute or namespace node is the element
6888 * to which the attribute or namespace node is attached
6889 * Namespace handling !!!
6890 */
6891 if (cur == NULL) {
6892 if (ctxt->context->node == NULL) return(NULL);
6893 switch (ctxt->context->node->type) {
6894 case XML_ELEMENT_NODE:
6895 case XML_TEXT_NODE:
6896 case XML_CDATA_SECTION_NODE:
6897 case XML_ENTITY_REF_NODE:
6898 case XML_ENTITY_NODE:
6899 case XML_PI_NODE:
6900 case XML_COMMENT_NODE:
6901 case XML_NOTATION_NODE:
6902 case XML_DTD_NODE:
6903 case XML_ELEMENT_DECL:
6904 case XML_ATTRIBUTE_DECL:
6905 case XML_XINCLUDE_START:
6906 case XML_XINCLUDE_END:
6907 case XML_ENTITY_DECL:
6908 if (ctxt->context->node->parent == NULL)
6909 return((xmlNodePtr) ctxt->context->doc);
6910 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6911 ((ctxt->context->node->parent->name[0] == ' ') ||
6912 (xmlStrEqual(ctxt->context->node->parent->name,
6913 BAD_CAST "fake node libxslt"))))
6914 return(NULL);
6915 return(ctxt->context->node->parent);
6916 case XML_ATTRIBUTE_NODE: {
6917 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
6918
6919 return(att->parent);
6920 }
6921 case XML_DOCUMENT_NODE:
6922 case XML_DOCUMENT_TYPE_NODE:
6923 case XML_DOCUMENT_FRAG_NODE:
6924 case XML_HTML_DOCUMENT_NODE:
6925 return(NULL);
6926 case XML_NAMESPACE_DECL: {
6927 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6928
6929 if ((ns->next != NULL) &&
6930 (ns->next->type != XML_NAMESPACE_DECL))
6931 return((xmlNodePtr) ns->next);
6932 return(NULL);
6933 }
6934 }
6935 }
6936 return(NULL);
6937}
6938
6939/**
6940 * xmlXPathNextAncestor:
6941 * @ctxt: the XPath Parser context
6942 * @cur: the current node in the traversal
6943 *
6944 * Traversal function for the "ancestor" direction
6945 * the ancestor axis contains the ancestors of the context node; the ancestors
6946 * of the context node consist of the parent of context node and the parent's
6947 * parent and so on; the nodes are ordered in reverse document order; thus the
6948 * parent is the first node on the axis, and the parent's parent is the second
6949 * node on the axis
6950 *
6951 * Returns the next element following that axis
6952 */
6953xmlNodePtr
6954xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6955 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6956 /*
6957 * the parent of an attribute or namespace node is the element
6958 * to which the attribute or namespace node is attached
6959 * !!!!!!!!!!!!!
6960 */
6961 if (cur == NULL) {
6962 if (ctxt->context->node == NULL) return(NULL);
6963 switch (ctxt->context->node->type) {
6964 case XML_ELEMENT_NODE:
6965 case XML_TEXT_NODE:
6966 case XML_CDATA_SECTION_NODE:
6967 case XML_ENTITY_REF_NODE:
6968 case XML_ENTITY_NODE:
6969 case XML_PI_NODE:
6970 case XML_COMMENT_NODE:
6971 case XML_DTD_NODE:
6972 case XML_ELEMENT_DECL:
6973 case XML_ATTRIBUTE_DECL:
6974 case XML_ENTITY_DECL:
6975 case XML_NOTATION_NODE:
6976 case XML_XINCLUDE_START:
6977 case XML_XINCLUDE_END:
6978 if (ctxt->context->node->parent == NULL)
6979 return((xmlNodePtr) ctxt->context->doc);
6980 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6981 ((ctxt->context->node->parent->name[0] == ' ') ||
6982 (xmlStrEqual(ctxt->context->node->parent->name,
6983 BAD_CAST "fake node libxslt"))))
6984 return(NULL);
6985 return(ctxt->context->node->parent);
6986 case XML_ATTRIBUTE_NODE: {
6987 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
6988
6989 return(tmp->parent);
6990 }
6991 case XML_DOCUMENT_NODE:
6992 case XML_DOCUMENT_TYPE_NODE:
6993 case XML_DOCUMENT_FRAG_NODE:
6994 case XML_HTML_DOCUMENT_NODE:
6995 return(NULL);
6996 case XML_NAMESPACE_DECL: {
6997 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6998
6999 if ((ns->next != NULL) &&
7000 (ns->next->type != XML_NAMESPACE_DECL))
7001 return((xmlNodePtr) ns->next);
7002 /* Bad, how did that namespace end up here ? */
7003 return(NULL);
7004 }
7005 }
7006 return(NULL);
7007 }
7008 if (cur == ctxt->context->doc->children)
7009 return((xmlNodePtr) ctxt->context->doc);
7010 if (cur == (xmlNodePtr) ctxt->context->doc)
7011 return(NULL);
7012 switch (cur->type) {
7013 case XML_ELEMENT_NODE:
7014 case XML_TEXT_NODE:
7015 case XML_CDATA_SECTION_NODE:
7016 case XML_ENTITY_REF_NODE:
7017 case XML_ENTITY_NODE:
7018 case XML_PI_NODE:
7019 case XML_COMMENT_NODE:
7020 case XML_NOTATION_NODE:
7021 case XML_DTD_NODE:
7022 case XML_ELEMENT_DECL:
7023 case XML_ATTRIBUTE_DECL:
7024 case XML_ENTITY_DECL:
7025 case XML_XINCLUDE_START:
7026 case XML_XINCLUDE_END:
7027 if (cur->parent == NULL)
7028 return(NULL);
7029 if ((cur->parent->type == XML_ELEMENT_NODE) &&
7030 ((cur->parent->name[0] == ' ') ||
7031 (xmlStrEqual(cur->parent->name,
7032 BAD_CAST "fake node libxslt"))))
7033 return(NULL);
7034 return(cur->parent);
7035 case XML_ATTRIBUTE_NODE: {
7036 xmlAttrPtr att = (xmlAttrPtr) cur;
7037
7038 return(att->parent);
7039 }
7040 case XML_NAMESPACE_DECL: {
7041 xmlNsPtr ns = (xmlNsPtr) cur;
7042
7043 if ((ns->next != NULL) &&
7044 (ns->next->type != XML_NAMESPACE_DECL))
7045 return((xmlNodePtr) ns->next);
7046 /* Bad, how did that namespace end up here ? */
7047 return(NULL);
7048 }
7049 case XML_DOCUMENT_NODE:
7050 case XML_DOCUMENT_TYPE_NODE:
7051 case XML_DOCUMENT_FRAG_NODE:
7052 case XML_HTML_DOCUMENT_NODE:
7053 return(NULL);
7054 }
7055 return(NULL);
7056}
7057
7058/**
7059 * xmlXPathNextAncestorOrSelf:
7060 * @ctxt: the XPath Parser context
7061 * @cur: the current node in the traversal
7062 *
7063 * Traversal function for the "ancestor-or-self" direction
7064 * he ancestor-or-self axis contains the context node and ancestors of
7065 * the context node in reverse document order; thus the context node is
7066 * the first node on the axis, and the context node's parent the second;
7067 * parent here is defined the same as with the parent axis.
7068 *
7069 * Returns the next element following that axis
7070 */
7071xmlNodePtr
7072xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7073 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7074 if (cur == NULL)
7075 return(ctxt->context->node);
7076 return(xmlXPathNextAncestor(ctxt, cur));
7077}
7078
7079/**
7080 * xmlXPathNextFollowingSibling:
7081 * @ctxt: the XPath Parser context
7082 * @cur: the current node in the traversal
7083 *
7084 * Traversal function for the "following-sibling" direction
7085 * The following-sibling axis contains the following siblings of the context
7086 * node in document order.
7087 *
7088 * Returns the next element following that axis
7089 */
7090xmlNodePtr
7091xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7092 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7093 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7094 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7095 return(NULL);
7096 if (cur == (xmlNodePtr) ctxt->context->doc)
7097 return(NULL);
7098 if (cur == NULL)
7099 return(ctxt->context->node->next);
7100 return(cur->next);
7101}
7102
7103/**
7104 * xmlXPathNextPrecedingSibling:
7105 * @ctxt: the XPath Parser context
7106 * @cur: the current node in the traversal
7107 *
7108 * Traversal function for the "preceding-sibling" direction
7109 * The preceding-sibling axis contains the preceding siblings of the context
7110 * node in reverse document order; the first preceding sibling is first on the
7111 * axis; the sibling preceding that node is the second on the axis and so on.
7112 *
7113 * Returns the next element following that axis
7114 */
7115xmlNodePtr
7116xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7117 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7118 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7119 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7120 return(NULL);
7121 if (cur == (xmlNodePtr) ctxt->context->doc)
7122 return(NULL);
7123 if (cur == NULL)
7124 return(ctxt->context->node->prev);
7125 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
7126 cur = cur->prev;
7127 if (cur == NULL)
7128 return(ctxt->context->node->prev);
7129 }
7130 return(cur->prev);
7131}
7132
7133/**
7134 * xmlXPathNextFollowing:
7135 * @ctxt: the XPath Parser context
7136 * @cur: the current node in the traversal
7137 *
7138 * Traversal function for the "following" direction
7139 * The following axis contains all nodes in the same document as the context
7140 * node that are after the context node in document order, excluding any
7141 * descendants and excluding attribute nodes and namespace nodes; the nodes
7142 * are ordered in document order
7143 *
7144 * Returns the next element following that axis
7145 */
7146xmlNodePtr
7147xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7148 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7149 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
7150 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
7151 return(cur->children);
7152
7153 if (cur == NULL) {
7154 cur = ctxt->context->node;
7155 if (cur->type == XML_ATTRIBUTE_NODE) {
7156 cur = cur->parent;
7157 } else if (cur->type == XML_NAMESPACE_DECL) {
7158 xmlNsPtr ns = (xmlNsPtr) cur;
7159
7160 if ((ns->next == NULL) ||
7161 (ns->next->type == XML_NAMESPACE_DECL))
7162 return (NULL);
7163 cur = (xmlNodePtr) ns->next;
7164 }
7165 }
7166 if (cur == NULL) return(NULL) ; /* ERROR */
7167 if (cur->next != NULL) return(cur->next) ;
7168 do {
7169 cur = cur->parent;
7170 if (cur == NULL) break;
7171 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
7172 if (cur->next != NULL) return(cur->next);
7173 } while (cur != NULL);
7174 return(cur);
7175}
7176
7177/*
7178 * xmlXPathIsAncestor:
7179 * @ancestor: the ancestor node
7180 * @node: the current node
7181 *
7182 * Check that @ancestor is a @node's ancestor
7183 *
7184 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
7185 */
7186static int
7187xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
7188 if ((ancestor == NULL) || (node == NULL)) return(0);
7189 if (node->type == XML_NAMESPACE_DECL)
7190 return(0);
7191 if (ancestor->type == XML_NAMESPACE_DECL)
7192 return(0);
7193 /* nodes need to be in the same document */
7194 if (ancestor->doc != node->doc) return(0);
7195 /* avoid searching if ancestor or node is the root node */
7196 if (ancestor == (xmlNodePtr) node->doc) return(1);
7197 if (node == (xmlNodePtr) ancestor->doc) return(0);
7198 while (node->parent != NULL) {
7199 if (node->parent == ancestor)
7200 return(1);
7201 node = node->parent;
7202 }
7203 return(0);
7204}
7205
7206/**
7207 * xmlXPathNextPreceding:
7208 * @ctxt: the XPath Parser context
7209 * @cur: the current node in the traversal
7210 *
7211 * Traversal function for the "preceding" direction
7212 * the preceding axis contains all nodes in the same document as the context
7213 * node that are before the context node in document order, excluding any
7214 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7215 * ordered in reverse document order
7216 *
7217 * Returns the next element following that axis
7218 */
7219xmlNodePtr
7220xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
7221{
7222 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7223 if (cur == NULL) {
7224 cur = ctxt->context->node;
7225 if (cur->type == XML_ATTRIBUTE_NODE) {
7226 cur = cur->parent;
7227 } else if (cur->type == XML_NAMESPACE_DECL) {
7228 xmlNsPtr ns = (xmlNsPtr) cur;
7229
7230 if ((ns->next == NULL) ||
7231 (ns->next->type == XML_NAMESPACE_DECL))
7232 return (NULL);
7233 cur = (xmlNodePtr) ns->next;
7234 }
7235 }
7236 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
7237 return (NULL);
7238 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7239 cur = cur->prev;
7240 do {
7241 if (cur->prev != NULL) {
7242 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
7243 return (cur);
7244 }
7245
7246 cur = cur->parent;
7247 if (cur == NULL)
7248 return (NULL);
7249 if (cur == ctxt->context->doc->children)
7250 return (NULL);
7251 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
7252 return (cur);
7253}
7254
7255/**
7256 * xmlXPathNextPrecedingInternal:
7257 * @ctxt: the XPath Parser context
7258 * @cur: the current node in the traversal
7259 *
7260 * Traversal function for the "preceding" direction
7261 * the preceding axis contains all nodes in the same document as the context
7262 * node that are before the context node in document order, excluding any
7263 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7264 * ordered in reverse document order
7265 * This is a faster implementation but internal only since it requires a
7266 * state kept in the parser context: ctxt->ancestor.
7267 *
7268 * Returns the next element following that axis
7269 */
7270static xmlNodePtr
7271xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
7272 xmlNodePtr cur)
7273{
7274 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7275 if (cur == NULL) {
7276 cur = ctxt->context->node;
7277 if (cur == NULL)
7278 return (NULL);
7279 if (cur->type == XML_ATTRIBUTE_NODE) {
7280 cur = cur->parent;
7281 } else if (cur->type == XML_NAMESPACE_DECL) {
7282 xmlNsPtr ns = (xmlNsPtr) cur;
7283
7284 if ((ns->next == NULL) ||
7285 (ns->next->type == XML_NAMESPACE_DECL))
7286 return (NULL);
7287 cur = (xmlNodePtr) ns->next;
7288 }
7289 ctxt->ancestor = cur->parent;
7290 }
7291 if (cur->type == XML_NAMESPACE_DECL)
7292 return(NULL);
7293 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7294 cur = cur->prev;
7295 while (cur->prev == NULL) {
7296 cur = cur->parent;
7297 if (cur == NULL)
7298 return (NULL);
7299 if (cur == ctxt->context->doc->children)
7300 return (NULL);
7301 if (cur != ctxt->ancestor)
7302 return (cur);
7303 ctxt->ancestor = cur->parent;
7304 }
7305 cur = cur->prev;
7306 while (cur->last != NULL)
7307 cur = cur->last;
7308 return (cur);
7309}
7310
7311/**
7312 * xmlXPathNextNamespace:
7313 * @ctxt: the XPath Parser context
7314 * @cur: the current attribute in the traversal
7315 *
7316 * Traversal function for the "namespace" direction
7317 * the namespace axis contains the namespace nodes of the context node;
7318 * the order of nodes on this axis is implementation-defined; the axis will
7319 * be empty unless the context node is an element
7320 *
7321 * We keep the XML namespace node at the end of the list.
7322 *
7323 * Returns the next element following that axis
7324 */
7325xmlNodePtr
7326xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7327 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7328 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
7329 if (cur == NULL) {
7330 if (ctxt->context->tmpNsList != NULL)
7331 xmlFree(ctxt->context->tmpNsList);
7332 ctxt->context->tmpNsNr = 0;
7333 if (xmlGetNsListSafe(ctxt->context->doc, ctxt->context->node,
7334 &ctxt->context->tmpNsList) < 0) {
7335 xmlXPathPErrMemory(ctxt);
7336 return(NULL);
7337 }
7338 if (ctxt->context->tmpNsList != NULL) {
7339 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
7340 ctxt->context->tmpNsNr++;
7341 }
7342 }
7343 return((xmlNodePtr) xmlXPathXMLNamespace);
7344 }
7345 if (ctxt->context->tmpNsNr > 0) {
7346 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
7347 } else {
7348 if (ctxt->context->tmpNsList != NULL)
7349 xmlFree(ctxt->context->tmpNsList);
7350 ctxt->context->tmpNsList = NULL;
7351 return(NULL);
7352 }
7353}
7354
7355/**
7356 * xmlXPathNextAttribute:
7357 * @ctxt: the XPath Parser context
7358 * @cur: the current attribute in the traversal
7359 *
7360 * Traversal function for the "attribute" direction
7361 * TODO: support DTD inherited default attributes
7362 *
7363 * Returns the next element following that axis
7364 */
7365xmlNodePtr
7366xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7367 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7368 if (ctxt->context->node == NULL)
7369 return(NULL);
7370 if (ctxt->context->node->type != XML_ELEMENT_NODE)
7371 return(NULL);
7372 if (cur == NULL) {
7373 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7374 return(NULL);
7375 return((xmlNodePtr)ctxt->context->node->properties);
7376 }
7377 return((xmlNodePtr)cur->next);
7378}
7379
7380/************************************************************************
7381 * *
7382 * NodeTest Functions *
7383 * *
7384 ************************************************************************/
7385
7386#define IS_FUNCTION 200
7387
7388
7389/************************************************************************
7390 * *
7391 * Implicit tree core function library *
7392 * *
7393 ************************************************************************/
7394
7395/**
7396 * xmlXPathRoot:
7397 * @ctxt: the XPath Parser context
7398 *
7399 * Initialize the context to the root of the document
7400 */
7401void
7402xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
7403 if ((ctxt == NULL) || (ctxt->context == NULL))
7404 return;
7405 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7406 (xmlNodePtr) ctxt->context->doc));
7407}
7408
7409/************************************************************************
7410 * *
7411 * The explicit core function library *
7412 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
7413 * *
7414 ************************************************************************/
7415
7416
7417/**
7418 * xmlXPathLastFunction:
7419 * @ctxt: the XPath Parser context
7420 * @nargs: the number of arguments
7421 *
7422 * Implement the last() XPath function
7423 * number last()
7424 * The last function returns the number of nodes in the context node list.
7425 */
7426void
7427xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7428 CHECK_ARITY(0);
7429 if (ctxt->context->contextSize >= 0) {
7430 valuePush(ctxt,
7431 xmlXPathCacheNewFloat(ctxt, (double) ctxt->context->contextSize));
7432 } else {
7433 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
7434 }
7435}
7436
7437/**
7438 * xmlXPathPositionFunction:
7439 * @ctxt: the XPath Parser context
7440 * @nargs: the number of arguments
7441 *
7442 * Implement the position() XPath function
7443 * number position()
7444 * The position function returns the position of the context node in the
7445 * context node list. The first position is 1, and so the last position
7446 * will be equal to last().
7447 */
7448void
7449xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7450 CHECK_ARITY(0);
7451 if (ctxt->context->proximityPosition >= 0) {
7452 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7453 (double) ctxt->context->proximityPosition));
7454 } else {
7455 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
7456 }
7457}
7458
7459/**
7460 * xmlXPathCountFunction:
7461 * @ctxt: the XPath Parser context
7462 * @nargs: the number of arguments
7463 *
7464 * Implement the count() XPath function
7465 * number count(node-set)
7466 */
7467void
7468xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7469 xmlXPathObjectPtr cur;
7470
7471 CHECK_ARITY(1);
7472 if ((ctxt->value == NULL) ||
7473 ((ctxt->value->type != XPATH_NODESET) &&
7474 (ctxt->value->type != XPATH_XSLT_TREE)))
7475 XP_ERROR(XPATH_INVALID_TYPE);
7476 cur = valuePop(ctxt);
7477
7478 if ((cur == NULL) || (cur->nodesetval == NULL))
7479 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
7480 else
7481 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7482 (double) cur->nodesetval->nodeNr));
7483 xmlXPathReleaseObject(ctxt->context, cur);
7484}
7485
7486/**
7487 * xmlXPathGetElementsByIds:
7488 * @doc: the document
7489 * @ids: a whitespace separated list of IDs
7490 *
7491 * Selects elements by their unique ID.
7492 *
7493 * Returns a node-set of selected elements.
7494 */
7495static xmlNodeSetPtr
7496xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
7497 xmlNodeSetPtr ret;
7498 const xmlChar *cur = ids;
7499 xmlChar *ID;
7500 xmlAttrPtr attr;
7501 xmlNodePtr elem = NULL;
7502
7503 if (ids == NULL) return(NULL);
7504
7505 ret = xmlXPathNodeSetCreate(NULL);
7506 if (ret == NULL)
7507 return(ret);
7508
7509 while (IS_BLANK_CH(*cur)) cur++;
7510 while (*cur != 0) {
7511 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
7512 cur++;
7513
7514 ID = xmlStrndup(ids, cur - ids);
7515 if (ID == NULL) {
7516 xmlXPathFreeNodeSet(ret);
7517 return(NULL);
7518 }
7519 /*
7520 * We used to check the fact that the value passed
7521 * was an NCName, but this generated much troubles for
7522 * me and Aleksey Sanin, people blatantly violated that
7523 * constraint, like Visa3D spec.
7524 * if (xmlValidateNCName(ID, 1) == 0)
7525 */
7526 attr = xmlGetID(doc, ID);
7527 xmlFree(ID);
7528 if (attr != NULL) {
7529 if (attr->type == XML_ATTRIBUTE_NODE)
7530 elem = attr->parent;
7531 else if (attr->type == XML_ELEMENT_NODE)
7532 elem = (xmlNodePtr) attr;
7533 else
7534 elem = NULL;
7535 if (elem != NULL) {
7536 if (xmlXPathNodeSetAdd(ret, elem) < 0) {
7537 xmlXPathFreeNodeSet(ret);
7538 return(NULL);
7539 }
7540 }
7541 }
7542
7543 while (IS_BLANK_CH(*cur)) cur++;
7544 ids = cur;
7545 }
7546 return(ret);
7547}
7548
7549/**
7550 * xmlXPathIdFunction:
7551 * @ctxt: the XPath Parser context
7552 * @nargs: the number of arguments
7553 *
7554 * Implement the id() XPath function
7555 * node-set id(object)
7556 * The id function selects elements by their unique ID
7557 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
7558 * then the result is the union of the result of applying id to the
7559 * string value of each of the nodes in the argument node-set. When the
7560 * argument to id is of any other type, the argument is converted to a
7561 * string as if by a call to the string function; the string is split
7562 * into a whitespace-separated list of tokens (whitespace is any sequence
7563 * of characters matching the production S); the result is a node-set
7564 * containing the elements in the same document as the context node that
7565 * have a unique ID equal to any of the tokens in the list.
7566 */
7567void
7568xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7569 xmlChar *tokens;
7570 xmlNodeSetPtr ret;
7571 xmlXPathObjectPtr obj;
7572
7573 CHECK_ARITY(1);
7574 obj = valuePop(ctxt);
7575 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7576 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7577 xmlNodeSetPtr ns;
7578 int i;
7579
7580 ret = xmlXPathNodeSetCreate(NULL);
7581 if (ret == NULL)
7582 xmlXPathPErrMemory(ctxt);
7583
7584 if (obj->nodesetval != NULL) {
7585 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7586 tokens =
7587 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7588 if (tokens == NULL)
7589 xmlXPathPErrMemory(ctxt);
7590 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7591 if (ns == NULL)
7592 xmlXPathPErrMemory(ctxt);
7593 ret = xmlXPathNodeSetMerge(ret, ns);
7594 if (ret == NULL)
7595 xmlXPathPErrMemory(ctxt);
7596 xmlXPathFreeNodeSet(ns);
7597 if (tokens != NULL)
7598 xmlFree(tokens);
7599 }
7600 }
7601 xmlXPathReleaseObject(ctxt->context, obj);
7602 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7603 return;
7604 }
7605 tokens = xmlXPathCastToString(obj);
7606 if (tokens == NULL)
7607 xmlXPathPErrMemory(ctxt);
7608 xmlXPathReleaseObject(ctxt->context, obj);
7609 ret = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7610 if (ret == NULL)
7611 xmlXPathPErrMemory(ctxt);
7612 xmlFree(tokens);
7613 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7614 return;
7615}
7616
7617/**
7618 * xmlXPathLocalNameFunction:
7619 * @ctxt: the XPath Parser context
7620 * @nargs: the number of arguments
7621 *
7622 * Implement the local-name() XPath function
7623 * string local-name(node-set?)
7624 * The local-name function returns a string containing the local part
7625 * of the name of the node in the argument node-set that is first in
7626 * document order. If the node-set is empty or the first node has no
7627 * name, an empty string is returned. If the argument is omitted it
7628 * defaults to the context node.
7629 */
7630void
7631xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7632 xmlXPathObjectPtr cur;
7633
7634 if (ctxt == NULL) return;
7635
7636 if (nargs == 0) {
7637 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7638 nargs = 1;
7639 }
7640
7641 CHECK_ARITY(1);
7642 if ((ctxt->value == NULL) ||
7643 ((ctxt->value->type != XPATH_NODESET) &&
7644 (ctxt->value->type != XPATH_XSLT_TREE)))
7645 XP_ERROR(XPATH_INVALID_TYPE);
7646 cur = valuePop(ctxt);
7647
7648 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7649 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7650 } else {
7651 int i = 0; /* Should be first in document order !!!!! */
7652 switch (cur->nodesetval->nodeTab[i]->type) {
7653 case XML_ELEMENT_NODE:
7654 case XML_ATTRIBUTE_NODE:
7655 case XML_PI_NODE:
7656 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7657 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7658 else
7659 valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7660 cur->nodesetval->nodeTab[i]->name));
7661 break;
7662 case XML_NAMESPACE_DECL:
7663 valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7664 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
7665 break;
7666 default:
7667 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7668 }
7669 }
7670 xmlXPathReleaseObject(ctxt->context, cur);
7671}
7672
7673/**
7674 * xmlXPathNamespaceURIFunction:
7675 * @ctxt: the XPath Parser context
7676 * @nargs: the number of arguments
7677 *
7678 * Implement the namespace-uri() XPath function
7679 * string namespace-uri(node-set?)
7680 * The namespace-uri function returns a string containing the
7681 * namespace URI of the expanded name of the node in the argument
7682 * node-set that is first in document order. If the node-set is empty,
7683 * the first node has no name, or the expanded name has no namespace
7684 * URI, an empty string is returned. If the argument is omitted it
7685 * defaults to the context node.
7686 */
7687void
7688xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7689 xmlXPathObjectPtr cur;
7690
7691 if (ctxt == NULL) return;
7692
7693 if (nargs == 0) {
7694 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7695 nargs = 1;
7696 }
7697 CHECK_ARITY(1);
7698 if ((ctxt->value == NULL) ||
7699 ((ctxt->value->type != XPATH_NODESET) &&
7700 (ctxt->value->type != XPATH_XSLT_TREE)))
7701 XP_ERROR(XPATH_INVALID_TYPE);
7702 cur = valuePop(ctxt);
7703
7704 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7705 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7706 } else {
7707 int i = 0; /* Should be first in document order !!!!! */
7708 switch (cur->nodesetval->nodeTab[i]->type) {
7709 case XML_ELEMENT_NODE:
7710 case XML_ATTRIBUTE_NODE:
7711 if (cur->nodesetval->nodeTab[i]->ns == NULL)
7712 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7713 else
7714 valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7715 cur->nodesetval->nodeTab[i]->ns->href));
7716 break;
7717 default:
7718 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7719 }
7720 }
7721 xmlXPathReleaseObject(ctxt->context, cur);
7722}
7723
7724/**
7725 * xmlXPathNameFunction:
7726 * @ctxt: the XPath Parser context
7727 * @nargs: the number of arguments
7728 *
7729 * Implement the name() XPath function
7730 * string name(node-set?)
7731 * The name function returns a string containing a QName representing
7732 * the name of the node in the argument node-set that is first in document
7733 * order. The QName must represent the name with respect to the namespace
7734 * declarations in effect on the node whose name is being represented.
7735 * Typically, this will be the form in which the name occurred in the XML
7736 * source. This need not be the case if there are namespace declarations
7737 * in effect on the node that associate multiple prefixes with the same
7738 * namespace. However, an implementation may include information about
7739 * the original prefix in its representation of nodes; in this case, an
7740 * implementation can ensure that the returned string is always the same
7741 * as the QName used in the XML source. If the argument it omitted it
7742 * defaults to the context node.
7743 * Libxml keep the original prefix so the "real qualified name" used is
7744 * returned.
7745 */
7746static void
7747xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
7748{
7749 xmlXPathObjectPtr cur;
7750
7751 if (nargs == 0) {
7752 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7753 nargs = 1;
7754 }
7755
7756 CHECK_ARITY(1);
7757 if ((ctxt->value == NULL) ||
7758 ((ctxt->value->type != XPATH_NODESET) &&
7759 (ctxt->value->type != XPATH_XSLT_TREE)))
7760 XP_ERROR(XPATH_INVALID_TYPE);
7761 cur = valuePop(ctxt);
7762
7763 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7764 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7765 } else {
7766 int i = 0; /* Should be first in document order !!!!! */
7767
7768 switch (cur->nodesetval->nodeTab[i]->type) {
7769 case XML_ELEMENT_NODE:
7770 case XML_ATTRIBUTE_NODE:
7771 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7772 valuePush(ctxt,
7773 xmlXPathCacheNewCString(ctxt, ""));
7774 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
7775 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
7776 valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7777 cur->nodesetval->nodeTab[i]->name));
7778 } else {
7779 xmlChar *fullname;
7780
7781 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
7782 cur->nodesetval->nodeTab[i]->ns->prefix,
7783 NULL, 0);
7784 if (fullname == cur->nodesetval->nodeTab[i]->name)
7785 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
7786 if (fullname == NULL)
7787 xmlXPathPErrMemory(ctxt);
7788 valuePush(ctxt, xmlXPathCacheWrapString(ctxt, fullname));
7789 }
7790 break;
7791 default:
7792 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7793 cur->nodesetval->nodeTab[i]));
7794 xmlXPathLocalNameFunction(ctxt, 1);
7795 }
7796 }
7797 xmlXPathReleaseObject(ctxt->context, cur);
7798}
7799
7800
7801/**
7802 * xmlXPathStringFunction:
7803 * @ctxt: the XPath Parser context
7804 * @nargs: the number of arguments
7805 *
7806 * Implement the string() XPath function
7807 * string string(object?)
7808 * The string function converts an object to a string as follows:
7809 * - A node-set is converted to a string by returning the value of
7810 * the node in the node-set that is first in document order.
7811 * If the node-set is empty, an empty string is returned.
7812 * - A number is converted to a string as follows
7813 * + NaN is converted to the string NaN
7814 * + positive zero is converted to the string 0
7815 * + negative zero is converted to the string 0
7816 * + positive infinity is converted to the string Infinity
7817 * + negative infinity is converted to the string -Infinity
7818 * + if the number is an integer, the number is represented in
7819 * decimal form as a Number with no decimal point and no leading
7820 * zeros, preceded by a minus sign (-) if the number is negative
7821 * + otherwise, the number is represented in decimal form as a
7822 * Number including a decimal point with at least one digit
7823 * before the decimal point and at least one digit after the
7824 * decimal point, preceded by a minus sign (-) if the number
7825 * is negative; there must be no leading zeros before the decimal
7826 * point apart possibly from the one required digit immediately
7827 * before the decimal point; beyond the one required digit
7828 * after the decimal point there must be as many, but only as
7829 * many, more digits as are needed to uniquely distinguish the
7830 * number from all other IEEE 754 numeric values.
7831 * - The boolean false value is converted to the string false.
7832 * The boolean true value is converted to the string true.
7833 *
7834 * If the argument is omitted, it defaults to a node-set with the
7835 * context node as its only member.
7836 */
7837void
7838xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7839 xmlXPathObjectPtr cur;
7840 xmlChar *stringval;
7841
7842 if (ctxt == NULL) return;
7843 if (nargs == 0) {
7844 stringval = xmlXPathCastNodeToString(ctxt->context->node);
7845 if (stringval == NULL)
7846 xmlXPathPErrMemory(ctxt);
7847 valuePush(ctxt, xmlXPathCacheWrapString(ctxt, stringval));
7848 return;
7849 }
7850
7851 CHECK_ARITY(1);
7852 cur = valuePop(ctxt);
7853 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7854 if (cur->type != XPATH_STRING) {
7855 stringval = xmlXPathCastToString(cur);
7856 if (stringval == NULL)
7857 xmlXPathPErrMemory(ctxt);
7858 xmlXPathReleaseObject(ctxt->context, cur);
7859 cur = xmlXPathCacheWrapString(ctxt, stringval);
7860 }
7861 valuePush(ctxt, cur);
7862}
7863
7864/**
7865 * xmlXPathStringLengthFunction:
7866 * @ctxt: the XPath Parser context
7867 * @nargs: the number of arguments
7868 *
7869 * Implement the string-length() XPath function
7870 * number string-length(string?)
7871 * The string-length returns the number of characters in the string
7872 * (see [3.6 Strings]). If the argument is omitted, it defaults to
7873 * the context node converted to a string, in other words the value
7874 * of the context node.
7875 */
7876void
7877xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7878 xmlXPathObjectPtr cur;
7879
7880 if (nargs == 0) {
7881 if ((ctxt == NULL) || (ctxt->context == NULL))
7882 return;
7883 if (ctxt->context->node == NULL) {
7884 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0));
7885 } else {
7886 xmlChar *content;
7887
7888 content = xmlXPathCastNodeToString(ctxt->context->node);
7889 if (content == NULL)
7890 xmlXPathPErrMemory(ctxt);
7891 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7892 xmlUTF8Strlen(content)));
7893 xmlFree(content);
7894 }
7895 return;
7896 }
7897 CHECK_ARITY(1);
7898 CAST_TO_STRING;
7899 CHECK_TYPE(XPATH_STRING);
7900 cur = valuePop(ctxt);
7901 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7902 xmlUTF8Strlen(cur->stringval)));
7903 xmlXPathReleaseObject(ctxt->context, cur);
7904}
7905
7906/**
7907 * xmlXPathConcatFunction:
7908 * @ctxt: the XPath Parser context
7909 * @nargs: the number of arguments
7910 *
7911 * Implement the concat() XPath function
7912 * string concat(string, string, string*)
7913 * The concat function returns the concatenation of its arguments.
7914 */
7915void
7916xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7917 xmlXPathObjectPtr cur, newobj;
7918 xmlChar *tmp;
7919
7920 if (ctxt == NULL) return;
7921 if (nargs < 2) {
7922 CHECK_ARITY(2);
7923 }
7924
7925 CAST_TO_STRING;
7926 cur = valuePop(ctxt);
7927 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
7928 xmlXPathReleaseObject(ctxt->context, cur);
7929 return;
7930 }
7931 nargs--;
7932
7933 while (nargs > 0) {
7934 CAST_TO_STRING;
7935 newobj = valuePop(ctxt);
7936 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
7937 xmlXPathReleaseObject(ctxt->context, newobj);
7938 xmlXPathReleaseObject(ctxt->context, cur);
7939 XP_ERROR(XPATH_INVALID_TYPE);
7940 }
7941 tmp = xmlStrcat(newobj->stringval, cur->stringval);
7942 if (tmp == NULL)
7943 xmlXPathPErrMemory(ctxt);
7944 newobj->stringval = cur->stringval;
7945 cur->stringval = tmp;
7946 xmlXPathReleaseObject(ctxt->context, newobj);
7947 nargs--;
7948 }
7949 valuePush(ctxt, cur);
7950}
7951
7952/**
7953 * xmlXPathContainsFunction:
7954 * @ctxt: the XPath Parser context
7955 * @nargs: the number of arguments
7956 *
7957 * Implement the contains() XPath function
7958 * boolean contains(string, string)
7959 * The contains function returns true if the first argument string
7960 * contains the second argument string, and otherwise returns false.
7961 */
7962void
7963xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7964 xmlXPathObjectPtr hay, needle;
7965
7966 CHECK_ARITY(2);
7967 CAST_TO_STRING;
7968 CHECK_TYPE(XPATH_STRING);
7969 needle = valuePop(ctxt);
7970 CAST_TO_STRING;
7971 hay = valuePop(ctxt);
7972
7973 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7974 xmlXPathReleaseObject(ctxt->context, hay);
7975 xmlXPathReleaseObject(ctxt->context, needle);
7976 XP_ERROR(XPATH_INVALID_TYPE);
7977 }
7978 if (xmlStrstr(hay->stringval, needle->stringval))
7979 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7980 else
7981 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7982 xmlXPathReleaseObject(ctxt->context, hay);
7983 xmlXPathReleaseObject(ctxt->context, needle);
7984}
7985
7986/**
7987 * xmlXPathStartsWithFunction:
7988 * @ctxt: the XPath Parser context
7989 * @nargs: the number of arguments
7990 *
7991 * Implement the starts-with() XPath function
7992 * boolean starts-with(string, string)
7993 * The starts-with function returns true if the first argument string
7994 * starts with the second argument string, and otherwise returns false.
7995 */
7996void
7997xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7998 xmlXPathObjectPtr hay, needle;
7999 int n;
8000
8001 CHECK_ARITY(2);
8002 CAST_TO_STRING;
8003 CHECK_TYPE(XPATH_STRING);
8004 needle = valuePop(ctxt);
8005 CAST_TO_STRING;
8006 hay = valuePop(ctxt);
8007
8008 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8009 xmlXPathReleaseObject(ctxt->context, hay);
8010 xmlXPathReleaseObject(ctxt->context, needle);
8011 XP_ERROR(XPATH_INVALID_TYPE);
8012 }
8013 n = xmlStrlen(needle->stringval);
8014 if (xmlStrncmp(hay->stringval, needle->stringval, n))
8015 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
8016 else
8017 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
8018 xmlXPathReleaseObject(ctxt->context, hay);
8019 xmlXPathReleaseObject(ctxt->context, needle);
8020}
8021
8022/**
8023 * xmlXPathSubstringFunction:
8024 * @ctxt: the XPath Parser context
8025 * @nargs: the number of arguments
8026 *
8027 * Implement the substring() XPath function
8028 * string substring(string, number, number?)
8029 * The substring function returns the substring of the first argument
8030 * starting at the position specified in the second argument with
8031 * length specified in the third argument. For example,
8032 * substring("12345",2,3) returns "234". If the third argument is not
8033 * specified, it returns the substring starting at the position specified
8034 * in the second argument and continuing to the end of the string. For
8035 * example, substring("12345",2) returns "2345". More precisely, each
8036 * character in the string (see [3.6 Strings]) is considered to have a
8037 * numeric position: the position of the first character is 1, the position
8038 * of the second character is 2 and so on. The returned substring contains
8039 * those characters for which the position of the character is greater than
8040 * or equal to the second argument and, if the third argument is specified,
8041 * less than the sum of the second and third arguments; the comparisons
8042 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8043 * - substring("12345", 1.5, 2.6) returns "234"
8044 * - substring("12345", 0, 3) returns "12"
8045 * - substring("12345", 0 div 0, 3) returns ""
8046 * - substring("12345", 1, 0 div 0) returns ""
8047 * - substring("12345", -42, 1 div 0) returns "12345"
8048 * - substring("12345", -1 div 0, 1 div 0) returns ""
8049 */
8050void
8051xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8052 xmlXPathObjectPtr str, start, len;
8053 double le=0, in;
8054 int i = 1, j = INT_MAX;
8055
8056 if (nargs < 2) {
8057 CHECK_ARITY(2);
8058 }
8059 if (nargs > 3) {
8060 CHECK_ARITY(3);
8061 }
8062 /*
8063 * take care of possible last (position) argument
8064 */
8065 if (nargs == 3) {
8066 CAST_TO_NUMBER;
8067 CHECK_TYPE(XPATH_NUMBER);
8068 len = valuePop(ctxt);
8069 le = len->floatval;
8070 xmlXPathReleaseObject(ctxt->context, len);
8071 }
8072
8073 CAST_TO_NUMBER;
8074 CHECK_TYPE(XPATH_NUMBER);
8075 start = valuePop(ctxt);
8076 in = start->floatval;
8077 xmlXPathReleaseObject(ctxt->context, start);
8078 CAST_TO_STRING;
8079 CHECK_TYPE(XPATH_STRING);
8080 str = valuePop(ctxt);
8081
8082 if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
8083 i = INT_MAX;
8084 } else if (in >= 1.0) {
8085 i = (int)in;
8086 if (in - floor(in) >= 0.5)
8087 i += 1;
8088 }
8089
8090 if (nargs == 3) {
8091 double rin, rle, end;
8092
8093 rin = floor(in);
8094 if (in - rin >= 0.5)
8095 rin += 1.0;
8096
8097 rle = floor(le);
8098 if (le - rle >= 0.5)
8099 rle += 1.0;
8100
8101 end = rin + rle;
8102 if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
8103 j = 1;
8104 } else if (end < INT_MAX) {
8105 j = (int)end;
8106 }
8107 }
8108
8109 i -= 1;
8110 j -= 1;
8111
8112 if ((i < j) && (i < xmlUTF8Strlen(str->stringval))) {
8113 xmlChar *ret = xmlUTF8Strsub(str->stringval, i, j - i);
8114 if (ret == NULL)
8115 xmlXPathPErrMemory(ctxt);
8116 valuePush(ctxt, xmlXPathCacheNewString(ctxt, ret));
8117 xmlFree(ret);
8118 } else {
8119 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
8120 }
8121
8122 xmlXPathReleaseObject(ctxt->context, str);
8123}
8124
8125/**
8126 * xmlXPathSubstringBeforeFunction:
8127 * @ctxt: the XPath Parser context
8128 * @nargs: the number of arguments
8129 *
8130 * Implement the substring-before() XPath function
8131 * string substring-before(string, string)
8132 * The substring-before function returns the substring of the first
8133 * argument string that precedes the first occurrence of the second
8134 * argument string in the first argument string, or the empty string
8135 * if the first argument string does not contain the second argument
8136 * string. For example, substring-before("1999/04/01","/") returns 1999.
8137 */
8138void
8139xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8140 xmlXPathObjectPtr str = NULL;
8141 xmlXPathObjectPtr find = NULL;
8142 const xmlChar *point;
8143 xmlChar *result;
8144
8145 CHECK_ARITY(2);
8146 CAST_TO_STRING;
8147 find = valuePop(ctxt);
8148 CAST_TO_STRING;
8149 str = valuePop(ctxt);
8150 if (ctxt->error != 0)
8151 goto error;
8152
8153 point = xmlStrstr(str->stringval, find->stringval);
8154 if (point == NULL) {
8155 result = xmlStrdup(BAD_CAST "");
8156 } else {
8157 result = xmlStrndup(str->stringval, point - str->stringval);
8158 }
8159 if (result == NULL) {
8160 xmlXPathPErrMemory(ctxt);
8161 goto error;
8162 }
8163 valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
8164
8165error:
8166 xmlXPathReleaseObject(ctxt->context, str);
8167 xmlXPathReleaseObject(ctxt->context, find);
8168}
8169
8170/**
8171 * xmlXPathSubstringAfterFunction:
8172 * @ctxt: the XPath Parser context
8173 * @nargs: the number of arguments
8174 *
8175 * Implement the substring-after() XPath function
8176 * string substring-after(string, string)
8177 * The substring-after function returns the substring of the first
8178 * argument string that follows the first occurrence of the second
8179 * argument string in the first argument string, or the empty string
8180 * if the first argument string does not contain the second argument
8181 * string. For example, substring-after("1999/04/01","/") returns 04/01,
8182 * and substring-after("1999/04/01","19") returns 99/04/01.
8183 */
8184void
8185xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8186 xmlXPathObjectPtr str = NULL;
8187 xmlXPathObjectPtr find = NULL;
8188 const xmlChar *point;
8189 xmlChar *result;
8190
8191 CHECK_ARITY(2);
8192 CAST_TO_STRING;
8193 find = valuePop(ctxt);
8194 CAST_TO_STRING;
8195 str = valuePop(ctxt);
8196 if (ctxt->error != 0)
8197 goto error;
8198
8199 point = xmlStrstr(str->stringval, find->stringval);
8200 if (point == NULL) {
8201 result = xmlStrdup(BAD_CAST "");
8202 } else {
8203 result = xmlStrdup(point + xmlStrlen(find->stringval));
8204 }
8205 if (result == NULL) {
8206 xmlXPathPErrMemory(ctxt);
8207 goto error;
8208 }
8209 valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
8210
8211error:
8212 xmlXPathReleaseObject(ctxt->context, str);
8213 xmlXPathReleaseObject(ctxt->context, find);
8214}
8215
8216/**
8217 * xmlXPathNormalizeFunction:
8218 * @ctxt: the XPath Parser context
8219 * @nargs: the number of arguments
8220 *
8221 * Implement the normalize-space() XPath function
8222 * string normalize-space(string?)
8223 * The normalize-space function returns the argument string with white
8224 * space normalized by stripping leading and trailing whitespace
8225 * and replacing sequences of whitespace characters by a single
8226 * space. Whitespace characters are the same allowed by the S production
8227 * in XML. If the argument is omitted, it defaults to the context
8228 * node converted to a string, in other words the value of the context node.
8229 */
8230void
8231xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8232 xmlChar *source, *target;
8233 int blank;
8234
8235 if (ctxt == NULL) return;
8236 if (nargs == 0) {
8237 /* Use current context node */
8238 source = xmlXPathCastNodeToString(ctxt->context->node);
8239 if (source == NULL)
8240 xmlXPathPErrMemory(ctxt);
8241 valuePush(ctxt, xmlXPathCacheWrapString(ctxt, source));
8242 nargs = 1;
8243 }
8244
8245 CHECK_ARITY(1);
8246 CAST_TO_STRING;
8247 CHECK_TYPE(XPATH_STRING);
8248 source = ctxt->value->stringval;
8249 if (source == NULL)
8250 return;
8251 target = source;
8252
8253 /* Skip leading whitespaces */
8254 while (IS_BLANK_CH(*source))
8255 source++;
8256
8257 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
8258 blank = 0;
8259 while (*source) {
8260 if (IS_BLANK_CH(*source)) {
8261 blank = 1;
8262 } else {
8263 if (blank) {
8264 *target++ = 0x20;
8265 blank = 0;
8266 }
8267 *target++ = *source;
8268 }
8269 source++;
8270 }
8271 *target = 0;
8272}
8273
8274/**
8275 * xmlXPathTranslateFunction:
8276 * @ctxt: the XPath Parser context
8277 * @nargs: the number of arguments
8278 *
8279 * Implement the translate() XPath function
8280 * string translate(string, string, string)
8281 * The translate function returns the first argument string with
8282 * occurrences of characters in the second argument string replaced
8283 * by the character at the corresponding position in the third argument
8284 * string. For example, translate("bar","abc","ABC") returns the string
8285 * BAr. If there is a character in the second argument string with no
8286 * character at a corresponding position in the third argument string
8287 * (because the second argument string is longer than the third argument
8288 * string), then occurrences of that character in the first argument
8289 * string are removed. For example, translate("--aaa--","abc-","ABC")
8290 * returns "AAA". If a character occurs more than once in second
8291 * argument string, then the first occurrence determines the replacement
8292 * character. If the third argument string is longer than the second
8293 * argument string, then excess characters are ignored.
8294 */
8295void
8296xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8297 xmlXPathObjectPtr str = NULL;
8298 xmlXPathObjectPtr from = NULL;
8299 xmlXPathObjectPtr to = NULL;
8300 xmlBufPtr target;
8301 int offset, max;
8302 int ch;
8303 const xmlChar *point;
8304 xmlChar *cptr, *content;
8305
8306 CHECK_ARITY(3);
8307
8308 CAST_TO_STRING;
8309 to = valuePop(ctxt);
8310 CAST_TO_STRING;
8311 from = valuePop(ctxt);
8312 CAST_TO_STRING;
8313 str = valuePop(ctxt);
8314 if (ctxt->error != 0)
8315 goto error;
8316
8317 /*
8318 * Account for quadratic runtime
8319 */
8320 if (ctxt->context->opLimit != 0) {
8321 unsigned long f1 = xmlStrlen(from->stringval);
8322 unsigned long f2 = xmlStrlen(str->stringval);
8323
8324 if ((f1 > 0) && (f2 > 0)) {
8325 unsigned long p;
8326
8327 f1 = f1 / 10 + 1;
8328 f2 = f2 / 10 + 1;
8329 p = f1 > ULONG_MAX / f2 ? ULONG_MAX : f1 * f2;
8330 if (xmlXPathCheckOpLimit(ctxt, p) < 0)
8331 goto error;
8332 }
8333 }
8334
8335 target = xmlBufCreateSize(64);
8336 if (target == NULL) {
8337 xmlXPathPErrMemory(ctxt);
8338 goto error;
8339 }
8340
8341 max = xmlUTF8Strlen(to->stringval);
8342 for (cptr = str->stringval; (ch=*cptr); ) {
8343 offset = xmlUTF8Strloc(from->stringval, cptr);
8344 if (offset >= 0) {
8345 if (offset < max) {
8346 point = xmlUTF8Strpos(to->stringval, offset);
8347 if (point)
8348 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
8349 }
8350 } else
8351 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
8352
8353 /* Step to next character in input */
8354 cptr++;
8355 if ( ch & 0x80 ) {
8356 /* if not simple ascii, verify proper format */
8357 if ( (ch & 0xc0) != 0xc0 ) {
8358 xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
8359 break;
8360 }
8361 /* then skip over remaining bytes for this char */
8362 while ( (ch <<= 1) & 0x80 )
8363 if ( (*cptr++ & 0xc0) != 0x80 ) {
8364 xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
8365 break;
8366 }
8367 if (ch & 0x80) /* must have had error encountered */
8368 break;
8369 }
8370 }
8371
8372 content = xmlBufDetach(target);
8373 if (content == NULL)
8374 xmlXPathPErrMemory(ctxt);
8375 else
8376 valuePush(ctxt, xmlXPathCacheWrapString(ctxt, content));
8377 xmlBufFree(target);
8378error:
8379 xmlXPathReleaseObject(ctxt->context, str);
8380 xmlXPathReleaseObject(ctxt->context, from);
8381 xmlXPathReleaseObject(ctxt->context, to);
8382}
8383
8384/**
8385 * xmlXPathBooleanFunction:
8386 * @ctxt: the XPath Parser context
8387 * @nargs: the number of arguments
8388 *
8389 * Implement the boolean() XPath function
8390 * boolean boolean(object)
8391 * The boolean function converts its argument to a boolean as follows:
8392 * - a number is true if and only if it is neither positive or
8393 * negative zero nor NaN
8394 * - a node-set is true if and only if it is non-empty
8395 * - a string is true if and only if its length is non-zero
8396 */
8397void
8398xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8399 xmlXPathObjectPtr cur;
8400
8401 CHECK_ARITY(1);
8402 cur = valuePop(ctxt);
8403 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8404 if (cur->type != XPATH_BOOLEAN) {
8405 int boolval = xmlXPathCastToBoolean(cur);
8406
8407 xmlXPathReleaseObject(ctxt->context, cur);
8408 cur = xmlXPathCacheNewBoolean(ctxt, boolval);
8409 }
8410 valuePush(ctxt, cur);
8411}
8412
8413/**
8414 * xmlXPathNotFunction:
8415 * @ctxt: the XPath Parser context
8416 * @nargs: the number of arguments
8417 *
8418 * Implement the not() XPath function
8419 * boolean not(boolean)
8420 * The not function returns true if its argument is false,
8421 * and false otherwise.
8422 */
8423void
8424xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8425 CHECK_ARITY(1);
8426 CAST_TO_BOOLEAN;
8427 CHECK_TYPE(XPATH_BOOLEAN);
8428 ctxt->value->boolval = ! ctxt->value->boolval;
8429}
8430
8431/**
8432 * xmlXPathTrueFunction:
8433 * @ctxt: the XPath Parser context
8434 * @nargs: the number of arguments
8435 *
8436 * Implement the true() XPath function
8437 * boolean true()
8438 */
8439void
8440xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8441 CHECK_ARITY(0);
8442 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
8443}
8444
8445/**
8446 * xmlXPathFalseFunction:
8447 * @ctxt: the XPath Parser context
8448 * @nargs: the number of arguments
8449 *
8450 * Implement the false() XPath function
8451 * boolean false()
8452 */
8453void
8454xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8455 CHECK_ARITY(0);
8456 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
8457}
8458
8459/**
8460 * xmlXPathLangFunction:
8461 * @ctxt: the XPath Parser context
8462 * @nargs: the number of arguments
8463 *
8464 * Implement the lang() XPath function
8465 * boolean lang(string)
8466 * The lang function returns true or false depending on whether the
8467 * language of the context node as specified by xml:lang attributes
8468 * is the same as or is a sublanguage of the language specified by
8469 * the argument string. The language of the context node is determined
8470 * by the value of the xml:lang attribute on the context node, or, if
8471 * the context node has no xml:lang attribute, by the value of the
8472 * xml:lang attribute on the nearest ancestor of the context node that
8473 * has an xml:lang attribute. If there is no such attribute, then lang
8474 * returns false. If there is such an attribute, then lang returns
8475 * true if the attribute value is equal to the argument ignoring case,
8476 * or if there is some suffix starting with - such that the attribute
8477 * value is equal to the argument ignoring that suffix of the attribute
8478 * value and ignoring case.
8479 */
8480void
8481xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8482 xmlXPathObjectPtr val;
8483 xmlNodePtr cur;
8484 xmlChar *theLang;
8485 const xmlChar *lang;
8486 int ret = 0;
8487 int i;
8488
8489 CHECK_ARITY(1);
8490 CAST_TO_STRING;
8491 CHECK_TYPE(XPATH_STRING);
8492 val = valuePop(ctxt);
8493 lang = val->stringval;
8494 cur = ctxt->context->node;
8495 while (cur != NULL) {
8496 if (xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE,
8497 &theLang) < 0)
8498 xmlXPathPErrMemory(ctxt);
8499 if (theLang != NULL)
8500 break;
8501 cur = cur->parent;
8502 }
8503 if ((theLang != NULL) && (lang != NULL)) {
8504 for (i = 0;lang[i] != 0;i++)
8505 if (toupper(lang[i]) != toupper(theLang[i]))
8506 goto not_equal;
8507 if ((theLang[i] == 0) || (theLang[i] == '-'))
8508 ret = 1;
8509 }
8510not_equal:
8511 if (theLang != NULL)
8512 xmlFree((void *)theLang);
8513
8514 xmlXPathReleaseObject(ctxt->context, val);
8515 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
8516}
8517
8518/**
8519 * xmlXPathNumberFunction:
8520 * @ctxt: the XPath Parser context
8521 * @nargs: the number of arguments
8522 *
8523 * Implement the number() XPath function
8524 * number number(object?)
8525 */
8526void
8527xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8528 xmlXPathObjectPtr cur;
8529 double res;
8530
8531 if (ctxt == NULL) return;
8532 if (nargs == 0) {
8533 if (ctxt->context->node == NULL) {
8534 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
8535 } else {
8536 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
8537 if (content == NULL)
8538 xmlXPathPErrMemory(ctxt);
8539
8540 res = xmlXPathStringEvalNumber(content);
8541 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8542 xmlFree(content);
8543 }
8544 return;
8545 }
8546
8547 CHECK_ARITY(1);
8548 cur = valuePop(ctxt);
8549 if (cur->type != XPATH_NUMBER) {
8550 double floatval;
8551
8552 floatval = xmlXPathCastToNumberInternal(ctxt, cur);
8553 xmlXPathReleaseObject(ctxt->context, cur);
8554 cur = xmlXPathCacheNewFloat(ctxt, floatval);
8555 }
8556 valuePush(ctxt, cur);
8557}
8558
8559/**
8560 * xmlXPathSumFunction:
8561 * @ctxt: the XPath Parser context
8562 * @nargs: the number of arguments
8563 *
8564 * Implement the sum() XPath function
8565 * number sum(node-set)
8566 * The sum function returns the sum of the values of the nodes in
8567 * the argument node-set.
8568 */
8569void
8570xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8571 xmlXPathObjectPtr cur;
8572 int i;
8573 double res = 0.0;
8574
8575 CHECK_ARITY(1);
8576 if ((ctxt->value == NULL) ||
8577 ((ctxt->value->type != XPATH_NODESET) &&
8578 (ctxt->value->type != XPATH_XSLT_TREE)))
8579 XP_ERROR(XPATH_INVALID_TYPE);
8580 cur = valuePop(ctxt);
8581
8582 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
8583 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
8584 res += xmlXPathNodeToNumberInternal(ctxt,
8585 cur->nodesetval->nodeTab[i]);
8586 }
8587 }
8588 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8589 xmlXPathReleaseObject(ctxt->context, cur);
8590}
8591
8592/**
8593 * xmlXPathFloorFunction:
8594 * @ctxt: the XPath Parser context
8595 * @nargs: the number of arguments
8596 *
8597 * Implement the floor() XPath function
8598 * number floor(number)
8599 * The floor function returns the largest (closest to positive infinity)
8600 * number that is not greater than the argument and that is an integer.
8601 */
8602void
8603xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8604 CHECK_ARITY(1);
8605 CAST_TO_NUMBER;
8606 CHECK_TYPE(XPATH_NUMBER);
8607
8608 ctxt->value->floatval = floor(ctxt->value->floatval);
8609}
8610
8611/**
8612 * xmlXPathCeilingFunction:
8613 * @ctxt: the XPath Parser context
8614 * @nargs: the number of arguments
8615 *
8616 * Implement the ceiling() XPath function
8617 * number ceiling(number)
8618 * The ceiling function returns the smallest (closest to negative infinity)
8619 * number that is not less than the argument and that is an integer.
8620 */
8621void
8622xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8623 CHECK_ARITY(1);
8624 CAST_TO_NUMBER;
8625 CHECK_TYPE(XPATH_NUMBER);
8626
8627#ifdef _AIX
8628 /* Work around buggy ceil() function on AIX */
8629 ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
8630#else
8631 ctxt->value->floatval = ceil(ctxt->value->floatval);
8632#endif
8633}
8634
8635/**
8636 * xmlXPathRoundFunction:
8637 * @ctxt: the XPath Parser context
8638 * @nargs: the number of arguments
8639 *
8640 * Implement the round() XPath function
8641 * number round(number)
8642 * The round function returns the number that is closest to the
8643 * argument and that is an integer. If there are two such numbers,
8644 * then the one that is closest to positive infinity is returned.
8645 */
8646void
8647xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8648 double f;
8649
8650 CHECK_ARITY(1);
8651 CAST_TO_NUMBER;
8652 CHECK_TYPE(XPATH_NUMBER);
8653
8654 f = ctxt->value->floatval;
8655
8656 if ((f >= -0.5) && (f < 0.5)) {
8657 /* Handles negative zero. */
8658 ctxt->value->floatval *= 0.0;
8659 }
8660 else {
8661 double rounded = floor(f);
8662 if (f - rounded >= 0.5)
8663 rounded += 1.0;
8664 ctxt->value->floatval = rounded;
8665 }
8666}
8667
8668/************************************************************************
8669 * *
8670 * The Parser *
8671 * *
8672 ************************************************************************/
8673
8674/*
8675 * a few forward declarations since we use a recursive call based
8676 * implementation.
8677 */
8678static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
8679static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
8680static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
8681static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
8682static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
8683 int qualified);
8684
8685/**
8686 * xmlXPathCurrentChar:
8687 * @ctxt: the XPath parser context
8688 * @cur: pointer to the beginning of the char
8689 * @len: pointer to the length of the char read
8690 *
8691 * The current char value, if using UTF-8 this may actually span multiple
8692 * bytes in the input buffer.
8693 *
8694 * Returns the current char value and its length
8695 */
8696
8697static int
8698xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
8699 unsigned char c;
8700 unsigned int val;
8701 const xmlChar *cur;
8702
8703 if (ctxt == NULL)
8704 return(0);
8705 cur = ctxt->cur;
8706
8707 /*
8708 * We are supposed to handle UTF8, check it's valid
8709 * From rfc2044: encoding of the Unicode values on UTF-8:
8710 *
8711 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
8712 * 0000 0000-0000 007F 0xxxxxxx
8713 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
8714 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
8715 *
8716 * Check for the 0x110000 limit too
8717 */
8718 c = *cur;
8719 if (c & 0x80) {
8720 if ((cur[1] & 0xc0) != 0x80)
8721 goto encoding_error;
8722 if ((c & 0xe0) == 0xe0) {
8723
8724 if ((cur[2] & 0xc0) != 0x80)
8725 goto encoding_error;
8726 if ((c & 0xf0) == 0xf0) {
8727 if (((c & 0xf8) != 0xf0) ||
8728 ((cur[3] & 0xc0) != 0x80))
8729 goto encoding_error;
8730 /* 4-byte code */
8731 *len = 4;
8732 val = (cur[0] & 0x7) << 18;
8733 val |= (cur[1] & 0x3f) << 12;
8734 val |= (cur[2] & 0x3f) << 6;
8735 val |= cur[3] & 0x3f;
8736 } else {
8737 /* 3-byte code */
8738 *len = 3;
8739 val = (cur[0] & 0xf) << 12;
8740 val |= (cur[1] & 0x3f) << 6;
8741 val |= cur[2] & 0x3f;
8742 }
8743 } else {
8744 /* 2-byte code */
8745 *len = 2;
8746 val = (cur[0] & 0x1f) << 6;
8747 val |= cur[1] & 0x3f;
8748 }
8749 if (!IS_CHAR(val)) {
8750 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
8751 }
8752 return(val);
8753 } else {
8754 /* 1-byte code */
8755 *len = 1;
8756 return(*cur);
8757 }
8758encoding_error:
8759 /*
8760 * If we detect an UTF8 error that probably means that the
8761 * input encoding didn't get properly advertised in the
8762 * declaration header. Report the error and switch the encoding
8763 * to ISO-Latin-1 (if you don't like this policy, just declare the
8764 * encoding !)
8765 */
8766 *len = 0;
8767 XP_ERROR0(XPATH_ENCODING_ERROR);
8768}
8769
8770/**
8771 * xmlXPathParseNCName:
8772 * @ctxt: the XPath Parser context
8773 *
8774 * parse an XML namespace non qualified name.
8775 *
8776 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
8777 *
8778 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
8779 * CombiningChar | Extender
8780 *
8781 * Returns the namespace name or NULL
8782 */
8783
8784xmlChar *
8785xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
8786 const xmlChar *in;
8787 xmlChar *ret;
8788 int count = 0;
8789
8790 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8791 /*
8792 * Accelerator for simple ASCII names
8793 */
8794 in = ctxt->cur;
8795 if (((*in >= 0x61) && (*in <= 0x7A)) ||
8796 ((*in >= 0x41) && (*in <= 0x5A)) ||
8797 (*in == '_')) {
8798 in++;
8799 while (((*in >= 0x61) && (*in <= 0x7A)) ||
8800 ((*in >= 0x41) && (*in <= 0x5A)) ||
8801 ((*in >= 0x30) && (*in <= 0x39)) ||
8802 (*in == '_') || (*in == '.') ||
8803 (*in == '-'))
8804 in++;
8805 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
8806 (*in == '[') || (*in == ']') || (*in == ':') ||
8807 (*in == '@') || (*in == '*')) {
8808 count = in - ctxt->cur;
8809 if (count == 0)
8810 return(NULL);
8811 ret = xmlStrndup(ctxt->cur, count);
8812 if (ret == NULL)
8813 xmlXPathPErrMemory(ctxt);
8814 ctxt->cur = in;
8815 return(ret);
8816 }
8817 }
8818 return(xmlXPathParseNameComplex(ctxt, 0));
8819}
8820
8821
8822/**
8823 * xmlXPathParseQName:
8824 * @ctxt: the XPath Parser context
8825 * @prefix: a xmlChar **
8826 *
8827 * parse an XML qualified name
8828 *
8829 * [NS 5] QName ::= (Prefix ':')? LocalPart
8830 *
8831 * [NS 6] Prefix ::= NCName
8832 *
8833 * [NS 7] LocalPart ::= NCName
8834 *
8835 * Returns the function returns the local part, and prefix is updated
8836 * to get the Prefix if any.
8837 */
8838
8839static xmlChar *
8840xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
8841 xmlChar *ret = NULL;
8842
8843 *prefix = NULL;
8844 ret = xmlXPathParseNCName(ctxt);
8845 if (ret && CUR == ':') {
8846 *prefix = ret;
8847 NEXT;
8848 ret = xmlXPathParseNCName(ctxt);
8849 }
8850 return(ret);
8851}
8852
8853/**
8854 * xmlXPathParseName:
8855 * @ctxt: the XPath Parser context
8856 *
8857 * parse an XML name
8858 *
8859 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8860 * CombiningChar | Extender
8861 *
8862 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8863 *
8864 * Returns the namespace name or NULL
8865 */
8866
8867xmlChar *
8868xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
8869 const xmlChar *in;
8870 xmlChar *ret;
8871 size_t count = 0;
8872
8873 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8874 /*
8875 * Accelerator for simple ASCII names
8876 */
8877 in = ctxt->cur;
8878 if (((*in >= 0x61) && (*in <= 0x7A)) ||
8879 ((*in >= 0x41) && (*in <= 0x5A)) ||
8880 (*in == '_') || (*in == ':')) {
8881 in++;
8882 while (((*in >= 0x61) && (*in <= 0x7A)) ||
8883 ((*in >= 0x41) && (*in <= 0x5A)) ||
8884 ((*in >= 0x30) && (*in <= 0x39)) ||
8885 (*in == '_') || (*in == '-') ||
8886 (*in == ':') || (*in == '.'))
8887 in++;
8888 if ((*in > 0) && (*in < 0x80)) {
8889 count = in - ctxt->cur;
8890 if (count > XML_MAX_NAME_LENGTH) {
8891 ctxt->cur = in;
8892 XP_ERRORNULL(XPATH_EXPR_ERROR);
8893 }
8894 ret = xmlStrndup(ctxt->cur, count);
8895 if (ret == NULL)
8896 xmlXPathPErrMemory(ctxt);
8897 ctxt->cur = in;
8898 return(ret);
8899 }
8900 }
8901 return(xmlXPathParseNameComplex(ctxt, 1));
8902}
8903
8904static xmlChar *
8905xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
8906 xmlChar *ret;
8907 xmlChar buf[XML_MAX_NAMELEN + 5];
8908 int len = 0, l;
8909 int c;
8910
8911 /*
8912 * Handler for more complex cases
8913 */
8914 c = CUR_CHAR(l);
8915 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8916 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
8917 (c == '*') || /* accelerators */
8918 (!IS_LETTER(c) && (c != '_') &&
8919 ((!qualified) || (c != ':')))) {
8920 return(NULL);
8921 }
8922
8923 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8924 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8925 (c == '.') || (c == '-') ||
8926 (c == '_') || ((qualified) && (c == ':')) ||
8927 (IS_COMBINING(c)) ||
8928 (IS_EXTENDER(c)))) {
8929 COPY_BUF(l,buf,len,c);
8930 NEXTL(l);
8931 c = CUR_CHAR(l);
8932 if (len >= XML_MAX_NAMELEN) {
8933 /*
8934 * Okay someone managed to make a huge name, so he's ready to pay
8935 * for the processing speed.
8936 */
8937 xmlChar *buffer;
8938 int max = len * 2;
8939
8940 if (len > XML_MAX_NAME_LENGTH) {
8941 XP_ERRORNULL(XPATH_EXPR_ERROR);
8942 }
8943 buffer = (xmlChar *) xmlMallocAtomic(max);
8944 if (buffer == NULL) {
8945 xmlXPathPErrMemory(ctxt);
8946 return(NULL);
8947 }
8948 memcpy(buffer, buf, len);
8949 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
8950 (c == '.') || (c == '-') ||
8951 (c == '_') || ((qualified) && (c == ':')) ||
8952 (IS_COMBINING(c)) ||
8953 (IS_EXTENDER(c))) {
8954 if (len + 10 > max) {
8955 xmlChar *tmp;
8956 if (max > XML_MAX_NAME_LENGTH) {
8957 xmlFree(buffer);
8958 XP_ERRORNULL(XPATH_EXPR_ERROR);
8959 }
8960 max *= 2;
8961 tmp = (xmlChar *) xmlRealloc(buffer, max);
8962 if (tmp == NULL) {
8963 xmlFree(buffer);
8964 xmlXPathPErrMemory(ctxt);
8965 return(NULL);
8966 }
8967 buffer = tmp;
8968 }
8969 COPY_BUF(l,buffer,len,c);
8970 NEXTL(l);
8971 c = CUR_CHAR(l);
8972 }
8973 buffer[len] = 0;
8974 return(buffer);
8975 }
8976 }
8977 if (len == 0)
8978 return(NULL);
8979 ret = xmlStrndup(buf, len);
8980 if (ret == NULL)
8981 xmlXPathPErrMemory(ctxt);
8982 return(ret);
8983}
8984
8985#define MAX_FRAC 20
8986
8987/**
8988 * xmlXPathStringEvalNumber:
8989 * @str: A string to scan
8990 *
8991 * [30a] Float ::= Number ('e' Digits?)?
8992 *
8993 * [30] Number ::= Digits ('.' Digits?)?
8994 * | '.' Digits
8995 * [31] Digits ::= [0-9]+
8996 *
8997 * Compile a Number in the string
8998 * In complement of the Number expression, this function also handles
8999 * negative values : '-' Number.
9000 *
9001 * Returns the double value.
9002 */
9003double
9004xmlXPathStringEvalNumber(const xmlChar *str) {
9005 const xmlChar *cur = str;
9006 double ret;
9007 int ok = 0;
9008 int isneg = 0;
9009 int exponent = 0;
9010 int is_exponent_negative = 0;
9011#ifdef __GNUC__
9012 unsigned long tmp = 0;
9013 double temp;
9014#endif
9015 if (cur == NULL) return(0);
9016 while (IS_BLANK_CH(*cur)) cur++;
9017 if (*cur == '-') {
9018 isneg = 1;
9019 cur++;
9020 }
9021 if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
9022 return(xmlXPathNAN);
9023 }
9024
9025#ifdef __GNUC__
9026 /*
9027 * tmp/temp is a workaround against a gcc compiler bug
9028 * http://veillard.com/gcc.bug
9029 */
9030 ret = 0;
9031 while ((*cur >= '0') && (*cur <= '9')) {
9032 ret = ret * 10;
9033 tmp = (*cur - '0');
9034 ok = 1;
9035 cur++;
9036 temp = (double) tmp;
9037 ret = ret + temp;
9038 }
9039#else
9040 ret = 0;
9041 while ((*cur >= '0') && (*cur <= '9')) {
9042 ret = ret * 10 + (*cur - '0');
9043 ok = 1;
9044 cur++;
9045 }
9046#endif
9047
9048 if (*cur == '.') {
9049 int v, frac = 0, max;
9050 double fraction = 0;
9051
9052 cur++;
9053 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9054 return(xmlXPathNAN);
9055 }
9056 while (*cur == '0') {
9057 frac = frac + 1;
9058 cur++;
9059 }
9060 max = frac + MAX_FRAC;
9061 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
9062 v = (*cur - '0');
9063 fraction = fraction * 10 + v;
9064 frac = frac + 1;
9065 cur++;
9066 }
9067 fraction /= pow(10.0, frac);
9068 ret = ret + fraction;
9069 while ((*cur >= '0') && (*cur <= '9'))
9070 cur++;
9071 }
9072 if ((*cur == 'e') || (*cur == 'E')) {
9073 cur++;
9074 if (*cur == '-') {
9075 is_exponent_negative = 1;
9076 cur++;
9077 } else if (*cur == '+') {
9078 cur++;
9079 }
9080 while ((*cur >= '0') && (*cur <= '9')) {
9081 if (exponent < 1000000)
9082 exponent = exponent * 10 + (*cur - '0');
9083 cur++;
9084 }
9085 }
9086 while (IS_BLANK_CH(*cur)) cur++;
9087 if (*cur != 0) return(xmlXPathNAN);
9088 if (isneg) ret = -ret;
9089 if (is_exponent_negative) exponent = -exponent;
9090 ret *= pow(10.0, (double)exponent);
9091 return(ret);
9092}
9093
9094/**
9095 * xmlXPathCompNumber:
9096 * @ctxt: the XPath Parser context
9097 *
9098 * [30] Number ::= Digits ('.' Digits?)?
9099 * | '.' Digits
9100 * [31] Digits ::= [0-9]+
9101 *
9102 * Compile a Number, then push it on the stack
9103 *
9104 */
9105static void
9106xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
9107{
9108 double ret = 0.0;
9109 int ok = 0;
9110 int exponent = 0;
9111 int is_exponent_negative = 0;
9112 xmlXPathObjectPtr num;
9113#ifdef __GNUC__
9114 unsigned long tmp = 0;
9115 double temp;
9116#endif
9117
9118 CHECK_ERROR;
9119 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
9120 XP_ERROR(XPATH_NUMBER_ERROR);
9121 }
9122#ifdef __GNUC__
9123 /*
9124 * tmp/temp is a workaround against a gcc compiler bug
9125 * http://veillard.com/gcc.bug
9126 */
9127 ret = 0;
9128 while ((CUR >= '0') && (CUR <= '9')) {
9129 ret = ret * 10;
9130 tmp = (CUR - '0');
9131 ok = 1;
9132 NEXT;
9133 temp = (double) tmp;
9134 ret = ret + temp;
9135 }
9136#else
9137 ret = 0;
9138 while ((CUR >= '0') && (CUR <= '9')) {
9139 ret = ret * 10 + (CUR - '0');
9140 ok = 1;
9141 NEXT;
9142 }
9143#endif
9144 if (CUR == '.') {
9145 int v, frac = 0, max;
9146 double fraction = 0;
9147
9148 NEXT;
9149 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
9150 XP_ERROR(XPATH_NUMBER_ERROR);
9151 }
9152 while (CUR == '0') {
9153 frac = frac + 1;
9154 NEXT;
9155 }
9156 max = frac + MAX_FRAC;
9157 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
9158 v = (CUR - '0');
9159 fraction = fraction * 10 + v;
9160 frac = frac + 1;
9161 NEXT;
9162 }
9163 fraction /= pow(10.0, frac);
9164 ret = ret + fraction;
9165 while ((CUR >= '0') && (CUR <= '9'))
9166 NEXT;
9167 }
9168 if ((CUR == 'e') || (CUR == 'E')) {
9169 NEXT;
9170 if (CUR == '-') {
9171 is_exponent_negative = 1;
9172 NEXT;
9173 } else if (CUR == '+') {
9174 NEXT;
9175 }
9176 while ((CUR >= '0') && (CUR <= '9')) {
9177 if (exponent < 1000000)
9178 exponent = exponent * 10 + (CUR - '0');
9179 NEXT;
9180 }
9181 if (is_exponent_negative)
9182 exponent = -exponent;
9183 ret *= pow(10.0, (double) exponent);
9184 }
9185 num = xmlXPathCacheNewFloat(ctxt, ret);
9186 if (num == NULL) {
9187 ctxt->error = XPATH_MEMORY_ERROR;
9188 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
9189 NULL) == -1) {
9190 xmlXPathReleaseObject(ctxt->context, num);
9191 }
9192}
9193
9194/**
9195 * xmlXPathParseLiteral:
9196 * @ctxt: the XPath Parser context
9197 *
9198 * Parse a Literal
9199 *
9200 * [29] Literal ::= '"' [^"]* '"'
9201 * | "'" [^']* "'"
9202 *
9203 * Returns the value found or NULL in case of error
9204 */
9205static xmlChar *
9206xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
9207 const xmlChar *q;
9208 xmlChar *ret = NULL;
9209 int quote;
9210
9211 if (CUR == '"') {
9212 quote = '"';
9213 } else if (CUR == '\'') {
9214 quote = '\'';
9215 } else {
9216 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
9217 }
9218
9219 NEXT;
9220 q = CUR_PTR;
9221 while (CUR != quote) {
9222 int ch;
9223 int len = 4;
9224
9225 if (CUR == 0)
9226 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
9227 ch = xmlGetUTF8Char(CUR_PTR, &len);
9228 if ((ch < 0) || (IS_CHAR(ch) == 0))
9229 XP_ERRORNULL(XPATH_INVALID_CHAR_ERROR);
9230 CUR_PTR += len;
9231 }
9232 ret = xmlStrndup(q, CUR_PTR - q);
9233 if (ret == NULL)
9234 xmlXPathPErrMemory(ctxt);
9235 NEXT;
9236 return(ret);
9237}
9238
9239/**
9240 * xmlXPathCompLiteral:
9241 * @ctxt: the XPath Parser context
9242 *
9243 * Parse a Literal and push it on the stack.
9244 *
9245 * [29] Literal ::= '"' [^"]* '"'
9246 * | "'" [^']* "'"
9247 *
9248 * TODO: xmlXPathCompLiteral memory allocation could be improved.
9249 */
9250static void
9251xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
9252 xmlChar *ret = NULL;
9253 xmlXPathObjectPtr lit;
9254
9255 ret = xmlXPathParseLiteral(ctxt);
9256 if (ret == NULL)
9257 return;
9258 lit = xmlXPathCacheNewString(ctxt, ret);
9259 if (lit == NULL) {
9260 ctxt->error = XPATH_MEMORY_ERROR;
9261 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
9262 NULL) == -1) {
9263 xmlXPathReleaseObject(ctxt->context, lit);
9264 }
9265 xmlFree(ret);
9266}
9267
9268/**
9269 * xmlXPathCompVariableReference:
9270 * @ctxt: the XPath Parser context
9271 *
9272 * Parse a VariableReference, evaluate it and push it on the stack.
9273 *
9274 * The variable bindings consist of a mapping from variable names
9275 * to variable values. The value of a variable is an object, which can be
9276 * of any of the types that are possible for the value of an expression,
9277 * and may also be of additional types not specified here.
9278 *
9279 * Early evaluation is possible since:
9280 * The variable bindings [...] used to evaluate a subexpression are
9281 * always the same as those used to evaluate the containing expression.
9282 *
9283 * [36] VariableReference ::= '$' QName
9284 */
9285static void
9286xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
9287 xmlChar *name;
9288 xmlChar *prefix;
9289
9290 SKIP_BLANKS;
9291 if (CUR != '$') {
9292 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9293 }
9294 NEXT;
9295 name = xmlXPathParseQName(ctxt, &prefix);
9296 if (name == NULL) {
9297 xmlFree(prefix);
9298 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9299 }
9300 ctxt->comp->last = -1;
9301 if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
9302 xmlFree(prefix);
9303 xmlFree(name);
9304 }
9305 SKIP_BLANKS;
9306 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
9307 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
9308 }
9309}
9310
9311/**
9312 * xmlXPathIsNodeType:
9313 * @name: a name string
9314 *
9315 * Is the name given a NodeType one.
9316 *
9317 * [38] NodeType ::= 'comment'
9318 * | 'text'
9319 * | 'processing-instruction'
9320 * | 'node'
9321 *
9322 * Returns 1 if true 0 otherwise
9323 */
9324int
9325xmlXPathIsNodeType(const xmlChar *name) {
9326 if (name == NULL)
9327 return(0);
9328
9329 if (xmlStrEqual(name, BAD_CAST "node"))
9330 return(1);
9331 if (xmlStrEqual(name, BAD_CAST "text"))
9332 return(1);
9333 if (xmlStrEqual(name, BAD_CAST "comment"))
9334 return(1);
9335 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9336 return(1);
9337 return(0);
9338}
9339
9340/**
9341 * xmlXPathCompFunctionCall:
9342 * @ctxt: the XPath Parser context
9343 *
9344 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
9345 * [17] Argument ::= Expr
9346 *
9347 * Compile a function call, the evaluation of all arguments are
9348 * pushed on the stack
9349 */
9350static void
9351xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
9352 xmlChar *name;
9353 xmlChar *prefix;
9354 int nbargs = 0;
9355 int sort = 1;
9356
9357 name = xmlXPathParseQName(ctxt, &prefix);
9358 if (name == NULL) {
9359 xmlFree(prefix);
9360 XP_ERROR(XPATH_EXPR_ERROR);
9361 }
9362 SKIP_BLANKS;
9363
9364 if (CUR != '(') {
9365 xmlFree(name);
9366 xmlFree(prefix);
9367 XP_ERROR(XPATH_EXPR_ERROR);
9368 }
9369 NEXT;
9370 SKIP_BLANKS;
9371
9372 /*
9373 * Optimization for count(): we don't need the node-set to be sorted.
9374 */
9375 if ((prefix == NULL) && (name[0] == 'c') &&
9376 xmlStrEqual(name, BAD_CAST "count"))
9377 {
9378 sort = 0;
9379 }
9380 ctxt->comp->last = -1;
9381 if (CUR != ')') {
9382 while (CUR != 0) {
9383 int op1 = ctxt->comp->last;
9384 ctxt->comp->last = -1;
9385 xmlXPathCompileExpr(ctxt, sort);
9386 if (ctxt->error != XPATH_EXPRESSION_OK) {
9387 xmlFree(name);
9388 xmlFree(prefix);
9389 return;
9390 }
9391 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
9392 nbargs++;
9393 if (CUR == ')') break;
9394 if (CUR != ',') {
9395 xmlFree(name);
9396 xmlFree(prefix);
9397 XP_ERROR(XPATH_EXPR_ERROR);
9398 }
9399 NEXT;
9400 SKIP_BLANKS;
9401 }
9402 }
9403 if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
9404 xmlFree(prefix);
9405 xmlFree(name);
9406 }
9407 NEXT;
9408 SKIP_BLANKS;
9409}
9410
9411/**
9412 * xmlXPathCompPrimaryExpr:
9413 * @ctxt: the XPath Parser context
9414 *
9415 * [15] PrimaryExpr ::= VariableReference
9416 * | '(' Expr ')'
9417 * | Literal
9418 * | Number
9419 * | FunctionCall
9420 *
9421 * Compile a primary expression.
9422 */
9423static void
9424xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
9425 SKIP_BLANKS;
9426 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
9427 else if (CUR == '(') {
9428 NEXT;
9429 SKIP_BLANKS;
9430 xmlXPathCompileExpr(ctxt, 1);
9431 CHECK_ERROR;
9432 if (CUR != ')') {
9433 XP_ERROR(XPATH_EXPR_ERROR);
9434 }
9435 NEXT;
9436 SKIP_BLANKS;
9437 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9438 xmlXPathCompNumber(ctxt);
9439 } else if ((CUR == '\'') || (CUR == '"')) {
9440 xmlXPathCompLiteral(ctxt);
9441 } else {
9442 xmlXPathCompFunctionCall(ctxt);
9443 }
9444 SKIP_BLANKS;
9445}
9446
9447/**
9448 * xmlXPathCompFilterExpr:
9449 * @ctxt: the XPath Parser context
9450 *
9451 * [20] FilterExpr ::= PrimaryExpr
9452 * | FilterExpr Predicate
9453 *
9454 * Compile a filter expression.
9455 * Square brackets are used to filter expressions in the same way that
9456 * they are used in location paths. It is an error if the expression to
9457 * be filtered does not evaluate to a node-set. The context node list
9458 * used for evaluating the expression in square brackets is the node-set
9459 * to be filtered listed in document order.
9460 */
9461
9462static void
9463xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
9464 xmlXPathCompPrimaryExpr(ctxt);
9465 CHECK_ERROR;
9466 SKIP_BLANKS;
9467
9468 while (CUR == '[') {
9469 xmlXPathCompPredicate(ctxt, 1);
9470 SKIP_BLANKS;
9471 }
9472
9473
9474}
9475
9476/**
9477 * xmlXPathScanName:
9478 * @ctxt: the XPath Parser context
9479 *
9480 * Trickery: parse an XML name but without consuming the input flow
9481 * Needed to avoid insanity in the parser state.
9482 *
9483 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9484 * CombiningChar | Extender
9485 *
9486 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9487 *
9488 * [6] Names ::= Name (S Name)*
9489 *
9490 * Returns the Name parsed or NULL
9491 */
9492
9493static xmlChar *
9494xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
9495 int l;
9496 int c;
9497 const xmlChar *cur;
9498 xmlChar *ret;
9499
9500 cur = ctxt->cur;
9501
9502 c = CUR_CHAR(l);
9503 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9504 (!IS_LETTER(c) && (c != '_') &&
9505 (c != ':'))) {
9506 return(NULL);
9507 }
9508
9509 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9510 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9511 (c == '.') || (c == '-') ||
9512 (c == '_') || (c == ':') ||
9513 (IS_COMBINING(c)) ||
9514 (IS_EXTENDER(c)))) {
9515 NEXTL(l);
9516 c = CUR_CHAR(l);
9517 }
9518 ret = xmlStrndup(cur, ctxt->cur - cur);
9519 if (ret == NULL)
9520 xmlXPathPErrMemory(ctxt);
9521 ctxt->cur = cur;
9522 return(ret);
9523}
9524
9525/**
9526 * xmlXPathCompPathExpr:
9527 * @ctxt: the XPath Parser context
9528 *
9529 * [19] PathExpr ::= LocationPath
9530 * | FilterExpr
9531 * | FilterExpr '/' RelativeLocationPath
9532 * | FilterExpr '//' RelativeLocationPath
9533 *
9534 * Compile a path expression.
9535 * The / operator and // operators combine an arbitrary expression
9536 * and a relative location path. It is an error if the expression
9537 * does not evaluate to a node-set.
9538 * The / operator does composition in the same way as when / is
9539 * used in a location path. As in location paths, // is short for
9540 * /descendant-or-self::node()/.
9541 */
9542
9543static void
9544xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
9545 int lc = 1; /* Should we branch to LocationPath ? */
9546 xmlChar *name = NULL; /* we may have to preparse a name to find out */
9547
9548 SKIP_BLANKS;
9549 if ((CUR == '$') || (CUR == '(') ||
9550 (IS_ASCII_DIGIT(CUR)) ||
9551 (CUR == '\'') || (CUR == '"') ||
9552 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9553 lc = 0;
9554 } else if (CUR == '*') {
9555 /* relative or absolute location path */
9556 lc = 1;
9557 } else if (CUR == '/') {
9558 /* relative or absolute location path */
9559 lc = 1;
9560 } else if (CUR == '@') {
9561 /* relative abbreviated attribute location path */
9562 lc = 1;
9563 } else if (CUR == '.') {
9564 /* relative abbreviated attribute location path */
9565 lc = 1;
9566 } else {
9567 /*
9568 * Problem is finding if we have a name here whether it's:
9569 * - a nodetype
9570 * - a function call in which case it's followed by '('
9571 * - an axis in which case it's followed by ':'
9572 * - a element name
9573 * We do an a priori analysis here rather than having to
9574 * maintain parsed token content through the recursive function
9575 * calls. This looks uglier but makes the code easier to
9576 * read/write/debug.
9577 */
9578 SKIP_BLANKS;
9579 name = xmlXPathScanName(ctxt);
9580 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
9581 lc = 1;
9582 xmlFree(name);
9583 } else if (name != NULL) {
9584 int len =xmlStrlen(name);
9585
9586
9587 while (NXT(len) != 0) {
9588 if (NXT(len) == '/') {
9589 /* element name */
9590 lc = 1;
9591 break;
9592 } else if (IS_BLANK_CH(NXT(len))) {
9593 /* ignore blanks */
9594 ;
9595 } else if (NXT(len) == ':') {
9596 lc = 1;
9597 break;
9598 } else if ((NXT(len) == '(')) {
9599 /* Node Type or Function */
9600 if (xmlXPathIsNodeType(name)) {
9601 lc = 1;
9602#ifdef LIBXML_XPTR_LOCS_ENABLED
9603 } else if (ctxt->xptr &&
9604 xmlStrEqual(name, BAD_CAST "range-to")) {
9605 lc = 1;
9606#endif
9607 } else {
9608 lc = 0;
9609 }
9610 break;
9611 } else if ((NXT(len) == '[')) {
9612 /* element name */
9613 lc = 1;
9614 break;
9615 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
9616 (NXT(len) == '=')) {
9617 lc = 1;
9618 break;
9619 } else {
9620 lc = 1;
9621 break;
9622 }
9623 len++;
9624 }
9625 if (NXT(len) == 0) {
9626 /* element name */
9627 lc = 1;
9628 }
9629 xmlFree(name);
9630 } else {
9631 /* make sure all cases are covered explicitly */
9632 XP_ERROR(XPATH_EXPR_ERROR);
9633 }
9634 }
9635
9636 if (lc) {
9637 if (CUR == '/') {
9638 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
9639 } else {
9640 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9641 }
9642 xmlXPathCompLocationPath(ctxt);
9643 } else {
9644 xmlXPathCompFilterExpr(ctxt);
9645 CHECK_ERROR;
9646 if ((CUR == '/') && (NXT(1) == '/')) {
9647 SKIP(2);
9648 SKIP_BLANKS;
9649
9650 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9651 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9652
9653 xmlXPathCompRelativeLocationPath(ctxt);
9654 } else if (CUR == '/') {
9655 xmlXPathCompRelativeLocationPath(ctxt);
9656 }
9657 }
9658 SKIP_BLANKS;
9659}
9660
9661/**
9662 * xmlXPathCompUnionExpr:
9663 * @ctxt: the XPath Parser context
9664 *
9665 * [18] UnionExpr ::= PathExpr
9666 * | UnionExpr '|' PathExpr
9667 *
9668 * Compile an union expression.
9669 */
9670
9671static void
9672xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
9673 xmlXPathCompPathExpr(ctxt);
9674 CHECK_ERROR;
9675 SKIP_BLANKS;
9676 while (CUR == '|') {
9677 int op1 = ctxt->comp->last;
9678 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9679
9680 NEXT;
9681 SKIP_BLANKS;
9682 xmlXPathCompPathExpr(ctxt);
9683
9684 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
9685
9686 SKIP_BLANKS;
9687 }
9688}
9689
9690/**
9691 * xmlXPathCompUnaryExpr:
9692 * @ctxt: the XPath Parser context
9693 *
9694 * [27] UnaryExpr ::= UnionExpr
9695 * | '-' UnaryExpr
9696 *
9697 * Compile an unary expression.
9698 */
9699
9700static void
9701xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
9702 int minus = 0;
9703 int found = 0;
9704
9705 SKIP_BLANKS;
9706 while (CUR == '-') {
9707 minus = 1 - minus;
9708 found = 1;
9709 NEXT;
9710 SKIP_BLANKS;
9711 }
9712
9713 xmlXPathCompUnionExpr(ctxt);
9714 CHECK_ERROR;
9715 if (found) {
9716 if (minus)
9717 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
9718 else
9719 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
9720 }
9721}
9722
9723/**
9724 * xmlXPathCompMultiplicativeExpr:
9725 * @ctxt: the XPath Parser context
9726 *
9727 * [26] MultiplicativeExpr ::= UnaryExpr
9728 * | MultiplicativeExpr MultiplyOperator UnaryExpr
9729 * | MultiplicativeExpr 'div' UnaryExpr
9730 * | MultiplicativeExpr 'mod' UnaryExpr
9731 * [34] MultiplyOperator ::= '*'
9732 *
9733 * Compile an Additive expression.
9734 */
9735
9736static void
9737xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
9738 xmlXPathCompUnaryExpr(ctxt);
9739 CHECK_ERROR;
9740 SKIP_BLANKS;
9741 while ((CUR == '*') ||
9742 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
9743 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
9744 int op = -1;
9745 int op1 = ctxt->comp->last;
9746
9747 if (CUR == '*') {
9748 op = 0;
9749 NEXT;
9750 } else if (CUR == 'd') {
9751 op = 1;
9752 SKIP(3);
9753 } else if (CUR == 'm') {
9754 op = 2;
9755 SKIP(3);
9756 }
9757 SKIP_BLANKS;
9758 xmlXPathCompUnaryExpr(ctxt);
9759 CHECK_ERROR;
9760 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
9761 SKIP_BLANKS;
9762 }
9763}
9764
9765/**
9766 * xmlXPathCompAdditiveExpr:
9767 * @ctxt: the XPath Parser context
9768 *
9769 * [25] AdditiveExpr ::= MultiplicativeExpr
9770 * | AdditiveExpr '+' MultiplicativeExpr
9771 * | AdditiveExpr '-' MultiplicativeExpr
9772 *
9773 * Compile an Additive expression.
9774 */
9775
9776static void
9777xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
9778
9779 xmlXPathCompMultiplicativeExpr(ctxt);
9780 CHECK_ERROR;
9781 SKIP_BLANKS;
9782 while ((CUR == '+') || (CUR == '-')) {
9783 int plus;
9784 int op1 = ctxt->comp->last;
9785
9786 if (CUR == '+') plus = 1;
9787 else plus = 0;
9788 NEXT;
9789 SKIP_BLANKS;
9790 xmlXPathCompMultiplicativeExpr(ctxt);
9791 CHECK_ERROR;
9792 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
9793 SKIP_BLANKS;
9794 }
9795}
9796
9797/**
9798 * xmlXPathCompRelationalExpr:
9799 * @ctxt: the XPath Parser context
9800 *
9801 * [24] RelationalExpr ::= AdditiveExpr
9802 * | RelationalExpr '<' AdditiveExpr
9803 * | RelationalExpr '>' AdditiveExpr
9804 * | RelationalExpr '<=' AdditiveExpr
9805 * | RelationalExpr '>=' AdditiveExpr
9806 *
9807 * A <= B > C is allowed ? Answer from James, yes with
9808 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
9809 * which is basically what got implemented.
9810 *
9811 * Compile a Relational expression, then push the result
9812 * on the stack
9813 */
9814
9815static void
9816xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
9817 xmlXPathCompAdditiveExpr(ctxt);
9818 CHECK_ERROR;
9819 SKIP_BLANKS;
9820 while ((CUR == '<') || (CUR == '>')) {
9821 int inf, strict;
9822 int op1 = ctxt->comp->last;
9823
9824 if (CUR == '<') inf = 1;
9825 else inf = 0;
9826 if (NXT(1) == '=') strict = 0;
9827 else strict = 1;
9828 NEXT;
9829 if (!strict) NEXT;
9830 SKIP_BLANKS;
9831 xmlXPathCompAdditiveExpr(ctxt);
9832 CHECK_ERROR;
9833 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
9834 SKIP_BLANKS;
9835 }
9836}
9837
9838/**
9839 * xmlXPathCompEqualityExpr:
9840 * @ctxt: the XPath Parser context
9841 *
9842 * [23] EqualityExpr ::= RelationalExpr
9843 * | EqualityExpr '=' RelationalExpr
9844 * | EqualityExpr '!=' RelationalExpr
9845 *
9846 * A != B != C is allowed ? Answer from James, yes with
9847 * (RelationalExpr = RelationalExpr) = RelationalExpr
9848 * (RelationalExpr != RelationalExpr) != RelationalExpr
9849 * which is basically what got implemented.
9850 *
9851 * Compile an Equality expression.
9852 *
9853 */
9854static void
9855xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
9856 xmlXPathCompRelationalExpr(ctxt);
9857 CHECK_ERROR;
9858 SKIP_BLANKS;
9859 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
9860 int eq;
9861 int op1 = ctxt->comp->last;
9862
9863 if (CUR == '=') eq = 1;
9864 else eq = 0;
9865 NEXT;
9866 if (!eq) NEXT;
9867 SKIP_BLANKS;
9868 xmlXPathCompRelationalExpr(ctxt);
9869 CHECK_ERROR;
9870 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
9871 SKIP_BLANKS;
9872 }
9873}
9874
9875/**
9876 * xmlXPathCompAndExpr:
9877 * @ctxt: the XPath Parser context
9878 *
9879 * [22] AndExpr ::= EqualityExpr
9880 * | AndExpr 'and' EqualityExpr
9881 *
9882 * Compile an AND expression.
9883 *
9884 */
9885static void
9886xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
9887 xmlXPathCompEqualityExpr(ctxt);
9888 CHECK_ERROR;
9889 SKIP_BLANKS;
9890 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
9891 int op1 = ctxt->comp->last;
9892 SKIP(3);
9893 SKIP_BLANKS;
9894 xmlXPathCompEqualityExpr(ctxt);
9895 CHECK_ERROR;
9896 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
9897 SKIP_BLANKS;
9898 }
9899}
9900
9901/**
9902 * xmlXPathCompileExpr:
9903 * @ctxt: the XPath Parser context
9904 *
9905 * [14] Expr ::= OrExpr
9906 * [21] OrExpr ::= AndExpr
9907 * | OrExpr 'or' AndExpr
9908 *
9909 * Parse and compile an expression
9910 */
9911static void
9912xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
9913 xmlXPathContextPtr xpctxt = ctxt->context;
9914
9915 if (xpctxt != NULL) {
9916 if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
9917 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9918 /*
9919 * Parsing a single '(' pushes about 10 functions on the call stack
9920 * before recursing!
9921 */
9922 xpctxt->depth += 10;
9923 }
9924
9925 xmlXPathCompAndExpr(ctxt);
9926 CHECK_ERROR;
9927 SKIP_BLANKS;
9928 while ((CUR == 'o') && (NXT(1) == 'r')) {
9929 int op1 = ctxt->comp->last;
9930 SKIP(2);
9931 SKIP_BLANKS;
9932 xmlXPathCompAndExpr(ctxt);
9933 CHECK_ERROR;
9934 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
9935 SKIP_BLANKS;
9936 }
9937 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
9938 /* more ops could be optimized too */
9939 /*
9940 * This is the main place to eliminate sorting for
9941 * operations which don't require a sorted node-set.
9942 * E.g. count().
9943 */
9944 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
9945 }
9946
9947 if (xpctxt != NULL)
9948 xpctxt->depth -= 10;
9949}
9950
9951/**
9952 * xmlXPathCompPredicate:
9953 * @ctxt: the XPath Parser context
9954 * @filter: act as a filter
9955 *
9956 * [8] Predicate ::= '[' PredicateExpr ']'
9957 * [9] PredicateExpr ::= Expr
9958 *
9959 * Compile a predicate expression
9960 */
9961static void
9962xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
9963 int op1 = ctxt->comp->last;
9964
9965 SKIP_BLANKS;
9966 if (CUR != '[') {
9967 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9968 }
9969 NEXT;
9970 SKIP_BLANKS;
9971
9972 ctxt->comp->last = -1;
9973 /*
9974 * This call to xmlXPathCompileExpr() will deactivate sorting
9975 * of the predicate result.
9976 * TODO: Sorting is still activated for filters, since I'm not
9977 * sure if needed. Normally sorting should not be needed, since
9978 * a filter can only diminish the number of items in a sequence,
9979 * but won't change its order; so if the initial sequence is sorted,
9980 * subsequent sorting is not needed.
9981 */
9982 if (! filter)
9983 xmlXPathCompileExpr(ctxt, 0);
9984 else
9985 xmlXPathCompileExpr(ctxt, 1);
9986 CHECK_ERROR;
9987
9988 if (CUR != ']') {
9989 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9990 }
9991
9992 if (filter)
9993 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
9994 else
9995 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
9996
9997 NEXT;
9998 SKIP_BLANKS;
9999}
10000
10001/**
10002 * xmlXPathCompNodeTest:
10003 * @ctxt: the XPath Parser context
10004 * @test: pointer to a xmlXPathTestVal
10005 * @type: pointer to a xmlXPathTypeVal
10006 * @prefix: placeholder for a possible name prefix
10007 *
10008 * [7] NodeTest ::= NameTest
10009 * | NodeType '(' ')'
10010 * | 'processing-instruction' '(' Literal ')'
10011 *
10012 * [37] NameTest ::= '*'
10013 * | NCName ':' '*'
10014 * | QName
10015 * [38] NodeType ::= 'comment'
10016 * | 'text'
10017 * | 'processing-instruction'
10018 * | 'node'
10019 *
10020 * Returns the name found and updates @test, @type and @prefix appropriately
10021 */
10022static xmlChar *
10023xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10024 xmlXPathTypeVal *type, xmlChar **prefix,
10025 xmlChar *name) {
10026 int blanks;
10027
10028 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10029 return(NULL);
10030 }
10031 *type = (xmlXPathTypeVal) 0;
10032 *test = (xmlXPathTestVal) 0;
10033 *prefix = NULL;
10034 SKIP_BLANKS;
10035
10036 if ((name == NULL) && (CUR == '*')) {
10037 /*
10038 * All elements
10039 */
10040 NEXT;
10041 *test = NODE_TEST_ALL;
10042 return(NULL);
10043 }
10044
10045 if (name == NULL)
10046 name = xmlXPathParseNCName(ctxt);
10047 if (name == NULL) {
10048 XP_ERRORNULL(XPATH_EXPR_ERROR);
10049 }
10050
10051 blanks = IS_BLANK_CH(CUR);
10052 SKIP_BLANKS;
10053 if (CUR == '(') {
10054 NEXT;
10055 /*
10056 * NodeType or PI search
10057 */
10058 if (xmlStrEqual(name, BAD_CAST "comment"))
10059 *type = NODE_TYPE_COMMENT;
10060 else if (xmlStrEqual(name, BAD_CAST "node"))
10061 *type = NODE_TYPE_NODE;
10062 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10063 *type = NODE_TYPE_PI;
10064 else if (xmlStrEqual(name, BAD_CAST "text"))
10065 *type = NODE_TYPE_TEXT;
10066 else {
10067 if (name != NULL)
10068 xmlFree(name);
10069 XP_ERRORNULL(XPATH_EXPR_ERROR);
10070 }
10071
10072 *test = NODE_TEST_TYPE;
10073
10074 SKIP_BLANKS;
10075 if (*type == NODE_TYPE_PI) {
10076 /*
10077 * Specific case: search a PI by name.
10078 */
10079 if (name != NULL)
10080 xmlFree(name);
10081 name = NULL;
10082 if (CUR != ')') {
10083 name = xmlXPathParseLiteral(ctxt);
10084 *test = NODE_TEST_PI;
10085 SKIP_BLANKS;
10086 }
10087 }
10088 if (CUR != ')') {
10089 if (name != NULL)
10090 xmlFree(name);
10091 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
10092 }
10093 NEXT;
10094 return(name);
10095 }
10096 *test = NODE_TEST_NAME;
10097 if ((!blanks) && (CUR == ':')) {
10098 NEXT;
10099
10100 /*
10101 * Since currently the parser context don't have a
10102 * namespace list associated:
10103 * The namespace name for this prefix can be computed
10104 * only at evaluation time. The compilation is done
10105 * outside of any context.
10106 */
10107#if 0
10108 *prefix = xmlXPathNsLookup(ctxt->context, name);
10109 if (name != NULL)
10110 xmlFree(name);
10111 if (*prefix == NULL) {
10112 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10113 }
10114#else
10115 *prefix = name;
10116#endif
10117
10118 if (CUR == '*') {
10119 /*
10120 * All elements
10121 */
10122 NEXT;
10123 *test = NODE_TEST_ALL;
10124 return(NULL);
10125 }
10126
10127 name = xmlXPathParseNCName(ctxt);
10128 if (name == NULL) {
10129 XP_ERRORNULL(XPATH_EXPR_ERROR);
10130 }
10131 }
10132 return(name);
10133}
10134
10135/**
10136 * xmlXPathIsAxisName:
10137 * @name: a preparsed name token
10138 *
10139 * [6] AxisName ::= 'ancestor'
10140 * | 'ancestor-or-self'
10141 * | 'attribute'
10142 * | 'child'
10143 * | 'descendant'
10144 * | 'descendant-or-self'
10145 * | 'following'
10146 * | 'following-sibling'
10147 * | 'namespace'
10148 * | 'parent'
10149 * | 'preceding'
10150 * | 'preceding-sibling'
10151 * | 'self'
10152 *
10153 * Returns the axis or 0
10154 */
10155static xmlXPathAxisVal
10156xmlXPathIsAxisName(const xmlChar *name) {
10157 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
10158 switch (name[0]) {
10159 case 'a':
10160 if (xmlStrEqual(name, BAD_CAST "ancestor"))
10161 ret = AXIS_ANCESTOR;
10162 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
10163 ret = AXIS_ANCESTOR_OR_SELF;
10164 if (xmlStrEqual(name, BAD_CAST "attribute"))
10165 ret = AXIS_ATTRIBUTE;
10166 break;
10167 case 'c':
10168 if (xmlStrEqual(name, BAD_CAST "child"))
10169 ret = AXIS_CHILD;
10170 break;
10171 case 'd':
10172 if (xmlStrEqual(name, BAD_CAST "descendant"))
10173 ret = AXIS_DESCENDANT;
10174 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
10175 ret = AXIS_DESCENDANT_OR_SELF;
10176 break;
10177 case 'f':
10178 if (xmlStrEqual(name, BAD_CAST "following"))
10179 ret = AXIS_FOLLOWING;
10180 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
10181 ret = AXIS_FOLLOWING_SIBLING;
10182 break;
10183 case 'n':
10184 if (xmlStrEqual(name, BAD_CAST "namespace"))
10185 ret = AXIS_NAMESPACE;
10186 break;
10187 case 'p':
10188 if (xmlStrEqual(name, BAD_CAST "parent"))
10189 ret = AXIS_PARENT;
10190 if (xmlStrEqual(name, BAD_CAST "preceding"))
10191 ret = AXIS_PRECEDING;
10192 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
10193 ret = AXIS_PRECEDING_SIBLING;
10194 break;
10195 case 's':
10196 if (xmlStrEqual(name, BAD_CAST "self"))
10197 ret = AXIS_SELF;
10198 break;
10199 }
10200 return(ret);
10201}
10202
10203/**
10204 * xmlXPathCompStep:
10205 * @ctxt: the XPath Parser context
10206 *
10207 * [4] Step ::= AxisSpecifier NodeTest Predicate*
10208 * | AbbreviatedStep
10209 *
10210 * [12] AbbreviatedStep ::= '.' | '..'
10211 *
10212 * [5] AxisSpecifier ::= AxisName '::'
10213 * | AbbreviatedAxisSpecifier
10214 *
10215 * [13] AbbreviatedAxisSpecifier ::= '@'?
10216 *
10217 * Modified for XPtr range support as:
10218 *
10219 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
10220 * | AbbreviatedStep
10221 * | 'range-to' '(' Expr ')' Predicate*
10222 *
10223 * Compile one step in a Location Path
10224 * A location step of . is short for self::node(). This is
10225 * particularly useful in conjunction with //. For example, the
10226 * location path .//para is short for
10227 * self::node()/descendant-or-self::node()/child::para
10228 * and so will select all para descendant elements of the context
10229 * node.
10230 * Similarly, a location step of .. is short for parent::node().
10231 * For example, ../title is short for parent::node()/child::title
10232 * and so will select the title children of the parent of the context
10233 * node.
10234 */
10235static void
10236xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
10237#ifdef LIBXML_XPTR_LOCS_ENABLED
10238 int rangeto = 0;
10239 int op2 = -1;
10240#endif
10241
10242 SKIP_BLANKS;
10243 if ((CUR == '.') && (NXT(1) == '.')) {
10244 SKIP(2);
10245 SKIP_BLANKS;
10246 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
10247 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10248 } else if (CUR == '.') {
10249 NEXT;
10250 SKIP_BLANKS;
10251 } else {
10252 xmlChar *name = NULL;
10253 xmlChar *prefix = NULL;
10254 xmlXPathTestVal test = (xmlXPathTestVal) 0;
10255 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
10256 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
10257 int op1;
10258
10259 /*
10260 * The modification needed for XPointer change to the production
10261 */
10262#ifdef LIBXML_XPTR_LOCS_ENABLED
10263 if (ctxt->xptr) {
10264 name = xmlXPathParseNCName(ctxt);
10265 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
10266 op2 = ctxt->comp->last;
10267 xmlFree(name);
10268 SKIP_BLANKS;
10269 if (CUR != '(') {
10270 XP_ERROR(XPATH_EXPR_ERROR);
10271 }
10272 NEXT;
10273 SKIP_BLANKS;
10274
10275 xmlXPathCompileExpr(ctxt, 1);
10276 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
10277 CHECK_ERROR;
10278
10279 SKIP_BLANKS;
10280 if (CUR != ')') {
10281 XP_ERROR(XPATH_EXPR_ERROR);
10282 }
10283 NEXT;
10284 rangeto = 1;
10285 goto eval_predicates;
10286 }
10287 }
10288#endif
10289 if (CUR == '*') {
10290 axis = AXIS_CHILD;
10291 } else {
10292 if (name == NULL)
10293 name = xmlXPathParseNCName(ctxt);
10294 if (name != NULL) {
10295 axis = xmlXPathIsAxisName(name);
10296 if (axis != 0) {
10297 SKIP_BLANKS;
10298 if ((CUR == ':') && (NXT(1) == ':')) {
10299 SKIP(2);
10300 xmlFree(name);
10301 name = NULL;
10302 } else {
10303 /* an element name can conflict with an axis one :-\ */
10304 axis = AXIS_CHILD;
10305 }
10306 } else {
10307 axis = AXIS_CHILD;
10308 }
10309 } else if (CUR == '@') {
10310 NEXT;
10311 axis = AXIS_ATTRIBUTE;
10312 } else {
10313 axis = AXIS_CHILD;
10314 }
10315 }
10316
10317 if (ctxt->error != XPATH_EXPRESSION_OK) {
10318 xmlFree(name);
10319 return;
10320 }
10321
10322 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
10323 if (test == 0)
10324 return;
10325
10326 if ((prefix != NULL) && (ctxt->context != NULL) &&
10327 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
10328 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
10329 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
10330 }
10331 }
10332
10333#ifdef LIBXML_XPTR_LOCS_ENABLED
10334eval_predicates:
10335#endif
10336 op1 = ctxt->comp->last;
10337 ctxt->comp->last = -1;
10338
10339 SKIP_BLANKS;
10340 while (CUR == '[') {
10341 xmlXPathCompPredicate(ctxt, 0);
10342 }
10343
10344#ifdef LIBXML_XPTR_LOCS_ENABLED
10345 if (rangeto) {
10346 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
10347 } else
10348#endif
10349 if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
10350 test, type, (void *)prefix, (void *)name) == -1) {
10351 xmlFree(prefix);
10352 xmlFree(name);
10353 }
10354 }
10355}
10356
10357/**
10358 * xmlXPathCompRelativeLocationPath:
10359 * @ctxt: the XPath Parser context
10360 *
10361 * [3] RelativeLocationPath ::= Step
10362 * | RelativeLocationPath '/' Step
10363 * | AbbreviatedRelativeLocationPath
10364 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
10365 *
10366 * Compile a relative location path.
10367 */
10368static void
10369xmlXPathCompRelativeLocationPath
10370(xmlXPathParserContextPtr ctxt) {
10371 SKIP_BLANKS;
10372 if ((CUR == '/') && (NXT(1) == '/')) {
10373 SKIP(2);
10374 SKIP_BLANKS;
10375 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10376 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10377 } else if (CUR == '/') {
10378 NEXT;
10379 SKIP_BLANKS;
10380 }
10381 xmlXPathCompStep(ctxt);
10382 CHECK_ERROR;
10383 SKIP_BLANKS;
10384 while (CUR == '/') {
10385 if ((CUR == '/') && (NXT(1) == '/')) {
10386 SKIP(2);
10387 SKIP_BLANKS;
10388 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10389 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10390 xmlXPathCompStep(ctxt);
10391 } else if (CUR == '/') {
10392 NEXT;
10393 SKIP_BLANKS;
10394 xmlXPathCompStep(ctxt);
10395 }
10396 SKIP_BLANKS;
10397 }
10398}
10399
10400/**
10401 * xmlXPathCompLocationPath:
10402 * @ctxt: the XPath Parser context
10403 *
10404 * [1] LocationPath ::= RelativeLocationPath
10405 * | AbsoluteLocationPath
10406 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
10407 * | AbbreviatedAbsoluteLocationPath
10408 * [10] AbbreviatedAbsoluteLocationPath ::=
10409 * '//' RelativeLocationPath
10410 *
10411 * Compile a location path
10412 *
10413 * // is short for /descendant-or-self::node()/. For example,
10414 * //para is short for /descendant-or-self::node()/child::para and
10415 * so will select any para element in the document (even a para element
10416 * that is a document element will be selected by //para since the
10417 * document element node is a child of the root node); div//para is
10418 * short for div/descendant-or-self::node()/child::para and so will
10419 * select all para descendants of div children.
10420 */
10421static void
10422xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
10423 SKIP_BLANKS;
10424 if (CUR != '/') {
10425 xmlXPathCompRelativeLocationPath(ctxt);
10426 } else {
10427 while (CUR == '/') {
10428 if ((CUR == '/') && (NXT(1) == '/')) {
10429 SKIP(2);
10430 SKIP_BLANKS;
10431 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10432 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10433 xmlXPathCompRelativeLocationPath(ctxt);
10434 } else if (CUR == '/') {
10435 NEXT;
10436 SKIP_BLANKS;
10437 if ((CUR != 0 ) &&
10438 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
10439 (CUR == '@') || (CUR == '*')))
10440 xmlXPathCompRelativeLocationPath(ctxt);
10441 }
10442 CHECK_ERROR;
10443 }
10444 }
10445}
10446
10447/************************************************************************
10448 * *
10449 * XPath precompiled expression evaluation *
10450 * *
10451 ************************************************************************/
10452
10453static int
10454xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
10455
10456/**
10457 * xmlXPathNodeSetFilter:
10458 * @ctxt: the XPath Parser context
10459 * @set: the node set to filter
10460 * @filterOpIndex: the index of the predicate/filter op
10461 * @minPos: minimum position in the filtered set (1-based)
10462 * @maxPos: maximum position in the filtered set (1-based)
10463 * @hasNsNodes: true if the node set may contain namespace nodes
10464 *
10465 * Filter a node set, keeping only nodes for which the predicate expression
10466 * matches. Afterwards, keep only nodes between minPos and maxPos in the
10467 * filtered result.
10468 */
10469static void
10470xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
10471 xmlNodeSetPtr set,
10472 int filterOpIndex,
10473 int minPos, int maxPos,
10474 int hasNsNodes)
10475{
10476 xmlXPathContextPtr xpctxt;
10477 xmlNodePtr oldnode;
10478 xmlDocPtr olddoc;
10479 xmlXPathStepOpPtr filterOp;
10480 int oldcs, oldpp;
10481 int i, j, pos;
10482
10483 if ((set == NULL) || (set->nodeNr == 0))
10484 return;
10485
10486 /*
10487 * Check if the node set contains a sufficient number of nodes for
10488 * the requested range.
10489 */
10490 if (set->nodeNr < minPos) {
10491 xmlXPathNodeSetClear(set, hasNsNodes);
10492 return;
10493 }
10494
10495 xpctxt = ctxt->context;
10496 oldnode = xpctxt->node;
10497 olddoc = xpctxt->doc;
10498 oldcs = xpctxt->contextSize;
10499 oldpp = xpctxt->proximityPosition;
10500 filterOp = &ctxt->comp->steps[filterOpIndex];
10501
10502 xpctxt->contextSize = set->nodeNr;
10503
10504 for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
10505 xmlNodePtr node = set->nodeTab[i];
10506 int res;
10507
10508 xpctxt->node = node;
10509 xpctxt->proximityPosition = i + 1;
10510
10511 /*
10512 * Also set the xpath document in case things like
10513 * key() are evaluated in the predicate.
10514 *
10515 * TODO: Get real doc for namespace nodes.
10516 */
10517 if ((node->type != XML_NAMESPACE_DECL) &&
10518 (node->doc != NULL))
10519 xpctxt->doc = node->doc;
10520
10521 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
10522
10523 if (ctxt->error != XPATH_EXPRESSION_OK)
10524 break;
10525 if (res < 0) {
10526 /* Shouldn't happen */
10527 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
10528 break;
10529 }
10530
10531 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
10532 if (i != j) {
10533 set->nodeTab[j] = node;
10534 set->nodeTab[i] = NULL;
10535 }
10536
10537 j += 1;
10538 } else {
10539 /* Remove the entry from the initial node set. */
10540 set->nodeTab[i] = NULL;
10541 if (node->type == XML_NAMESPACE_DECL)
10542 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10543 }
10544
10545 if (res != 0) {
10546 if (pos == maxPos) {
10547 i += 1;
10548 break;
10549 }
10550
10551 pos += 1;
10552 }
10553 }
10554
10555 /* Free remaining nodes. */
10556 if (hasNsNodes) {
10557 for (; i < set->nodeNr; i++) {
10558 xmlNodePtr node = set->nodeTab[i];
10559 if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
10560 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10561 }
10562 }
10563
10564 set->nodeNr = j;
10565
10566 /* If too many elements were removed, shrink table to preserve memory. */
10567 if ((set->nodeMax > XML_NODESET_DEFAULT) &&
10568 (set->nodeNr < set->nodeMax / 2)) {
10569 xmlNodePtr *tmp;
10570 int nodeMax = set->nodeNr;
10571
10572 if (nodeMax < XML_NODESET_DEFAULT)
10573 nodeMax = XML_NODESET_DEFAULT;
10574 tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
10575 nodeMax * sizeof(xmlNodePtr));
10576 if (tmp == NULL) {
10577 xmlXPathPErrMemory(ctxt);
10578 } else {
10579 set->nodeTab = tmp;
10580 set->nodeMax = nodeMax;
10581 }
10582 }
10583
10584 xpctxt->node = oldnode;
10585 xpctxt->doc = olddoc;
10586 xpctxt->contextSize = oldcs;
10587 xpctxt->proximityPosition = oldpp;
10588}
10589
10590#ifdef LIBXML_XPTR_LOCS_ENABLED
10591/**
10592 * xmlXPathLocationSetFilter:
10593 * @ctxt: the XPath Parser context
10594 * @locset: the location set to filter
10595 * @filterOpIndex: the index of the predicate/filter op
10596 * @minPos: minimum position in the filtered set (1-based)
10597 * @maxPos: maximum position in the filtered set (1-based)
10598 *
10599 * Filter a location set, keeping only nodes for which the predicate
10600 * expression matches. Afterwards, keep only nodes between minPos and maxPos
10601 * in the filtered result.
10602 */
10603static void
10604xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
10605 xmlLocationSetPtr locset,
10606 int filterOpIndex,
10607 int minPos, int maxPos)
10608{
10609 xmlXPathContextPtr xpctxt;
10610 xmlNodePtr oldnode;
10611 xmlDocPtr olddoc;
10612 xmlXPathStepOpPtr filterOp;
10613 int oldcs, oldpp;
10614 int i, j, pos;
10615
10616 if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
10617 return;
10618
10619 xpctxt = ctxt->context;
10620 oldnode = xpctxt->node;
10621 olddoc = xpctxt->doc;
10622 oldcs = xpctxt->contextSize;
10623 oldpp = xpctxt->proximityPosition;
10624 filterOp = &ctxt->comp->steps[filterOpIndex];
10625
10626 xpctxt->contextSize = locset->locNr;
10627
10628 for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
10629 xmlNodePtr contextNode = locset->locTab[i]->user;
10630 int res;
10631
10632 xpctxt->node = contextNode;
10633 xpctxt->proximityPosition = i + 1;
10634
10635 /*
10636 * Also set the xpath document in case things like
10637 * key() are evaluated in the predicate.
10638 *
10639 * TODO: Get real doc for namespace nodes.
10640 */
10641 if ((contextNode->type != XML_NAMESPACE_DECL) &&
10642 (contextNode->doc != NULL))
10643 xpctxt->doc = contextNode->doc;
10644
10645 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
10646
10647 if (ctxt->error != XPATH_EXPRESSION_OK)
10648 break;
10649 if (res < 0) {
10650 /* Shouldn't happen */
10651 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
10652 break;
10653 }
10654
10655 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
10656 if (i != j) {
10657 locset->locTab[j] = locset->locTab[i];
10658 locset->locTab[i] = NULL;
10659 }
10660
10661 j += 1;
10662 } else {
10663 /* Remove the entry from the initial location set. */
10664 xmlXPathFreeObject(locset->locTab[i]);
10665 locset->locTab[i] = NULL;
10666 }
10667
10668 if (res != 0) {
10669 if (pos == maxPos) {
10670 i += 1;
10671 break;
10672 }
10673
10674 pos += 1;
10675 }
10676 }
10677
10678 /* Free remaining nodes. */
10679 for (; i < locset->locNr; i++)
10680 xmlXPathFreeObject(locset->locTab[i]);
10681
10682 locset->locNr = j;
10683
10684 /* If too many elements were removed, shrink table to preserve memory. */
10685 if ((locset->locMax > XML_NODESET_DEFAULT) &&
10686 (locset->locNr < locset->locMax / 2)) {
10687 xmlXPathObjectPtr *tmp;
10688 int locMax = locset->locNr;
10689
10690 if (locMax < XML_NODESET_DEFAULT)
10691 locMax = XML_NODESET_DEFAULT;
10692 tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
10693 locMax * sizeof(xmlXPathObjectPtr));
10694 if (tmp == NULL) {
10695 xmlXPathPErrMemory(ctxt);
10696 } else {
10697 locset->locTab = tmp;
10698 locset->locMax = locMax;
10699 }
10700 }
10701
10702 xpctxt->node = oldnode;
10703 xpctxt->doc = olddoc;
10704 xpctxt->contextSize = oldcs;
10705 xpctxt->proximityPosition = oldpp;
10706}
10707#endif /* LIBXML_XPTR_LOCS_ENABLED */
10708
10709/**
10710 * xmlXPathCompOpEvalPredicate:
10711 * @ctxt: the XPath Parser context
10712 * @op: the predicate op
10713 * @set: the node set to filter
10714 * @minPos: minimum position in the filtered set (1-based)
10715 * @maxPos: maximum position in the filtered set (1-based)
10716 * @hasNsNodes: true if the node set may contain namespace nodes
10717 *
10718 * Filter a node set, keeping only nodes for which the sequence of predicate
10719 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
10720 * in the filtered result.
10721 */
10722static void
10723xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
10724 xmlXPathStepOpPtr op,
10725 xmlNodeSetPtr set,
10726 int minPos, int maxPos,
10727 int hasNsNodes)
10728{
10729 if (op->ch1 != -1) {
10730 xmlXPathCompExprPtr comp = ctxt->comp;
10731 /*
10732 * Process inner predicates first.
10733 */
10734 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
10735 XP_ERROR(XPATH_INVALID_OPERAND);
10736 }
10737 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10738 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10739 ctxt->context->depth += 1;
10740 xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
10741 1, set->nodeNr, hasNsNodes);
10742 ctxt->context->depth -= 1;
10743 CHECK_ERROR;
10744 }
10745
10746 if (op->ch2 != -1)
10747 xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
10748}
10749
10750static int
10751xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
10752 xmlXPathStepOpPtr op,
10753 int *maxPos)
10754{
10755
10756 xmlXPathStepOpPtr exprOp;
10757
10758 /*
10759 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
10760 */
10761
10762 /*
10763 * If not -1, then ch1 will point to:
10764 * 1) For predicates (XPATH_OP_PREDICATE):
10765 * - an inner predicate operator
10766 * 2) For filters (XPATH_OP_FILTER):
10767 * - an inner filter operator OR
10768 * - an expression selecting the node set.
10769 * E.g. "key('a', 'b')" or "(//foo | //bar)".
10770 */
10771 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
10772 return(0);
10773
10774 if (op->ch2 != -1) {
10775 exprOp = &ctxt->comp->steps[op->ch2];
10776 } else
10777 return(0);
10778
10779 if ((exprOp != NULL) &&
10780 (exprOp->op == XPATH_OP_VALUE) &&
10781 (exprOp->value4 != NULL) &&
10782 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
10783 {
10784 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
10785
10786 /*
10787 * We have a "[n]" predicate here.
10788 * TODO: Unfortunately this simplistic test here is not
10789 * able to detect a position() predicate in compound
10790 * expressions like "[@attr = 'a" and position() = 1],
10791 * and even not the usage of position() in
10792 * "[position() = 1]"; thus - obviously - a position-range,
10793 * like it "[position() < 5]", is also not detected.
10794 * Maybe we could rewrite the AST to ease the optimization.
10795 */
10796
10797 if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
10798 *maxPos = (int) floatval;
10799 if (floatval == (double) *maxPos)
10800 return(1);
10801 }
10802 }
10803 return(0);
10804}
10805
10806static int
10807xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
10808 xmlXPathStepOpPtr op,
10809 xmlNodePtr * first, xmlNodePtr * last,
10810 int toBool)
10811{
10812
10813#define XP_TEST_HIT \
10814 if (hasAxisRange != 0) { \
10815 if (++pos == maxPos) { \
10816 if (addNode(seq, cur) < 0) \
10817 xmlXPathPErrMemory(ctxt); \
10818 goto axis_range_end; } \
10819 } else { \
10820 if (addNode(seq, cur) < 0) \
10821 xmlXPathPErrMemory(ctxt); \
10822 if (breakOnFirstHit) goto first_hit; }
10823
10824#define XP_TEST_HIT_NS \
10825 if (hasAxisRange != 0) { \
10826 if (++pos == maxPos) { \
10827 hasNsNodes = 1; \
10828 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
10829 xmlXPathPErrMemory(ctxt); \
10830 goto axis_range_end; } \
10831 } else { \
10832 hasNsNodes = 1; \
10833 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
10834 xmlXPathPErrMemory(ctxt); \
10835 if (breakOnFirstHit) goto first_hit; }
10836
10837 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
10838 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
10839 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
10840 const xmlChar *prefix = op->value4;
10841 const xmlChar *name = op->value5;
10842 const xmlChar *URI = NULL;
10843
10844 int total = 0, hasNsNodes = 0;
10845 /* The popped object holding the context nodes */
10846 xmlXPathObjectPtr obj;
10847 /* The set of context nodes for the node tests */
10848 xmlNodeSetPtr contextSeq;
10849 int contextIdx;
10850 xmlNodePtr contextNode;
10851 /* The final resulting node set wrt to all context nodes */
10852 xmlNodeSetPtr outSeq;
10853 /*
10854 * The temporary resulting node set wrt 1 context node.
10855 * Used to feed predicate evaluation.
10856 */
10857 xmlNodeSetPtr seq;
10858 xmlNodePtr cur;
10859 /* First predicate operator */
10860 xmlXPathStepOpPtr predOp;
10861 int maxPos; /* The requested position() (when a "[n]" predicate) */
10862 int hasPredicateRange, hasAxisRange, pos;
10863 int breakOnFirstHit;
10864
10865 xmlXPathTraversalFunction next = NULL;
10866 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
10867 xmlXPathNodeSetMergeFunction mergeAndClear;
10868 xmlNodePtr oldContextNode;
10869 xmlXPathContextPtr xpctxt = ctxt->context;
10870
10871
10872 CHECK_TYPE0(XPATH_NODESET);
10873 obj = valuePop(ctxt);
10874 /*
10875 * Setup namespaces.
10876 */
10877 if (prefix != NULL) {
10878 URI = xmlXPathNsLookup(xpctxt, prefix);
10879 if (URI == NULL) {
10880 xmlXPathReleaseObject(xpctxt, obj);
10881 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10882 }
10883 }
10884 /*
10885 * Setup axis.
10886 *
10887 * MAYBE FUTURE TODO: merging optimizations:
10888 * - If the nodes to be traversed wrt to the initial nodes and
10889 * the current axis cannot overlap, then we could avoid searching
10890 * for duplicates during the merge.
10891 * But the question is how/when to evaluate if they cannot overlap.
10892 * Example: if we know that for two initial nodes, the one is
10893 * not in the ancestor-or-self axis of the other, then we could safely
10894 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
10895 * the descendant-or-self axis.
10896 */
10897 mergeAndClear = xmlXPathNodeSetMergeAndClear;
10898 switch (axis) {
10899 case AXIS_ANCESTOR:
10900 first = NULL;
10901 next = xmlXPathNextAncestor;
10902 break;
10903 case AXIS_ANCESTOR_OR_SELF:
10904 first = NULL;
10905 next = xmlXPathNextAncestorOrSelf;
10906 break;
10907 case AXIS_ATTRIBUTE:
10908 first = NULL;
10909 last = NULL;
10910 next = xmlXPathNextAttribute;
10911 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10912 break;
10913 case AXIS_CHILD:
10914 last = NULL;
10915 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
10916 (type == NODE_TYPE_NODE))
10917 {
10918 /*
10919 * Optimization if an element node type is 'element'.
10920 */
10921 next = xmlXPathNextChildElement;
10922 } else
10923 next = xmlXPathNextChild;
10924 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10925 break;
10926 case AXIS_DESCENDANT:
10927 last = NULL;
10928 next = xmlXPathNextDescendant;
10929 break;
10930 case AXIS_DESCENDANT_OR_SELF:
10931 last = NULL;
10932 next = xmlXPathNextDescendantOrSelf;
10933 break;
10934 case AXIS_FOLLOWING:
10935 last = NULL;
10936 next = xmlXPathNextFollowing;
10937 break;
10938 case AXIS_FOLLOWING_SIBLING:
10939 last = NULL;
10940 next = xmlXPathNextFollowingSibling;
10941 break;
10942 case AXIS_NAMESPACE:
10943 first = NULL;
10944 last = NULL;
10945 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
10946 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10947 break;
10948 case AXIS_PARENT:
10949 first = NULL;
10950 next = xmlXPathNextParent;
10951 break;
10952 case AXIS_PRECEDING:
10953 first = NULL;
10954 next = xmlXPathNextPrecedingInternal;
10955 break;
10956 case AXIS_PRECEDING_SIBLING:
10957 first = NULL;
10958 next = xmlXPathNextPrecedingSibling;
10959 break;
10960 case AXIS_SELF:
10961 first = NULL;
10962 last = NULL;
10963 next = xmlXPathNextSelf;
10964 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10965 break;
10966 }
10967
10968 if (next == NULL) {
10969 xmlXPathReleaseObject(xpctxt, obj);
10970 return(0);
10971 }
10972 contextSeq = obj->nodesetval;
10973 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
10974 valuePush(ctxt, obj);
10975 return(0);
10976 }
10977 /*
10978 * Predicate optimization ---------------------------------------------
10979 * If this step has a last predicate, which contains a position(),
10980 * then we'll optimize (although not exactly "position()", but only
10981 * the short-hand form, i.e., "[n]".
10982 *
10983 * Example - expression "/foo[parent::bar][1]":
10984 *
10985 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
10986 * ROOT -- op->ch1
10987 * PREDICATE -- op->ch2 (predOp)
10988 * PREDICATE -- predOp->ch1 = [parent::bar]
10989 * SORT
10990 * COLLECT 'parent' 'name' 'node' bar
10991 * NODE
10992 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
10993 *
10994 */
10995 maxPos = 0;
10996 predOp = NULL;
10997 hasPredicateRange = 0;
10998 hasAxisRange = 0;
10999 if (op->ch2 != -1) {
11000 /*
11001 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
11002 */
11003 predOp = &ctxt->comp->steps[op->ch2];
11004 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
11005 if (predOp->ch1 != -1) {
11006 /*
11007 * Use the next inner predicate operator.
11008 */
11009 predOp = &ctxt->comp->steps[predOp->ch1];
11010 hasPredicateRange = 1;
11011 } else {
11012 /*
11013 * There's no other predicate than the [n] predicate.
11014 */
11015 predOp = NULL;
11016 hasAxisRange = 1;
11017 }
11018 }
11019 }
11020 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
11021 /*
11022 * Axis traversal -----------------------------------------------------
11023 */
11024 /*
11025 * 2.3 Node Tests
11026 * - For the attribute axis, the principal node type is attribute.
11027 * - For the namespace axis, the principal node type is namespace.
11028 * - For other axes, the principal node type is element.
11029 *
11030 * A node test * is true for any node of the
11031 * principal node type. For example, child::* will
11032 * select all element children of the context node
11033 */
11034 oldContextNode = xpctxt->node;
11035 addNode = xmlXPathNodeSetAddUnique;
11036 outSeq = NULL;
11037 seq = NULL;
11038 contextNode = NULL;
11039 contextIdx = 0;
11040
11041
11042 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
11043 (ctxt->error == XPATH_EXPRESSION_OK)) {
11044 xpctxt->node = contextSeq->nodeTab[contextIdx++];
11045
11046 if (seq == NULL) {
11047 seq = xmlXPathNodeSetCreate(NULL);
11048 if (seq == NULL) {
11049 xmlXPathPErrMemory(ctxt);
11050 total = 0;
11051 goto error;
11052 }
11053 }
11054 /*
11055 * Traverse the axis and test the nodes.
11056 */
11057 pos = 0;
11058 cur = NULL;
11059 hasNsNodes = 0;
11060 do {
11061 if (OP_LIMIT_EXCEEDED(ctxt, 1))
11062 goto error;
11063
11064 cur = next(ctxt, cur);
11065 if (cur == NULL)
11066 break;
11067
11068 /*
11069 * QUESTION TODO: What does the "first" and "last" stuff do?
11070 */
11071 if ((first != NULL) && (*first != NULL)) {
11072 if (*first == cur)
11073 break;
11074 if (((total % 256) == 0) &&
11075#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11076 (xmlXPathCmpNodesExt(*first, cur) >= 0))
11077#else
11078 (xmlXPathCmpNodes(*first, cur) >= 0))
11079#endif
11080 {
11081 break;
11082 }
11083 }
11084 if ((last != NULL) && (*last != NULL)) {
11085 if (*last == cur)
11086 break;
11087 if (((total % 256) == 0) &&
11088#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11089 (xmlXPathCmpNodesExt(cur, *last) >= 0))
11090#else
11091 (xmlXPathCmpNodes(cur, *last) >= 0))
11092#endif
11093 {
11094 break;
11095 }
11096 }
11097
11098 total++;
11099
11100 switch (test) {
11101 case NODE_TEST_NONE:
11102 total = 0;
11103 goto error;
11104 case NODE_TEST_TYPE:
11105 if (type == NODE_TYPE_NODE) {
11106 switch (cur->type) {
11107 case XML_DOCUMENT_NODE:
11108 case XML_HTML_DOCUMENT_NODE:
11109 case XML_ELEMENT_NODE:
11110 case XML_ATTRIBUTE_NODE:
11111 case XML_PI_NODE:
11112 case XML_COMMENT_NODE:
11113 case XML_CDATA_SECTION_NODE:
11114 case XML_TEXT_NODE:
11115 XP_TEST_HIT
11116 break;
11117 case XML_NAMESPACE_DECL: {
11118 if (axis == AXIS_NAMESPACE) {
11119 XP_TEST_HIT_NS
11120 } else {
11121 hasNsNodes = 1;
11122 XP_TEST_HIT
11123 }
11124 break;
11125 }
11126 default:
11127 break;
11128 }
11129 } else if (cur->type == (xmlElementType) type) {
11130 if (cur->type == XML_NAMESPACE_DECL)
11131 XP_TEST_HIT_NS
11132 else
11133 XP_TEST_HIT
11134 } else if ((type == NODE_TYPE_TEXT) &&
11135 (cur->type == XML_CDATA_SECTION_NODE))
11136 {
11137 XP_TEST_HIT
11138 }
11139 break;
11140 case NODE_TEST_PI:
11141 if ((cur->type == XML_PI_NODE) &&
11142 ((name == NULL) || xmlStrEqual(name, cur->name)))
11143 {
11144 XP_TEST_HIT
11145 }
11146 break;
11147 case NODE_TEST_ALL:
11148 if (axis == AXIS_ATTRIBUTE) {
11149 if (cur->type == XML_ATTRIBUTE_NODE)
11150 {
11151 if (prefix == NULL)
11152 {
11153 XP_TEST_HIT
11154 } else if ((cur->ns != NULL) &&
11155 (xmlStrEqual(URI, cur->ns->href)))
11156 {
11157 XP_TEST_HIT
11158 }
11159 }
11160 } else if (axis == AXIS_NAMESPACE) {
11161 if (cur->type == XML_NAMESPACE_DECL)
11162 {
11163 XP_TEST_HIT_NS
11164 }
11165 } else {
11166 if (cur->type == XML_ELEMENT_NODE) {
11167 if (prefix == NULL)
11168 {
11169 XP_TEST_HIT
11170
11171 } else if ((cur->ns != NULL) &&
11172 (xmlStrEqual(URI, cur->ns->href)))
11173 {
11174 XP_TEST_HIT
11175 }
11176 }
11177 }
11178 break;
11179 case NODE_TEST_NS:{
11180 /* TODO */
11181 break;
11182 }
11183 case NODE_TEST_NAME:
11184 if (axis == AXIS_ATTRIBUTE) {
11185 if (cur->type != XML_ATTRIBUTE_NODE)
11186 break;
11187 } else if (axis == AXIS_NAMESPACE) {
11188 if (cur->type != XML_NAMESPACE_DECL)
11189 break;
11190 } else {
11191 if (cur->type != XML_ELEMENT_NODE)
11192 break;
11193 }
11194 switch (cur->type) {
11195 case XML_ELEMENT_NODE:
11196 if (xmlStrEqual(name, cur->name)) {
11197 if (prefix == NULL) {
11198 if (cur->ns == NULL)
11199 {
11200 XP_TEST_HIT
11201 }
11202 } else {
11203 if ((cur->ns != NULL) &&
11204 (xmlStrEqual(URI, cur->ns->href)))
11205 {
11206 XP_TEST_HIT
11207 }
11208 }
11209 }
11210 break;
11211 case XML_ATTRIBUTE_NODE:{
11212 xmlAttrPtr attr = (xmlAttrPtr) cur;
11213
11214 if (xmlStrEqual(name, attr->name)) {
11215 if (prefix == NULL) {
11216 if ((attr->ns == NULL) ||
11217 (attr->ns->prefix == NULL))
11218 {
11219 XP_TEST_HIT
11220 }
11221 } else {
11222 if ((attr->ns != NULL) &&
11223 (xmlStrEqual(URI,
11224 attr->ns->href)))
11225 {
11226 XP_TEST_HIT
11227 }
11228 }
11229 }
11230 break;
11231 }
11232 case XML_NAMESPACE_DECL:
11233 if (cur->type == XML_NAMESPACE_DECL) {
11234 xmlNsPtr ns = (xmlNsPtr) cur;
11235
11236 if ((ns->prefix != NULL) && (name != NULL)
11237 && (xmlStrEqual(ns->prefix, name)))
11238 {
11239 XP_TEST_HIT_NS
11240 }
11241 }
11242 break;
11243 default:
11244 break;
11245 }
11246 break;
11247 } /* switch(test) */
11248 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
11249
11250 goto apply_predicates;
11251
11252axis_range_end: /* ----------------------------------------------------- */
11253 /*
11254 * We have a "/foo[n]", and position() = n was reached.
11255 * Note that we can have as well "/foo/::parent::foo[1]", so
11256 * a duplicate-aware merge is still needed.
11257 * Merge with the result.
11258 */
11259 if (outSeq == NULL) {
11260 outSeq = seq;
11261 seq = NULL;
11262 } else {
11263 outSeq = mergeAndClear(outSeq, seq);
11264 if (outSeq == NULL)
11265 xmlXPathPErrMemory(ctxt);
11266 }
11267 /*
11268 * Break if only a true/false result was requested.
11269 */
11270 if (toBool)
11271 break;
11272 continue;
11273
11274first_hit: /* ---------------------------------------------------------- */
11275 /*
11276 * Break if only a true/false result was requested and
11277 * no predicates existed and a node test succeeded.
11278 */
11279 if (outSeq == NULL) {
11280 outSeq = seq;
11281 seq = NULL;
11282 } else {
11283 outSeq = mergeAndClear(outSeq, seq);
11284 if (outSeq == NULL)
11285 xmlXPathPErrMemory(ctxt);
11286 }
11287 break;
11288
11289apply_predicates: /* --------------------------------------------------- */
11290 if (ctxt->error != XPATH_EXPRESSION_OK)
11291 goto error;
11292
11293 /*
11294 * Apply predicates.
11295 */
11296 if ((predOp != NULL) && (seq->nodeNr > 0)) {
11297 /*
11298 * E.g. when we have a "/foo[some expression][n]".
11299 */
11300 /*
11301 * QUESTION TODO: The old predicate evaluation took into
11302 * account location-sets.
11303 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
11304 * Do we expect such a set here?
11305 * All what I learned now from the evaluation semantics
11306 * does not indicate that a location-set will be processed
11307 * here, so this looks OK.
11308 */
11309 /*
11310 * Iterate over all predicates, starting with the outermost
11311 * predicate.
11312 * TODO: Problem: we cannot execute the inner predicates first
11313 * since we cannot go back *up* the operator tree!
11314 * Options we have:
11315 * 1) Use of recursive functions (like is it currently done
11316 * via xmlXPathCompOpEval())
11317 * 2) Add a predicate evaluation information stack to the
11318 * context struct
11319 * 3) Change the way the operators are linked; we need a
11320 * "parent" field on xmlXPathStepOp
11321 *
11322 * For the moment, I'll try to solve this with a recursive
11323 * function: xmlXPathCompOpEvalPredicate().
11324 */
11325 if (hasPredicateRange != 0)
11326 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
11327 hasNsNodes);
11328 else
11329 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
11330 hasNsNodes);
11331
11332 if (ctxt->error != XPATH_EXPRESSION_OK) {
11333 total = 0;
11334 goto error;
11335 }
11336 }
11337
11338 if (seq->nodeNr > 0) {
11339 /*
11340 * Add to result set.
11341 */
11342 if (outSeq == NULL) {
11343 outSeq = seq;
11344 seq = NULL;
11345 } else {
11346 outSeq = mergeAndClear(outSeq, seq);
11347 if (outSeq == NULL)
11348 xmlXPathPErrMemory(ctxt);
11349 }
11350
11351 if (toBool)
11352 break;
11353 }
11354 }
11355
11356error:
11357 if ((obj->boolval) && (obj->user != NULL)) {
11358 /*
11359 * QUESTION TODO: What does this do and why?
11360 * TODO: Do we have to do this also for the "error"
11361 * cleanup further down?
11362 */
11363 ctxt->value->boolval = 1;
11364 ctxt->value->user = obj->user;
11365 obj->user = NULL;
11366 obj->boolval = 0;
11367 }
11368 xmlXPathReleaseObject(xpctxt, obj);
11369
11370 /*
11371 * Ensure we return at least an empty set.
11372 */
11373 if (outSeq == NULL) {
11374 if ((seq != NULL) && (seq->nodeNr == 0)) {
11375 outSeq = seq;
11376 } else {
11377 outSeq = xmlXPathNodeSetCreate(NULL);
11378 if (outSeq == NULL)
11379 xmlXPathPErrMemory(ctxt);
11380 }
11381 }
11382 if ((seq != NULL) && (seq != outSeq)) {
11383 xmlXPathFreeNodeSet(seq);
11384 }
11385 /*
11386 * Hand over the result. Better to push the set also in
11387 * case of errors.
11388 */
11389 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, outSeq));
11390 /*
11391 * Reset the context node.
11392 */
11393 xpctxt->node = oldContextNode;
11394 /*
11395 * When traversing the namespace axis in "toBool" mode, it's
11396 * possible that tmpNsList wasn't freed.
11397 */
11398 if (xpctxt->tmpNsList != NULL) {
11399 xmlFree(xpctxt->tmpNsList);
11400 xpctxt->tmpNsList = NULL;
11401 }
11402
11403 return(total);
11404}
11405
11406static int
11407xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11408 xmlXPathStepOpPtr op, xmlNodePtr * first);
11409
11410/**
11411 * xmlXPathCompOpEvalFirst:
11412 * @ctxt: the XPath parser context with the compiled expression
11413 * @op: an XPath compiled operation
11414 * @first: the first elem found so far
11415 *
11416 * Evaluate the Precompiled XPath operation searching only the first
11417 * element in document order
11418 *
11419 * Returns the number of examined objects.
11420 */
11421static int
11422xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
11423 xmlXPathStepOpPtr op, xmlNodePtr * first)
11424{
11425 int total = 0, cur;
11426 xmlXPathCompExprPtr comp;
11427 xmlXPathObjectPtr arg1, arg2;
11428
11429 CHECK_ERROR0;
11430 if (OP_LIMIT_EXCEEDED(ctxt, 1))
11431 return(0);
11432 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11433 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11434 ctxt->context->depth += 1;
11435 comp = ctxt->comp;
11436 switch (op->op) {
11437 case XPATH_OP_END:
11438 break;
11439 case XPATH_OP_UNION:
11440 total =
11441 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11442 first);
11443 CHECK_ERROR0;
11444 if ((ctxt->value != NULL)
11445 && (ctxt->value->type == XPATH_NODESET)
11446 && (ctxt->value->nodesetval != NULL)
11447 && (ctxt->value->nodesetval->nodeNr >= 1)) {
11448 /*
11449 * limit tree traversing to first node in the result
11450 */
11451 /*
11452 * OPTIMIZE TODO: This implicitly sorts
11453 * the result, even if not needed. E.g. if the argument
11454 * of the count() function, no sorting is needed.
11455 * OPTIMIZE TODO: How do we know if the node-list wasn't
11456 * already sorted?
11457 */
11458 if (ctxt->value->nodesetval->nodeNr > 1)
11459 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11460 *first = ctxt->value->nodesetval->nodeTab[0];
11461 }
11462 cur =
11463 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
11464 first);
11465 CHECK_ERROR0;
11466
11467 arg2 = valuePop(ctxt);
11468 arg1 = valuePop(ctxt);
11469 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11470 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11471 xmlXPathReleaseObject(ctxt->context, arg1);
11472 xmlXPathReleaseObject(ctxt->context, arg2);
11473 XP_ERROR0(XPATH_INVALID_TYPE);
11474 }
11475 if ((ctxt->context->opLimit != 0) &&
11476 (((arg1->nodesetval != NULL) &&
11477 (xmlXPathCheckOpLimit(ctxt,
11478 arg1->nodesetval->nodeNr) < 0)) ||
11479 ((arg2->nodesetval != NULL) &&
11480 (xmlXPathCheckOpLimit(ctxt,
11481 arg2->nodesetval->nodeNr) < 0)))) {
11482 xmlXPathReleaseObject(ctxt->context, arg1);
11483 xmlXPathReleaseObject(ctxt->context, arg2);
11484 break;
11485 }
11486
11487 if ((arg2->nodesetval != NULL) &&
11488 (arg2->nodesetval->nodeNr != 0)) {
11489 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11490 arg2->nodesetval);
11491 if (arg1->nodesetval == NULL)
11492 xmlXPathPErrMemory(ctxt);
11493 }
11494 valuePush(ctxt, arg1);
11495 xmlXPathReleaseObject(ctxt->context, arg2);
11496 /* optimizer */
11497 if (total > cur)
11498 xmlXPathCompSwap(op);
11499 total += cur;
11500 break;
11501 case XPATH_OP_ROOT:
11502 xmlXPathRoot(ctxt);
11503 break;
11504 case XPATH_OP_NODE:
11505 if (op->ch1 != -1)
11506 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11507 CHECK_ERROR0;
11508 if (op->ch2 != -1)
11509 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11510 CHECK_ERROR0;
11511 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11512 ctxt->context->node));
11513 break;
11514 case XPATH_OP_COLLECT:{
11515 if (op->ch1 == -1)
11516 break;
11517
11518 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11519 CHECK_ERROR0;
11520
11521 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
11522 break;
11523 }
11524 case XPATH_OP_VALUE:
11525 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11526 break;
11527 case XPATH_OP_SORT:
11528 if (op->ch1 != -1)
11529 total +=
11530 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11531 first);
11532 CHECK_ERROR0;
11533 if ((ctxt->value != NULL)
11534 && (ctxt->value->type == XPATH_NODESET)
11535 && (ctxt->value->nodesetval != NULL)
11536 && (ctxt->value->nodesetval->nodeNr > 1))
11537 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11538 break;
11539#ifdef XP_OPTIMIZED_FILTER_FIRST
11540 case XPATH_OP_FILTER:
11541 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
11542 break;
11543#endif
11544 default:
11545 total += xmlXPathCompOpEval(ctxt, op);
11546 break;
11547 }
11548
11549 ctxt->context->depth -= 1;
11550 return(total);
11551}
11552
11553/**
11554 * xmlXPathCompOpEvalLast:
11555 * @ctxt: the XPath parser context with the compiled expression
11556 * @op: an XPath compiled operation
11557 * @last: the last elem found so far
11558 *
11559 * Evaluate the Precompiled XPath operation searching only the last
11560 * element in document order
11561 *
11562 * Returns the number of nodes traversed
11563 */
11564static int
11565xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
11566 xmlNodePtr * last)
11567{
11568 int total = 0, cur;
11569 xmlXPathCompExprPtr comp;
11570 xmlXPathObjectPtr arg1, arg2;
11571
11572 CHECK_ERROR0;
11573 if (OP_LIMIT_EXCEEDED(ctxt, 1))
11574 return(0);
11575 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11576 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11577 ctxt->context->depth += 1;
11578 comp = ctxt->comp;
11579 switch (op->op) {
11580 case XPATH_OP_END:
11581 break;
11582 case XPATH_OP_UNION:
11583 total =
11584 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
11585 CHECK_ERROR0;
11586 if ((ctxt->value != NULL)
11587 && (ctxt->value->type == XPATH_NODESET)
11588 && (ctxt->value->nodesetval != NULL)
11589 && (ctxt->value->nodesetval->nodeNr >= 1)) {
11590 /*
11591 * limit tree traversing to first node in the result
11592 */
11593 if (ctxt->value->nodesetval->nodeNr > 1)
11594 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11595 *last =
11596 ctxt->value->nodesetval->nodeTab[ctxt->value->
11597 nodesetval->nodeNr -
11598 1];
11599 }
11600 cur =
11601 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
11602 CHECK_ERROR0;
11603 if ((ctxt->value != NULL)
11604 && (ctxt->value->type == XPATH_NODESET)
11605 && (ctxt->value->nodesetval != NULL)
11606 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
11607 }
11608
11609 arg2 = valuePop(ctxt);
11610 arg1 = valuePop(ctxt);
11611 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11612 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11613 xmlXPathReleaseObject(ctxt->context, arg1);
11614 xmlXPathReleaseObject(ctxt->context, arg2);
11615 XP_ERROR0(XPATH_INVALID_TYPE);
11616 }
11617 if ((ctxt->context->opLimit != 0) &&
11618 (((arg1->nodesetval != NULL) &&
11619 (xmlXPathCheckOpLimit(ctxt,
11620 arg1->nodesetval->nodeNr) < 0)) ||
11621 ((arg2->nodesetval != NULL) &&
11622 (xmlXPathCheckOpLimit(ctxt,
11623 arg2->nodesetval->nodeNr) < 0)))) {
11624 xmlXPathReleaseObject(ctxt->context, arg1);
11625 xmlXPathReleaseObject(ctxt->context, arg2);
11626 break;
11627 }
11628
11629 if ((arg2->nodesetval != NULL) &&
11630 (arg2->nodesetval->nodeNr != 0)) {
11631 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11632 arg2->nodesetval);
11633 if (arg1->nodesetval == NULL)
11634 xmlXPathPErrMemory(ctxt);
11635 }
11636 valuePush(ctxt, arg1);
11637 xmlXPathReleaseObject(ctxt->context, arg2);
11638 /* optimizer */
11639 if (total > cur)
11640 xmlXPathCompSwap(op);
11641 total += cur;
11642 break;
11643 case XPATH_OP_ROOT:
11644 xmlXPathRoot(ctxt);
11645 break;
11646 case XPATH_OP_NODE:
11647 if (op->ch1 != -1)
11648 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11649 CHECK_ERROR0;
11650 if (op->ch2 != -1)
11651 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11652 CHECK_ERROR0;
11653 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11654 ctxt->context->node));
11655 break;
11656 case XPATH_OP_COLLECT:{
11657 if (op->ch1 == -1)
11658 break;
11659
11660 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11661 CHECK_ERROR0;
11662
11663 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
11664 break;
11665 }
11666 case XPATH_OP_VALUE:
11667 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11668 break;
11669 case XPATH_OP_SORT:
11670 if (op->ch1 != -1)
11671 total +=
11672 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
11673 last);
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 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11680 break;
11681 default:
11682 total += xmlXPathCompOpEval(ctxt, op);
11683 break;
11684 }
11685
11686 ctxt->context->depth -= 1;
11687 return (total);
11688}
11689
11690#ifdef XP_OPTIMIZED_FILTER_FIRST
11691static int
11692xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11693 xmlXPathStepOpPtr op, xmlNodePtr * first)
11694{
11695 int total = 0;
11696 xmlXPathCompExprPtr comp;
11697 xmlXPathObjectPtr obj;
11698 xmlNodeSetPtr set;
11699
11700 CHECK_ERROR0;
11701 comp = ctxt->comp;
11702 /*
11703 * Optimization for ()[last()] selection i.e. the last elem
11704 */
11705 if ((op->ch1 != -1) && (op->ch2 != -1) &&
11706 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11707 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11708 int f = comp->steps[op->ch2].ch1;
11709
11710 if ((f != -1) &&
11711 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11712 (comp->steps[f].value5 == NULL) &&
11713 (comp->steps[f].value == 0) &&
11714 (comp->steps[f].value4 != NULL) &&
11715 (xmlStrEqual
11716 (comp->steps[f].value4, BAD_CAST "last"))) {
11717 xmlNodePtr last = NULL;
11718
11719 total +=
11720 xmlXPathCompOpEvalLast(ctxt,
11721 &comp->steps[op->ch1],
11722 &last);
11723 CHECK_ERROR0;
11724 /*
11725 * The nodeset should be in document order,
11726 * Keep only the last value
11727 */
11728 if ((ctxt->value != NULL) &&
11729 (ctxt->value->type == XPATH_NODESET) &&
11730 (ctxt->value->nodesetval != NULL) &&
11731 (ctxt->value->nodesetval->nodeTab != NULL) &&
11732 (ctxt->value->nodesetval->nodeNr > 1)) {
11733 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11734 *first = *(ctxt->value->nodesetval->nodeTab);
11735 }
11736 return (total);
11737 }
11738 }
11739
11740 if (op->ch1 != -1)
11741 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11742 CHECK_ERROR0;
11743 if (op->ch2 == -1)
11744 return (total);
11745 if (ctxt->value == NULL)
11746 return (total);
11747
11748#ifdef LIBXML_XPTR_LOCS_ENABLED
11749 /*
11750 * Hum are we filtering the result of an XPointer expression
11751 */
11752 if (ctxt->value->type == XPATH_LOCATIONSET) {
11753 xmlLocationSetPtr locset = ctxt->value->user;
11754
11755 if (locset != NULL) {
11756 xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
11757 if (locset->locNr > 0)
11758 *first = (xmlNodePtr) locset->locTab[0]->user;
11759 }
11760
11761 return (total);
11762 }
11763#endif /* LIBXML_XPTR_LOCS_ENABLED */
11764
11765 /*
11766 * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
11767 * the stack. We have to temporarily remove the nodeset object from the
11768 * stack to avoid freeing it prematurely.
11769 */
11770 CHECK_TYPE0(XPATH_NODESET);
11771 obj = valuePop(ctxt);
11772 set = obj->nodesetval;
11773 if (set != NULL) {
11774 xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
11775 if (set->nodeNr > 0)
11776 *first = set->nodeTab[0];
11777 }
11778 valuePush(ctxt, obj);
11779
11780 return (total);
11781}
11782#endif /* XP_OPTIMIZED_FILTER_FIRST */
11783
11784/**
11785 * xmlXPathCompOpEval:
11786 * @ctxt: the XPath parser context with the compiled expression
11787 * @op: an XPath compiled operation
11788 *
11789 * Evaluate the Precompiled XPath operation
11790 * Returns the number of nodes traversed
11791 */
11792static int
11793xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
11794{
11795 int total = 0;
11796 int equal, ret;
11797 xmlXPathCompExprPtr comp;
11798 xmlXPathObjectPtr arg1, arg2;
11799
11800 CHECK_ERROR0;
11801 if (OP_LIMIT_EXCEEDED(ctxt, 1))
11802 return(0);
11803 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11804 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11805 ctxt->context->depth += 1;
11806 comp = ctxt->comp;
11807 switch (op->op) {
11808 case XPATH_OP_END:
11809 break;
11810 case XPATH_OP_AND:
11811 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11812 CHECK_ERROR0;
11813 xmlXPathBooleanFunction(ctxt, 1);
11814 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
11815 break;
11816 arg2 = valuePop(ctxt);
11817 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11818 if (ctxt->error) {
11819 xmlXPathFreeObject(arg2);
11820 break;
11821 }
11822 xmlXPathBooleanFunction(ctxt, 1);
11823 if (ctxt->value != NULL)
11824 ctxt->value->boolval &= arg2->boolval;
11825 xmlXPathReleaseObject(ctxt->context, arg2);
11826 break;
11827 case XPATH_OP_OR:
11828 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11829 CHECK_ERROR0;
11830 xmlXPathBooleanFunction(ctxt, 1);
11831 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
11832 break;
11833 arg2 = valuePop(ctxt);
11834 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11835 if (ctxt->error) {
11836 xmlXPathFreeObject(arg2);
11837 break;
11838 }
11839 xmlXPathBooleanFunction(ctxt, 1);
11840 if (ctxt->value != NULL)
11841 ctxt->value->boolval |= arg2->boolval;
11842 xmlXPathReleaseObject(ctxt->context, arg2);
11843 break;
11844 case XPATH_OP_EQUAL:
11845 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11846 CHECK_ERROR0;
11847 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11848 CHECK_ERROR0;
11849 if (op->value)
11850 equal = xmlXPathEqualValues(ctxt);
11851 else
11852 equal = xmlXPathNotEqualValues(ctxt);
11853 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, equal));
11854 break;
11855 case XPATH_OP_CMP:
11856 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11857 CHECK_ERROR0;
11858 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11859 CHECK_ERROR0;
11860 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
11861 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
11862 break;
11863 case XPATH_OP_PLUS:
11864 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11865 CHECK_ERROR0;
11866 if (op->ch2 != -1) {
11867 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11868 }
11869 CHECK_ERROR0;
11870 if (op->value == 0)
11871 xmlXPathSubValues(ctxt);
11872 else if (op->value == 1)
11873 xmlXPathAddValues(ctxt);
11874 else if (op->value == 2)
11875 xmlXPathValueFlipSign(ctxt);
11876 else if (op->value == 3) {
11877 CAST_TO_NUMBER;
11878 CHECK_TYPE0(XPATH_NUMBER);
11879 }
11880 break;
11881 case XPATH_OP_MULT:
11882 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11883 CHECK_ERROR0;
11884 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11885 CHECK_ERROR0;
11886 if (op->value == 0)
11887 xmlXPathMultValues(ctxt);
11888 else if (op->value == 1)
11889 xmlXPathDivValues(ctxt);
11890 else if (op->value == 2)
11891 xmlXPathModValues(ctxt);
11892 break;
11893 case XPATH_OP_UNION:
11894 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11895 CHECK_ERROR0;
11896 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11897 CHECK_ERROR0;
11898
11899 arg2 = valuePop(ctxt);
11900 arg1 = valuePop(ctxt);
11901 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11902 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11903 xmlXPathReleaseObject(ctxt->context, arg1);
11904 xmlXPathReleaseObject(ctxt->context, arg2);
11905 XP_ERROR0(XPATH_INVALID_TYPE);
11906 }
11907 if ((ctxt->context->opLimit != 0) &&
11908 (((arg1->nodesetval != NULL) &&
11909 (xmlXPathCheckOpLimit(ctxt,
11910 arg1->nodesetval->nodeNr) < 0)) ||
11911 ((arg2->nodesetval != NULL) &&
11912 (xmlXPathCheckOpLimit(ctxt,
11913 arg2->nodesetval->nodeNr) < 0)))) {
11914 xmlXPathReleaseObject(ctxt->context, arg1);
11915 xmlXPathReleaseObject(ctxt->context, arg2);
11916 break;
11917 }
11918
11919 if (((arg2->nodesetval != NULL) &&
11920 (arg2->nodesetval->nodeNr != 0)))
11921 {
11922 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11923 arg2->nodesetval);
11924 if (arg1->nodesetval == NULL)
11925 xmlXPathPErrMemory(ctxt);
11926 }
11927
11928 valuePush(ctxt, arg1);
11929 xmlXPathReleaseObject(ctxt->context, arg2);
11930 break;
11931 case XPATH_OP_ROOT:
11932 xmlXPathRoot(ctxt);
11933 break;
11934 case XPATH_OP_NODE:
11935 if (op->ch1 != -1)
11936 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11937 CHECK_ERROR0;
11938 if (op->ch2 != -1)
11939 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11940 CHECK_ERROR0;
11941 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11942 ctxt->context->node));
11943 break;
11944 case XPATH_OP_COLLECT:{
11945 if (op->ch1 == -1)
11946 break;
11947
11948 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11949 CHECK_ERROR0;
11950
11951 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
11952 break;
11953 }
11954 case XPATH_OP_VALUE:
11955 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11956 break;
11957 case XPATH_OP_VARIABLE:{
11958 xmlXPathObjectPtr val;
11959
11960 if (op->ch1 != -1)
11961 total +=
11962 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11963 if (op->value5 == NULL) {
11964 val = xmlXPathVariableLookup(ctxt->context, op->value4);
11965 if (val == NULL)
11966 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
11967 valuePush(ctxt, val);
11968 } else {
11969 const xmlChar *URI;
11970
11971 URI = xmlXPathNsLookup(ctxt->context, op->value5);
11972 if (URI == NULL) {
11973 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11974 break;
11975 }
11976 val = xmlXPathVariableLookupNS(ctxt->context,
11977 op->value4, URI);
11978 if (val == NULL)
11979 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
11980 valuePush(ctxt, val);
11981 }
11982 break;
11983 }
11984 case XPATH_OP_FUNCTION:{
11985 xmlXPathFunction func;
11986 const xmlChar *oldFunc, *oldFuncURI;
11987 int i;
11988 int frame;
11989
11990 frame = ctxt->valueNr;
11991 if (op->ch1 != -1) {
11992 total +=
11993 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11994 if (ctxt->error != XPATH_EXPRESSION_OK)
11995 break;
11996 }
11997 if (ctxt->valueNr < frame + op->value)
11998 XP_ERROR0(XPATH_INVALID_OPERAND);
11999 for (i = 0; i < op->value; i++) {
12000 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL)
12001 XP_ERROR0(XPATH_INVALID_OPERAND);
12002 }
12003 if (op->cache != NULL)
12004 func = op->cache;
12005 else {
12006 const xmlChar *URI = NULL;
12007
12008 if (op->value5 == NULL)
12009 func =
12010 xmlXPathFunctionLookup(ctxt->context,
12011 op->value4);
12012 else {
12013 URI = xmlXPathNsLookup(ctxt->context, op->value5);
12014 if (URI == NULL)
12015 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12016 func = xmlXPathFunctionLookupNS(ctxt->context,
12017 op->value4, URI);
12018 }
12019 if (func == NULL)
12020 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
12021 op->cache = func;
12022 op->cacheURI = (void *) URI;
12023 }
12024 oldFunc = ctxt->context->function;
12025 oldFuncURI = ctxt->context->functionURI;
12026 ctxt->context->function = op->value4;
12027 ctxt->context->functionURI = op->cacheURI;
12028 func(ctxt, op->value);
12029 ctxt->context->function = oldFunc;
12030 ctxt->context->functionURI = oldFuncURI;
12031 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
12032 (ctxt->valueNr != frame + 1))
12033 XP_ERROR0(XPATH_STACK_ERROR);
12034 break;
12035 }
12036 case XPATH_OP_ARG:
12037 if (op->ch1 != -1) {
12038 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12039 CHECK_ERROR0;
12040 }
12041 if (op->ch2 != -1) {
12042 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12043 CHECK_ERROR0;
12044 }
12045 break;
12046 case XPATH_OP_PREDICATE:
12047 case XPATH_OP_FILTER:{
12048 xmlXPathObjectPtr obj;
12049 xmlNodeSetPtr set;
12050
12051 /*
12052 * Optimization for ()[1] selection i.e. the first elem
12053 */
12054 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12055#ifdef XP_OPTIMIZED_FILTER_FIRST
12056 /*
12057 * FILTER TODO: Can we assume that the inner processing
12058 * will result in an ordered list if we have an
12059 * XPATH_OP_FILTER?
12060 * What about an additional field or flag on
12061 * xmlXPathObject like @sorted ? This way we wouldn't need
12062 * to assume anything, so it would be more robust and
12063 * easier to optimize.
12064 */
12065 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
12066 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
12067#else
12068 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12069#endif
12070 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
12071 xmlXPathObjectPtr val;
12072
12073 val = comp->steps[op->ch2].value4;
12074 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
12075 (val->floatval == 1.0)) {
12076 xmlNodePtr first = NULL;
12077
12078 total +=
12079 xmlXPathCompOpEvalFirst(ctxt,
12080 &comp->steps[op->ch1],
12081 &first);
12082 CHECK_ERROR0;
12083 /*
12084 * The nodeset should be in document order,
12085 * Keep only the first value
12086 */
12087 if ((ctxt->value != NULL) &&
12088 (ctxt->value->type == XPATH_NODESET) &&
12089 (ctxt->value->nodesetval != NULL) &&
12090 (ctxt->value->nodesetval->nodeNr > 1))
12091 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
12092 1, 1);
12093 break;
12094 }
12095 }
12096 /*
12097 * Optimization for ()[last()] selection i.e. the last elem
12098 */
12099 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12100 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12101 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12102 int f = comp->steps[op->ch2].ch1;
12103
12104 if ((f != -1) &&
12105 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12106 (comp->steps[f].value5 == NULL) &&
12107 (comp->steps[f].value == 0) &&
12108 (comp->steps[f].value4 != NULL) &&
12109 (xmlStrEqual
12110 (comp->steps[f].value4, BAD_CAST "last"))) {
12111 xmlNodePtr last = NULL;
12112
12113 total +=
12114 xmlXPathCompOpEvalLast(ctxt,
12115 &comp->steps[op->ch1],
12116 &last);
12117 CHECK_ERROR0;
12118 /*
12119 * The nodeset should be in document order,
12120 * Keep only the last value
12121 */
12122 if ((ctxt->value != NULL) &&
12123 (ctxt->value->type == XPATH_NODESET) &&
12124 (ctxt->value->nodesetval != NULL) &&
12125 (ctxt->value->nodesetval->nodeTab != NULL) &&
12126 (ctxt->value->nodesetval->nodeNr > 1))
12127 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12128 break;
12129 }
12130 }
12131 /*
12132 * Process inner predicates first.
12133 * Example "index[parent::book][1]":
12134 * ...
12135 * PREDICATE <-- we are here "[1]"
12136 * PREDICATE <-- process "[parent::book]" first
12137 * SORT
12138 * COLLECT 'parent' 'name' 'node' book
12139 * NODE
12140 * ELEM Object is a number : 1
12141 */
12142 if (op->ch1 != -1)
12143 total +=
12144 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12145 CHECK_ERROR0;
12146 if (op->ch2 == -1)
12147 break;
12148 if (ctxt->value == NULL)
12149 break;
12150
12151#ifdef LIBXML_XPTR_LOCS_ENABLED
12152 /*
12153 * Hum are we filtering the result of an XPointer expression
12154 */
12155 if (ctxt->value->type == XPATH_LOCATIONSET) {
12156 xmlLocationSetPtr locset = ctxt->value->user;
12157 xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
12158 1, locset->locNr);
12159 break;
12160 }
12161#endif /* LIBXML_XPTR_LOCS_ENABLED */
12162
12163 /*
12164 * In case of errors, xmlXPathNodeSetFilter can pop additional
12165 * nodes from the stack. We have to temporarily remove the
12166 * nodeset object from the stack to avoid freeing it
12167 * prematurely.
12168 */
12169 CHECK_TYPE0(XPATH_NODESET);
12170 obj = valuePop(ctxt);
12171 set = obj->nodesetval;
12172 if (set != NULL)
12173 xmlXPathNodeSetFilter(ctxt, set, op->ch2,
12174 1, set->nodeNr, 1);
12175 valuePush(ctxt, obj);
12176 break;
12177 }
12178 case XPATH_OP_SORT:
12179 if (op->ch1 != -1)
12180 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12181 CHECK_ERROR0;
12182 if ((ctxt->value != NULL) &&
12183 (ctxt->value->type == XPATH_NODESET) &&
12184 (ctxt->value->nodesetval != NULL) &&
12185 (ctxt->value->nodesetval->nodeNr > 1))
12186 {
12187 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12188 }
12189 break;
12190#ifdef LIBXML_XPTR_LOCS_ENABLED
12191 case XPATH_OP_RANGETO:{
12192 xmlXPathObjectPtr range;
12193 xmlXPathObjectPtr res, obj;
12194 xmlXPathObjectPtr tmp;
12195 xmlLocationSetPtr newlocset = NULL;
12196 xmlLocationSetPtr oldlocset;
12197 xmlNodeSetPtr oldset;
12198 xmlNodePtr oldnode = ctxt->context->node;
12199 int oldcs = ctxt->context->contextSize;
12200 int oldpp = ctxt->context->proximityPosition;
12201 int i, j;
12202
12203 if (op->ch1 != -1) {
12204 total +=
12205 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12206 CHECK_ERROR0;
12207 }
12208 if (ctxt->value == NULL) {
12209 XP_ERROR0(XPATH_INVALID_OPERAND);
12210 }
12211 if (op->ch2 == -1)
12212 break;
12213
12214 if (ctxt->value->type == XPATH_LOCATIONSET) {
12215 /*
12216 * Extract the old locset, and then evaluate the result of the
12217 * expression for all the element in the locset. use it to grow
12218 * up a new locset.
12219 */
12220 CHECK_TYPE0(XPATH_LOCATIONSET);
12221
12222 if ((ctxt->value->user == NULL) ||
12223 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
12224 break;
12225
12226 obj = valuePop(ctxt);
12227 oldlocset = obj->user;
12228
12229 newlocset = xmlXPtrLocationSetCreate(NULL);
12230
12231 for (i = 0; i < oldlocset->locNr; i++) {
12232 /*
12233 * Run the evaluation with a node list made of a
12234 * single item in the nodelocset.
12235 */
12236 ctxt->context->node = oldlocset->locTab[i]->user;
12237 ctxt->context->contextSize = oldlocset->locNr;
12238 ctxt->context->proximityPosition = i + 1;
12239 tmp = xmlXPathCacheNewNodeSet(ctxt,
12240 ctxt->context->node);
12241 valuePush(ctxt, tmp);
12242
12243 if (op->ch2 != -1)
12244 total +=
12245 xmlXPathCompOpEval(ctxt,
12246 &comp->steps[op->ch2]);
12247 if (ctxt->error != XPATH_EXPRESSION_OK) {
12248 xmlXPtrFreeLocationSet(newlocset);
12249 goto rangeto_error;
12250 }
12251
12252 res = valuePop(ctxt);
12253 if (res->type == XPATH_LOCATIONSET) {
12254 xmlLocationSetPtr rloc =
12255 (xmlLocationSetPtr)res->user;
12256 for (j=0; j<rloc->locNr; j++) {
12257 range = xmlXPtrNewRange(
12258 oldlocset->locTab[i]->user,
12259 oldlocset->locTab[i]->index,
12260 rloc->locTab[j]->user2,
12261 rloc->locTab[j]->index2);
12262 if (range != NULL) {
12263 xmlXPtrLocationSetAdd(newlocset, range);
12264 }
12265 }
12266 } else {
12267 range = xmlXPtrNewRangeNodeObject(
12268 (xmlNodePtr)oldlocset->locTab[i]->user, res);
12269 if (range != NULL) {
12270 xmlXPtrLocationSetAdd(newlocset,range);
12271 }
12272 }
12273
12274 /*
12275 * Cleanup
12276 */
12277 if (res != NULL) {
12278 xmlXPathReleaseObject(ctxt->context, res);
12279 }
12280 if (ctxt->value == tmp) {
12281 res = valuePop(ctxt);
12282 xmlXPathReleaseObject(ctxt->context, res);
12283 }
12284 }
12285 } else { /* Not a location set */
12286 CHECK_TYPE0(XPATH_NODESET);
12287 obj = valuePop(ctxt);
12288 oldset = obj->nodesetval;
12289
12290 newlocset = xmlXPtrLocationSetCreate(NULL);
12291
12292 if (oldset != NULL) {
12293 for (i = 0; i < oldset->nodeNr; i++) {
12294 /*
12295 * Run the evaluation with a node list made of a single item
12296 * in the nodeset.
12297 */
12298 ctxt->context->node = oldset->nodeTab[i];
12299 /*
12300 * OPTIMIZE TODO: Avoid recreation for every iteration.
12301 */
12302 tmp = xmlXPathCacheNewNodeSet(ctxt,
12303 ctxt->context->node);
12304 valuePush(ctxt, tmp);
12305
12306 if (op->ch2 != -1)
12307 total +=
12308 xmlXPathCompOpEval(ctxt,
12309 &comp->steps[op->ch2]);
12310 if (ctxt->error != XPATH_EXPRESSION_OK) {
12311 xmlXPtrFreeLocationSet(newlocset);
12312 goto rangeto_error;
12313 }
12314
12315 res = valuePop(ctxt);
12316 range =
12317 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
12318 res);
12319 if (range != NULL) {
12320 xmlXPtrLocationSetAdd(newlocset, range);
12321 }
12322
12323 /*
12324 * Cleanup
12325 */
12326 if (res != NULL) {
12327 xmlXPathReleaseObject(ctxt->context, res);
12328 }
12329 if (ctxt->value == tmp) {
12330 res = valuePop(ctxt);
12331 xmlXPathReleaseObject(ctxt->context, res);
12332 }
12333 }
12334 }
12335 }
12336
12337 /*
12338 * The result is used as the new evaluation set.
12339 */
12340 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12341rangeto_error:
12342 xmlXPathReleaseObject(ctxt->context, obj);
12343 ctxt->context->node = oldnode;
12344 ctxt->context->contextSize = oldcs;
12345 ctxt->context->proximityPosition = oldpp;
12346 break;
12347 }
12348#endif /* LIBXML_XPTR_LOCS_ENABLED */
12349 default:
12350 XP_ERROR0(XPATH_INVALID_OPERAND);
12351 break;
12352 }
12353
12354 ctxt->context->depth -= 1;
12355 return (total);
12356}
12357
12358/**
12359 * xmlXPathCompOpEvalToBoolean:
12360 * @ctxt: the XPath parser context
12361 *
12362 * Evaluates if the expression evaluates to true.
12363 *
12364 * Returns 1 if true, 0 if false and -1 on API or internal errors.
12365 */
12366static int
12367xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
12368 xmlXPathStepOpPtr op,
12369 int isPredicate)
12370{
12371 xmlXPathObjectPtr resObj = NULL;
12372
12373start:
12374 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12375 return(0);
12376 /* comp = ctxt->comp; */
12377 switch (op->op) {
12378 case XPATH_OP_END:
12379 return (0);
12380 case XPATH_OP_VALUE:
12381 resObj = (xmlXPathObjectPtr) op->value4;
12382 if (isPredicate)
12383 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
12384 return(xmlXPathCastToBoolean(resObj));
12385 case XPATH_OP_SORT:
12386 /*
12387 * We don't need sorting for boolean results. Skip this one.
12388 */
12389 if (op->ch1 != -1) {
12390 op = &ctxt->comp->steps[op->ch1];
12391 goto start;
12392 }
12393 return(0);
12394 case XPATH_OP_COLLECT:
12395 if (op->ch1 == -1)
12396 return(0);
12397
12398 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
12399 if (ctxt->error != XPATH_EXPRESSION_OK)
12400 return(-1);
12401
12402 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
12403 if (ctxt->error != XPATH_EXPRESSION_OK)
12404 return(-1);
12405
12406 resObj = valuePop(ctxt);
12407 if (resObj == NULL)
12408 return(-1);
12409 break;
12410 default:
12411 /*
12412 * Fallback to call xmlXPathCompOpEval().
12413 */
12414 xmlXPathCompOpEval(ctxt, op);
12415 if (ctxt->error != XPATH_EXPRESSION_OK)
12416 return(-1);
12417
12418 resObj = valuePop(ctxt);
12419 if (resObj == NULL)
12420 return(-1);
12421 break;
12422 }
12423
12424 if (resObj) {
12425 int res;
12426
12427 if (resObj->type == XPATH_BOOLEAN) {
12428 res = resObj->boolval;
12429 } else if (isPredicate) {
12430 /*
12431 * For predicates a result of type "number" is handled
12432 * differently:
12433 * SPEC XPath 1.0:
12434 * "If the result is a number, the result will be converted
12435 * to true if the number is equal to the context position
12436 * and will be converted to false otherwise;"
12437 */
12438 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
12439 } else {
12440 res = xmlXPathCastToBoolean(resObj);
12441 }
12442 xmlXPathReleaseObject(ctxt->context, resObj);
12443 return(res);
12444 }
12445
12446 return(0);
12447}
12448
12449#ifdef XPATH_STREAMING
12450/**
12451 * xmlXPathRunStreamEval:
12452 * @pctxt: the XPath parser context with the compiled expression
12453 *
12454 * Evaluate the Precompiled Streamable XPath expression in the given context.
12455 */
12456static int
12457xmlXPathRunStreamEval(xmlXPathParserContextPtr pctxt, xmlPatternPtr comp,
12458 xmlXPathObjectPtr *resultSeq, int toBool)
12459{
12460 int max_depth, min_depth;
12461 int from_root;
12462 int ret, depth;
12463 int eval_all_nodes;
12464 xmlNodePtr cur = NULL, limit = NULL;
12465 xmlStreamCtxtPtr patstream = NULL;
12466 xmlXPathContextPtr ctxt = pctxt->context;
12467
12468 if ((ctxt == NULL) || (comp == NULL))
12469 return(-1);
12470 max_depth = xmlPatternMaxDepth(comp);
12471 if (max_depth == -1)
12472 return(-1);
12473 if (max_depth == -2)
12474 max_depth = 10000;
12475 min_depth = xmlPatternMinDepth(comp);
12476 if (min_depth == -1)
12477 return(-1);
12478 from_root = xmlPatternFromRoot(comp);
12479 if (from_root < 0)
12480 return(-1);
12481#if 0
12482 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
12483#endif
12484
12485 if (! toBool) {
12486 if (resultSeq == NULL)
12487 return(-1);
12488 *resultSeq = xmlXPathCacheNewNodeSet(pctxt, NULL);
12489 if (*resultSeq == NULL)
12490 return(-1);
12491 }
12492
12493 /*
12494 * handle the special cases of "/" amd "." being matched
12495 */
12496 if (min_depth == 0) {
12497 int res;
12498
12499 if (from_root) {
12500 /* Select "/" */
12501 if (toBool)
12502 return(1);
12503 res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
12504 (xmlNodePtr) ctxt->doc);
12505 } else {
12506 /* Select "self::node()" */
12507 if (toBool)
12508 return(1);
12509 res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
12510 ctxt->node);
12511 }
12512
12513 if (res < 0)
12514 xmlXPathPErrMemory(pctxt);
12515 }
12516 if (max_depth == 0) {
12517 return(0);
12518 }
12519
12520 if (from_root) {
12521 cur = (xmlNodePtr)ctxt->doc;
12522 } else if (ctxt->node != NULL) {
12523 switch (ctxt->node->type) {
12524 case XML_ELEMENT_NODE:
12525 case XML_DOCUMENT_NODE:
12526 case XML_DOCUMENT_FRAG_NODE:
12527 case XML_HTML_DOCUMENT_NODE:
12528 cur = ctxt->node;
12529 break;
12530 case XML_ATTRIBUTE_NODE:
12531 case XML_TEXT_NODE:
12532 case XML_CDATA_SECTION_NODE:
12533 case XML_ENTITY_REF_NODE:
12534 case XML_ENTITY_NODE:
12535 case XML_PI_NODE:
12536 case XML_COMMENT_NODE:
12537 case XML_NOTATION_NODE:
12538 case XML_DTD_NODE:
12539 case XML_DOCUMENT_TYPE_NODE:
12540 case XML_ELEMENT_DECL:
12541 case XML_ATTRIBUTE_DECL:
12542 case XML_ENTITY_DECL:
12543 case XML_NAMESPACE_DECL:
12544 case XML_XINCLUDE_START:
12545 case XML_XINCLUDE_END:
12546 break;
12547 }
12548 limit = cur;
12549 }
12550 if (cur == NULL) {
12551 return(0);
12552 }
12553
12554 patstream = xmlPatternGetStreamCtxt(comp);
12555 if (patstream == NULL) {
12556 xmlXPathPErrMemory(pctxt);
12557 return(-1);
12558 }
12559
12560 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
12561
12562 if (from_root) {
12563 ret = xmlStreamPush(patstream, NULL, NULL);
12564 if (ret < 0) {
12565 } else if (ret == 1) {
12566 if (toBool)
12567 goto return_1;
12568 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) < 0)
12569 xmlXPathPErrMemory(pctxt);
12570 }
12571 }
12572 depth = 0;
12573 goto scan_children;
12574next_node:
12575 do {
12576 if (ctxt->opLimit != 0) {
12577 if (ctxt->opCount >= ctxt->opLimit) {
12578 xmlXPathErr(ctxt, XPATH_RECURSION_LIMIT_EXCEEDED);
12579 xmlFreeStreamCtxt(patstream);
12580 return(-1);
12581 }
12582 ctxt->opCount++;
12583 }
12584
12585 switch (cur->type) {
12586 case XML_ELEMENT_NODE:
12587 case XML_TEXT_NODE:
12588 case XML_CDATA_SECTION_NODE:
12589 case XML_COMMENT_NODE:
12590 case XML_PI_NODE:
12591 if (cur->type == XML_ELEMENT_NODE) {
12592 ret = xmlStreamPush(patstream, cur->name,
12593 (cur->ns ? cur->ns->href : NULL));
12594 } else if (eval_all_nodes)
12595 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
12596 else
12597 break;
12598
12599 if (ret < 0) {
12600 xmlXPathPErrMemory(pctxt);
12601 } else if (ret == 1) {
12602 if (toBool)
12603 goto return_1;
12604 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
12605 cur) < 0)
12606 xmlXPathPErrMemory(pctxt);
12607 }
12608 if ((cur->children == NULL) || (depth >= max_depth)) {
12609 ret = xmlStreamPop(patstream);
12610 while (cur->next != NULL) {
12611 cur = cur->next;
12612 if ((cur->type != XML_ENTITY_DECL) &&
12613 (cur->type != XML_DTD_NODE))
12614 goto next_node;
12615 }
12616 }
12617 default:
12618 break;
12619 }
12620
12621scan_children:
12622 if (cur->type == XML_NAMESPACE_DECL) break;
12623 if ((cur->children != NULL) && (depth < max_depth)) {
12624 /*
12625 * Do not descend on entities declarations
12626 */
12627 if (cur->children->type != XML_ENTITY_DECL) {
12628 cur = cur->children;
12629 depth++;
12630 /*
12631 * Skip DTDs
12632 */
12633 if (cur->type != XML_DTD_NODE)
12634 continue;
12635 }
12636 }
12637
12638 if (cur == limit)
12639 break;
12640
12641 while (cur->next != NULL) {
12642 cur = cur->next;
12643 if ((cur->type != XML_ENTITY_DECL) &&
12644 (cur->type != XML_DTD_NODE))
12645 goto next_node;
12646 }
12647
12648 do {
12649 cur = cur->parent;
12650 depth--;
12651 if ((cur == NULL) || (cur == limit) ||
12652 (cur->type == XML_DOCUMENT_NODE))
12653 goto done;
12654 if (cur->type == XML_ELEMENT_NODE) {
12655 ret = xmlStreamPop(patstream);
12656 } else if ((eval_all_nodes) &&
12657 ((cur->type == XML_TEXT_NODE) ||
12658 (cur->type == XML_CDATA_SECTION_NODE) ||
12659 (cur->type == XML_COMMENT_NODE) ||
12660 (cur->type == XML_PI_NODE)))
12661 {
12662 ret = xmlStreamPop(patstream);
12663 }
12664 if (cur->next != NULL) {
12665 cur = cur->next;
12666 break;
12667 }
12668 } while (cur != NULL);
12669
12670 } while ((cur != NULL) && (depth >= 0));
12671
12672done:
12673
12674 if (patstream)
12675 xmlFreeStreamCtxt(patstream);
12676 return(0);
12677
12678return_1:
12679 if (patstream)
12680 xmlFreeStreamCtxt(patstream);
12681 return(1);
12682}
12683#endif /* XPATH_STREAMING */
12684
12685/**
12686 * xmlXPathRunEval:
12687 * @ctxt: the XPath parser context with the compiled expression
12688 * @toBool: evaluate to a boolean result
12689 *
12690 * Evaluate the Precompiled XPath expression in the given context.
12691 */
12692static int
12693xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
12694{
12695 xmlXPathCompExprPtr comp;
12696 int oldDepth;
12697
12698 if ((ctxt == NULL) || (ctxt->comp == NULL))
12699 return(-1);
12700
12701 if (ctxt->valueTab == NULL) {
12702 /* Allocate the value stack */
12703 ctxt->valueTab = (xmlXPathObjectPtr *)
12704 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
12705 if (ctxt->valueTab == NULL) {
12706 xmlXPathPErrMemory(ctxt);
12707 return(-1);
12708 }
12709 ctxt->valueNr = 0;
12710 ctxt->valueMax = 10;
12711 ctxt->value = NULL;
12712 }
12713#ifdef XPATH_STREAMING
12714 if (ctxt->comp->stream) {
12715 int res;
12716
12717 if (toBool) {
12718 /*
12719 * Evaluation to boolean result.
12720 */
12721 res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, NULL, 1);
12722 if (res != -1)
12723 return(res);
12724 } else {
12725 xmlXPathObjectPtr resObj = NULL;
12726
12727 /*
12728 * Evaluation to a sequence.
12729 */
12730 res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, &resObj, 0);
12731
12732 if ((res != -1) && (resObj != NULL)) {
12733 valuePush(ctxt, resObj);
12734 return(0);
12735 }
12736 if (resObj != NULL)
12737 xmlXPathReleaseObject(ctxt->context, resObj);
12738 }
12739 /*
12740 * QUESTION TODO: This falls back to normal XPath evaluation
12741 * if res == -1. Is this intended?
12742 */
12743 }
12744#endif
12745 comp = ctxt->comp;
12746 if (comp->last < 0) {
12747 xmlXPathErr(ctxt, XPATH_STACK_ERROR);
12748 return(-1);
12749 }
12750 oldDepth = ctxt->context->depth;
12751 if (toBool)
12752 return(xmlXPathCompOpEvalToBoolean(ctxt,
12753 &comp->steps[comp->last], 0));
12754 else
12755 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
12756 ctxt->context->depth = oldDepth;
12757
12758 return(0);
12759}
12760
12761/************************************************************************
12762 * *
12763 * Public interfaces *
12764 * *
12765 ************************************************************************/
12766
12767/**
12768 * xmlXPathEvalPredicate:
12769 * @ctxt: the XPath context
12770 * @res: the Predicate Expression evaluation result
12771 *
12772 * Evaluate a predicate result for the current node.
12773 * A PredicateExpr is evaluated by evaluating the Expr and converting
12774 * the result to a boolean. If the result is a number, the result will
12775 * be converted to true if the number is equal to the position of the
12776 * context node in the context node list (as returned by the position
12777 * function) and will be converted to false otherwise; if the result
12778 * is not a number, then the result will be converted as if by a call
12779 * to the boolean function.
12780 *
12781 * Returns 1 if predicate is true, 0 otherwise
12782 */
12783int
12784xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
12785 if ((ctxt == NULL) || (res == NULL)) return(0);
12786 switch (res->type) {
12787 case XPATH_BOOLEAN:
12788 return(res->boolval);
12789 case XPATH_NUMBER:
12790 return(res->floatval == ctxt->proximityPosition);
12791 case XPATH_NODESET:
12792 case XPATH_XSLT_TREE:
12793 if (res->nodesetval == NULL)
12794 return(0);
12795 return(res->nodesetval->nodeNr != 0);
12796 case XPATH_STRING:
12797 return((res->stringval != NULL) &&
12798 (xmlStrlen(res->stringval) != 0));
12799 default:
12800 break;
12801 }
12802 return(0);
12803}
12804
12805/**
12806 * xmlXPathEvaluatePredicateResult:
12807 * @ctxt: the XPath Parser context
12808 * @res: the Predicate Expression evaluation result
12809 *
12810 * Evaluate a predicate result for the current node.
12811 * A PredicateExpr is evaluated by evaluating the Expr and converting
12812 * the result to a boolean. If the result is a number, the result will
12813 * be converted to true if the number is equal to the position of the
12814 * context node in the context node list (as returned by the position
12815 * function) and will be converted to false otherwise; if the result
12816 * is not a number, then the result will be converted as if by a call
12817 * to the boolean function.
12818 *
12819 * Returns 1 if predicate is true, 0 otherwise
12820 */
12821int
12822xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
12823 xmlXPathObjectPtr res) {
12824 if ((ctxt == NULL) || (res == NULL)) return(0);
12825 switch (res->type) {
12826 case XPATH_BOOLEAN:
12827 return(res->boolval);
12828 case XPATH_NUMBER:
12829#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
12830 return((res->floatval == ctxt->context->proximityPosition) &&
12831 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
12832#else
12833 return(res->floatval == ctxt->context->proximityPosition);
12834#endif
12835 case XPATH_NODESET:
12836 case XPATH_XSLT_TREE:
12837 if (res->nodesetval == NULL)
12838 return(0);
12839 return(res->nodesetval->nodeNr != 0);
12840 case XPATH_STRING:
12841 return((res->stringval != NULL) && (res->stringval[0] != 0));
12842#ifdef LIBXML_XPTR_LOCS_ENABLED
12843 case XPATH_LOCATIONSET:{
12844 xmlLocationSetPtr ptr = res->user;
12845 if (ptr == NULL)
12846 return(0);
12847 return (ptr->locNr != 0);
12848 }
12849#endif
12850 default:
12851 break;
12852 }
12853 return(0);
12854}
12855
12856#ifdef XPATH_STREAMING
12857/**
12858 * xmlXPathTryStreamCompile:
12859 * @ctxt: an XPath context
12860 * @str: the XPath expression
12861 *
12862 * Try to compile the XPath expression as a streamable subset.
12863 *
12864 * Returns the compiled expression or NULL if failed to compile.
12865 */
12866static xmlXPathCompExprPtr
12867xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
12868 /*
12869 * Optimization: use streaming patterns when the XPath expression can
12870 * be compiled to a stream lookup
12871 */
12872 xmlPatternPtr stream;
12873 xmlXPathCompExprPtr comp;
12874 xmlDictPtr dict = NULL;
12875 const xmlChar **namespaces = NULL;
12876 xmlNsPtr ns;
12877 int i, j;
12878
12879 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
12880 (!xmlStrchr(str, '@'))) {
12881 const xmlChar *tmp;
12882 int res;
12883
12884 /*
12885 * We don't try to handle expressions using the verbose axis
12886 * specifiers ("::"), just the simplified form at this point.
12887 * Additionally, if there is no list of namespaces available and
12888 * there's a ":" in the expression, indicating a prefixed QName,
12889 * then we won't try to compile either. xmlPatterncompile() needs
12890 * to have a list of namespaces at compilation time in order to
12891 * compile prefixed name tests.
12892 */
12893 tmp = xmlStrchr(str, ':');
12894 if ((tmp != NULL) &&
12895 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
12896 return(NULL);
12897
12898 if (ctxt != NULL) {
12899 dict = ctxt->dict;
12900 if (ctxt->nsNr > 0) {
12901 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
12902 if (namespaces == NULL) {
12903 xmlXPathErrMemory(ctxt);
12904 return(NULL);
12905 }
12906 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
12907 ns = ctxt->namespaces[j];
12908 namespaces[i++] = ns->href;
12909 namespaces[i++] = ns->prefix;
12910 }
12911 namespaces[i++] = NULL;
12912 namespaces[i] = NULL;
12913 }
12914 }
12915
12916 res = xmlPatternCompileSafe(str, dict, XML_PATTERN_XPATH, namespaces,
12917 &stream);
12918 if (namespaces != NULL) {
12919 xmlFree((xmlChar **)namespaces);
12920 }
12921 if (res < 0) {
12922 xmlXPathErrMemory(ctxt);
12923 return(NULL);
12924 }
12925 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
12926 comp = xmlXPathNewCompExpr();
12927 if (comp == NULL) {
12928 xmlXPathErrMemory(ctxt);
12929 xmlFreePattern(stream);
12930 return(NULL);
12931 }
12932 comp->stream = stream;
12933 comp->dict = dict;
12934 if (comp->dict)
12935 xmlDictReference(comp->dict);
12936 return(comp);
12937 }
12938 xmlFreePattern(stream);
12939 }
12940 return(NULL);
12941}
12942#endif /* XPATH_STREAMING */
12943
12944static void
12945xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
12946 xmlXPathStepOpPtr op)
12947{
12948 xmlXPathCompExprPtr comp = pctxt->comp;
12949 xmlXPathContextPtr ctxt;
12950
12951 /*
12952 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
12953 * internal representation.
12954 */
12955
12956 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
12957 (op->ch1 != -1) &&
12958 (op->ch2 == -1 /* no predicate */))
12959 {
12960 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
12961
12962 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
12963 ((xmlXPathAxisVal) prevop->value ==
12964 AXIS_DESCENDANT_OR_SELF) &&
12965 (prevop->ch2 == -1) &&
12966 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
12967 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
12968 {
12969 /*
12970 * This is a "descendant-or-self::node()" without predicates.
12971 * Try to eliminate it.
12972 */
12973
12974 switch ((xmlXPathAxisVal) op->value) {
12975 case AXIS_CHILD:
12976 case AXIS_DESCENDANT:
12977 /*
12978 * Convert "descendant-or-self::node()/child::" or
12979 * "descendant-or-self::node()/descendant::" to
12980 * "descendant::"
12981 */
12982 op->ch1 = prevop->ch1;
12983 op->value = AXIS_DESCENDANT;
12984 break;
12985 case AXIS_SELF:
12986 case AXIS_DESCENDANT_OR_SELF:
12987 /*
12988 * Convert "descendant-or-self::node()/self::" or
12989 * "descendant-or-self::node()/descendant-or-self::" to
12990 * to "descendant-or-self::"
12991 */
12992 op->ch1 = prevop->ch1;
12993 op->value = AXIS_DESCENDANT_OR_SELF;
12994 break;
12995 default:
12996 break;
12997 }
12998 }
12999 }
13000
13001 /* OP_VALUE has invalid ch1. */
13002 if (op->op == XPATH_OP_VALUE)
13003 return;
13004
13005 /* Recurse */
13006 ctxt = pctxt->context;
13007 if (ctxt != NULL) {
13008 if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
13009 return;
13010 ctxt->depth += 1;
13011 }
13012 if (op->ch1 != -1)
13013 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
13014 if (op->ch2 != -1)
13015 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
13016 if (ctxt != NULL)
13017 ctxt->depth -= 1;
13018}
13019
13020/**
13021 * xmlXPathCtxtCompile:
13022 * @ctxt: an XPath context
13023 * @str: the XPath expression
13024 *
13025 * Compile an XPath expression
13026 *
13027 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
13028 * the caller has to free the object.
13029 */
13030xmlXPathCompExprPtr
13031xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
13032 xmlXPathParserContextPtr pctxt;
13033 xmlXPathCompExprPtr comp;
13034 int oldDepth = 0;
13035
13036#ifdef XPATH_STREAMING
13037 comp = xmlXPathTryStreamCompile(ctxt, str);
13038 if (comp != NULL)
13039 return(comp);
13040#endif
13041
13042 xmlInitParser();
13043
13044 pctxt = xmlXPathNewParserContext(str, ctxt);
13045 if (pctxt == NULL)
13046 return NULL;
13047 if (ctxt != NULL)
13048 oldDepth = ctxt->depth;
13049 xmlXPathCompileExpr(pctxt, 1);
13050 if (ctxt != NULL)
13051 ctxt->depth = oldDepth;
13052
13053 if( pctxt->error != XPATH_EXPRESSION_OK )
13054 {
13055 xmlXPathFreeParserContext(pctxt);
13056 return(NULL);
13057 }
13058
13059 if (*pctxt->cur != 0) {
13060 /*
13061 * aleksey: in some cases this line prints *second* error message
13062 * (see bug #78858) and probably this should be fixed.
13063 * However, we are not sure that all error messages are printed
13064 * out in other places. It's not critical so we leave it as-is for now
13065 */
13066 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
13067 comp = NULL;
13068 } else {
13069 comp = pctxt->comp;
13070 if ((comp->nbStep > 1) && (comp->last >= 0)) {
13071 if (ctxt != NULL)
13072 oldDepth = ctxt->depth;
13073 xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
13074 if (ctxt != NULL)
13075 ctxt->depth = oldDepth;
13076 }
13077 pctxt->comp = NULL;
13078 }
13079 xmlXPathFreeParserContext(pctxt);
13080
13081 if (comp != NULL) {
13082 comp->expr = xmlStrdup(str);
13083 }
13084 return(comp);
13085}
13086
13087/**
13088 * xmlXPathCompile:
13089 * @str: the XPath expression
13090 *
13091 * Compile an XPath expression
13092 *
13093 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
13094 * the caller has to free the object.
13095 */
13096xmlXPathCompExprPtr
13097xmlXPathCompile(const xmlChar *str) {
13098 return(xmlXPathCtxtCompile(NULL, str));
13099}
13100
13101/**
13102 * xmlXPathCompiledEvalInternal:
13103 * @comp: the compiled XPath expression
13104 * @ctxt: the XPath context
13105 * @resObj: the resulting XPath object or NULL
13106 * @toBool: 1 if only a boolean result is requested
13107 *
13108 * Evaluate the Precompiled XPath expression in the given context.
13109 * The caller has to free @resObj.
13110 *
13111 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13112 * the caller has to free the object.
13113 */
13114static int
13115xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
13116 xmlXPathContextPtr ctxt,
13117 xmlXPathObjectPtr *resObjPtr,
13118 int toBool)
13119{
13120 xmlXPathParserContextPtr pctxt;
13121 xmlXPathObjectPtr resObj = NULL;
13122#ifndef LIBXML_THREAD_ENABLED
13123 static int reentance = 0;
13124#endif
13125 int res;
13126
13127 if (comp == NULL)
13128 return(-1);
13129 xmlInitParser();
13130
13131 xmlResetError(&ctxt->lastError);
13132
13133#ifndef LIBXML_THREAD_ENABLED
13134 reentance++;
13135 if (reentance > 1)
13136 xmlXPathDisableOptimizer = 1;
13137#endif
13138
13139 pctxt = xmlXPathCompParserContext(comp, ctxt);
13140 if (pctxt == NULL)
13141 return(-1);
13142 res = xmlXPathRunEval(pctxt, toBool);
13143
13144 if (pctxt->error == XPATH_EXPRESSION_OK) {
13145 if (pctxt->valueNr != ((toBool) ? 0 : 1))
13146 xmlXPathErr(pctxt, XPATH_STACK_ERROR);
13147 else if (!toBool)
13148 resObj = valuePop(pctxt);
13149 }
13150
13151 if (resObjPtr)
13152 *resObjPtr = resObj;
13153 else
13154 xmlXPathReleaseObject(ctxt, resObj);
13155
13156 pctxt->comp = NULL;
13157 xmlXPathFreeParserContext(pctxt);
13158#ifndef LIBXML_THREAD_ENABLED
13159 reentance--;
13160#endif
13161
13162 return(res);
13163}
13164
13165/**
13166 * xmlXPathCompiledEval:
13167 * @comp: the compiled XPath expression
13168 * @ctx: the XPath context
13169 *
13170 * Evaluate the Precompiled XPath expression in the given context.
13171 *
13172 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13173 * the caller has to free the object.
13174 */
13175xmlXPathObjectPtr
13176xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
13177{
13178 xmlXPathObjectPtr res = NULL;
13179
13180 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
13181 return(res);
13182}
13183
13184/**
13185 * xmlXPathCompiledEvalToBoolean:
13186 * @comp: the compiled XPath expression
13187 * @ctxt: the XPath context
13188 *
13189 * Applies the XPath boolean() function on the result of the given
13190 * compiled expression.
13191 *
13192 * Returns 1 if the expression evaluated to true, 0 if to false and
13193 * -1 in API and internal errors.
13194 */
13195int
13196xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
13197 xmlXPathContextPtr ctxt)
13198{
13199 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
13200}
13201
13202/**
13203 * xmlXPathEvalExpr:
13204 * @ctxt: the XPath Parser context
13205 *
13206 * Parse and evaluate an XPath expression in the given context,
13207 * then push the result on the context stack
13208 */
13209void
13210xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
13211#ifdef XPATH_STREAMING
13212 xmlXPathCompExprPtr comp;
13213#endif
13214 int oldDepth = 0;
13215
13216 if (ctxt == NULL)
13217 return;
13218 if (ctxt->context->lastError.code != 0)
13219 return;
13220
13221#ifdef XPATH_STREAMING
13222 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
13223 if ((comp == NULL) &&
13224 (ctxt->context->lastError.code == XML_ERR_NO_MEMORY)) {
13225 xmlXPathPErrMemory(ctxt);
13226 return;
13227 }
13228 if (comp != NULL) {
13229 if (ctxt->comp != NULL)
13230 xmlXPathFreeCompExpr(ctxt->comp);
13231 ctxt->comp = comp;
13232 } else
13233#endif
13234 {
13235 if (ctxt->context != NULL)
13236 oldDepth = ctxt->context->depth;
13237 xmlXPathCompileExpr(ctxt, 1);
13238 if (ctxt->context != NULL)
13239 ctxt->context->depth = oldDepth;
13240 CHECK_ERROR;
13241
13242 /* Check for trailing characters. */
13243 if (*ctxt->cur != 0)
13244 XP_ERROR(XPATH_EXPR_ERROR);
13245
13246 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
13247 if (ctxt->context != NULL)
13248 oldDepth = ctxt->context->depth;
13249 xmlXPathOptimizeExpression(ctxt,
13250 &ctxt->comp->steps[ctxt->comp->last]);
13251 if (ctxt->context != NULL)
13252 ctxt->context->depth = oldDepth;
13253 }
13254 }
13255
13256 xmlXPathRunEval(ctxt, 0);
13257}
13258
13259/**
13260 * xmlXPathEval:
13261 * @str: the XPath expression
13262 * @ctx: the XPath context
13263 *
13264 * Evaluate the XPath Location Path in the given context.
13265 *
13266 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13267 * the caller has to free the object.
13268 */
13269xmlXPathObjectPtr
13270xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
13271 xmlXPathParserContextPtr ctxt;
13272 xmlXPathObjectPtr res;
13273
13274 if (ctx == NULL)
13275 return(NULL);
13276
13277 xmlInitParser();
13278
13279 xmlResetError(&ctx->lastError);
13280
13281 ctxt = xmlXPathNewParserContext(str, ctx);
13282 if (ctxt == NULL)
13283 return NULL;
13284 xmlXPathEvalExpr(ctxt);
13285
13286 if (ctxt->error != XPATH_EXPRESSION_OK) {
13287 res = NULL;
13288 } else if (ctxt->valueNr != 1) {
13289 xmlXPathErr(ctxt, XPATH_STACK_ERROR);
13290 res = NULL;
13291 } else {
13292 res = valuePop(ctxt);
13293 }
13294
13295 xmlXPathFreeParserContext(ctxt);
13296 return(res);
13297}
13298
13299/**
13300 * xmlXPathSetContextNode:
13301 * @node: the node to to use as the context node
13302 * @ctx: the XPath context
13303 *
13304 * Sets 'node' as the context node. The node must be in the same
13305 * document as that associated with the context.
13306 *
13307 * Returns -1 in case of error or 0 if successful
13308 */
13309int
13310xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
13311 if ((node == NULL) || (ctx == NULL))
13312 return(-1);
13313
13314 if (node->doc == ctx->doc) {
13315 ctx->node = node;
13316 return(0);
13317 }
13318 return(-1);
13319}
13320
13321/**
13322 * xmlXPathNodeEval:
13323 * @node: the node to to use as the context node
13324 * @str: the XPath expression
13325 * @ctx: the XPath context
13326 *
13327 * Evaluate the XPath Location Path in the given context. The node 'node'
13328 * is set as the context node. The context node is not restored.
13329 *
13330 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13331 * the caller has to free the object.
13332 */
13333xmlXPathObjectPtr
13334xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
13335 if (str == NULL)
13336 return(NULL);
13337 if (xmlXPathSetContextNode(node, ctx) < 0)
13338 return(NULL);
13339 return(xmlXPathEval(str, ctx));
13340}
13341
13342/**
13343 * xmlXPathEvalExpression:
13344 * @str: the XPath expression
13345 * @ctxt: the XPath context
13346 *
13347 * Alias for xmlXPathEval().
13348 *
13349 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13350 * the caller has to free the object.
13351 */
13352xmlXPathObjectPtr
13353xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
13354 return(xmlXPathEval(str, ctxt));
13355}
13356
13357/************************************************************************
13358 * *
13359 * Extra functions not pertaining to the XPath spec *
13360 * *
13361 ************************************************************************/
13362/**
13363 * xmlXPathEscapeUriFunction:
13364 * @ctxt: the XPath Parser context
13365 * @nargs: the number of arguments
13366 *
13367 * Implement the escape-uri() XPath function
13368 * string escape-uri(string $str, bool $escape-reserved)
13369 *
13370 * This function applies the URI escaping rules defined in section 2 of [RFC
13371 * 2396] to the string supplied as $uri-part, which typically represents all
13372 * or part of a URI. The effect of the function is to replace any special
13373 * character in the string by an escape sequence of the form %xx%yy...,
13374 * where xxyy... is the hexadecimal representation of the octets used to
13375 * represent the character in UTF-8.
13376 *
13377 * The set of characters that are escaped depends on the setting of the
13378 * boolean argument $escape-reserved.
13379 *
13380 * If $escape-reserved is true, all characters are escaped other than lower
13381 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
13382 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
13383 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
13384 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
13385 * A-F).
13386 *
13387 * If $escape-reserved is false, the behavior differs in that characters
13388 * referred to in [RFC 2396] as reserved characters are not escaped. These
13389 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
13390 *
13391 * [RFC 2396] does not define whether escaped URIs should use lower case or
13392 * upper case for hexadecimal digits. To ensure that escaped URIs can be
13393 * compared using string comparison functions, this function must always use
13394 * the upper-case letters A-F.
13395 *
13396 * Generally, $escape-reserved should be set to true when escaping a string
13397 * that is to form a single part of a URI, and to false when escaping an
13398 * entire URI or URI reference.
13399 *
13400 * In the case of non-ascii characters, the string is encoded according to
13401 * utf-8 and then converted according to RFC 2396.
13402 *
13403 * Examples
13404 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
13405 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
13406 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
13407 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
13408 *
13409 */
13410static void
13411xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
13412 xmlXPathObjectPtr str;
13413 int escape_reserved;
13414 xmlBufPtr target;
13415 xmlChar *cptr;
13416 xmlChar escape[4];
13417
13418 CHECK_ARITY(2);
13419
13420 escape_reserved = xmlXPathPopBoolean(ctxt);
13421
13422 CAST_TO_STRING;
13423 str = valuePop(ctxt);
13424
13425 target = xmlBufCreateSize(64);
13426
13427 escape[0] = '%';
13428 escape[3] = 0;
13429
13430 if (target) {
13431 for (cptr = str->stringval; *cptr; cptr++) {
13432 if ((*cptr >= 'A' && *cptr <= 'Z') ||
13433 (*cptr >= 'a' && *cptr <= 'z') ||
13434 (*cptr >= '0' && *cptr <= '9') ||
13435 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
13436 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
13437 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
13438 (*cptr == '%' &&
13439 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
13440 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
13441 (cptr[1] >= '0' && cptr[1] <= '9')) &&
13442 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
13443 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
13444 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
13445 (!escape_reserved &&
13446 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
13447 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
13448 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
13449 *cptr == ','))) {
13450 xmlBufAdd(target, cptr, 1);
13451 } else {
13452 if ((*cptr >> 4) < 10)
13453 escape[1] = '0' + (*cptr >> 4);
13454 else
13455 escape[1] = 'A' - 10 + (*cptr >> 4);
13456 if ((*cptr & 0xF) < 10)
13457 escape[2] = '0' + (*cptr & 0xF);
13458 else
13459 escape[2] = 'A' - 10 + (*cptr & 0xF);
13460
13461 xmlBufAdd(target, &escape[0], 3);
13462 }
13463 }
13464 }
13465 valuePush(ctxt, xmlXPathCacheNewString(ctxt, xmlBufContent(target)));
13466 xmlBufFree(target);
13467 xmlXPathReleaseObject(ctxt->context, str);
13468}
13469
13470/**
13471 * xmlXPathRegisterAllFunctions:
13472 * @ctxt: the XPath context
13473 *
13474 * Registers all default XPath functions in this context
13475 */
13476void
13477xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
13478{
13479 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
13480 xmlXPathBooleanFunction);
13481 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
13482 xmlXPathCeilingFunction);
13483 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
13484 xmlXPathCountFunction);
13485 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
13486 xmlXPathConcatFunction);
13487 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
13488 xmlXPathContainsFunction);
13489 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
13490 xmlXPathIdFunction);
13491 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
13492 xmlXPathFalseFunction);
13493 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
13494 xmlXPathFloorFunction);
13495 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
13496 xmlXPathLastFunction);
13497 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
13498 xmlXPathLangFunction);
13499 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
13500 xmlXPathLocalNameFunction);
13501 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
13502 xmlXPathNotFunction);
13503 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
13504 xmlXPathNameFunction);
13505 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
13506 xmlXPathNamespaceURIFunction);
13507 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
13508 xmlXPathNormalizeFunction);
13509 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
13510 xmlXPathNumberFunction);
13511 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
13512 xmlXPathPositionFunction);
13513 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
13514 xmlXPathRoundFunction);
13515 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
13516 xmlXPathStringFunction);
13517 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
13518 xmlXPathStringLengthFunction);
13519 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
13520 xmlXPathStartsWithFunction);
13521 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
13522 xmlXPathSubstringFunction);
13523 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
13524 xmlXPathSubstringBeforeFunction);
13525 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
13526 xmlXPathSubstringAfterFunction);
13527 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
13528 xmlXPathSumFunction);
13529 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
13530 xmlXPathTrueFunction);
13531 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
13532 xmlXPathTranslateFunction);
13533
13534 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
13535 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
13536 xmlXPathEscapeUriFunction);
13537}
13538
13539#endif /* LIBXML_XPATH_ENABLED */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette