ReactOS 0.4.15-dev-7961-gdcf9eb0
xpath.c
Go to the documentation of this file.
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/valid.h>
35#include <libxml/xpath.h>
38#include <libxml/hash.h>
39#ifdef LIBXML_XPTR_LOCS_ENABLED
40#include <libxml/xpointer.h>
41#endif
42#ifdef LIBXML_DEBUG_ENABLED
43#include <libxml/debugXML.h>
44#endif
45#include <libxml/xmlerror.h>
46#include <libxml/threads.h>
47#include <libxml/globals.h>
48#ifdef LIBXML_PATTERN_ENABLED
49#include <libxml/pattern.h>
50#endif
51
52#include "buf.h"
53
54#ifdef LIBXML_PATTERN_ENABLED
55#define XPATH_STREAMING
56#endif
57
58#define TODO \
59 xmlGenericError(xmlGenericErrorContext, \
60 "Unimplemented block at %s:%d\n", \
61 __FILE__, __LINE__);
62
70#define WITH_TIM_SORT
71
72/*
73* XP_OPTIMIZED_NON_ELEM_COMPARISON:
74* If defined, this will use xmlXPathCmpNodesExt() instead of
75* xmlXPathCmpNodes(). The new function is optimized comparison of
76* non-element nodes; actually it will speed up comparison only if
77* xmlXPathOrderDocElems() was called in order to index the elements of
78* a tree in document order; Libxslt does such an indexing, thus it will
79* benefit from this optimization.
80*/
81#define XP_OPTIMIZED_NON_ELEM_COMPARISON
82
83/*
84* XP_OPTIMIZED_FILTER_FIRST:
85* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
86* in a way, that it stop evaluation at the first node.
87*/
88#define XP_OPTIMIZED_FILTER_FIRST
89
90/*
91* XP_DEBUG_OBJ_USAGE:
92* Internal flag to enable tracking of how much XPath objects have been
93* created.
94*/
95/* #define XP_DEBUG_OBJ_USAGE */
96
97/*
98 * XPATH_MAX_STEPS:
99 * when compiling an XPath expression we arbitrary limit the maximum
100 * number of step operation in the compiled expression. 1000000 is
101 * an insanely large value which should never be reached under normal
102 * circumstances
103 */
104#define XPATH_MAX_STEPS 1000000
105
106/*
107 * XPATH_MAX_STACK_DEPTH:
108 * when evaluating an XPath expression we arbitrary limit the maximum
109 * number of object allowed to be pushed on the stack. 1000000 is
110 * an insanely large value which should never be reached under normal
111 * circumstances
112 */
113#define XPATH_MAX_STACK_DEPTH 1000000
114
115/*
116 * XPATH_MAX_NODESET_LENGTH:
117 * when evaluating an XPath expression nodesets are created and we
118 * arbitrary limit the maximum length of those node set. 10000000 is
119 * an insanely large value which should never be reached under normal
120 * circumstances, one would first need to construct an in memory tree
121 * with more than 10 millions nodes.
122 */
123#define XPATH_MAX_NODESET_LENGTH 10000000
124
125/*
126 * XPATH_MAX_RECRUSION_DEPTH:
127 * Maximum amount of nested functions calls when parsing or evaluating
128 * expressions
129 */
130#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
131#define XPATH_MAX_RECURSION_DEPTH 500
132#else
133#define XPATH_MAX_RECURSION_DEPTH 5000
134#endif
135
136/*
137 * TODO:
138 * There are a few spots where some tests are done which depend upon ascii
139 * data. These should be enhanced for full UTF8 support (see particularly
140 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
141 */
142
143#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
155static int
157 int depth1, depth2;
158 int misc = 0, precedence1 = 0, precedence2 = 0;
159 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
161 ptrdiff_t l1, l2;
162
163 if ((node1 == NULL) || (node2 == NULL))
164 return(-2);
165
166 if (node1 == node2)
167 return(0);
168
169 /*
170 * a couple of optimizations which will avoid computations in most cases
171 */
172 switch (node1->type) {
173 case XML_ELEMENT_NODE:
174 if (node2->type == XML_ELEMENT_NODE) {
175 if ((0 > (ptrdiff_t) node1->content) &&
176 (0 > (ptrdiff_t) node2->content) &&
177 (node1->doc == node2->doc))
178 {
179 l1 = -((ptrdiff_t) node1->content);
180 l2 = -((ptrdiff_t) node2->content);
181 if (l1 < l2)
182 return(1);
183 if (l1 > l2)
184 return(-1);
185 } else
186 goto turtle_comparison;
187 }
188 break;
190 precedence1 = 1; /* element is owner */
191 miscNode1 = node1;
192 node1 = node1->parent;
193 misc = 1;
194 break;
195 case XML_TEXT_NODE:
197 case XML_COMMENT_NODE:
198 case XML_PI_NODE: {
199 miscNode1 = node1;
200 /*
201 * Find nearest element node.
202 */
203 if (node1->prev != NULL) {
204 do {
205 node1 = node1->prev;
206 if (node1->type == XML_ELEMENT_NODE) {
207 precedence1 = 3; /* element in prev-sibl axis */
208 break;
209 }
210 if (node1->prev == NULL) {
211 precedence1 = 2; /* element is parent */
212 /*
213 * URGENT TODO: Are there any cases, where the
214 * parent of such a node is not an element node?
215 */
216 node1 = node1->parent;
217 break;
218 }
219 } while (1);
220 } else {
221 precedence1 = 2; /* element is parent */
222 node1 = node1->parent;
223 }
224 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
225 (0 <= (ptrdiff_t) node1->content)) {
226 /*
227 * Fallback for whatever case.
228 */
229 node1 = miscNode1;
230 precedence1 = 0;
231 } else
232 misc = 1;
233 }
234 break;
236 /*
237 * TODO: why do we return 1 for namespace nodes?
238 */
239 return(1);
240 default:
241 break;
242 }
243 switch (node2->type) {
244 case XML_ELEMENT_NODE:
245 break;
247 precedence2 = 1; /* element is owner */
248 miscNode2 = node2;
249 node2 = node2->parent;
250 misc = 1;
251 break;
252 case XML_TEXT_NODE:
254 case XML_COMMENT_NODE:
255 case XML_PI_NODE: {
256 miscNode2 = node2;
257 if (node2->prev != NULL) {
258 do {
259 node2 = node2->prev;
260 if (node2->type == XML_ELEMENT_NODE) {
261 precedence2 = 3; /* element in prev-sibl axis */
262 break;
263 }
264 if (node2->prev == NULL) {
265 precedence2 = 2; /* element is parent */
266 node2 = node2->parent;
267 break;
268 }
269 } while (1);
270 } else {
271 precedence2 = 2; /* element is parent */
272 node2 = node2->parent;
273 }
274 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
275 (0 <= (ptrdiff_t) node2->content))
276 {
277 node2 = miscNode2;
278 precedence2 = 0;
279 } else
280 misc = 1;
281 }
282 break;
284 return(1);
285 default:
286 break;
287 }
288 if (misc) {
289 if (node1 == node2) {
290 if (precedence1 == precedence2) {
291 /*
292 * The ugly case; but normally there aren't many
293 * adjacent non-element nodes around.
294 */
295 cur = miscNode2->prev;
296 while (cur != NULL) {
297 if (cur == miscNode1)
298 return(1);
299 if (cur->type == XML_ELEMENT_NODE)
300 return(-1);
301 cur = cur->prev;
302 }
303 return (-1);
304 } else {
305 /*
306 * Evaluate based on higher precedence wrt to the element.
307 * TODO: This assumes attributes are sorted before content.
308 * Is this 100% correct?
309 */
310 if (precedence1 < precedence2)
311 return(1);
312 else
313 return(-1);
314 }
315 }
316 /*
317 * Special case: One of the helper-elements is contained by the other.
318 * <foo>
319 * <node2>
320 * <node1>Text-1(precedence1 == 2)</node1>
321 * </node2>
322 * Text-6(precedence2 == 3)
323 * </foo>
324 */
325 if ((precedence2 == 3) && (precedence1 > 1)) {
326 cur = node1->parent;
327 while (cur) {
328 if (cur == node2)
329 return(1);
330 cur = cur->parent;
331 }
332 }
333 if ((precedence1 == 3) && (precedence2 > 1)) {
334 cur = node2->parent;
335 while (cur) {
336 if (cur == node1)
337 return(-1);
338 cur = cur->parent;
339 }
340 }
341 }
342
343 /*
344 * Speedup using document order if available.
345 */
346 if ((node1->type == XML_ELEMENT_NODE) &&
347 (node2->type == XML_ELEMENT_NODE) &&
348 (0 > (ptrdiff_t) node1->content) &&
349 (0 > (ptrdiff_t) node2->content) &&
350 (node1->doc == node2->doc)) {
351
352 l1 = -((ptrdiff_t) node1->content);
353 l2 = -((ptrdiff_t) node2->content);
354 if (l1 < l2)
355 return(1);
356 if (l1 > l2)
357 return(-1);
358 }
359
360turtle_comparison:
361
362 if (node1 == node2->prev)
363 return(1);
364 if (node1 == node2->next)
365 return(-1);
366 /*
367 * compute depth to root
368 */
369 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
370 if (cur->parent == node1)
371 return(1);
372 depth2++;
373 }
374 root = cur;
375 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
376 if (cur->parent == node2)
377 return(-1);
378 depth1++;
379 }
380 /*
381 * Distinct document (or distinct entities :-( ) case.
382 */
383 if (root != cur) {
384 return(-2);
385 }
386 /*
387 * get the nearest common ancestor.
388 */
389 while (depth1 > depth2) {
390 depth1--;
391 node1 = node1->parent;
392 }
393 while (depth2 > depth1) {
394 depth2--;
395 node2 = node2->parent;
396 }
397 while (node1->parent != node2->parent) {
398 node1 = node1->parent;
399 node2 = node2->parent;
400 /* should not happen but just in case ... */
401 if ((node1 == NULL) || (node2 == NULL))
402 return(-2);
403 }
404 /*
405 * Find who's first.
406 */
407 if (node1 == node2->prev)
408 return(1);
409 if (node1 == node2->next)
410 return(-1);
411 /*
412 * Speedup using document order if available.
413 */
414 if ((node1->type == XML_ELEMENT_NODE) &&
415 (node2->type == XML_ELEMENT_NODE) &&
416 (0 > (ptrdiff_t) node1->content) &&
417 (0 > (ptrdiff_t) node2->content) &&
418 (node1->doc == node2->doc)) {
419
420 l1 = -((ptrdiff_t) node1->content);
421 l2 = -((ptrdiff_t) node2->content);
422 if (l1 < l2)
423 return(1);
424 if (l1 > l2)
425 return(-1);
426 }
427
428 for (cur = node1->next;cur != NULL;cur = cur->next)
429 if (cur == node2)
430 return(1);
431 return(-1); /* assume there is no sibling list corruption */
432}
433#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
434
435/*
436 * Wrapper for the Timsort algorithm from timsort.h
437 */
438#ifdef WITH_TIM_SORT
439#define SORT_NAME libxml_domnode
440#define SORT_TYPE xmlNodePtr
451static
453#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
455 {
456 int res = xmlXPathCmpNodesExt(x, y);
457 return res == -2 ? res : -res;
458 }
459#else
460 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
461 {
462 int res = xmlXPathCmpNodes(x, y);
463 return res == -2 ? res : -res;
464 }
465#endif
466#define SORT_CMP(x, y) (wrap_cmp(x, y))
467#include "timsort.h"
468#endif /* WITH_TIM_SORT */
469
470#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
471
472/************************************************************************
473 * *
474 * Floating point stuff *
475 * *
476 ************************************************************************/
477
478double xmlXPathNAN = 0.0;
479double xmlXPathPINF = 0.0;
480double xmlXPathNINF = 0.0;
481
490ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
491void
492xmlXPathInit(void) {
493#if defined(NAN) && defined(INFINITY)
494 xmlXPathNAN = NAN;
495 xmlXPathPINF = INFINITY;
496 xmlXPathNINF = -INFINITY;
497#else
498 /* MSVC doesn't allow division by zero in constant expressions. */
499 double zero = 0.0;
500 xmlXPathNAN = 0.0 / zero;
501 xmlXPathPINF = 1.0 / zero;
502 xmlXPathNINF = -xmlXPathPINF;
503#endif
504}
505
512int
513xmlXPathIsNaN(double val) {
514#ifdef isnan
515 return isnan(val);
516#else
517 return !(val == val);
518#endif
519}
520
527int
528xmlXPathIsInf(double val) {
529#ifdef isinf
530 return isinf(val) ? (val > 0 ? 1 : -1) : 0;
531#else
532 if (val >= xmlXPathPINF)
533 return 1;
534 if (val <= -xmlXPathPINF)
535 return -1;
536 return 0;
537#endif
538}
539
540#endif /* SCHEMAS or XPATH */
541
542#ifdef LIBXML_XPATH_ENABLED
543
544/*
545 * TODO: when compatibility allows remove all "fake node libxslt" strings
546 * the test should just be name[0] = ' '
547 */
548#ifdef DEBUG_XPATH_EXPRESSION
549#define DEBUG_STEP
550#define DEBUG_EXPR
551#define DEBUG_EVAL_COUNTS
552#endif
553
554static xmlNs xmlXPathXMLNamespaceStruct = {
555 NULL,
558 BAD_CAST "xml",
559 NULL,
560 NULL
561};
562static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
563#ifndef LIBXML_THREAD_ENABLED
564/*
565 * Optimizer is disabled only when threaded apps are detected while
566 * the library ain't compiled for thread safety.
567 */
568static int xmlXPathDisableOptimizer = 0;
569#endif
570
571/************************************************************************
572 * *
573 * Error handling routines *
574 * *
575 ************************************************************************/
576
583#define XP_ERRORNULL(X) \
584 { xmlXPathErr(ctxt, X); return(NULL); }
585
586/*
587 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
588 */
589static const char* const xmlXPathErrorMessages[] = {
590 "Ok\n",
591 "Number encoding\n",
592 "Unfinished literal\n",
593 "Start of literal\n",
594 "Expected $ for variable reference\n",
595 "Undefined variable\n",
596 "Invalid predicate\n",
597 "Invalid expression\n",
598 "Missing closing curly brace\n",
599 "Unregistered function\n",
600 "Invalid operand\n",
601 "Invalid type\n",
602 "Invalid number of arguments\n",
603 "Invalid context size\n",
604 "Invalid context position\n",
605 "Memory allocation error\n",
606 "Syntax error\n",
607 "Resource error\n",
608 "Sub resource error\n",
609 "Undefined namespace prefix\n",
610 "Encoding error\n",
611 "Char out of XML range\n",
612 "Invalid or incomplete context\n",
613 "Stack usage error\n",
614 "Forbidden variable\n",
615 "Operation limit exceeded\n",
616 "Recursion limit exceeded\n",
617 "?? Unknown error ??\n" /* Must be last in the list! */
618};
619#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
620 sizeof(xmlXPathErrorMessages[0])) - 1)
628static void
629xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
630{
631 if (ctxt != NULL) {
632 xmlResetError(&ctxt->lastError);
633 if (extra) {
634 xmlChar buf[200];
635
636 xmlStrPrintf(buf, 200,
637 "Memory allocation failed : %s\n",
638 extra);
639 ctxt->lastError.message = (char *) xmlStrdup(buf);
640 } else {
641 ctxt->lastError.message = (char *)
642 xmlStrdup(BAD_CAST "Memory allocation failed\n");
643 }
644 ctxt->lastError.domain = XML_FROM_XPATH;
645 ctxt->lastError.code = XML_ERR_NO_MEMORY;
646 if (ctxt->error != NULL)
647 ctxt->error(ctxt->userData, &ctxt->lastError);
648 } else {
649 if (extra)
650 __xmlRaiseError(NULL, NULL, NULL,
653 extra, NULL, NULL, 0, 0,
654 "Memory allocation failed : %s\n", extra);
655 else
656 __xmlRaiseError(NULL, NULL, NULL,
659 NULL, NULL, NULL, 0, 0,
660 "Memory allocation failed\n");
661 }
662}
663
671static void
672xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
673{
674 if (ctxt == NULL)
675 xmlXPathErrMemory(NULL, extra);
676 else {
677 ctxt->error = XPATH_MEMORY_ERROR;
678 xmlXPathErrMemory(ctxt->context, extra);
679 }
680}
681
689void
690xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
691{
692 if ((error < 0) || (error > MAXERRNO))
693 error = MAXERRNO;
694 if (ctxt == NULL) {
695 __xmlRaiseError(NULL, NULL, NULL,
697 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
699 NULL, NULL, NULL, 0, 0,
700 "%s", xmlXPathErrorMessages[error]);
701 return;
702 }
703 ctxt->error = error;
704 if (ctxt->context == NULL) {
705 __xmlRaiseError(NULL, NULL, NULL,
707 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
709 (const char *) ctxt->base, NULL, NULL,
710 ctxt->cur - ctxt->base, 0,
711 "%s", xmlXPathErrorMessages[error]);
712 return;
713 }
714
715 /* cleanup current last error */
716 xmlResetError(&ctxt->context->lastError);
717
718 ctxt->context->lastError.domain = XML_FROM_XPATH;
719 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
720 XPATH_EXPRESSION_OK;
721 ctxt->context->lastError.level = XML_ERR_ERROR;
722 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
723 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
724 ctxt->context->lastError.node = ctxt->context->debugNode;
725 if (ctxt->context->error != NULL) {
726 ctxt->context->error(ctxt->context->userData,
727 &ctxt->context->lastError);
728 } else {
729 __xmlRaiseError(NULL, NULL, NULL,
730 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
731 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
733 (const char *) ctxt->base, NULL, NULL,
734 ctxt->cur - ctxt->base, 0,
735 "%s", xmlXPathErrorMessages[error]);
736 }
737
738}
739
749void
750xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
751 int line ATTRIBUTE_UNUSED, int no) {
752 xmlXPathErr(ctxt, no);
753}
754
763static int
764xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
765 xmlXPathContextPtr xpctxt = ctxt->context;
766
767 if ((opCount > xpctxt->opLimit) ||
768 (xpctxt->opCount > xpctxt->opLimit - opCount)) {
769 xpctxt->opCount = xpctxt->opLimit;
770 xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
771 return(-1);
772 }
773
774 xpctxt->opCount += opCount;
775 return(0);
776}
777
778#define OP_LIMIT_EXCEEDED(ctxt, n) \
779 ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
780
781/************************************************************************
782 * *
783 * Utilities *
784 * *
785 ************************************************************************/
786
792typedef struct _xmlPointerList xmlPointerList;
793typedef xmlPointerList *xmlPointerListPtr;
794struct _xmlPointerList {
795 void **items;
796 int number;
797 int size;
798};
799/*
800* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
801* and here, we should make the functions public.
802*/
803static int
804xmlPointerListAddSize(xmlPointerListPtr list,
805 void *item,
806 int initialSize)
807{
808 if (list->items == NULL) {
809 if (initialSize <= 0)
810 initialSize = 1;
811 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
812 if (list->items == NULL) {
813 xmlXPathErrMemory(NULL,
814 "xmlPointerListCreate: allocating item\n");
815 return(-1);
816 }
817 list->number = 0;
818 list->size = initialSize;
819 } else if (list->size <= list->number) {
820 if (list->size > 50000000) {
821 xmlXPathErrMemory(NULL,
822 "xmlPointerListAddSize: re-allocating item\n");
823 return(-1);
824 }
825 list->size *= 2;
826 list->items = (void **) xmlRealloc(list->items,
827 list->size * sizeof(void *));
828 if (list->items == NULL) {
829 xmlXPathErrMemory(NULL,
830 "xmlPointerListAddSize: re-allocating item\n");
831 list->size = 0;
832 return(-1);
833 }
834 }
835 list->items[list->number++] = item;
836 return(0);
837}
838
846static xmlPointerListPtr
847xmlPointerListCreate(int initialSize)
848{
849 xmlPointerListPtr ret;
850
851 ret = xmlMalloc(sizeof(xmlPointerList));
852 if (ret == NULL) {
853 xmlXPathErrMemory(NULL,
854 "xmlPointerListCreate: allocating item\n");
855 return (NULL);
856 }
857 memset(ret, 0, sizeof(xmlPointerList));
858 if (initialSize > 0) {
859 xmlPointerListAddSize(ret, NULL, initialSize);
860 ret->number = 0;
861 }
862 return (ret);
863}
864
871static void
872xmlPointerListFree(xmlPointerListPtr list)
873{
874 if (list == NULL)
875 return;
876 if (list->items != NULL)
877 xmlFree(list->items);
878 xmlFree(list);
879}
880
881/************************************************************************
882 * *
883 * Parser Types *
884 * *
885 ************************************************************************/
886
887/*
888 * Types are private:
889 */
890
891typedef enum {
892 XPATH_OP_END=0,
893 XPATH_OP_AND,
894 XPATH_OP_OR,
895 XPATH_OP_EQUAL,
896 XPATH_OP_CMP,
897 XPATH_OP_PLUS,
898 XPATH_OP_MULT,
899 XPATH_OP_UNION,
900 XPATH_OP_ROOT,
901 XPATH_OP_NODE,
902 XPATH_OP_COLLECT,
903 XPATH_OP_VALUE, /* 11 */
904 XPATH_OP_VARIABLE,
905 XPATH_OP_FUNCTION,
906 XPATH_OP_ARG,
907 XPATH_OP_PREDICATE,
908 XPATH_OP_FILTER, /* 16 */
909 XPATH_OP_SORT /* 17 */
910#ifdef LIBXML_XPTR_LOCS_ENABLED
911 ,XPATH_OP_RANGETO
912#endif
913} xmlXPathOp;
914
915typedef enum {
916 AXIS_ANCESTOR = 1,
917 AXIS_ANCESTOR_OR_SELF,
920 AXIS_DESCENDANT,
921 AXIS_DESCENDANT_OR_SELF,
922 AXIS_FOLLOWING,
923 AXIS_FOLLOWING_SIBLING,
924 AXIS_NAMESPACE,
925 AXIS_PARENT,
926 AXIS_PRECEDING,
927 AXIS_PRECEDING_SIBLING,
928 AXIS_SELF
929} xmlXPathAxisVal;
930
931typedef enum {
932 NODE_TEST_NONE = 0,
933 NODE_TEST_TYPE = 1,
934 NODE_TEST_PI = 2,
935 NODE_TEST_ALL = 3,
936 NODE_TEST_NS = 4,
937 NODE_TEST_NAME = 5
938} xmlXPathTestVal;
939
940typedef enum {
941 NODE_TYPE_NODE = 0,
942 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
943 NODE_TYPE_TEXT = XML_TEXT_NODE,
944 NODE_TYPE_PI = XML_PI_NODE
945} xmlXPathTypeVal;
946
947typedef struct _xmlXPathStepOp xmlXPathStepOp;
948typedef xmlXPathStepOp *xmlXPathStepOpPtr;
949struct _xmlXPathStepOp {
950 xmlXPathOp op; /* The identifier of the operation */
951 int ch1; /* First child */
952 int ch2; /* Second child */
953 int value;
954 int value2;
955 int value3;
956 void *value4;
957 void *value5;
958 xmlXPathFunction cache;
959 void *cacheURI;
960};
961
962struct _xmlXPathCompExpr {
963 int nbStep; /* Number of steps in this expression */
964 int maxStep; /* Maximum number of steps allocated */
965 xmlXPathStepOp *steps; /* ops for computation of this expression */
966 int last; /* index of last step in expression */
967 xmlChar *expr; /* the expression being computed */
968 xmlDictPtr dict; /* the dictionary to use if any */
969#ifdef DEBUG_EVAL_COUNTS
970 int nb;
972#endif
973#ifdef XPATH_STREAMING
974 xmlPatternPtr stream;
975#endif
976};
977
978/************************************************************************
979 * *
980 * Forward declarations *
981 * *
982 ************************************************************************/
983static void
984xmlXPathFreeValueTree(xmlNodeSetPtr obj);
985static void
986xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
987static int
988xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
989 xmlXPathStepOpPtr op, xmlNodePtr *first);
990static int
991xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
992 xmlXPathStepOpPtr op,
993 int isPredicate);
994static void
995xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
996
997/************************************************************************
998 * *
999 * Parser Type functions *
1000 * *
1001 ************************************************************************/
1002
1010static xmlXPathCompExprPtr
1011xmlXPathNewCompExpr(void) {
1012 xmlXPathCompExprPtr cur;
1013
1014 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1015 if (cur == NULL) {
1016 xmlXPathErrMemory(NULL, "allocating component\n");
1017 return(NULL);
1018 }
1019 memset(cur, 0, sizeof(xmlXPathCompExpr));
1020 cur->maxStep = 10;
1021 cur->nbStep = 0;
1022 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1023 sizeof(xmlXPathStepOp));
1024 if (cur->steps == NULL) {
1025 xmlXPathErrMemory(NULL, "allocating steps\n");
1026 xmlFree(cur);
1027 return(NULL);
1028 }
1029 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1030 cur->last = -1;
1031#ifdef DEBUG_EVAL_COUNTS
1032 cur->nb = 0;
1033#endif
1034 return(cur);
1035}
1036
1043void
1044xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1045{
1046 xmlXPathStepOpPtr op;
1047 int i;
1048
1049 if (comp == NULL)
1050 return;
1051 if (comp->dict == NULL) {
1052 for (i = 0; i < comp->nbStep; i++) {
1053 op = &comp->steps[i];
1054 if (op->value4 != NULL) {
1055 if (op->op == XPATH_OP_VALUE)
1056 xmlXPathFreeObject(op->value4);
1057 else
1058 xmlFree(op->value4);
1059 }
1060 if (op->value5 != NULL)
1061 xmlFree(op->value5);
1062 }
1063 } else {
1064 for (i = 0; i < comp->nbStep; i++) {
1065 op = &comp->steps[i];
1066 if (op->value4 != NULL) {
1067 if (op->op == XPATH_OP_VALUE)
1068 xmlXPathFreeObject(op->value4);
1069 }
1070 }
1071 xmlDictFree(comp->dict);
1072 }
1073 if (comp->steps != NULL) {
1074 xmlFree(comp->steps);
1075 }
1076#ifdef DEBUG_EVAL_COUNTS
1077 if (comp->string != NULL) {
1078 xmlFree(comp->string);
1079 }
1080#endif
1081#ifdef XPATH_STREAMING
1082 if (comp->stream != NULL) {
1083 xmlFreePatternList(comp->stream);
1084 }
1085#endif
1086 if (comp->expr != NULL) {
1087 xmlFree(comp->expr);
1088 }
1089
1090 xmlFree(comp);
1091}
1092
1109static int
1110xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1111 xmlXPathOp op, int value,
1112 int value2, int value3, void *value4, void *value5) {
1113 xmlXPathCompExprPtr comp = ctxt->comp;
1114 if (comp->nbStep >= comp->maxStep) {
1115 xmlXPathStepOp *real;
1116
1117 if (comp->maxStep >= XPATH_MAX_STEPS) {
1118 xmlXPathPErrMemory(ctxt, "adding step\n");
1119 return(-1);
1120 }
1121 comp->maxStep *= 2;
1122 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1123 comp->maxStep * sizeof(xmlXPathStepOp));
1124 if (real == NULL) {
1125 comp->maxStep /= 2;
1126 xmlXPathPErrMemory(ctxt, "adding step\n");
1127 return(-1);
1128 }
1129 comp->steps = real;
1130 }
1131 comp->last = comp->nbStep;
1132 comp->steps[comp->nbStep].ch1 = ch1;
1133 comp->steps[comp->nbStep].ch2 = ch2;
1134 comp->steps[comp->nbStep].op = op;
1135 comp->steps[comp->nbStep].value = value;
1136 comp->steps[comp->nbStep].value2 = value2;
1137 comp->steps[comp->nbStep].value3 = value3;
1138 if ((comp->dict != NULL) &&
1139 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1140 (op == XPATH_OP_COLLECT))) {
1141 if (value4 != NULL) {
1142 comp->steps[comp->nbStep].value4 = (xmlChar *)
1143 (void *)xmlDictLookup(comp->dict, value4, -1);
1144 xmlFree(value4);
1145 } else
1146 comp->steps[comp->nbStep].value4 = NULL;
1147 if (value5 != NULL) {
1148 comp->steps[comp->nbStep].value5 = (xmlChar *)
1149 (void *)xmlDictLookup(comp->dict, value5, -1);
1150 xmlFree(value5);
1151 } else
1152 comp->steps[comp->nbStep].value5 = NULL;
1153 } else {
1154 comp->steps[comp->nbStep].value4 = value4;
1155 comp->steps[comp->nbStep].value5 = value5;
1156 }
1157 comp->steps[comp->nbStep].cache = NULL;
1158 return(comp->nbStep++);
1159}
1160
1168static void
1169xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1170 int tmp;
1171
1172#ifndef LIBXML_THREAD_ENABLED
1173 /*
1174 * Since this manipulates possibly shared variables, this is
1175 * disabled if one detects that the library is used in a multithreaded
1176 * application
1177 */
1178 if (xmlXPathDisableOptimizer)
1179 return;
1180#endif
1181
1182 tmp = op->ch1;
1183 op->ch1 = op->ch2;
1184 op->ch2 = tmp;
1185}
1186
1187#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1188 xmlXPathCompExprAdd(ctxt, (op1), (op2), \
1189 (op), (val), (val2), (val3), (val4), (val5))
1190#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1191 xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \
1192 (op), (val), (val2), (val3), (val4), (val5))
1193
1194#define PUSH_LEAVE_EXPR(op, val, val2) \
1195xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1196
1197#define PUSH_UNARY_EXPR(op, ch, val, val2) \
1198xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1199
1200#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1201xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
1202 (val), (val2), 0 ,NULL ,NULL)
1203
1204/************************************************************************
1205 * *
1206 * XPath object cache structures *
1207 * *
1208 ************************************************************************/
1209
1210/* #define XP_DEFAULT_CACHE_ON */
1211
1212#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1213
1214typedef struct _xmlXPathContextCache xmlXPathContextCache;
1215typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1216struct _xmlXPathContextCache {
1217 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1218 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1219 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1220 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1221 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
1222 int maxNodeset;
1223 int maxString;
1224 int maxBoolean;
1225 int maxNumber;
1226 int maxMisc;
1227#ifdef XP_DEBUG_OBJ_USAGE
1228 int dbgCachedAll;
1229 int dbgCachedNodeset;
1230 int dbgCachedString;
1231 int dbgCachedBool;
1232 int dbgCachedNumber;
1233 int dbgCachedPoint;
1234 int dbgCachedRange;
1235 int dbgCachedLocset;
1236 int dbgCachedUsers;
1237 int dbgCachedXSLTTree;
1238 int dbgCachedUndefined;
1239
1240
1241 int dbgReusedAll;
1242 int dbgReusedNodeset;
1243 int dbgReusedString;
1244 int dbgReusedBool;
1245 int dbgReusedNumber;
1246 int dbgReusedPoint;
1247 int dbgReusedRange;
1248 int dbgReusedLocset;
1249 int dbgReusedUsers;
1250 int dbgReusedXSLTTree;
1251 int dbgReusedUndefined;
1252
1253#endif
1254};
1255
1256/************************************************************************
1257 * *
1258 * Debugging related functions *
1259 * *
1260 ************************************************************************/
1261
1262#define STRANGE \
1263 xmlGenericError(xmlGenericErrorContext, \
1264 "Internal error at %s:%d\n", \
1265 __FILE__, __LINE__);
1266
1267#ifdef LIBXML_DEBUG_ENABLED
1268static void
1269xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1270 int i;
1271 char shift[100];
1272
1273 for (i = 0;((i < depth) && (i < 25));i++)
1274 shift[2 * i] = shift[2 * i + 1] = ' ';
1275 shift[2 * i] = shift[2 * i + 1] = 0;
1276 if (cur == NULL) {
1277 fprintf(output, "%s", shift);
1278 fprintf(output, "Node is NULL !\n");
1279 return;
1280
1281 }
1282
1283 if ((cur->type == XML_DOCUMENT_NODE) ||
1284 (cur->type == XML_HTML_DOCUMENT_NODE)) {
1285 fprintf(output, "%s", shift);
1286 fprintf(output, " /\n");
1287 } else if (cur->type == XML_ATTRIBUTE_NODE)
1288 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1289 else
1290 xmlDebugDumpOneNode(output, cur, depth);
1291}
1292static void
1293xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1294 xmlNodePtr tmp;
1295 int i;
1296 char shift[100];
1297
1298 for (i = 0;((i < depth) && (i < 25));i++)
1299 shift[2 * i] = shift[2 * i + 1] = ' ';
1300 shift[2 * i] = shift[2 * i + 1] = 0;
1301 if (cur == NULL) {
1302 fprintf(output, "%s", shift);
1303 fprintf(output, "Node is NULL !\n");
1304 return;
1305
1306 }
1307
1308 while (cur != NULL) {
1309 tmp = cur;
1310 cur = cur->next;
1311 xmlDebugDumpOneNode(output, tmp, depth);
1312 }
1313}
1314
1315static void
1316xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1317 int i;
1318 char shift[100];
1319
1320 for (i = 0;((i < depth) && (i < 25));i++)
1321 shift[2 * i] = shift[2 * i + 1] = ' ';
1322 shift[2 * i] = shift[2 * i + 1] = 0;
1323
1324 if (cur == NULL) {
1325 fprintf(output, "%s", shift);
1326 fprintf(output, "NodeSet is NULL !\n");
1327 return;
1328
1329 }
1330
1331 if (cur != NULL) {
1332 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1333 for (i = 0;i < cur->nodeNr;i++) {
1334 fprintf(output, "%s", shift);
1335 fprintf(output, "%d", i + 1);
1336 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1337 }
1338 }
1339}
1340
1341static void
1342xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1343 int i;
1344 char shift[100];
1345
1346 for (i = 0;((i < depth) && (i < 25));i++)
1347 shift[2 * i] = shift[2 * i + 1] = ' ';
1348 shift[2 * i] = shift[2 * i + 1] = 0;
1349
1350 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1351 fprintf(output, "%s", shift);
1352 fprintf(output, "Value Tree is NULL !\n");
1353 return;
1354
1355 }
1356
1357 fprintf(output, "%s", shift);
1358 fprintf(output, "%d", i + 1);
1359 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1360}
1361#if defined(LIBXML_XPTR_LOCS_ENABLED)
1362static void
1363xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1364 int i;
1365 char shift[100];
1366
1367 for (i = 0;((i < depth) && (i < 25));i++)
1368 shift[2 * i] = shift[2 * i + 1] = ' ';
1369 shift[2 * i] = shift[2 * i + 1] = 0;
1370
1371 if (cur == NULL) {
1372 fprintf(output, "%s", shift);
1373 fprintf(output, "LocationSet is NULL !\n");
1374 return;
1375
1376 }
1377
1378 for (i = 0;i < cur->locNr;i++) {
1379 fprintf(output, "%s", shift);
1380 fprintf(output, "%d : ", i + 1);
1381 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1382 }
1383}
1384#endif /* LIBXML_XPTR_LOCS_ENABLED */
1385
1394void
1395xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1396 int i;
1397 char shift[100];
1398
1399 if (output == NULL) return;
1400
1401 for (i = 0;((i < depth) && (i < 25));i++)
1402 shift[2 * i] = shift[2 * i + 1] = ' ';
1403 shift[2 * i] = shift[2 * i + 1] = 0;
1404
1405
1406 fprintf(output, "%s", shift);
1407
1408 if (cur == NULL) {
1409 fprintf(output, "Object is empty (NULL)\n");
1410 return;
1411 }
1412 switch(cur->type) {
1413 case XPATH_UNDEFINED:
1414 fprintf(output, "Object is uninitialized\n");
1415 break;
1416 case XPATH_NODESET:
1417 fprintf(output, "Object is a Node Set :\n");
1418 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1419 break;
1420 case XPATH_XSLT_TREE:
1421 fprintf(output, "Object is an XSLT value tree :\n");
1422 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1423 break;
1424 case XPATH_BOOLEAN:
1425 fprintf(output, "Object is a Boolean : ");
1426 if (cur->boolval) fprintf(output, "true\n");
1427 else fprintf(output, "false\n");
1428 break;
1429 case XPATH_NUMBER:
1430 switch (xmlXPathIsInf(cur->floatval)) {
1431 case 1:
1432 fprintf(output, "Object is a number : Infinity\n");
1433 break;
1434 case -1:
1435 fprintf(output, "Object is a number : -Infinity\n");
1436 break;
1437 default:
1438 if (xmlXPathIsNaN(cur->floatval)) {
1439 fprintf(output, "Object is a number : NaN\n");
1440 } else if (cur->floatval == 0) {
1441 /* Omit sign for negative zero. */
1442 fprintf(output, "Object is a number : 0\n");
1443 } else {
1444 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1445 }
1446 }
1447 break;
1448 case XPATH_STRING:
1449 fprintf(output, "Object is a string : ");
1450 xmlDebugDumpString(output, cur->stringval);
1451 fprintf(output, "\n");
1452 break;
1453#ifdef LIBXML_XPTR_LOCS_ENABLED
1454 case XPATH_POINT:
1455 fprintf(output, "Object is a point : index %d in node", cur->index);
1456 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1457 fprintf(output, "\n");
1458 break;
1459 case XPATH_RANGE:
1460 if ((cur->user2 == NULL) ||
1461 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1462 fprintf(output, "Object is a collapsed range :\n");
1463 fprintf(output, "%s", shift);
1464 if (cur->index >= 0)
1465 fprintf(output, "index %d in ", cur->index);
1466 fprintf(output, "node\n");
1467 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1468 depth + 1);
1469 } else {
1470 fprintf(output, "Object is a range :\n");
1471 fprintf(output, "%s", shift);
1472 fprintf(output, "From ");
1473 if (cur->index >= 0)
1474 fprintf(output, "index %d in ", cur->index);
1475 fprintf(output, "node\n");
1476 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1477 depth + 1);
1478 fprintf(output, "%s", shift);
1479 fprintf(output, "To ");
1480 if (cur->index2 >= 0)
1481 fprintf(output, "index %d in ", cur->index2);
1482 fprintf(output, "node\n");
1483 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1484 depth + 1);
1485 fprintf(output, "\n");
1486 }
1487 break;
1488 case XPATH_LOCATIONSET:
1489 fprintf(output, "Object is a Location Set:\n");
1490 xmlXPathDebugDumpLocationSet(output,
1491 (xmlLocationSetPtr) cur->user, depth);
1492 break;
1493#endif /* LIBXML_XPTR_LOCS_ENABLED */
1494 case XPATH_USERS:
1495 fprintf(output, "Object is user defined\n");
1496 break;
1497 }
1498}
1499
1500static void
1501xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1502 xmlXPathStepOpPtr op, int depth) {
1503 int i;
1504 char shift[100];
1505
1506 for (i = 0;((i < depth) && (i < 25));i++)
1507 shift[2 * i] = shift[2 * i + 1] = ' ';
1508 shift[2 * i] = shift[2 * i + 1] = 0;
1509
1510 fprintf(output, "%s", shift);
1511 if (op == NULL) {
1512 fprintf(output, "Step is NULL\n");
1513 return;
1514 }
1515 switch (op->op) {
1516 case XPATH_OP_END:
1517 fprintf(output, "END"); break;
1518 case XPATH_OP_AND:
1519 fprintf(output, "AND"); break;
1520 case XPATH_OP_OR:
1521 fprintf(output, "OR"); break;
1522 case XPATH_OP_EQUAL:
1523 if (op->value)
1524 fprintf(output, "EQUAL =");
1525 else
1526 fprintf(output, "EQUAL !=");
1527 break;
1528 case XPATH_OP_CMP:
1529 if (op->value)
1530 fprintf(output, "CMP <");
1531 else
1532 fprintf(output, "CMP >");
1533 if (!op->value2)
1534 fprintf(output, "=");
1535 break;
1536 case XPATH_OP_PLUS:
1537 if (op->value == 0)
1538 fprintf(output, "PLUS -");
1539 else if (op->value == 1)
1540 fprintf(output, "PLUS +");
1541 else if (op->value == 2)
1542 fprintf(output, "PLUS unary -");
1543 else if (op->value == 3)
1544 fprintf(output, "PLUS unary - -");
1545 break;
1546 case XPATH_OP_MULT:
1547 if (op->value == 0)
1548 fprintf(output, "MULT *");
1549 else if (op->value == 1)
1550 fprintf(output, "MULT div");
1551 else
1552 fprintf(output, "MULT mod");
1553 break;
1554 case XPATH_OP_UNION:
1555 fprintf(output, "UNION"); break;
1556 case XPATH_OP_ROOT:
1557 fprintf(output, "ROOT"); break;
1558 case XPATH_OP_NODE:
1559 fprintf(output, "NODE"); break;
1560 case XPATH_OP_SORT:
1561 fprintf(output, "SORT"); break;
1562 case XPATH_OP_COLLECT: {
1563 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1564 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1565 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1566 const xmlChar *prefix = op->value4;
1567 const xmlChar *name = op->value5;
1568
1569 fprintf(output, "COLLECT ");
1570 switch (axis) {
1571 case AXIS_ANCESTOR:
1572 fprintf(output, " 'ancestors' "); break;
1573 case AXIS_ANCESTOR_OR_SELF:
1574 fprintf(output, " 'ancestors-or-self' "); break;
1575 case AXIS_ATTRIBUTE:
1576 fprintf(output, " 'attributes' "); break;
1577 case AXIS_CHILD:
1578 fprintf(output, " 'child' "); break;
1579 case AXIS_DESCENDANT:
1580 fprintf(output, " 'descendant' "); break;
1581 case AXIS_DESCENDANT_OR_SELF:
1582 fprintf(output, " 'descendant-or-self' "); break;
1583 case AXIS_FOLLOWING:
1584 fprintf(output, " 'following' "); break;
1585 case AXIS_FOLLOWING_SIBLING:
1586 fprintf(output, " 'following-siblings' "); break;
1587 case AXIS_NAMESPACE:
1588 fprintf(output, " 'namespace' "); break;
1589 case AXIS_PARENT:
1590 fprintf(output, " 'parent' "); break;
1591 case AXIS_PRECEDING:
1592 fprintf(output, " 'preceding' "); break;
1593 case AXIS_PRECEDING_SIBLING:
1594 fprintf(output, " 'preceding-sibling' "); break;
1595 case AXIS_SELF:
1596 fprintf(output, " 'self' "); break;
1597 }
1598 switch (test) {
1599 case NODE_TEST_NONE:
1600 fprintf(output, "'none' "); break;
1601 case NODE_TEST_TYPE:
1602 fprintf(output, "'type' "); break;
1603 case NODE_TEST_PI:
1604 fprintf(output, "'PI' "); break;
1605 case NODE_TEST_ALL:
1606 fprintf(output, "'all' "); break;
1607 case NODE_TEST_NS:
1608 fprintf(output, "'namespace' "); break;
1609 case NODE_TEST_NAME:
1610 fprintf(output, "'name' "); break;
1611 }
1612 switch (type) {
1613 case NODE_TYPE_NODE:
1614 fprintf(output, "'node' "); break;
1615 case NODE_TYPE_COMMENT:
1616 fprintf(output, "'comment' "); break;
1617 case NODE_TYPE_TEXT:
1618 fprintf(output, "'text' "); break;
1619 case NODE_TYPE_PI:
1620 fprintf(output, "'PI' "); break;
1621 }
1622 if (prefix != NULL)
1623 fprintf(output, "%s:", prefix);
1624 if (name != NULL)
1625 fprintf(output, "%s", (const char *) name);
1626 break;
1627
1628 }
1629 case XPATH_OP_VALUE: {
1630 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1631
1632 fprintf(output, "ELEM ");
1633 xmlXPathDebugDumpObject(output, object, 0);
1634 goto finish;
1635 }
1636 case XPATH_OP_VARIABLE: {
1637 const xmlChar *prefix = op->value5;
1638 const xmlChar *name = op->value4;
1639
1640 if (prefix != NULL)
1641 fprintf(output, "VARIABLE %s:%s", prefix, name);
1642 else
1643 fprintf(output, "VARIABLE %s", name);
1644 break;
1645 }
1646 case XPATH_OP_FUNCTION: {
1647 int nbargs = op->value;
1648 const xmlChar *prefix = op->value5;
1649 const xmlChar *name = op->value4;
1650
1651 if (prefix != NULL)
1652 fprintf(output, "FUNCTION %s:%s(%d args)",
1653 prefix, name, nbargs);
1654 else
1655 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1656 break;
1657 }
1658 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1659 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1660 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1661#ifdef LIBXML_XPTR_LOCS_ENABLED
1662 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1663#endif
1664 default:
1665 fprintf(output, "UNKNOWN %d\n", op->op); return;
1666 }
1667 fprintf(output, "\n");
1668finish:
1669 if (op->ch1 >= 0)
1670 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1671 if (op->ch2 >= 0)
1672 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1673}
1674
1683void
1684xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1685 int depth) {
1686 int i;
1687 char shift[100];
1688
1689 if ((output == NULL) || (comp == NULL)) return;
1690
1691 for (i = 0;((i < depth) && (i < 25));i++)
1692 shift[2 * i] = shift[2 * i + 1] = ' ';
1693 shift[2 * i] = shift[2 * i + 1] = 0;
1694
1695 fprintf(output, "%s", shift);
1696
1697#ifdef XPATH_STREAMING
1698 if (comp->stream) {
1699 fprintf(output, "Streaming Expression\n");
1700 } else
1701#endif
1702 {
1703 fprintf(output, "Compiled Expression : %d elements\n",
1704 comp->nbStep);
1705 i = comp->last;
1706 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1707 }
1708}
1709
1710#ifdef XP_DEBUG_OBJ_USAGE
1711
1712/*
1713* XPath object usage related debugging variables.
1714*/
1715static int xmlXPathDebugObjCounterUndefined = 0;
1716static int xmlXPathDebugObjCounterNodeset = 0;
1717static int xmlXPathDebugObjCounterBool = 0;
1718static int xmlXPathDebugObjCounterNumber = 0;
1719static int xmlXPathDebugObjCounterString = 0;
1720static int xmlXPathDebugObjCounterPoint = 0;
1721static int xmlXPathDebugObjCounterRange = 0;
1722static int xmlXPathDebugObjCounterLocset = 0;
1723static int xmlXPathDebugObjCounterUsers = 0;
1724static int xmlXPathDebugObjCounterXSLTTree = 0;
1725static int xmlXPathDebugObjCounterAll = 0;
1726
1727static int xmlXPathDebugObjTotalUndefined = 0;
1728static int xmlXPathDebugObjTotalNodeset = 0;
1729static int xmlXPathDebugObjTotalBool = 0;
1730static int xmlXPathDebugObjTotalNumber = 0;
1731static int xmlXPathDebugObjTotalString = 0;
1732static int xmlXPathDebugObjTotalPoint = 0;
1733static int xmlXPathDebugObjTotalRange = 0;
1734static int xmlXPathDebugObjTotalLocset = 0;
1735static int xmlXPathDebugObjTotalUsers = 0;
1736static int xmlXPathDebugObjTotalXSLTTree = 0;
1737static int xmlXPathDebugObjTotalAll = 0;
1738
1739static int xmlXPathDebugObjMaxUndefined = 0;
1740static int xmlXPathDebugObjMaxNodeset = 0;
1741static int xmlXPathDebugObjMaxBool = 0;
1742static int xmlXPathDebugObjMaxNumber = 0;
1743static int xmlXPathDebugObjMaxString = 0;
1744static int xmlXPathDebugObjMaxPoint = 0;
1745static int xmlXPathDebugObjMaxRange = 0;
1746static int xmlXPathDebugObjMaxLocset = 0;
1747static int xmlXPathDebugObjMaxUsers = 0;
1748static int xmlXPathDebugObjMaxXSLTTree = 0;
1749static int xmlXPathDebugObjMaxAll = 0;
1750
1751static void
1752xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1753{
1754 if (ctxt != NULL) {
1755 if (ctxt->cache != NULL) {
1756 xmlXPathContextCachePtr cache =
1757 (xmlXPathContextCachePtr) ctxt->cache;
1758
1759 cache->dbgCachedAll = 0;
1760 cache->dbgCachedNodeset = 0;
1761 cache->dbgCachedString = 0;
1762 cache->dbgCachedBool = 0;
1763 cache->dbgCachedNumber = 0;
1764 cache->dbgCachedPoint = 0;
1765 cache->dbgCachedRange = 0;
1766 cache->dbgCachedLocset = 0;
1767 cache->dbgCachedUsers = 0;
1768 cache->dbgCachedXSLTTree = 0;
1769 cache->dbgCachedUndefined = 0;
1770
1771 cache->dbgReusedAll = 0;
1772 cache->dbgReusedNodeset = 0;
1773 cache->dbgReusedString = 0;
1774 cache->dbgReusedBool = 0;
1775 cache->dbgReusedNumber = 0;
1776 cache->dbgReusedPoint = 0;
1777 cache->dbgReusedRange = 0;
1778 cache->dbgReusedLocset = 0;
1779 cache->dbgReusedUsers = 0;
1780 cache->dbgReusedXSLTTree = 0;
1781 cache->dbgReusedUndefined = 0;
1782 }
1783 }
1784
1785 xmlXPathDebugObjCounterUndefined = 0;
1786 xmlXPathDebugObjCounterNodeset = 0;
1787 xmlXPathDebugObjCounterBool = 0;
1788 xmlXPathDebugObjCounterNumber = 0;
1789 xmlXPathDebugObjCounterString = 0;
1790 xmlXPathDebugObjCounterPoint = 0;
1791 xmlXPathDebugObjCounterRange = 0;
1792 xmlXPathDebugObjCounterLocset = 0;
1793 xmlXPathDebugObjCounterUsers = 0;
1794 xmlXPathDebugObjCounterXSLTTree = 0;
1795 xmlXPathDebugObjCounterAll = 0;
1796
1797 xmlXPathDebugObjTotalUndefined = 0;
1798 xmlXPathDebugObjTotalNodeset = 0;
1799 xmlXPathDebugObjTotalBool = 0;
1800 xmlXPathDebugObjTotalNumber = 0;
1801 xmlXPathDebugObjTotalString = 0;
1802 xmlXPathDebugObjTotalPoint = 0;
1803 xmlXPathDebugObjTotalRange = 0;
1804 xmlXPathDebugObjTotalLocset = 0;
1805 xmlXPathDebugObjTotalUsers = 0;
1806 xmlXPathDebugObjTotalXSLTTree = 0;
1807 xmlXPathDebugObjTotalAll = 0;
1808
1809 xmlXPathDebugObjMaxUndefined = 0;
1810 xmlXPathDebugObjMaxNodeset = 0;
1811 xmlXPathDebugObjMaxBool = 0;
1812 xmlXPathDebugObjMaxNumber = 0;
1813 xmlXPathDebugObjMaxString = 0;
1814 xmlXPathDebugObjMaxPoint = 0;
1815 xmlXPathDebugObjMaxRange = 0;
1816 xmlXPathDebugObjMaxLocset = 0;
1817 xmlXPathDebugObjMaxUsers = 0;
1818 xmlXPathDebugObjMaxXSLTTree = 0;
1819 xmlXPathDebugObjMaxAll = 0;
1820
1821}
1822
1823static void
1824xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1825 xmlXPathObjectType objType)
1826{
1827 int isCached = 0;
1828
1829 if (ctxt != NULL) {
1830 if (ctxt->cache != NULL) {
1831 xmlXPathContextCachePtr cache =
1832 (xmlXPathContextCachePtr) ctxt->cache;
1833
1834 isCached = 1;
1835
1836 cache->dbgReusedAll++;
1837 switch (objType) {
1838 case XPATH_UNDEFINED:
1839 cache->dbgReusedUndefined++;
1840 break;
1841 case XPATH_NODESET:
1842 cache->dbgReusedNodeset++;
1843 break;
1844 case XPATH_BOOLEAN:
1845 cache->dbgReusedBool++;
1846 break;
1847 case XPATH_NUMBER:
1848 cache->dbgReusedNumber++;
1849 break;
1850 case XPATH_STRING:
1851 cache->dbgReusedString++;
1852 break;
1853#ifdef LIBXML_XPTR_LOCS_ENABLED
1854 case XPATH_POINT:
1855 cache->dbgReusedPoint++;
1856 break;
1857 case XPATH_RANGE:
1858 cache->dbgReusedRange++;
1859 break;
1860 case XPATH_LOCATIONSET:
1861 cache->dbgReusedLocset++;
1862 break;
1863#endif /* LIBXML_XPTR_LOCS_ENABLED */
1864 case XPATH_USERS:
1865 cache->dbgReusedUsers++;
1866 break;
1867 case XPATH_XSLT_TREE:
1868 cache->dbgReusedXSLTTree++;
1869 break;
1870 default:
1871 break;
1872 }
1873 }
1874 }
1875
1876 switch (objType) {
1877 case XPATH_UNDEFINED:
1878 if (! isCached)
1879 xmlXPathDebugObjTotalUndefined++;
1880 xmlXPathDebugObjCounterUndefined++;
1881 if (xmlXPathDebugObjCounterUndefined >
1882 xmlXPathDebugObjMaxUndefined)
1883 xmlXPathDebugObjMaxUndefined =
1884 xmlXPathDebugObjCounterUndefined;
1885 break;
1886 case XPATH_NODESET:
1887 if (! isCached)
1888 xmlXPathDebugObjTotalNodeset++;
1889 xmlXPathDebugObjCounterNodeset++;
1890 if (xmlXPathDebugObjCounterNodeset >
1891 xmlXPathDebugObjMaxNodeset)
1892 xmlXPathDebugObjMaxNodeset =
1893 xmlXPathDebugObjCounterNodeset;
1894 break;
1895 case XPATH_BOOLEAN:
1896 if (! isCached)
1897 xmlXPathDebugObjTotalBool++;
1898 xmlXPathDebugObjCounterBool++;
1899 if (xmlXPathDebugObjCounterBool >
1900 xmlXPathDebugObjMaxBool)
1901 xmlXPathDebugObjMaxBool =
1902 xmlXPathDebugObjCounterBool;
1903 break;
1904 case XPATH_NUMBER:
1905 if (! isCached)
1906 xmlXPathDebugObjTotalNumber++;
1907 xmlXPathDebugObjCounterNumber++;
1908 if (xmlXPathDebugObjCounterNumber >
1909 xmlXPathDebugObjMaxNumber)
1910 xmlXPathDebugObjMaxNumber =
1911 xmlXPathDebugObjCounterNumber;
1912 break;
1913 case XPATH_STRING:
1914 if (! isCached)
1915 xmlXPathDebugObjTotalString++;
1916 xmlXPathDebugObjCounterString++;
1917 if (xmlXPathDebugObjCounterString >
1918 xmlXPathDebugObjMaxString)
1919 xmlXPathDebugObjMaxString =
1920 xmlXPathDebugObjCounterString;
1921 break;
1922#ifdef LIBXML_XPTR_LOCS_ENABLED
1923 case XPATH_POINT:
1924 if (! isCached)
1925 xmlXPathDebugObjTotalPoint++;
1926 xmlXPathDebugObjCounterPoint++;
1927 if (xmlXPathDebugObjCounterPoint >
1928 xmlXPathDebugObjMaxPoint)
1929 xmlXPathDebugObjMaxPoint =
1930 xmlXPathDebugObjCounterPoint;
1931 break;
1932 case XPATH_RANGE:
1933 if (! isCached)
1934 xmlXPathDebugObjTotalRange++;
1935 xmlXPathDebugObjCounterRange++;
1936 if (xmlXPathDebugObjCounterRange >
1937 xmlXPathDebugObjMaxRange)
1938 xmlXPathDebugObjMaxRange =
1939 xmlXPathDebugObjCounterRange;
1940 break;
1941 case XPATH_LOCATIONSET:
1942 if (! isCached)
1943 xmlXPathDebugObjTotalLocset++;
1944 xmlXPathDebugObjCounterLocset++;
1945 if (xmlXPathDebugObjCounterLocset >
1946 xmlXPathDebugObjMaxLocset)
1947 xmlXPathDebugObjMaxLocset =
1948 xmlXPathDebugObjCounterLocset;
1949 break;
1950#endif /* LIBXML_XPTR_LOCS_ENABLED */
1951 case XPATH_USERS:
1952 if (! isCached)
1953 xmlXPathDebugObjTotalUsers++;
1954 xmlXPathDebugObjCounterUsers++;
1955 if (xmlXPathDebugObjCounterUsers >
1956 xmlXPathDebugObjMaxUsers)
1957 xmlXPathDebugObjMaxUsers =
1958 xmlXPathDebugObjCounterUsers;
1959 break;
1960 case XPATH_XSLT_TREE:
1961 if (! isCached)
1962 xmlXPathDebugObjTotalXSLTTree++;
1963 xmlXPathDebugObjCounterXSLTTree++;
1964 if (xmlXPathDebugObjCounterXSLTTree >
1965 xmlXPathDebugObjMaxXSLTTree)
1966 xmlXPathDebugObjMaxXSLTTree =
1967 xmlXPathDebugObjCounterXSLTTree;
1968 break;
1969 default:
1970 break;
1971 }
1972 if (! isCached)
1973 xmlXPathDebugObjTotalAll++;
1974 xmlXPathDebugObjCounterAll++;
1975 if (xmlXPathDebugObjCounterAll >
1976 xmlXPathDebugObjMaxAll)
1977 xmlXPathDebugObjMaxAll =
1978 xmlXPathDebugObjCounterAll;
1979}
1980
1981static void
1982xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1983 xmlXPathObjectType objType)
1984{
1985 int isCached = 0;
1986
1987 if (ctxt != NULL) {
1988 if (ctxt->cache != NULL) {
1989 xmlXPathContextCachePtr cache =
1990 (xmlXPathContextCachePtr) ctxt->cache;
1991
1992 isCached = 1;
1993
1994 cache->dbgCachedAll++;
1995 switch (objType) {
1996 case XPATH_UNDEFINED:
1997 cache->dbgCachedUndefined++;
1998 break;
1999 case XPATH_NODESET:
2000 cache->dbgCachedNodeset++;
2001 break;
2002 case XPATH_BOOLEAN:
2003 cache->dbgCachedBool++;
2004 break;
2005 case XPATH_NUMBER:
2006 cache->dbgCachedNumber++;
2007 break;
2008 case XPATH_STRING:
2009 cache->dbgCachedString++;
2010 break;
2011#ifdef LIBXML_XPTR_LOCS_ENABLED
2012 case XPATH_POINT:
2013 cache->dbgCachedPoint++;
2014 break;
2015 case XPATH_RANGE:
2016 cache->dbgCachedRange++;
2017 break;
2018 case XPATH_LOCATIONSET:
2019 cache->dbgCachedLocset++;
2020 break;
2021#endif /* LIBXML_XPTR_LOCS_ENABLED */
2022 case XPATH_USERS:
2023 cache->dbgCachedUsers++;
2024 break;
2025 case XPATH_XSLT_TREE:
2026 cache->dbgCachedXSLTTree++;
2027 break;
2028 default:
2029 break;
2030 }
2031
2032 }
2033 }
2034 switch (objType) {
2035 case XPATH_UNDEFINED:
2036 xmlXPathDebugObjCounterUndefined--;
2037 break;
2038 case XPATH_NODESET:
2039 xmlXPathDebugObjCounterNodeset--;
2040 break;
2041 case XPATH_BOOLEAN:
2042 xmlXPathDebugObjCounterBool--;
2043 break;
2044 case XPATH_NUMBER:
2045 xmlXPathDebugObjCounterNumber--;
2046 break;
2047 case XPATH_STRING:
2048 xmlXPathDebugObjCounterString--;
2049 break;
2050#ifdef LIBXML_XPTR_LOCS_ENABLED
2051 case XPATH_POINT:
2052 xmlXPathDebugObjCounterPoint--;
2053 break;
2054 case XPATH_RANGE:
2055 xmlXPathDebugObjCounterRange--;
2056 break;
2057 case XPATH_LOCATIONSET:
2058 xmlXPathDebugObjCounterLocset--;
2059 break;
2060#endif /* LIBXML_XPTR_LOCS_ENABLED */
2061 case XPATH_USERS:
2062 xmlXPathDebugObjCounterUsers--;
2063 break;
2064 case XPATH_XSLT_TREE:
2065 xmlXPathDebugObjCounterXSLTTree--;
2066 break;
2067 default:
2068 break;
2069 }
2070 xmlXPathDebugObjCounterAll--;
2071}
2072
2073static void
2074xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2075{
2076 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2077 reqXSLTTree, reqUndefined;
2078 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2079 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2080 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2081 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2082 int leftObjs = xmlXPathDebugObjCounterAll;
2083
2084 reqAll = xmlXPathDebugObjTotalAll;
2085 reqNodeset = xmlXPathDebugObjTotalNodeset;
2086 reqString = xmlXPathDebugObjTotalString;
2087 reqBool = xmlXPathDebugObjTotalBool;
2088 reqNumber = xmlXPathDebugObjTotalNumber;
2089 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2090 reqUndefined = xmlXPathDebugObjTotalUndefined;
2091
2092 printf("# XPath object usage:\n");
2093
2094 if (ctxt != NULL) {
2095 if (ctxt->cache != NULL) {
2096 xmlXPathContextCachePtr cache =
2097 (xmlXPathContextCachePtr) ctxt->cache;
2098
2099 reAll = cache->dbgReusedAll;
2100 reqAll += reAll;
2101 reNodeset = cache->dbgReusedNodeset;
2102 reqNodeset += reNodeset;
2103 reString = cache->dbgReusedString;
2104 reqString += reString;
2105 reBool = cache->dbgReusedBool;
2106 reqBool += reBool;
2107 reNumber = cache->dbgReusedNumber;
2108 reqNumber += reNumber;
2109 reXSLTTree = cache->dbgReusedXSLTTree;
2110 reqXSLTTree += reXSLTTree;
2111 reUndefined = cache->dbgReusedUndefined;
2112 reqUndefined += reUndefined;
2113
2114 caAll = cache->dbgCachedAll;
2115 caBool = cache->dbgCachedBool;
2116 caNodeset = cache->dbgCachedNodeset;
2117 caString = cache->dbgCachedString;
2118 caNumber = cache->dbgCachedNumber;
2119 caXSLTTree = cache->dbgCachedXSLTTree;
2120 caUndefined = cache->dbgCachedUndefined;
2121
2122 if (cache->nodesetObjs)
2123 leftObjs -= cache->nodesetObjs->number;
2124 if (cache->stringObjs)
2125 leftObjs -= cache->stringObjs->number;
2126 if (cache->booleanObjs)
2127 leftObjs -= cache->booleanObjs->number;
2128 if (cache->numberObjs)
2129 leftObjs -= cache->numberObjs->number;
2130 if (cache->miscObjs)
2131 leftObjs -= cache->miscObjs->number;
2132 }
2133 }
2134
2135 printf("# all\n");
2136 printf("# total : %d\n", reqAll);
2137 printf("# left : %d\n", leftObjs);
2138 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2139 printf("# reused : %d\n", reAll);
2140 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2141
2142 printf("# node-sets\n");
2143 printf("# total : %d\n", reqNodeset);
2144 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2145 printf("# reused : %d\n", reNodeset);
2146 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2147
2148 printf("# strings\n");
2149 printf("# total : %d\n", reqString);
2150 printf("# created: %d\n", xmlXPathDebugObjTotalString);
2151 printf("# reused : %d\n", reString);
2152 printf("# max : %d\n", xmlXPathDebugObjMaxString);
2153
2154 printf("# booleans\n");
2155 printf("# total : %d\n", reqBool);
2156 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2157 printf("# reused : %d\n", reBool);
2158 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2159
2160 printf("# numbers\n");
2161 printf("# total : %d\n", reqNumber);
2162 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2163 printf("# reused : %d\n", reNumber);
2164 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2165
2166 printf("# XSLT result tree fragments\n");
2167 printf("# total : %d\n", reqXSLTTree);
2168 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2169 printf("# reused : %d\n", reXSLTTree);
2170 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2171
2172 printf("# undefined\n");
2173 printf("# total : %d\n", reqUndefined);
2174 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2175 printf("# reused : %d\n", reUndefined);
2176 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2177
2178}
2179
2180#endif /* XP_DEBUG_OBJ_USAGE */
2181
2182#endif /* LIBXML_DEBUG_ENABLED */
2183
2184/************************************************************************
2185 * *
2186 * XPath object caching *
2187 * *
2188 ************************************************************************/
2189
2197static xmlXPathContextCachePtr
2198xmlXPathNewCache(void)
2199{
2200 xmlXPathContextCachePtr ret;
2201
2202 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2203 if (ret == NULL) {
2204 xmlXPathErrMemory(NULL, "creating object cache\n");
2205 return(NULL);
2206 }
2207 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2208 ret->maxNodeset = 100;
2209 ret->maxString = 100;
2210 ret->maxBoolean = 100;
2211 ret->maxNumber = 100;
2212 ret->maxMisc = 100;
2213 return(ret);
2214}
2215
2216static void
2217xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2218{
2219 int i;
2220 xmlXPathObjectPtr obj;
2221
2222 if (list == NULL)
2223 return;
2224
2225 for (i = 0; i < list->number; i++) {
2226 obj = list->items[i];
2227 /*
2228 * Note that it is already assured that we don't need to
2229 * look out for namespace nodes in the node-set.
2230 */
2231 if (obj->nodesetval != NULL) {
2232 if (obj->nodesetval->nodeTab != NULL)
2233 xmlFree(obj->nodesetval->nodeTab);
2234 xmlFree(obj->nodesetval);
2235 }
2236 xmlFree(obj);
2237#ifdef XP_DEBUG_OBJ_USAGE
2238 xmlXPathDebugObjCounterAll--;
2239#endif
2240 }
2241 xmlPointerListFree(list);
2242}
2243
2244static void
2245xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2246{
2247 if (cache == NULL)
2248 return;
2249 if (cache->nodesetObjs)
2250 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2251 if (cache->stringObjs)
2252 xmlXPathCacheFreeObjectList(cache->stringObjs);
2253 if (cache->booleanObjs)
2254 xmlXPathCacheFreeObjectList(cache->booleanObjs);
2255 if (cache->numberObjs)
2256 xmlXPathCacheFreeObjectList(cache->numberObjs);
2257 if (cache->miscObjs)
2258 xmlXPathCacheFreeObjectList(cache->miscObjs);
2259 xmlFree(cache);
2260}
2261
2284int
2285xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2286 int active,
2287 int value,
2288 int options)
2289{
2290 if (ctxt == NULL)
2291 return(-1);
2292 if (active) {
2293 xmlXPathContextCachePtr cache;
2294
2295 if (ctxt->cache == NULL) {
2296 ctxt->cache = xmlXPathNewCache();
2297 if (ctxt->cache == NULL)
2298 return(-1);
2299 }
2300 cache = (xmlXPathContextCachePtr) ctxt->cache;
2301 if (options == 0) {
2302 if (value < 0)
2303 value = 100;
2304 cache->maxNodeset = value;
2305 cache->maxString = value;
2306 cache->maxNumber = value;
2307 cache->maxBoolean = value;
2308 cache->maxMisc = value;
2309 }
2310 } else if (ctxt->cache != NULL) {
2311 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2312 ctxt->cache = NULL;
2313 }
2314 return(0);
2315}
2316
2327static xmlXPathObjectPtr
2328xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2329{
2330 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2331 xmlXPathContextCachePtr cache =
2332 (xmlXPathContextCachePtr) ctxt->cache;
2333
2334 if ((cache->miscObjs != NULL) &&
2335 (cache->miscObjs->number != 0))
2336 {
2337 xmlXPathObjectPtr ret;
2338
2339 ret = (xmlXPathObjectPtr)
2340 cache->miscObjs->items[--cache->miscObjs->number];
2341 ret->type = XPATH_NODESET;
2342 ret->nodesetval = val;
2343#ifdef XP_DEBUG_OBJ_USAGE
2344 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2345#endif
2346 return(ret);
2347 }
2348 }
2349
2350 return(xmlXPathWrapNodeSet(val));
2351
2352}
2353
2364static xmlXPathObjectPtr
2365xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2366{
2367 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2368 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2369
2370 if ((cache->stringObjs != NULL) &&
2371 (cache->stringObjs->number != 0))
2372 {
2373
2374 xmlXPathObjectPtr ret;
2375
2376 ret = (xmlXPathObjectPtr)
2377 cache->stringObjs->items[--cache->stringObjs->number];
2378 ret->type = XPATH_STRING;
2379 ret->stringval = val;
2380#ifdef XP_DEBUG_OBJ_USAGE
2381 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2382#endif
2383 return(ret);
2384 } else if ((cache->miscObjs != NULL) &&
2385 (cache->miscObjs->number != 0))
2386 {
2387 xmlXPathObjectPtr ret;
2388 /*
2389 * Fallback to misc-cache.
2390 */
2391 ret = (xmlXPathObjectPtr)
2392 cache->miscObjs->items[--cache->miscObjs->number];
2393
2394 ret->type = XPATH_STRING;
2395 ret->stringval = val;
2396#ifdef XP_DEBUG_OBJ_USAGE
2397 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2398#endif
2399 return(ret);
2400 }
2401 }
2402 return(xmlXPathWrapString(val));
2403}
2404
2416static xmlXPathObjectPtr
2417xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2418{
2419 if ((ctxt != NULL) && (ctxt->cache)) {
2420 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2421
2422 if ((cache->nodesetObjs != NULL) &&
2423 (cache->nodesetObjs->number != 0))
2424 {
2425 xmlXPathObjectPtr ret;
2426 /*
2427 * Use the nodeset-cache.
2428 */
2429 ret = (xmlXPathObjectPtr)
2430 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2431 ret->type = XPATH_NODESET;
2432 ret->boolval = 0;
2433 if (val) {
2434 if ((ret->nodesetval->nodeMax == 0) ||
2435 (val->type == XML_NAMESPACE_DECL))
2436 {
2437 /* TODO: Check memory error. */
2438 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2439 } else {
2440 ret->nodesetval->nodeTab[0] = val;
2441 ret->nodesetval->nodeNr = 1;
2442 }
2443 }
2444#ifdef XP_DEBUG_OBJ_USAGE
2445 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2446#endif
2447 return(ret);
2448 } else if ((cache->miscObjs != NULL) &&
2449 (cache->miscObjs->number != 0))
2450 {
2451 xmlXPathObjectPtr ret;
2452 /*
2453 * Fallback to misc-cache.
2454 */
2455
2456 ret = (xmlXPathObjectPtr)
2457 cache->miscObjs->items[--cache->miscObjs->number];
2458
2459 ret->type = XPATH_NODESET;
2460 ret->boolval = 0;
2461 ret->nodesetval = xmlXPathNodeSetCreate(val);
2462 if (ret->nodesetval == NULL) {
2463 ctxt->lastError.domain = XML_FROM_XPATH;
2464 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2465 return(NULL);
2466 }
2467#ifdef XP_DEBUG_OBJ_USAGE
2468 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2469#endif
2470 return(ret);
2471 }
2472 }
2473 return(xmlXPathNewNodeSet(val));
2474}
2475
2486static xmlXPathObjectPtr
2487xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2488{
2489 if ((ctxt != NULL) && (ctxt->cache)) {
2490 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2491
2492 if ((cache->stringObjs != NULL) &&
2493 (cache->stringObjs->number != 0))
2494 {
2495 xmlXPathObjectPtr ret;
2496
2497 ret = (xmlXPathObjectPtr)
2498 cache->stringObjs->items[--cache->stringObjs->number];
2499
2500 ret->type = XPATH_STRING;
2501 ret->stringval = xmlStrdup(BAD_CAST val);
2502#ifdef XP_DEBUG_OBJ_USAGE
2503 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2504#endif
2505 return(ret);
2506 } else if ((cache->miscObjs != NULL) &&
2507 (cache->miscObjs->number != 0))
2508 {
2509 xmlXPathObjectPtr ret;
2510
2511 ret = (xmlXPathObjectPtr)
2512 cache->miscObjs->items[--cache->miscObjs->number];
2513
2514 ret->type = XPATH_STRING;
2515 ret->stringval = xmlStrdup(BAD_CAST val);
2516#ifdef XP_DEBUG_OBJ_USAGE
2517 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2518#endif
2519 return(ret);
2520 }
2521 }
2522 return(xmlXPathNewCString(val));
2523}
2524
2535static xmlXPathObjectPtr
2536xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2537{
2538 if ((ctxt != NULL) && (ctxt->cache)) {
2539 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2540
2541 if ((cache->stringObjs != NULL) &&
2542 (cache->stringObjs->number != 0))
2543 {
2544 xmlXPathObjectPtr ret;
2545
2546 ret = (xmlXPathObjectPtr)
2547 cache->stringObjs->items[--cache->stringObjs->number];
2548 ret->type = XPATH_STRING;
2549 if (val != NULL)
2550 ret->stringval = xmlStrdup(val);
2551 else
2552 ret->stringval = xmlStrdup((const xmlChar *)"");
2553#ifdef XP_DEBUG_OBJ_USAGE
2554 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2555#endif
2556 return(ret);
2557 } else if ((cache->miscObjs != NULL) &&
2558 (cache->miscObjs->number != 0))
2559 {
2560 xmlXPathObjectPtr ret;
2561
2562 ret = (xmlXPathObjectPtr)
2563 cache->miscObjs->items[--cache->miscObjs->number];
2564
2565 ret->type = XPATH_STRING;
2566 if (val != NULL)
2567 ret->stringval = xmlStrdup(val);
2568 else
2569 ret->stringval = xmlStrdup((const xmlChar *)"");
2570#ifdef XP_DEBUG_OBJ_USAGE
2571 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2572#endif
2573 return(ret);
2574 }
2575 }
2576 return(xmlXPathNewString(val));
2577}
2578
2589static xmlXPathObjectPtr
2590xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2591{
2592 if ((ctxt != NULL) && (ctxt->cache)) {
2593 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2594
2595 if ((cache->booleanObjs != NULL) &&
2596 (cache->booleanObjs->number != 0))
2597 {
2598 xmlXPathObjectPtr ret;
2599
2600 ret = (xmlXPathObjectPtr)
2601 cache->booleanObjs->items[--cache->booleanObjs->number];
2602 ret->type = XPATH_BOOLEAN;
2603 ret->boolval = (val != 0);
2604#ifdef XP_DEBUG_OBJ_USAGE
2605 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2606#endif
2607 return(ret);
2608 } else if ((cache->miscObjs != NULL) &&
2609 (cache->miscObjs->number != 0))
2610 {
2611 xmlXPathObjectPtr ret;
2612
2613 ret = (xmlXPathObjectPtr)
2614 cache->miscObjs->items[--cache->miscObjs->number];
2615
2616 ret->type = XPATH_BOOLEAN;
2617 ret->boolval = (val != 0);
2618#ifdef XP_DEBUG_OBJ_USAGE
2619 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2620#endif
2621 return(ret);
2622 }
2623 }
2624 return(xmlXPathNewBoolean(val));
2625}
2626
2637static xmlXPathObjectPtr
2638xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2639{
2640 if ((ctxt != NULL) && (ctxt->cache)) {
2641 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2642
2643 if ((cache->numberObjs != NULL) &&
2644 (cache->numberObjs->number != 0))
2645 {
2646 xmlXPathObjectPtr ret;
2647
2648 ret = (xmlXPathObjectPtr)
2649 cache->numberObjs->items[--cache->numberObjs->number];
2650 ret->type = XPATH_NUMBER;
2651 ret->floatval = val;
2652#ifdef XP_DEBUG_OBJ_USAGE
2653 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2654#endif
2655 return(ret);
2656 } else if ((cache->miscObjs != NULL) &&
2657 (cache->miscObjs->number != 0))
2658 {
2659 xmlXPathObjectPtr ret;
2660
2661 ret = (xmlXPathObjectPtr)
2662 cache->miscObjs->items[--cache->miscObjs->number];
2663
2664 ret->type = XPATH_NUMBER;
2665 ret->floatval = val;
2666#ifdef XP_DEBUG_OBJ_USAGE
2667 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2668#endif
2669 return(ret);
2670 }
2671 }
2672 return(xmlXPathNewFloat(val));
2673}
2674
2687static xmlXPathObjectPtr
2688xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2689 xmlChar *res = NULL;
2690
2691 if (val == NULL)
2692 return(xmlXPathCacheNewCString(ctxt, ""));
2693
2694 switch (val->type) {
2695 case XPATH_UNDEFINED:
2696#ifdef DEBUG_EXPR
2697 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2698#endif
2699 break;
2700 case XPATH_NODESET:
2701 case XPATH_XSLT_TREE:
2702 res = xmlXPathCastNodeSetToString(val->nodesetval);
2703 break;
2704 case XPATH_STRING:
2705 return(val);
2706 case XPATH_BOOLEAN:
2707 res = xmlXPathCastBooleanToString(val->boolval);
2708 break;
2709 case XPATH_NUMBER:
2710 res = xmlXPathCastNumberToString(val->floatval);
2711 break;
2712 case XPATH_USERS:
2713#ifdef LIBXML_XPTR_LOCS_ENABLED
2714 case XPATH_POINT:
2715 case XPATH_RANGE:
2716 case XPATH_LOCATIONSET:
2717#endif /* LIBXML_XPTR_LOCS_ENABLED */
2718 TODO;
2719 break;
2720 }
2721 xmlXPathReleaseObject(ctxt, val);
2722 if (res == NULL)
2723 return(xmlXPathCacheNewCString(ctxt, ""));
2724 return(xmlXPathCacheWrapString(ctxt, res));
2725}
2726
2737static xmlXPathObjectPtr
2738xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2739{
2740 if (val == NULL)
2741 return(NULL);
2742
2743 if (XP_HAS_CACHE(ctxt)) {
2744 switch (val->type) {
2745 case XPATH_NODESET:
2746 return(xmlXPathCacheWrapNodeSet(ctxt,
2747 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2748 case XPATH_STRING:
2749 return(xmlXPathCacheNewString(ctxt, val->stringval));
2750 case XPATH_BOOLEAN:
2751 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2752 case XPATH_NUMBER:
2753 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2754 default:
2755 break;
2756 }
2757 }
2758 return(xmlXPathObjectCopy(val));
2759}
2760
2772static xmlXPathObjectPtr
2773xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2774 xmlXPathObjectPtr ret;
2775
2776 if (val == NULL)
2777 return(xmlXPathCacheNewBoolean(ctxt, 0));
2778 if (val->type == XPATH_BOOLEAN)
2779 return(val);
2780 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2781 xmlXPathReleaseObject(ctxt, val);
2782 return(ret);
2783}
2784
2796static xmlXPathObjectPtr
2797xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2798 xmlXPathObjectPtr ret;
2799
2800 if (val == NULL)
2801 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2802 if (val->type == XPATH_NUMBER)
2803 return(val);
2804 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2805 xmlXPathReleaseObject(ctxt, val);
2806 return(ret);
2807}
2808
2809/************************************************************************
2810 * *
2811 * Parser stacks related functions and macros *
2812 * *
2813 ************************************************************************/
2814
2823static int
2824xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2825 int ret;
2826
2827 if (ctxt == NULL)
2828 return(0);
2829 ret = ctxt->valueFrame;
2830 ctxt->valueFrame = ctxt->valueNr;
2831 return(ret);
2832}
2833
2841static void
2842xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2843 if (ctxt == NULL)
2844 return;
2845 if (ctxt->valueNr < ctxt->valueFrame) {
2846 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2847 }
2848 ctxt->valueFrame = frame;
2849}
2850
2859xmlXPathObjectPtr
2860valuePop(xmlXPathParserContextPtr ctxt)
2861{
2862 xmlXPathObjectPtr ret;
2863
2864 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2865 return (NULL);
2866
2867 if (ctxt->valueNr <= ctxt->valueFrame) {
2868 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2869 return (NULL);
2870 }
2871
2872 ctxt->valueNr--;
2873 if (ctxt->valueNr > 0)
2874 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2875 else
2876 ctxt->value = NULL;
2877 ret = ctxt->valueTab[ctxt->valueNr];
2878 ctxt->valueTab[ctxt->valueNr] = NULL;
2879 return (ret);
2880}
2891int
2892valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2893{
2894 if (ctxt == NULL) return(-1);
2895 if (value == NULL) {
2896 /*
2897 * A NULL value typically indicates that a memory allocation failed,
2898 * so we set ctxt->error here to propagate the error.
2899 */
2900 ctxt->error = XPATH_MEMORY_ERROR;
2901 return(-1);
2902 }
2903 if (ctxt->valueNr >= ctxt->valueMax) {
2904 xmlXPathObjectPtr *tmp;
2905
2906 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2907 xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2908 return (-1);
2909 }
2910 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2911 2 * ctxt->valueMax *
2912 sizeof(ctxt->valueTab[0]));
2913 if (tmp == NULL) {
2914 xmlXPathPErrMemory(ctxt, "pushing value\n");
2915 return (-1);
2916 }
2917 ctxt->valueMax *= 2;
2918 ctxt->valueTab = tmp;
2919 }
2920 ctxt->valueTab[ctxt->valueNr] = value;
2921 ctxt->value = value;
2922 return (ctxt->valueNr++);
2923}
2924
2934int
2935xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2936 xmlXPathObjectPtr obj;
2937 int ret;
2938
2939 obj = valuePop(ctxt);
2940 if (obj == NULL) {
2941 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2942 return(0);
2943 }
2944 if (obj->type != XPATH_BOOLEAN)
2945 ret = xmlXPathCastToBoolean(obj);
2946 else
2947 ret = obj->boolval;
2948 xmlXPathReleaseObject(ctxt->context, obj);
2949 return(ret);
2950}
2951
2961double
2962xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2963 xmlXPathObjectPtr obj;
2964 double ret;
2965
2966 obj = valuePop(ctxt);
2967 if (obj == NULL) {
2968 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2969 return(0);
2970 }
2971 if (obj->type != XPATH_NUMBER)
2972 ret = xmlXPathCastToNumber(obj);
2973 else
2974 ret = obj->floatval;
2975 xmlXPathReleaseObject(ctxt->context, obj);
2976 return(ret);
2977}
2978
2988xmlChar *
2989xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2990 xmlXPathObjectPtr obj;
2991 xmlChar * ret;
2992
2993 obj = valuePop(ctxt);
2994 if (obj == NULL) {
2995 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2996 return(NULL);
2997 }
2998 ret = xmlXPathCastToString(obj); /* this does required strdup */
2999 /* TODO: needs refactoring somewhere else */
3000 if (obj->stringval == ret)
3001 obj->stringval = NULL;
3002 xmlXPathReleaseObject(ctxt->context, obj);
3003 return(ret);
3004}
3005
3015xmlNodeSetPtr
3016xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
3017 xmlXPathObjectPtr obj;
3018 xmlNodeSetPtr ret;
3019
3020 if (ctxt == NULL) return(NULL);
3021 if (ctxt->value == NULL) {
3022 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3023 return(NULL);
3024 }
3025 if (!xmlXPathStackIsNodeSet(ctxt)) {
3026 xmlXPathSetTypeError(ctxt);
3027 return(NULL);
3028 }
3029 obj = valuePop(ctxt);
3030 ret = obj->nodesetval;
3031#if 0
3032 /* to fix memory leak of not clearing obj->user */
3033 if (obj->boolval && obj->user != NULL)
3035#endif
3036 obj->nodesetval = NULL;
3037 xmlXPathReleaseObject(ctxt->context, obj);
3038 return(ret);
3039}
3040
3050void *
3051xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3052 xmlXPathObjectPtr obj;
3053 void * ret;
3054
3055 if ((ctxt == NULL) || (ctxt->value == NULL)) {
3056 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3057 return(NULL);
3058 }
3059 if (ctxt->value->type != XPATH_USERS) {
3060 xmlXPathSetTypeError(ctxt);
3061 return(NULL);
3062 }
3063 obj = valuePop(ctxt);
3064 ret = obj->user;
3065 obj->user = NULL;
3066 xmlXPathReleaseObject(ctxt->context, obj);
3067 return(ret);
3068}
3069
3070/*
3071 * Macros for accessing the content. Those should be used only by the parser,
3072 * and not exported.
3073 *
3074 * Dirty macros, i.e. one need to make assumption on the context to use them
3075 *
3076 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3077 * CUR returns the current xmlChar value, i.e. a 8 bit value
3078 * in ISO-Latin or UTF-8.
3079 * This should be used internally by the parser
3080 * only to compare to ASCII values otherwise it would break when
3081 * running with UTF-8 encoding.
3082 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3083 * to compare on ASCII based substring.
3084 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3085 * strings within the parser.
3086 * CURRENT Returns the current char value, with the full decoding of
3087 * UTF-8 if we are using this mode. It returns an int.
3088 * NEXT Skip to the next character, this does the proper decoding
3089 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3090 * It returns the pointer to the current xmlChar.
3091 */
3092
3093#define CUR (*ctxt->cur)
3094#define SKIP(val) ctxt->cur += (val)
3095#define NXT(val) ctxt->cur[(val)]
3096#define CUR_PTR ctxt->cur
3097#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3098
3099#define COPY_BUF(l,b,i,v) \
3100 if (l == 1) b[i++] = (xmlChar) v; \
3101 else i += xmlCopyChar(l,&b[i],v)
3102
3103#define NEXTL(l) ctxt->cur += l
3104
3105#define SKIP_BLANKS \
3106 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3107
3108#define CURRENT (*ctxt->cur)
3109#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3110
3111
3112#ifndef DBL_DIG
3113#define DBL_DIG 16
3114#endif
3115#ifndef DBL_EPSILON
3116#define DBL_EPSILON 1E-9
3117#endif
3118
3119#define UPPER_DOUBLE 1E9
3120#define LOWER_DOUBLE 1E-5
3121#define LOWER_DOUBLE_EXP 5
3122
3123#define INTEGER_DIGITS DBL_DIG
3124#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3125#define EXPONENT_DIGITS (3 + 2)
3126
3135static void
3136xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3137{
3138 switch (xmlXPathIsInf(number)) {
3139 case 1:
3140 if (buffersize > (int)sizeof("Infinity"))
3141 snprintf(buffer, buffersize, "Infinity");
3142 break;
3143 case -1:
3144 if (buffersize > (int)sizeof("-Infinity"))
3145 snprintf(buffer, buffersize, "-Infinity");
3146 break;
3147 default:
3148 if (xmlXPathIsNaN(number)) {
3149 if (buffersize > (int)sizeof("NaN"))
3150 snprintf(buffer, buffersize, "NaN");
3151 } else if (number == 0) {
3152 /* Omit sign for negative zero. */
3153 snprintf(buffer, buffersize, "0");
3154 } else if ((number > INT_MIN) && (number < INT_MAX) &&
3155 (number == (int) number)) {
3156 char work[30];
3157 char *ptr, *cur;
3158 int value = (int) number;
3159
3160 ptr = &buffer[0];
3161 if (value == 0) {
3162 *ptr++ = '0';
3163 } else {
3164 snprintf(work, 29, "%d", value);
3165 cur = &work[0];
3166 while ((*cur) && (ptr - buffer < buffersize)) {
3167 *ptr++ = *cur++;
3168 }
3169 }
3170 if (ptr - buffer < buffersize) {
3171 *ptr = 0;
3172 } else if (buffersize > 0) {
3173 ptr--;
3174 *ptr = 0;
3175 }
3176 } else {
3177 /*
3178 For the dimension of work,
3179 DBL_DIG is number of significant digits
3180 EXPONENT is only needed for "scientific notation"
3181 3 is sign, decimal point, and terminating zero
3182 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3183 Note that this dimension is slightly (a few characters)
3184 larger than actually necessary.
3185 */
3186 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3187 int integer_place, fraction_place;
3188 char *ptr;
3189 char *after_fraction;
3190 double absolute_value;
3191 int size;
3192
3193 absolute_value = fabs(number);
3194
3195 /*
3196 * First choose format - scientific or regular floating point.
3197 * In either case, result is in work, and after_fraction points
3198 * just past the fractional part.
3199 */
3200 if ( ((absolute_value > UPPER_DOUBLE) ||
3201 (absolute_value < LOWER_DOUBLE)) &&
3202 (absolute_value != 0.0) ) {
3203 /* Use scientific notation */
3204 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3205 fraction_place = DBL_DIG - 1;
3206 size = snprintf(work, sizeof(work),"%*.*e",
3207 integer_place, fraction_place, number);
3208 while ((size > 0) && (work[size] != 'e')) size--;
3209
3210 }
3211 else {
3212 /* Use regular notation */
3213 if (absolute_value > 0.0) {
3214 integer_place = (int)log10(absolute_value);
3215 if (integer_place > 0)
3216 fraction_place = DBL_DIG - integer_place - 1;
3217 else
3218 fraction_place = DBL_DIG - integer_place;
3219 } else {
3220 fraction_place = 1;
3221 }
3222 size = snprintf(work, sizeof(work), "%0.*f",
3223 fraction_place, number);
3224 }
3225
3226 /* Remove leading spaces sometimes inserted by snprintf */
3227 while (work[0] == ' ') {
3228 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3229 size--;
3230 }
3231
3232 /* Remove fractional trailing zeroes */
3233 after_fraction = work + size;
3234 ptr = after_fraction;
3235 while (*(--ptr) == '0')
3236 ;
3237 if (*ptr != '.')
3238 ptr++;
3239 while ((*ptr++ = *after_fraction++) != 0);
3240
3241 /* Finally copy result back to caller */
3242 size = strlen(work) + 1;
3243 if (size > buffersize) {
3244 work[buffersize - 1] = 0;
3245 size = buffersize;
3246 }
3247 memmove(buffer, work, size);
3248 }
3249 break;
3250 }
3251}
3252
3253
3254/************************************************************************
3255 * *
3256 * Routines to handle NodeSets *
3257 * *
3258 ************************************************************************/
3259
3273long
3274xmlXPathOrderDocElems(xmlDocPtr doc) {
3275 ptrdiff_t count = 0;
3277
3278 if (doc == NULL)
3279 return(-1);
3280 cur = doc->children;
3281 while (cur != NULL) {
3282 if (cur->type == XML_ELEMENT_NODE) {
3283 cur->content = (void *) (-(++count));
3284 if (cur->children != NULL) {
3285 cur = cur->children;
3286 continue;
3287 }
3288 }
3289 if (cur->next != NULL) {
3290 cur = cur->next;
3291 continue;
3292 }
3293 do {
3294 cur = cur->parent;
3295 if (cur == NULL)
3296 break;
3297 if (cur == (xmlNodePtr) doc) {
3298 cur = NULL;
3299 break;
3300 }
3301 if (cur->next != NULL) {
3302 cur = cur->next;
3303 break;
3304 }
3305 } while (cur != NULL);
3306 }
3307 return((long) count);
3308}
3309
3320int
3321xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3322 int depth1, depth2;
3323 int attr1 = 0, attr2 = 0;
3324 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3326
3327 if ((node1 == NULL) || (node2 == NULL))
3328 return(-2);
3329 /*
3330 * a couple of optimizations which will avoid computations in most cases
3331 */
3332 if (node1 == node2) /* trivial case */
3333 return(0);
3334 if (node1->type == XML_ATTRIBUTE_NODE) {
3335 attr1 = 1;
3336 attrNode1 = node1;
3337 node1 = node1->parent;
3338 }
3339 if (node2->type == XML_ATTRIBUTE_NODE) {
3340 attr2 = 1;
3341 attrNode2 = node2;
3342 node2 = node2->parent;
3343 }
3344 if (node1 == node2) {
3345 if (attr1 == attr2) {
3346 /* not required, but we keep attributes in order */
3347 if (attr1 != 0) {
3348 cur = attrNode2->prev;
3349 while (cur != NULL) {
3350 if (cur == attrNode1)
3351 return (1);
3352 cur = cur->prev;
3353 }
3354 return (-1);
3355 }
3356 return(0);
3357 }
3358 if (attr2 == 1)
3359 return(1);
3360 return(-1);
3361 }
3362 if ((node1->type == XML_NAMESPACE_DECL) ||
3363 (node2->type == XML_NAMESPACE_DECL))
3364 return(1);
3365 if (node1 == node2->prev)
3366 return(1);
3367 if (node1 == node2->next)
3368 return(-1);
3369
3370 /*
3371 * Speedup using document order if available.
3372 */
3373 if ((node1->type == XML_ELEMENT_NODE) &&
3374 (node2->type == XML_ELEMENT_NODE) &&
3375 (0 > (ptrdiff_t) node1->content) &&
3376 (0 > (ptrdiff_t) node2->content) &&
3377 (node1->doc == node2->doc)) {
3378 ptrdiff_t l1, l2;
3379
3380 l1 = -((ptrdiff_t) node1->content);
3381 l2 = -((ptrdiff_t) node2->content);
3382 if (l1 < l2)
3383 return(1);
3384 if (l1 > l2)
3385 return(-1);
3386 }
3387
3388 /*
3389 * compute depth to root
3390 */
3391 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3392 if (cur->parent == node1)
3393 return(1);
3394 depth2++;
3395 }
3396 root = cur;
3397 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3398 if (cur->parent == node2)
3399 return(-1);
3400 depth1++;
3401 }
3402 /*
3403 * Distinct document (or distinct entities :-( ) case.
3404 */
3405 if (root != cur) {
3406 return(-2);
3407 }
3408 /*
3409 * get the nearest common ancestor.
3410 */
3411 while (depth1 > depth2) {
3412 depth1--;
3413 node1 = node1->parent;
3414 }
3415 while (depth2 > depth1) {
3416 depth2--;
3417 node2 = node2->parent;
3418 }
3419 while (node1->parent != node2->parent) {
3420 node1 = node1->parent;
3421 node2 = node2->parent;
3422 /* should not happen but just in case ... */
3423 if ((node1 == NULL) || (node2 == NULL))
3424 return(-2);
3425 }
3426 /*
3427 * Find who's first.
3428 */
3429 if (node1 == node2->prev)
3430 return(1);
3431 if (node1 == node2->next)
3432 return(-1);
3433 /*
3434 * Speedup using document order if available.
3435 */
3436 if ((node1->type == XML_ELEMENT_NODE) &&
3437 (node2->type == XML_ELEMENT_NODE) &&
3438 (0 > (ptrdiff_t) node1->content) &&
3439 (0 > (ptrdiff_t) node2->content) &&
3440 (node1->doc == node2->doc)) {
3441 ptrdiff_t l1, l2;
3442
3443 l1 = -((ptrdiff_t) node1->content);
3444 l2 = -((ptrdiff_t) node2->content);
3445 if (l1 < l2)
3446 return(1);
3447 if (l1 > l2)
3448 return(-1);
3449 }
3450
3451 for (cur = node1->next;cur != NULL;cur = cur->next)
3452 if (cur == node2)
3453 return(1);
3454 return(-1); /* assume there is no sibling list corruption */
3455}
3456
3463void
3464xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3465#ifndef WITH_TIM_SORT
3466 int i, j, incr, len;
3467 xmlNodePtr tmp;
3468#endif
3469
3470 if (set == NULL)
3471 return;
3472
3473#ifndef WITH_TIM_SORT
3474 /*
3475 * Use the old Shell's sort implementation to sort the node-set
3476 * Timsort ought to be quite faster
3477 */
3478 len = set->nodeNr;
3479 for (incr = len / 2; incr > 0; incr /= 2) {
3480 for (i = incr; i < len; i++) {
3481 j = i - incr;
3482 while (j >= 0) {
3483#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3484 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3485 set->nodeTab[j + incr]) == -1)
3486#else
3487 if (xmlXPathCmpNodes(set->nodeTab[j],
3488 set->nodeTab[j + incr]) == -1)
3489#endif
3490 {
3491 tmp = set->nodeTab[j];
3492 set->nodeTab[j] = set->nodeTab[j + incr];
3493 set->nodeTab[j + incr] = tmp;
3494 j -= incr;
3495 } else
3496 break;
3497 }
3498 }
3499 }
3500#else /* WITH_TIM_SORT */
3501 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3502#endif /* WITH_TIM_SORT */
3503}
3504
3505#define XML_NODESET_DEFAULT 10
3517static xmlNodePtr
3518xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3519 xmlNsPtr cur;
3520
3521 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3522 return(NULL);
3523 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3524 return((xmlNodePtr) ns);
3525
3526 /*
3527 * Allocate a new Namespace and fill the fields.
3528 */
3529 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3530 if (cur == NULL) {
3531 xmlXPathErrMemory(NULL, "duplicating namespace\n");
3532 return(NULL);
3533 }
3534 memset(cur, 0, sizeof(xmlNs));
3535 cur->type = XML_NAMESPACE_DECL;
3536 if (ns->href != NULL)
3537 cur->href = xmlStrdup(ns->href);
3538 if (ns->prefix != NULL)
3539 cur->prefix = xmlStrdup(ns->prefix);
3540 cur->next = (xmlNsPtr) node;
3541 return((xmlNodePtr) cur);
3542}
3543
3552void
3553xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3554 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3555 return;
3556
3557 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3558 if (ns->href != NULL)
3559 xmlFree((xmlChar *)ns->href);
3560 if (ns->prefix != NULL)
3561 xmlFree((xmlChar *)ns->prefix);
3562 xmlFree(ns);
3563 }
3564}
3565
3574xmlNodeSetPtr
3575xmlXPathNodeSetCreate(xmlNodePtr val) {
3576 xmlNodeSetPtr ret;
3577
3578 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3579 if (ret == NULL) {
3580 xmlXPathErrMemory(NULL, "creating nodeset\n");
3581 return(NULL);
3582 }
3583 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3584 if (val != NULL) {
3585 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3586 sizeof(xmlNodePtr));
3587 if (ret->nodeTab == NULL) {
3588 xmlXPathErrMemory(NULL, "creating nodeset\n");
3589 xmlFree(ret);
3590 return(NULL);
3591 }
3592 memset(ret->nodeTab, 0 ,
3593 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3594 ret->nodeMax = XML_NODESET_DEFAULT;
3595 if (val->type == XML_NAMESPACE_DECL) {
3596 xmlNsPtr ns = (xmlNsPtr) val;
3597
3598 /* TODO: Check memory error. */
3599 ret->nodeTab[ret->nodeNr++] =
3600 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3601 } else
3602 ret->nodeTab[ret->nodeNr++] = val;
3603 }
3604 return(ret);
3605}
3606
3616int
3617xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3618 int i;
3619
3620 if ((cur == NULL) || (val == NULL)) return(0);
3621 if (val->type == XML_NAMESPACE_DECL) {
3622 for (i = 0; i < cur->nodeNr; i++) {
3623 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3624 xmlNsPtr ns1, ns2;
3625
3626 ns1 = (xmlNsPtr) val;
3627 ns2 = (xmlNsPtr) cur->nodeTab[i];
3628 if (ns1 == ns2)
3629 return(1);
3630 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3631 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3632 return(1);
3633 }
3634 }
3635 } else {
3636 for (i = 0; i < cur->nodeNr; i++) {
3637 if (cur->nodeTab[i] == val)
3638 return(1);
3639 }
3640 }
3641 return(0);
3642}
3643
3654int
3655xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3656 int i;
3657
3658
3659 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3660 (ns->type != XML_NAMESPACE_DECL) ||
3661 (node->type != XML_ELEMENT_NODE))
3662 return(-1);
3663
3664 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3665 /*
3666 * prevent duplicates
3667 */
3668 for (i = 0;i < cur->nodeNr;i++) {
3669 if ((cur->nodeTab[i] != NULL) &&
3670 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3671 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3672 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3673 return(0);
3674 }
3675
3676 /*
3677 * grow the nodeTab if needed
3678 */
3679 if (cur->nodeMax == 0) {
3680 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3681 sizeof(xmlNodePtr));
3682 if (cur->nodeTab == NULL) {
3683 xmlXPathErrMemory(NULL, "growing nodeset\n");
3684 return(-1);
3685 }
3686 memset(cur->nodeTab, 0 ,
3687 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3688 cur->nodeMax = XML_NODESET_DEFAULT;
3689 } else if (cur->nodeNr == cur->nodeMax) {
3691
3692 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3693 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3694 return(-1);
3695 }
3696 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3697 sizeof(xmlNodePtr));
3698 if (temp == NULL) {
3699 xmlXPathErrMemory(NULL, "growing nodeset\n");
3700 return(-1);
3701 }
3702 cur->nodeMax *= 2;
3703 cur->nodeTab = temp;
3704 }
3705 /* TODO: Check memory error. */
3706 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3707 return(0);
3708}
3709
3719int
3720xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3721 int i;
3722
3723 if ((cur == NULL) || (val == NULL)) return(-1);
3724
3725 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3726 /*
3727 * prevent duplicates
3728 */
3729 for (i = 0;i < cur->nodeNr;i++)
3730 if (cur->nodeTab[i] == val) return(0);
3731
3732 /*
3733 * grow the nodeTab if needed
3734 */
3735 if (cur->nodeMax == 0) {
3736 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3737 sizeof(xmlNodePtr));
3738 if (cur->nodeTab == NULL) {
3739 xmlXPathErrMemory(NULL, "growing nodeset\n");
3740 return(-1);
3741 }
3742 memset(cur->nodeTab, 0 ,
3743 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3744 cur->nodeMax = XML_NODESET_DEFAULT;
3745 } else if (cur->nodeNr == cur->nodeMax) {
3747
3748 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3749 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3750 return(-1);
3751 }
3752 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3753 sizeof(xmlNodePtr));
3754 if (temp == NULL) {
3755 xmlXPathErrMemory(NULL, "growing nodeset\n");
3756 return(-1);
3757 }
3758 cur->nodeMax *= 2;
3759 cur->nodeTab = temp;
3760 }
3761 if (val->type == XML_NAMESPACE_DECL) {
3762 xmlNsPtr ns = (xmlNsPtr) val;
3763
3764 /* TODO: Check memory error. */
3765 cur->nodeTab[cur->nodeNr++] =
3766 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3767 } else
3768 cur->nodeTab[cur->nodeNr++] = val;
3769 return(0);
3770}
3771
3782int
3783xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3784 if ((cur == NULL) || (val == NULL)) return(-1);
3785
3786 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3787 /*
3788 * grow the nodeTab if needed
3789 */
3790 if (cur->nodeMax == 0) {
3791 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3792 sizeof(xmlNodePtr));
3793 if (cur->nodeTab == NULL) {
3794 xmlXPathErrMemory(NULL, "growing nodeset\n");
3795 return(-1);
3796 }
3797 memset(cur->nodeTab, 0 ,
3798 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3799 cur->nodeMax = XML_NODESET_DEFAULT;
3800 } else if (cur->nodeNr == cur->nodeMax) {
3802
3803 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3804 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3805 return(-1);
3806 }
3807 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3808 sizeof(xmlNodePtr));
3809 if (temp == NULL) {
3810 xmlXPathErrMemory(NULL, "growing nodeset\n");
3811 return(-1);
3812 }
3813 cur->nodeTab = temp;
3814 cur->nodeMax *= 2;
3815 }
3816 if (val->type == XML_NAMESPACE_DECL) {
3817 xmlNsPtr ns = (xmlNsPtr) val;
3818
3819 /* TODO: Check memory error. */
3820 cur->nodeTab[cur->nodeNr++] =
3821 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3822 } else
3823 cur->nodeTab[cur->nodeNr++] = val;
3824 return(0);
3825}
3826
3837xmlNodeSetPtr
3838xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3839 int i, j, initNr, skip;
3840 xmlNodePtr n1, n2;
3841
3842 if (val2 == NULL) return(val1);
3843 if (val1 == NULL) {
3844 val1 = xmlXPathNodeSetCreate(NULL);
3845 if (val1 == NULL)
3846 return (NULL);
3847#if 0
3848 /*
3849 * TODO: The optimization won't work in every case, since
3850 * those nasty namespace nodes need to be added with
3851 * xmlXPathNodeSetDupNs() to the set; thus a pure
3852 * memcpy is not possible.
3853 * If there was a flag on the nodesetval, indicating that
3854 * some temporary nodes are in, that would be helpful.
3855 */
3856 /*
3857 * Optimization: Create an equally sized node-set
3858 * and memcpy the content.
3859 */
3860 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3861 if (val1 == NULL)
3862 return(NULL);
3863 if (val2->nodeNr != 0) {
3864 if (val2->nodeNr == 1)
3865 *(val1->nodeTab) = *(val2->nodeTab);
3866 else {
3867 memcpy(val1->nodeTab, val2->nodeTab,
3868 val2->nodeNr * sizeof(xmlNodePtr));
3869 }
3870 val1->nodeNr = val2->nodeNr;
3871 }
3872 return(val1);
3873#endif
3874 }
3875
3876 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3877 initNr = val1->nodeNr;
3878
3879 for (i = 0;i < val2->nodeNr;i++) {
3880 n2 = val2->nodeTab[i];
3881 /*
3882 * check against duplicates
3883 */
3884 skip = 0;
3885 for (j = 0; j < initNr; j++) {
3886 n1 = val1->nodeTab[j];
3887 if (n1 == n2) {
3888 skip = 1;
3889 break;
3890 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3891 (n2->type == XML_NAMESPACE_DECL)) {
3892 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3893 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3894 ((xmlNsPtr) n2)->prefix)))
3895 {
3896 skip = 1;
3897 break;
3898 }
3899 }
3900 }
3901 if (skip)
3902 continue;
3903
3904 /*
3905 * grow the nodeTab if needed
3906 */
3907 if (val1->nodeMax == 0) {
3908 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3909 sizeof(xmlNodePtr));
3910 if (val1->nodeTab == NULL) {
3911 xmlXPathErrMemory(NULL, "merging nodeset\n");
3912 return(NULL);
3913 }
3914 memset(val1->nodeTab, 0 ,
3915 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3916 val1->nodeMax = XML_NODESET_DEFAULT;
3917 } else if (val1->nodeNr == val1->nodeMax) {
3919
3920 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3921 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3922 return(NULL);
3923 }
3924 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3925 sizeof(xmlNodePtr));
3926 if (temp == NULL) {
3927 xmlXPathErrMemory(NULL, "merging nodeset\n");
3928 return(NULL);
3929 }
3930 val1->nodeTab = temp;
3931 val1->nodeMax *= 2;
3932 }
3933 if (n2->type == XML_NAMESPACE_DECL) {
3934 xmlNsPtr ns = (xmlNsPtr) n2;
3935
3936 /* TODO: Check memory error. */
3937 val1->nodeTab[val1->nodeNr++] =
3938 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3939 } else
3940 val1->nodeTab[val1->nodeNr++] = n2;
3941 }
3942
3943 return(val1);
3944}
3945
3946
3957static xmlNodeSetPtr
3958xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3959{
3960 {
3961 int i, j, initNbSet1;
3962 xmlNodePtr n1, n2;
3963
3964 initNbSet1 = set1->nodeNr;
3965 for (i = 0;i < set2->nodeNr;i++) {
3966 n2 = set2->nodeTab[i];
3967 /*
3968 * Skip duplicates.
3969 */
3970 for (j = 0; j < initNbSet1; j++) {
3971 n1 = set1->nodeTab[j];
3972 if (n1 == n2) {
3973 goto skip_node;
3974 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3975 (n2->type == XML_NAMESPACE_DECL))
3976 {
3977 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3978 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3979 ((xmlNsPtr) n2)->prefix)))
3980 {
3981 /*
3982 * Free the namespace node.
3983 */
3984 set2->nodeTab[i] = NULL;
3985 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3986 goto skip_node;
3987 }
3988 }
3989 }
3990 /*
3991 * grow the nodeTab if needed
3992 */
3993 if (set1->nodeMax == 0) {
3994 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3995 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3996 if (set1->nodeTab == NULL) {
3997 xmlXPathErrMemory(NULL, "merging nodeset\n");
3998 return(NULL);
3999 }
4000 memset(set1->nodeTab, 0,
4001 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4002 set1->nodeMax = XML_NODESET_DEFAULT;
4003 } else if (set1->nodeNr >= set1->nodeMax) {
4005
4006 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4007 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4008 return(NULL);
4009 }
4011 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4012 if (temp == NULL) {
4013 xmlXPathErrMemory(NULL, "merging nodeset\n");
4014 return(NULL);
4015 }
4016 set1->nodeTab = temp;
4017 set1->nodeMax *= 2;
4018 }
4019 set1->nodeTab[set1->nodeNr++] = n2;
4020skip_node:
4021 {}
4022 }
4023 }
4024 set2->nodeNr = 0;
4025 return(set1);
4026}
4027
4038static xmlNodeSetPtr
4039xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
4040{
4041 {
4042 int i;
4043 xmlNodePtr n2;
4044
4045 for (i = 0;i < set2->nodeNr;i++) {
4046 n2 = set2->nodeTab[i];
4047 if (set1->nodeMax == 0) {
4048 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4049 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4050 if (set1->nodeTab == NULL) {
4051 xmlXPathErrMemory(NULL, "merging nodeset\n");
4052 return(NULL);
4053 }
4054 memset(set1->nodeTab, 0,
4055 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4056 set1->nodeMax = XML_NODESET_DEFAULT;
4057 } else if (set1->nodeNr >= set1->nodeMax) {
4059
4060 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4061 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4062 return(NULL);
4063 }
4065 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4066 if (temp == NULL) {
4067 xmlXPathErrMemory(NULL, "merging nodeset\n");
4068 return(NULL);
4069 }
4070 set1->nodeTab = temp;
4071 set1->nodeMax *= 2;
4072 }
4073 set1->nodeTab[set1->nodeNr++] = n2;
4074 }
4075 }
4076 set2->nodeNr = 0;
4077 return(set1);
4078}
4079
4087void
4088xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4089 int i;
4090
4091 if (cur == NULL) return;
4092 if (val == NULL) return;
4093
4094 /*
4095 * find node in nodeTab
4096 */
4097 for (i = 0;i < cur->nodeNr;i++)
4098 if (cur->nodeTab[i] == val) break;
4099
4100 if (i >= cur->nodeNr) { /* not found */
4101#ifdef DEBUG
4103 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4104 val->name);
4105#endif
4106 return;
4107 }
4108 if ((cur->nodeTab[i] != NULL) &&
4109 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4110 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4111 cur->nodeNr--;
4112 for (;i < cur->nodeNr;i++)
4113 cur->nodeTab[i] = cur->nodeTab[i + 1];
4114 cur->nodeTab[cur->nodeNr] = NULL;
4115}
4116
4124void
4125xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4126 if (cur == NULL) return;
4127 if (val >= cur->nodeNr) return;
4128 if ((cur->nodeTab[val] != NULL) &&
4129 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4130 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4131 cur->nodeNr--;
4132 for (;val < cur->nodeNr;val++)
4133 cur->nodeTab[val] = cur->nodeTab[val + 1];
4134 cur->nodeTab[cur->nodeNr] = NULL;
4135}
4136
4143void
4144xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4145 if (obj == NULL) return;
4146 if (obj->nodeTab != NULL) {
4147 int i;
4148
4149 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4150 for (i = 0;i < obj->nodeNr;i++)
4151 if ((obj->nodeTab[i] != NULL) &&
4152 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4153 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4154 xmlFree(obj->nodeTab);
4155 }
4156 xmlFree(obj);
4157}
4158
4168static void
4169xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4170{
4171 if ((set == NULL) || (pos >= set->nodeNr))
4172 return;
4173 else if ((hasNsNodes)) {
4174 int i;
4176
4177 for (i = pos; i < set->nodeNr; i++) {
4178 node = set->nodeTab[i];
4179 if ((node != NULL) &&
4180 (node->type == XML_NAMESPACE_DECL))
4181 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4182 }
4183 }
4184 set->nodeNr = pos;
4185}
4186
4195static void
4196xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4197{
4198 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4199}
4200
4209static void
4210xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4211{
4212 int i;
4214
4215 if ((set == NULL) || (set->nodeNr <= 1))
4216 return;
4217 for (i = 0; i < set->nodeNr - 1; i++) {
4218 node = set->nodeTab[i];
4219 if ((node != NULL) &&
4220 (node->type == XML_NAMESPACE_DECL))
4221 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4222 }
4223 set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4224 set->nodeNr = 1;
4225}
4226
4234static void
4235xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4236 int i;
4237
4238 if (obj == NULL) return;
4239
4240 if (obj->nodeTab != NULL) {
4241 for (i = 0;i < obj->nodeNr;i++) {
4242 if (obj->nodeTab[i] != NULL) {
4243 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4244 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4245 } else {
4246 xmlFreeNodeList(obj->nodeTab[i]);
4247 }
4248 }
4249 }
4250 xmlFree(obj->nodeTab);
4251 }
4252 xmlFree(obj);
4253}
4254
4255#if defined(DEBUG) || defined(DEBUG_STEP)
4263void
4264xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4265 int i;
4266
4267 if (output == NULL) output = xmlGenericErrorContext;
4268 if (obj == NULL) {
4269 fprintf(output, "NodeSet == NULL !\n");
4270 return;
4271 }
4272 if (obj->nodeNr == 0) {
4273 fprintf(output, "NodeSet is empty\n");
4274 return;
4275 }
4276 if (obj->nodeTab == NULL) {
4277 fprintf(output, " nodeTab == NULL !\n");
4278 return;
4279 }
4280 for (i = 0; i < obj->nodeNr; i++) {
4281 if (obj->nodeTab[i] == NULL) {
4282 fprintf(output, " NULL !\n");
4283 return;
4284 }
4285 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4286 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4287 fprintf(output, " /");
4288 else if (obj->nodeTab[i]->name == NULL)
4289 fprintf(output, " noname!");
4290 else fprintf(output, " %s", obj->nodeTab[i]->name);
4291 }
4292 fprintf(output, "\n");
4293}
4294#endif
4295
4305xmlXPathObjectPtr
4306xmlXPathNewNodeSet(xmlNodePtr val) {
4307 xmlXPathObjectPtr ret;
4308
4309 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4310 if (ret == NULL) {
4311 xmlXPathErrMemory(NULL, "creating nodeset\n");
4312 return(NULL);
4313 }
4314 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4315 ret->type = XPATH_NODESET;
4316 ret->boolval = 0;
4317 /* TODO: Check memory error. */
4318 ret->nodesetval = xmlXPathNodeSetCreate(val);
4319 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4320#ifdef XP_DEBUG_OBJ_USAGE
4321 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4322#endif
4323 return(ret);
4324}
4325
4335xmlXPathObjectPtr
4336xmlXPathNewValueTree(xmlNodePtr val) {
4337 xmlXPathObjectPtr ret;
4338
4339 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4340 if (ret == NULL) {
4341 xmlXPathErrMemory(NULL, "creating result value tree\n");
4342 return(NULL);
4343 }
4344 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4345 ret->type = XPATH_XSLT_TREE;
4346 ret->boolval = 1;
4347 ret->user = (void *) val;
4348 ret->nodesetval = xmlXPathNodeSetCreate(val);
4349#ifdef XP_DEBUG_OBJ_USAGE
4350 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4351#endif
4352 return(ret);
4353}
4354
4364xmlXPathObjectPtr
4365xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4366{
4367 xmlXPathObjectPtr ret;
4368 int i;
4369
4370 if (val == NULL)
4371 ret = NULL;
4372 else if (val->nodeTab == NULL)
4373 ret = xmlXPathNewNodeSet(NULL);
4374 else {
4375 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4376 if (ret) {
4377 for (i = 1; i < val->nodeNr; ++i) {
4378 /* TODO: Propagate memory error. */
4379 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4380 < 0) break;
4381 }
4382 }
4383 }
4384
4385 return (ret);
4386}
4387
4396xmlXPathObjectPtr
4397xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4398 xmlXPathObjectPtr ret;
4399
4400 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4401 if (ret == NULL) {
4402 xmlXPathErrMemory(NULL, "creating node set object\n");
4403 return(NULL);
4404 }
4405 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4406 ret->type = XPATH_NODESET;
4407 ret->nodesetval = val;
4408#ifdef XP_DEBUG_OBJ_USAGE
4409 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4410#endif
4411 return(ret);
4412}
4413
4421void
4422xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4423 if (obj == NULL) return;
4424#ifdef XP_DEBUG_OBJ_USAGE
4425 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4426#endif
4427 xmlFree(obj);
4428}
4429
4441xmlNodeSetPtr
4442xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4443 xmlNodeSetPtr ret;
4444 int i, l1;
4446
4447 if (xmlXPathNodeSetIsEmpty(nodes2))
4448 return(nodes1);
4449
4450 /* TODO: Check memory error. */
4451 ret = xmlXPathNodeSetCreate(NULL);
4452 if (xmlXPathNodeSetIsEmpty(nodes1))
4453 return(ret);
4454
4455 l1 = xmlXPathNodeSetGetLength(nodes1);
4456
4457 for (i = 0; i < l1; i++) {
4458 cur = xmlXPathNodeSetItem(nodes1, i);
4459 if (!xmlXPathNodeSetContains(nodes2, cur)) {
4460 /* TODO: Propagate memory error. */
4461 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4462 break;
4463 }
4464 }
4465 return(ret);
4466}
4467
4479xmlNodeSetPtr
4480xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4481 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4482 int i, l1;
4484
4485 if (ret == NULL)
4486 return(ret);
4487 if (xmlXPathNodeSetIsEmpty(nodes1))
4488 return(ret);
4489 if (xmlXPathNodeSetIsEmpty(nodes2))
4490 return(ret);
4491
4492 l1 = xmlXPathNodeSetGetLength(nodes1);
4493
4494 for (i = 0; i < l1; i++) {
4495 cur = xmlXPathNodeSetItem(nodes1, i);
4496 if (xmlXPathNodeSetContains(nodes2, cur)) {
4497 /* TODO: Propagate memory error. */
4498 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4499 break;
4500 }
4501 }
4502 return(ret);
4503}
4504
4515xmlNodeSetPtr
4516xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4517 xmlNodeSetPtr ret;
4519 int i, l;
4520 xmlChar * strval;
4522
4523 if (xmlXPathNodeSetIsEmpty(nodes))
4524 return(nodes);
4525
4526 ret = xmlXPathNodeSetCreate(NULL);
4527 if (ret == NULL)
4528 return(ret);
4529 l = xmlXPathNodeSetGetLength(nodes);
4530 hash = xmlHashCreate (l);
4531 for (i = 0; i < l; i++) {
4532 cur = xmlXPathNodeSetItem(nodes, i);
4533 strval = xmlXPathCastNodeToString(cur);
4534 if (xmlHashLookup(hash, strval) == NULL) {
4536 /* TODO: Propagate memory error. */
4537 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4538 break;
4539 } else {
4540 xmlFree(strval);
4541 }
4542 }
4544 return(ret);
4545}
4546
4559xmlNodeSetPtr
4560xmlXPathDistinct (xmlNodeSetPtr nodes) {
4561 if (xmlXPathNodeSetIsEmpty(nodes))
4562 return(nodes);
4563
4564 xmlXPathNodeSetSort(nodes);
4565 return(xmlXPathDistinctSorted(nodes));
4566}
4567
4579int
4580xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4581 int i, l;
4583
4584 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4585 xmlXPathNodeSetIsEmpty(nodes2))
4586 return(0);
4587
4588 l = xmlXPathNodeSetGetLength(nodes1);
4589 for (i = 0; i < l; i++) {
4590 cur = xmlXPathNodeSetItem(nodes1, i);
4591 if (xmlXPathNodeSetContains(nodes2, cur))
4592 return(1);
4593 }
4594 return(0);
4595}
4596
4609xmlNodeSetPtr
4610xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4611 int i, l;
4613 xmlNodeSetPtr ret;
4614
4615 if (node == NULL)
4616 return(nodes);
4617
4618 ret = xmlXPathNodeSetCreate(NULL);
4619 if (ret == NULL)
4620 return(ret);
4621 if (xmlXPathNodeSetIsEmpty(nodes) ||
4622 (!xmlXPathNodeSetContains(nodes, node)))
4623 return(ret);
4624
4625 l = xmlXPathNodeSetGetLength(nodes);
4626 for (i = 0; i < l; i++) {
4627 cur = xmlXPathNodeSetItem(nodes, i);
4628 if (cur == node)
4629 break;
4630 /* TODO: Propagate memory error. */
4631 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4632 break;
4633 }
4634 return(ret);
4635}
4636
4651xmlNodeSetPtr
4652xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4653 xmlXPathNodeSetSort(nodes);
4654 return(xmlXPathNodeLeadingSorted(nodes, node));
4655}
4656
4669xmlNodeSetPtr
4670xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4671 if (xmlXPathNodeSetIsEmpty(nodes2))
4672 return(nodes1);
4673 return(xmlXPathNodeLeadingSorted(nodes1,
4674 xmlXPathNodeSetItem(nodes2, 1)));
4675}
4676
4691xmlNodeSetPtr
4692xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4693 if (xmlXPathNodeSetIsEmpty(nodes2))
4694 return(nodes1);
4695 if (xmlXPathNodeSetIsEmpty(nodes1))
4696 return(xmlXPathNodeSetCreate(NULL));
4697 xmlXPathNodeSetSort(nodes1);
4698 xmlXPathNodeSetSort(nodes2);
4699 return(xmlXPathNodeLeadingSorted(nodes1,
4700 xmlXPathNodeSetItem(nodes2, 1)));
4701}
4702
4715xmlNodeSetPtr
4716xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4717 int i, l;
4719 xmlNodeSetPtr ret;
4720
4721 if (node == NULL)
4722 return(nodes);
4723
4724 ret = xmlXPathNodeSetCreate(NULL);
4725 if (ret == NULL)
4726 return(ret);
4727 if (xmlXPathNodeSetIsEmpty(nodes) ||
4728 (!xmlXPathNodeSetContains(nodes, node)))
4729 return(ret);
4730
4731 l = xmlXPathNodeSetGetLength(nodes);
4732 for (i = l - 1; i >= 0; i--) {
4733 cur = xmlXPathNodeSetItem(nodes, i);
4734 if (cur == node)
4735 break;
4736 /* TODO: Propagate memory error. */
4737 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4738 break;
4739 }
4740 xmlXPathNodeSetSort(ret); /* bug 413451 */
4741 return(ret);
4742}
4743
4758xmlNodeSetPtr
4759xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4760 xmlXPathNodeSetSort(nodes);
4761 return(xmlXPathNodeTrailingSorted(nodes, node));
4762}
4763
4776xmlNodeSetPtr
4777xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4778 if (xmlXPathNodeSetIsEmpty(nodes2))
4779 return(nodes1);
4780 return(xmlXPathNodeTrailingSorted(nodes1,
4781 xmlXPathNodeSetItem(nodes2, 0)));
4782}
4783
4798xmlNodeSetPtr
4799xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4800 if (xmlXPathNodeSetIsEmpty(nodes2))
4801 return(nodes1);
4802 if (xmlXPathNodeSetIsEmpty(nodes1))
4803 return(xmlXPathNodeSetCreate(NULL));
4804 xmlXPathNodeSetSort(nodes1);
4805 xmlXPathNodeSetSort(nodes2);
4806 return(xmlXPathNodeTrailingSorted(nodes1,
4807 xmlXPathNodeSetItem(nodes2, 0)));
4808}
4809
4810/************************************************************************
4811 * *
4812 * Routines to handle extra functions *
4813 * *
4814 ************************************************************************/
4815
4826int
4827xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4828 xmlXPathFunction f) {
4829 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4830}
4831
4843int
4844xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4845 const xmlChar *ns_uri, xmlXPathFunction f) {
4846 if (ctxt == NULL)
4847 return(-1);
4848 if (name == NULL)
4849 return(-1);
4850
4851 if (ctxt->funcHash == NULL)
4852 ctxt->funcHash = xmlHashCreate(0);
4853 if (ctxt->funcHash == NULL)
4854 return(-1);
4855 if (f == NULL)
4856 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4858 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4860}
4861
4870void
4871xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4872 xmlXPathFuncLookupFunc f,
4873 void *funcCtxt) {
4874 if (ctxt == NULL)
4875 return;
4876 ctxt->funcLookupFunc = f;
4877 ctxt->funcLookupData = funcCtxt;
4878}
4879
4890xmlXPathFunction
4891xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4892 if (ctxt == NULL)
4893 return (NULL);
4894
4895 if (ctxt->funcLookupFunc != NULL) {
4896 xmlXPathFunction ret;
4897 xmlXPathFuncLookupFunc f;
4898
4899 f = ctxt->funcLookupFunc;
4900 ret = f(ctxt->funcLookupData, name, NULL);
4901 if (ret != NULL)
4902 return(ret);
4903 }
4904 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4905}
4906
4918xmlXPathFunction
4919xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4920 const xmlChar *ns_uri) {
4921 xmlXPathFunction ret;
4922
4923 if (ctxt == NULL)
4924 return(NULL);
4925 if (name == NULL)
4926 return(NULL);
4927
4928 if (ctxt->funcLookupFunc != NULL) {
4929 xmlXPathFuncLookupFunc f;
4930
4931 f = ctxt->funcLookupFunc;
4932 ret = f(ctxt->funcLookupData, name, ns_uri);
4933 if (ret != NULL)
4934 return(ret);
4935 }
4936
4937 if (ctxt->funcHash == NULL)
4938 return(NULL);
4939
4941 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4943 return(ret);
4944}
4945
4952void
4953xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4954 if (ctxt == NULL)
4955 return;
4956
4957 xmlHashFree(ctxt->funcHash, NULL);
4958 ctxt->funcHash = NULL;
4959}
4960
4961/************************************************************************
4962 * *
4963 * Routines to handle Variables *
4964 * *
4965 ************************************************************************/
4966
4978int
4979xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4980 xmlXPathObjectPtr value) {
4981 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4982}
4983
4996int
4997xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4998 const xmlChar *ns_uri,
4999 xmlXPathObjectPtr value) {
5000 if (ctxt == NULL)
5001 return(-1);
5002 if (name == NULL)
5003 return(-1);
5004
5005 if (ctxt->varHash == NULL)
5006 ctxt->varHash = xmlHashCreate(0);
5007 if (ctxt->varHash == NULL)
5008 return(-1);
5009 if (value == NULL)
5010 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5011 xmlXPathFreeObjectEntry));
5012 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5013 (void *) value, xmlXPathFreeObjectEntry));
5014}
5015
5024void
5025xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5026 xmlXPathVariableLookupFunc f, void *data) {
5027 if (ctxt == NULL)
5028 return;
5029 ctxt->varLookupFunc = f;
5030 ctxt->varLookupData = data;
5031}
5032
5043xmlXPathObjectPtr
5044xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5045 if (ctxt == NULL)
5046 return(NULL);
5047
5048 if (ctxt->varLookupFunc != NULL) {
5049 xmlXPathObjectPtr ret;
5050
5051 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5052 (ctxt->varLookupData, name, NULL);
5053 return(ret);
5054 }
5055 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5056}
5057
5069xmlXPathObjectPtr
5070xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5071 const xmlChar *ns_uri) {
5072 if (ctxt == NULL)
5073 return(NULL);
5074
5075 if (ctxt->varLookupFunc != NULL) {
5076 xmlXPathObjectPtr ret;
5077
5078 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5079 (ctxt->varLookupData, name, ns_uri);
5080 if (ret != NULL) return(ret);
5081 }
5082
5083 if (ctxt->varHash == NULL)
5084 return(NULL);
5085 if (name == NULL)
5086 return(NULL);
5087
5088 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5089 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5090}
5091
5098void
5099xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5100 if (ctxt == NULL)
5101 return;
5102
5103 xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5104 ctxt->varHash = NULL;
5105}
5106
5118int
5119xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5120 const xmlChar *ns_uri) {
5121 if (ctxt == NULL)
5122 return(-1);
5123 if (prefix == NULL)
5124 return(-1);
5125 if (prefix[0] == 0)
5126 return(-1);
5127
5128 if (ctxt->nsHash == NULL)
5129 ctxt->nsHash = xmlHashCreate(10);
5130 if (ctxt->nsHash == NULL)
5131 return(-1);
5132 if (ns_uri == NULL)
5133 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5135 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5137}
5138
5149const xmlChar *
5150xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5151 if (ctxt == NULL)
5152 return(NULL);
5153 if (prefix == NULL)
5154 return(NULL);
5155
5156#ifdef XML_XML_NAMESPACE
5157 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5158 return(XML_XML_NAMESPACE);
5159#endif
5160
5161 if (ctxt->namespaces != NULL) {
5162 int i;
5163
5164 for (i = 0;i < ctxt->nsNr;i++) {
5165 if ((ctxt->namespaces[i] != NULL) &&
5166 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5167 return(ctxt->namespaces[i]->href);
5168 }
5169 }
5170
5171 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5172}
5173
5180void
5181xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5182 if (ctxt == NULL)
5183 return;
5184
5186 ctxt->nsHash = NULL;
5187}
5188
5189/************************************************************************
5190 * *
5191 * Routines to handle Values *
5192 * *
5193 ************************************************************************/
5194
5195/* Allocations are terrible, one needs to optimize all this !!! */
5196
5205xmlXPathObjectPtr
5206xmlXPathNewFloat(double val) {
5207 xmlXPathObjectPtr ret;
5208
5209 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5210 if (ret == NULL) {
5211 xmlXPathErrMemory(NULL, "creating float object\n");
5212 return(NULL);
5213 }
5214 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5215 ret->type = XPATH_NUMBER;
5216 ret->floatval = val;
5217#ifdef XP_DEBUG_OBJ_USAGE
5218 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5219#endif
5220 return(ret);
5221}
5222
5231xmlXPathObjectPtr
5232xmlXPathNewBoolean(int val) {
5233 xmlXPathObjectPtr ret;
5234
5235 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5236 if (ret == NULL) {
5237 xmlXPathErrMemory(NULL, "creating boolean object\n");
5238 return(NULL);
5239 }
5240 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5241 ret->type = XPATH_BOOLEAN;
5242 ret->boolval = (val != 0);
5243#ifdef XP_DEBUG_OBJ_USAGE
5244 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5245#endif
5246 return(ret);
5247}
5248
5257xmlXPathObjectPtr
5258xmlXPathNewString(const xmlChar *val) {
5259 xmlXPathObjectPtr ret;
5260
5261 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5262 if (ret == NULL) {
5263 xmlXPathErrMemory(NULL, "creating string object\n");
5264 return(NULL);
5265 }
5266 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5267 ret->type = XPATH_STRING;
5268 if (val != NULL)
5269 ret->stringval = xmlStrdup(val);
5270 else
5271 ret->stringval = xmlStrdup((const xmlChar *)"");
5272#ifdef XP_DEBUG_OBJ_USAGE
5273 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5274#endif
5275 return(ret);
5276}
5277
5286xmlXPathObjectPtr
5287xmlXPathWrapString (xmlChar *val) {
5288 xmlXPathObjectPtr ret;
5289
5290 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5291 if (ret == NULL) {
5292 xmlXPathErrMemory(NULL, "creating string object\n");
5293 return(NULL);
5294 }
5295 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5296 ret->type = XPATH_STRING;
5297 ret->stringval = val;
5298#ifdef XP_DEBUG_OBJ_USAGE
5299 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5300#endif
5301 return(ret);
5302}
5303
5312xmlXPathObjectPtr
5313xmlXPathNewCString(const char *val) {
5314 xmlXPathObjectPtr ret;
5315
5316 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5317 if (ret == NULL) {
5318 xmlXPathErrMemory(NULL, "creating string object\n");
5319 return(NULL);
5320 }
5321 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5322 ret->type = XPATH_STRING;
5323 ret->stringval = xmlStrdup(BAD_CAST val);
5324#ifdef XP_DEBUG_OBJ_USAGE
5325 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5326#endif
5327 return(ret);
5328}
5329
5338xmlXPathObjectPtr
5339xmlXPathWrapCString (char * val) {
5340 return(xmlXPathWrapString((xmlChar *)(val)));
5341}
5342
5351xmlXPathObjectPtr
5352xmlXPathWrapExternal (void *val) {
5353 xmlXPathObjectPtr ret;
5354
5355 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5356 if (ret == NULL) {
5357 xmlXPathErrMemory(NULL, "creating user object\n");
5358 return(NULL);
5359 }
5360 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5361 ret->type = XPATH_USERS;
5362 ret->user = val;
5363#ifdef XP_DEBUG_OBJ_USAGE
5364 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5365#endif
5366 return(ret);
5367}
5368
5377xmlXPathObjectPtr
5378xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5379 xmlXPathObjectPtr ret;
5380
5381 if (val == NULL)
5382 return(NULL);
5383
5384 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5385 if (ret == NULL) {
5386 xmlXPathErrMemory(NULL, "copying object\n");
5387 return(NULL);
5388 }
5389 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5390#ifdef XP_DEBUG_OBJ_USAGE
5391 xmlXPathDebugObjUsageRequested(NULL, val->type);
5392#endif
5393 switch (val->type) {
5394 case XPATH_BOOLEAN:
5395 case XPATH_NUMBER:
5396#ifdef LIBXML_XPTR_LOCS_ENABLED
5397 case XPATH_POINT:
5398 case XPATH_RANGE:
5399#endif /* LIBXML_XPTR_LOCS_ENABLED */
5400 break;
5401 case XPATH_STRING:
5402 ret->stringval = xmlStrdup(val->stringval);
5403 break;
5404 case XPATH_XSLT_TREE:
5405#if 0
5406/*
5407 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5408 this previous handling is no longer correct, and can cause some serious
5409 problems (ref. bug 145547)
5410*/
5411 if ((val->nodesetval != NULL) &&
5412 (val->nodesetval->nodeTab != NULL)) {
5413 xmlNodePtr cur, tmp;
5414 xmlDocPtr top;
5415
5416 ret->boolval = 1;
5417 top = xmlNewDoc(NULL);
5418 top->name = (char *)
5419 xmlStrdup(val->nodesetval->nodeTab[0]->name);
5420 ret->user = top;
5421 if (top != NULL) {
5422 top->doc = top;
5423 cur = val->nodesetval->nodeTab[0]->children;
5424 while (cur != NULL) {
5425 tmp = xmlDocCopyNode(cur, top, 1);
5426 xmlAddChild((xmlNodePtr) top, tmp);
5427 cur = cur->next;
5428 }
5429 }
5430
5431 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5432 } else
5433 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5434 /* Deallocate the copied tree value */
5435 break;
5436#endif
5437 case XPATH_NODESET:
5438 /* TODO: Check memory error. */
5439 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5440 /* Do not deallocate the copied tree value */
5441 ret->boolval = 0;
5442 break;
5443#ifdef LIBXML_XPTR_LOCS_ENABLED
5444 case XPATH_LOCATIONSET:
5445 {
5446 xmlLocationSetPtr loc = val->user;
5447 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5448 break;
5449 }
5450#endif
5451 case XPATH_USERS:
5452 ret->user = val->user;
5453 break;
5454 case XPATH_UNDEFINED:
5456 "xmlXPathObjectCopy: unsupported type %d\n",
5457 val->type);
5458 break;
5459 }
5460 return(ret);
5461}
5462
5469void
5470xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5471 if (obj == NULL) return;
5472 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5473 if (obj->boolval) {
5474#if 0
5475 if (obj->user != NULL) {
5476 xmlXPathFreeNodeSet(obj->nodesetval);
5478 } else
5479#endif
5480 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5481 if (obj->nodesetval != NULL)
5482 xmlXPathFreeValueTree(obj->nodesetval);
5483 } else {
5484 if (obj->nodesetval != NULL)
5485 xmlXPathFreeNodeSet(obj->nodesetval);
5486 }
5487#ifdef LIBXML_XPTR_LOCS_ENABLED
5488 } else if (obj->type == XPATH_LOCATIONSET) {
5489 if (obj->user != NULL)
5490 xmlXPtrFreeLocationSet(obj->user);
5491#endif
5492 } else if (obj->type == XPATH_STRING) {
5493 if (obj->stringval != NULL)
5494 xmlFree(obj->stringval);
5495 }
5496#ifdef XP_DEBUG_OBJ_USAGE
5497 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5498#endif
5499 xmlFree(obj);
5500}
5501
5502static void
5503xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5504 xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5505}
5506
5514static void
5515xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5516{
5517#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5518 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5519 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5520
5521#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5522
5523 if (obj == NULL)
5524 return;
5525 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5526 xmlXPathFreeObject(obj);
5527 } else {
5528 xmlXPathContextCachePtr cache =
5529 (xmlXPathContextCachePtr) ctxt->cache;
5530
5531 switch (obj->type) {
5532 case XPATH_NODESET:
5533 case XPATH_XSLT_TREE:
5534 if (obj->nodesetval != NULL) {
5535 if (obj->boolval) {
5536 /*
5537 * It looks like the @boolval is used for
5538 * evaluation if this an XSLT Result Tree Fragment.
5539 * TODO: Check if this assumption is correct.
5540 */
5541 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5542 xmlXPathFreeValueTree(obj->nodesetval);
5543 obj->nodesetval = NULL;
5544 } else if ((obj->nodesetval->nodeMax <= 40) &&
5545 (XP_CACHE_WANTS(cache->nodesetObjs,
5546 cache->maxNodeset)))
5547 {
5548 XP_CACHE_ADD(cache->nodesetObjs, obj);
5549 goto obj_cached;
5550 } else {
5551 xmlXPathFreeNodeSet(obj->nodesetval);
5552 obj->nodesetval = NULL;
5553 }
5554 }
5555 break;
5556 case XPATH_STRING:
5557 if (obj->stringval != NULL)
5558 xmlFree(obj->stringval);
5559
5560 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5561 XP_CACHE_ADD(cache->stringObjs, obj);
5562 goto obj_cached;
5563 }
5564 break;
5565 case XPATH_BOOLEAN:
5566 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5567 XP_CACHE_ADD(cache->booleanObjs, obj);
5568 goto obj_cached;
5569 }
5570 break;
5571 case XPATH_NUMBER:
5572 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5573 XP_CACHE_ADD(cache->numberObjs, obj);
5574 goto obj_cached;
5575 }
5576 break;
5577#ifdef LIBXML_XPTR_LOCS_ENABLED
5578 case XPATH_LOCATIONSET:
5579 if (obj->user != NULL) {
5580 xmlXPtrFreeLocationSet(obj->user);
5581 }
5582 goto free_obj;
5583#endif
5584 default:
5585 goto free_obj;
5586 }
5587
5588 /*
5589 * Fallback to adding to the misc-objects slot.
5590 */
5591 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5592 XP_CACHE_ADD(cache->miscObjs, obj);
5593 } else
5594 goto free_obj;
5595
5596obj_cached:
5597
5598#ifdef XP_DEBUG_OBJ_USAGE
5599 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5600#endif
5601
5602 if (obj->nodesetval != NULL) {
5603 xmlNodeSetPtr tmpset = obj->nodesetval;
5604
5605 /*
5606 * TODO: Due to those nasty ns-nodes, we need to traverse
5607 * the list and free the ns-nodes.
5608 * URGENT TODO: Check if it's actually slowing things down.
5609 * Maybe we shouldn't try to preserve the list.
5610 */
5611 if (tmpset->nodeNr > 1) {
5612 int i;
5614
5615 for (i = 0; i < tmpset->nodeNr; i++) {
5616 node = tmpset->nodeTab[i];
5617 if ((node != NULL) &&
5618 (node->type == XML_NAMESPACE_DECL))
5619 {
5620 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5621 }
5622 }
5623 } else if (tmpset->nodeNr == 1) {
5624 if ((tmpset->nodeTab[0] != NULL) &&
5625 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5626 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5627 }
5628 tmpset->nodeNr = 0;
5629 memset(obj, 0, sizeof(xmlXPathObject));
5630 obj->nodesetval = tmpset;
5631 } else
5632 memset(obj, 0, sizeof(xmlXPathObject));
5633
5634 return;
5635
5636free_obj:
5637 /*
5638 * Cache is full; free the object.
5639 */
5640 if (obj->nodesetval != NULL)
5641 xmlXPathFreeNodeSet(obj->nodesetval);
5642#ifdef XP_DEBUG_OBJ_USAGE
5643 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5644#endif
5645 xmlFree(obj);
5646 }
5647 return;
5648}
5649
5650
5651/************************************************************************
5652 * *
5653 * Type Casting Routines *
5654 * *
5655 ************************************************************************/
5656
5665xmlChar *
5666xmlXPathCastBooleanToString (int val) {
5667 xmlChar *ret;
5668 if (val)
5669 ret = xmlStrdup((const xmlChar *) "true");
5670 else
5671 ret = xmlStrdup((const xmlChar *) "false");
5672 return(ret);
5673}
5674
5683xmlChar *
5684xmlXPathCastNumberToString (double val) {
5685 xmlChar *ret;
5686 switch (xmlXPathIsInf(val)) {
5687 case 1:
5688 ret = xmlStrdup((const xmlChar *) "Infinity");
5689 break;
5690 case -1:
5691 ret = xmlStrdup((const xmlChar *) "-Infinity");
5692 break;
5693 default:
5694 if (xmlXPathIsNaN(val)) {
5695 ret = xmlStrdup((const xmlChar *) "NaN");
5696 } else if (val == 0) {
5697 /* Omit sign for negative zero. */
5698 ret = xmlStrdup((const xmlChar *) "0");
5699 } else {
5700 /* could be improved */
5701 char buf[100];
5702 xmlXPathFormatNumber(val, buf, 99);
5703 buf[99] = 0;
5704 ret = xmlStrdup((const xmlChar *) buf);
5705 }
5706 }
5707 return(ret);
5708}
5709
5718xmlChar *
5719xmlXPathCastNodeToString (xmlNodePtr node) {
5720xmlChar *ret;
5721 if ((ret = xmlNodeGetContent(node)) == NULL)
5722 ret = xmlStrdup((const xmlChar *) "");
5723 return(ret);
5724}
5725
5734xmlChar *
5735xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5736 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5737 return(xmlStrdup((const xmlChar *) ""));
5738
5739 if (ns->nodeNr > 1)
5740 xmlXPathNodeSetSort(ns);
5741 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5742}
5743
5753xmlChar *
5754xmlXPathCastToString(xmlXPathObjectPtr val) {
5755 xmlChar *ret = NULL;
5756
5757 if (val == NULL)
5758 return(xmlStrdup((const xmlChar *) ""));
5759 switch (val->type) {
5760 case XPATH_UNDEFINED:
5761#ifdef DEBUG_EXPR
5762 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5763#endif
5764 ret = xmlStrdup((const xmlChar *) "");
5765 break;
5766 case XPATH_NODESET:
5767 case XPATH_XSLT_TREE:
5768 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5769 break;
5770 case XPATH_STRING:
5771 return(xmlStrdup(val->stringval));
5772 case XPATH_BOOLEAN:
5773 ret = xmlXPathCastBooleanToString(val->boolval);
5774 break;
5775 case XPATH_NUMBER: {
5776 ret = xmlXPathCastNumberToString(val->floatval);
5777 break;
5778 }
5779 case XPATH_USERS:
5780#ifdef LIBXML_XPTR_LOCS_ENABLED
5781 case XPATH_POINT:
5782 case XPATH_RANGE:
5783 case XPATH_LOCATIONSET:
5784#endif /* LIBXML_XPTR_LOCS_ENABLED */
5785 TODO
5786 ret = xmlStrdup((const xmlChar *) "");
5787 break;
5788 }
5789 return(ret);
5790}
5791
5801xmlXPathObjectPtr
5802xmlXPathConvertString(xmlXPathObjectPtr val) {
5803 xmlChar *res = NULL;
5804
5805 if (val == NULL)
5806 return(xmlXPathNewCString(""));
5807
5808 switch (val->type) {
5809 case XPATH_UNDEFINED:
5810#ifdef DEBUG_EXPR
5811 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5812#endif
5813 break;
5814 case XPATH_NODESET:
5815 case XPATH_XSLT_TREE:
5816 res = xmlXPathCastNodeSetToString(val->nodesetval);
5817 break;
5818 case XPATH_STRING:
5819 return(val);
5820 case XPATH_BOOLEAN:
5821 res = xmlXPathCastBooleanToString(val->boolval);
5822 break;
5823 case XPATH_NUMBER:
5824 res = xmlXPathCastNumberToString(val->floatval);
5825 break;
5826 case XPATH_USERS:
5827#ifdef LIBXML_XPTR_LOCS_ENABLED
5828 case XPATH_POINT:
5829 case XPATH_RANGE:
5830 case XPATH_LOCATIONSET:
5831#endif /* LIBXML_XPTR_LOCS_ENABLED */
5832 TODO;
5833 break;
5834 }
5835 xmlXPathFreeObject(val);
5836 if (res == NULL)
5837 return(xmlXPathNewCString(""));
5838 return(xmlXPathWrapString(res));
5839}
5840
5849double
5850xmlXPathCastBooleanToNumber(int val) {
5851 if (val)
5852 return(1.0);
5853 return(0.0);
5854}
5855
5864double
5865xmlXPathCastStringToNumber(const xmlChar * val) {
5867}
5868
5877double
5878xmlXPathCastNodeToNumber (xmlNodePtr node) {
5879 xmlChar *strval;
5880 double ret;
5881
5882 if (node == NULL)
5883 return(xmlXPathNAN);
5884 strval = xmlXPathCastNodeToString(node);
5885 if (strval == NULL)
5886 return(xmlXPathNAN);
5887 ret = xmlXPathCastStringToNumber(strval);
5888 xmlFree(strval);
5889
5890 return(ret);
5891}
5892
5901double
5902xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5903 xmlChar *str;
5904 double ret;
5905
5906 if (ns == NULL)
5907 return(xmlXPathNAN);
5908 str = xmlXPathCastNodeSetToString(ns);
5909 ret = xmlXPathCastStringToNumber(str);
5910 xmlFree(str);
5911 return(ret);
5912}
5913
5922double
5923xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5924 double ret = 0.0;
5925
5926 if (val == NULL)
5927 return(xmlXPathNAN);
5928 switch (val->type) {
5929 case XPATH_UNDEFINED:
5930#ifdef DEBUG_EXPR
5931 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5932#endif
5933 ret = xmlXPathNAN;
5934 break;
5935 case XPATH_NODESET:
5936 case XPATH_XSLT_TREE:
5937 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5938 break;
5939 case XPATH_STRING:
5940 ret = xmlXPathCastStringToNumber(val->stringval);
5941 break;
5942 case XPATH_NUMBER:
5943 ret = val->floatval;
5944 break;
5945 case XPATH_BOOLEAN:
5946 ret = xmlXPathCastBooleanToNumber(val->boolval);
5947 break;
5948 case XPATH_USERS:
5949#ifdef LIBXML_XPTR_LOCS_ENABLED
5950 case XPATH_POINT:
5951 case XPATH_RANGE:
5952 case XPATH_LOCATIONSET:
5953#endif /* LIBXML_XPTR_LOCS_ENABLED */
5954 TODO;
5955 ret = xmlXPathNAN;
5956 break;
5957 }
5958 return(ret);
5959}
5960
5970xmlXPathObjectPtr
5971xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5972 xmlXPathObjectPtr ret;
5973
5974 if (val == NULL)
5975 return(xmlXPathNewFloat(0.0));
5976 if (val->type == XPATH_NUMBER)
5977 return(val);
5978 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5979 xmlXPathFreeObject(val);
5980 return(ret);
5981}
5982
5991int
5992xmlXPathCastNumberToBoolean (double val) {
5993 if (xmlXPathIsNaN(val) || (val == 0.0))
5994 return(0);
5995 return(1);
5996}
5997
6006int
6007xmlXPathCastStringToBoolean (const xmlChar *val) {
6008 if ((val == NULL) || (xmlStrlen(val) == 0))
6009 return(0);
6010 return(1);
6011}
6012
6021int
6022xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6023 if ((ns == NULL) || (ns->nodeNr == 0))
6024 return(0);
6025 return(1);
6026}
6027
6036int
6037xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6038 int ret = 0;
6039
6040 if (val == NULL)
6041 return(0);
6042 switch (val->type) {
6043 case XPATH_UNDEFINED:
6044#ifdef DEBUG_EXPR
6045 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6046#endif
6047 ret = 0;
6048 break;
6049 case XPATH_NODESET:
6050 case XPATH_XSLT_TREE:
6051 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6052 break;
6053 case XPATH_STRING:
6054 ret = xmlXPathCastStringToBoolean(val->stringval);
6055 break;
6056 case XPATH_NUMBER:
6057 ret = xmlXPathCastNumberToBoolean(val->floatval);
6058 break;
6059 case XPATH_BOOLEAN:
6060 ret = val->boolval;
6061 break;
6062 case XPATH_USERS:
6063#ifdef LIBXML_XPTR_LOCS_ENABLED
6064 case XPATH_POINT:
6065 case XPATH_RANGE:
6066 case XPATH_LOCATIONSET:
6067#endif /* LIBXML_XPTR_LOCS_ENABLED */
6068 TODO;
6069 ret = 0;
6070 break;
6071 }
6072 return(ret);
6073}
6074
6075
6085xmlXPathObjectPtr
6086xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6087 xmlXPathObjectPtr ret;
6088
6089 if (val == NULL)
6090 return(xmlXPathNewBoolean(0));
6091 if (val->type == XPATH_BOOLEAN)
6092 return(val);
6093 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6094 xmlXPathFreeObject(val);
6095 return(ret);
6096}
6097
6098/************************************************************************
6099 * *
6100 * Routines to handle XPath contexts *
6101 * *
6102 ************************************************************************/
6103
6112xmlXPathContextPtr
6113xmlXPathNewContext(xmlDocPtr doc) {
6114 xmlXPathContextPtr ret;
6115
6116 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6117 if (ret == NULL) {
6118 xmlXPathErrMemory(NULL, "creating context\n");
6119 return(NULL);
6120 }
6121 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6122 ret->doc = doc;
6123 ret->node = NULL;
6124
6125 ret->varHash = NULL;
6126
6127 ret->nb_types = 0;
6128 ret->max_types = 0;
6129 ret->types = NULL;
6130
6131 ret->funcHash = xmlHashCreate(0);
6132
6133 ret->nb_axis = 0;
6134 ret->max_axis = 0;
6135 ret->axis = NULL;
6136
6137 ret->nsHash = NULL;
6138 ret->user = NULL;
6139
6140 ret->contextSize = -1;
6141 ret->proximityPosition = -1;
6142
6143#ifdef XP_DEFAULT_CACHE_ON
6144 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6145 xmlXPathFreeContext(ret);
6146 return(NULL);
6147 }
6148#endif
6149
6150 xmlXPathRegisterAllFunctions(ret);
6151
6152 return(ret);
6153}
6154
6161void
6162xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6163 if (ctxt == NULL) return;
6164
6165 if (ctxt->cache != NULL)
6166 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6167 xmlXPathRegisteredNsCleanup(ctxt);
6168 xmlXPathRegisteredFuncsCleanup(ctxt);
6169 xmlXPathRegisteredVariablesCleanup(ctxt);
6170 xmlResetError(&ctxt->lastError);
6171 xmlFree(ctxt);
6172}
6173
6174/************************************************************************
6175 * *
6176 * Routines to handle XPath parser contexts *
6177 * *
6178 ************************************************************************/
6179
6180#define CHECK_CTXT(ctxt) \
6181 if (ctxt == NULL) { \
6182 __xmlRaiseError(NULL, NULL, NULL, \
6183 NULL, NULL, XML_FROM_XPATH, \
6184 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6185 __FILE__, __LINE__, \
6186 NULL, NULL, NULL, 0, 0, \
6187 "NULL context pointer\n"); \
6188 return(NULL); \
6189 } \
6190
6191#define CHECK_CTXT_NEG(ctxt) \
6192 if (ctxt == NULL) { \
6193 __xmlRaiseError(NULL, NULL, NULL, \
6194 NULL, NULL, XML_FROM_XPATH, \
6195 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6196 __FILE__, __LINE__, \
6197 NULL, NULL, NULL, 0, 0, \
6198 "NULL context pointer\n"); \
6199 return(-1); \
6200 } \
6201
6202
6203#define CHECK_CONTEXT(ctxt) \
6204 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6205 (ctxt->doc->children == NULL)) { \
6206 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6207 return(NULL); \
6208 }
6209
6210
6220xmlXPathParserContextPtr
6221xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6222 xmlXPathParserContextPtr ret;
6223
6224 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6225 if (ret == NULL) {
6226 xmlXPathErrMemory(ctxt, "creating parser context\n");
6227 return(NULL);
6228 }
6229 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6230 ret->cur = ret->base = str;
6231 ret->context = ctxt;
6232
6233 ret->comp = xmlXPathNewCompExpr();
6234 if (ret->comp == NULL) {
6235 xmlFree(ret->valueTab);
6236 xmlFree(ret);
6237 return(NULL);
6238 }
6239 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6240 ret->comp->dict = ctxt->dict;
6241 xmlDictReference(ret->comp->dict);
6242 }
6243
6244 return(ret);
6245}
6246
6256static xmlXPathParserContextPtr
6257xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6258 xmlXPathParserContextPtr ret;
6259
6260 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6261 if (ret == NULL) {
6262 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6263 return(NULL);
6264 }
6265 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6266
6267 /* Allocate the value stack */
6268 ret->valueTab = (xmlXPathObjectPtr *)
6269 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6270 if (ret->valueTab == NULL) {
6271 xmlFree(ret);
6272 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6273 return(NULL);
6274 }
6275 ret->valueNr = 0;
6276 ret->valueMax = 10;
6277 ret->value = NULL;
6278 ret->valueFrame = 0;
6279
6280 ret->context = ctxt;
6281 ret->comp = comp;
6282
6283 return(ret);
6284}
6285
6292void
6293xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6294 int i;
6295
6296 if (ctxt->valueTab != NULL) {
6297 for (i = 0; i < ctxt->valueNr; i++) {
6298 if (ctxt->context)
6299 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6300 else
6301 xmlXPathFreeObject(ctxt->valueTab[i]);
6302 }
6303 xmlFree(ctxt->valueTab);
6304 }
6305 if (ctxt->comp != NULL) {
6306#ifdef XPATH_STREAMING
6307 if (ctxt->comp->stream != NULL) {
6308 xmlFreePatternList(ctxt->comp->stream);
6309 ctxt->comp->stream = NULL;
6310 }
6311#endif
6312 xmlXPathFreeCompExpr(ctxt->comp);
6313 }
6314 xmlFree(ctxt);
6315}
6316
6317/************************************************************************
6318 * *
6319 * The implicit core function library *
6320 * *
6321 ************************************************************************/
6322
6332static unsigned int
6333xmlXPathNodeValHash(xmlNodePtr node) {
6334 int len = 2;
6335 const xmlChar * string = NULL;
6336 xmlNodePtr tmp = NULL;
6337 unsigned int ret = 0;
6338
6339 if (node == NULL)
6340 return(0);
6341
6342 if (node->type == XML_DOCUMENT_NODE) {
6344 if (tmp == NULL)
6345 node = node->children;
6346 else
6347 node = tmp;
6348
6349 if (node == NULL)
6350 return(0);
6351 }
6352
6353 switch (node->type) {
6354 case XML_COMMENT_NODE:
6355 case XML_PI_NODE:
6357 case XML_TEXT_NODE:
6358 string = node->content;
6359 if (string == NULL)
6360 return(0);
6361 if (string[0] == 0)
6362 return(0);
6363 return(((unsigned int) string[0]) +
6364 (((unsigned int) string[1]) << 8));
6365 case XML_NAMESPACE_DECL:
6366 string = ((xmlNsPtr)node)->href;
6367 if (string == NULL)
6368 return(0);
6369 if (string[0] == 0)
6370 return(0);
6371 return(((unsigned int) string[0]) +
6372 (((unsigned int) string[1]) << 8));
6373 case XML_ATTRIBUTE_NODE:
6374 tmp = ((xmlAttrPtr) node)->children;
6375 break;
6376 case XML_ELEMENT_NODE:
6377 tmp = node->children;
6378 break;
6379 default:
6380 return(0);
6381 }
6382 while (tmp != NULL) {
6383 switch (tmp->type) {
6385 case XML_TEXT_NODE:
6386 string = tmp->content;
6387 break;
6388 default:
6389 string = NULL;
6390 break;
6391 }
6392 if ((string != NULL) && (string[0] != 0)) {
6393 if (len == 1) {
6394 return(ret + (((unsigned int) string[0]) << 8));
6395 }
6396 if (string[1] == 0) {
6397 len = 1;
6398 ret = (unsigned int) string[0];
6399 } else {
6400 return(((unsigned int) string[0]) +
6401 (((unsigned int) string[1]) << 8));
6402 }
6403 }
6404 /*
6405 * Skip to next node
6406 */
6407 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6408 if (tmp->children->type != XML_ENTITY_DECL) {
6409 tmp = tmp->children;
6410 continue;
6411 }
6412 }
6413 if (tmp == node)
6414 break;
6415
6416 if (tmp->next != NULL) {
6417 tmp = tmp->next;
6418 continue;
6419 }
6420
6421 do {
6422 tmp = tmp->parent;
6423 if (tmp == NULL)
6424 break;
6425 if (tmp == node) {
6426 tmp = NULL;
6427 break;
6428 }
6429 if (tmp->next != NULL) {
6430 tmp = tmp->next;
6431 break;
6432 }
6433 } while (tmp != NULL);
6434 }
6435 return(ret);
6436}
6437
6447static unsigned int
6448xmlXPathStringHash(const xmlChar * string) {
6449 if (string == NULL)
6450 return((unsigned int) 0);
6451 if (string[0] == 0)
6452 return(0);
6453 return(((unsigned int) string[0]) +
6454 (((unsigned int) string[1]) << 8));
6455}
6456
6479static int
6480xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6481 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6482 int i, ret = 0;
6483 xmlNodeSetPtr ns;
6484 xmlChar *str2;
6485
6486 if ((f == NULL) || (arg == NULL) ||
6487 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6488 xmlXPathReleaseObject(ctxt->context, arg);
6489 xmlXPathReleaseObject(ctxt->context, f);
6490 return(0);
6491 }
6492 ns = arg->nodesetval;
6493 if (ns != NULL) {
6494 for (i = 0;i < ns->nodeNr;i++) {
6495 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6496 if (str2 != NULL) {
6497 valuePush(ctxt,
6498 xmlXPathCacheNewString(ctxt->context, str2));
6499 xmlFree(str2);
6500 xmlXPathNumberFunction(ctxt, 1);
6501 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6502 ret = xmlXPathCompareValues(ctxt, inf, strict);
6503 if (ret)
6504 break;
6505 }
6506 }
6507 }
6508 xmlXPathReleaseObject(ctxt->context, arg);
6509 xmlXPathReleaseObject(ctxt->context, f);
6510 return(ret);
6511}
6512
6534static int
6535xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6536 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6537 int i, ret = 0;
6538 xmlNodeSetPtr ns;
6539 xmlChar *str2;
6540
6541 if ((s == NULL) || (arg == NULL) ||
6542 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6543 xmlXPathReleaseObject(ctxt->context, arg);
6544 xmlXPathReleaseObject(ctxt->context, s);
6545 return(0);
6546 }
6547 ns = arg->nodesetval;
6548 if (ns != NULL) {
6549 for (i = 0;i < ns->nodeNr;i++) {
6550 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6551 if (str2 != NULL) {
6552 valuePush(ctxt,
6553 xmlXPathCacheNewString(ctxt->context, str2));
6554 xmlFree(str2);
6555 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6556 ret = xmlXPathCompareValues(ctxt, inf, strict);
6557 if (ret)
6558 break;
6559 }
6560 }
6561 }
6562 xmlXPathReleaseObject(ctxt->context, arg);
6563 xmlXPathReleaseObject(ctxt->context, s);
6564 return(ret);
6565}
6566
6595static int
6596xmlXPathCompareNodeSets(int inf, int strict,
6597 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6598 int i, j, init = 0;
6599 double val1;
6600 double *values2;
6601 int ret = 0;
6602 xmlNodeSetPtr ns1;
6603 xmlNodeSetPtr ns2;
6604
6605 if ((arg1 == NULL) ||
6606 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6607 xmlXPathFreeObject(arg2);
6608 return(0);
6609 }
6610 if ((arg2 == NULL) ||
6611 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6612 xmlXPathFreeObject(arg1);
6613 xmlXPathFreeObject(arg2);
6614 return(0);
6615 }
6616
6617 ns1 = arg1->nodesetval;
6618 ns2 = arg2->nodesetval;
6619
6620 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6621 xmlXPathFreeObject(arg1);
6622 xmlXPathFreeObject(arg2);
6623 return(0);
6624 }
6625 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6626 xmlXPathFreeObject(arg1);
6627 xmlXPathFreeObject(arg2);
6628 return(0);
6629 }
6630
6631 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6632 if (values2 == NULL) {
6633 /* TODO: Propagate memory error. */
6634 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6635 xmlXPathFreeObject(arg1);
6636 xmlXPathFreeObject(arg2);
6637 return(0);
6638 }
6639 for (i = 0;i < ns1->nodeNr;i++) {
6640 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6641 if (xmlXPathIsNaN(val1))
6642 continue;
6643 for (j = 0;j < ns2->nodeNr;j++) {
6644 if (init == 0) {
6645 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6646 }
6647 if (xmlXPathIsNaN(values2[j]))
6648 continue;
6649 if (inf && strict)
6650 ret = (val1 < values2[j]);
6651 else if (inf && !strict)
6652 ret = (val1 <= values2[j]);
6653 else if (!inf && strict)
6654 ret = (val1 > values2[j]);
6655 else if (!inf && !strict)
6656 ret = (val1 >= values2[j]);
6657 if (ret)
6658 break;
6659 }
6660 if (ret)
6661 break;
6662 init = 1;
6663 }
6664 xmlFree(values2);
6665 xmlXPathFreeObject(arg1);
6666 xmlXPathFreeObject(arg2);
6667 return(ret);
6668}
6669
6691static int
6692xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6693 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6694 if ((val == NULL) || (arg == NULL) ||
6695 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6696 return(0);
6697
6698 switch(val->type) {
6699 case XPATH_NUMBER:
6700 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6701 case XPATH_NODESET:
6702 case XPATH_XSLT_TREE:
6703 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6704 case XPATH_STRING:
6705 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6706 case XPATH_BOOLEAN:
6707 valuePush(ctxt, arg);
6708 xmlXPathBooleanFunction(ctxt, 1);
6709 valuePush(ctxt, val);
6710 return(xmlXPathCompareValues(ctxt, inf, strict));
6711 default:
6713 "xmlXPathCompareNodeSetValue: Can't compare node set "
6714 "and object of type %d\n",
6715 val->type);
6716 xmlXPathReleaseObject(ctxt->context, arg);
6717 xmlXPathReleaseObject(ctxt->context, val);
6718 XP_ERROR0(XPATH_INVALID_TYPE);
6719 }
6720 return(0);
6721}
6722
6737static int
6738xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6739{
6740 int i;
6741 xmlNodeSetPtr ns;
6742 xmlChar *str2;
6743 unsigned int hash;
6744
6745 if ((str == NULL) || (arg == NULL) ||
6746 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6747 return (0);
6748 ns = arg->nodesetval;
6749 /*
6750 * A NULL nodeset compared with a string is always false
6751 * (since there is no node equal, and no node not equal)
6752 */
6753 if ((ns == NULL) || (ns->nodeNr <= 0) )
6754 return (0);
6755 hash = xmlXPathStringHash(str);
6756 for (i = 0; i < ns->nodeNr; i++) {
6757 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6758 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6759 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6760 xmlFree(str2);
6761 if (neq)
6762 continue;
6763 return (1);
6764 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6765 if (neq)
6766 continue;
6767 return (1);
6768 } else if (neq) {
6769 if (str2 != NULL)
6770 xmlFree(str2);
6771 return (1);
6772 }
6773 if (str2 != NULL)
6774 xmlFree(str2);
6775 } else if (neq)
6776 return (1);
6777 }
6778 return (0);
6779}
6780
6796static int
6797xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6798 xmlXPathObjectPtr arg, double f, int neq) {
6799 int i, ret=0;
6800 xmlNodeSetPtr ns;
6801 xmlChar *str2;
6802 xmlXPathObjectPtr val;
6803 double v;
6804
6805 if ((arg == NULL) ||
6806 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6807 return(0);
6808
6809 ns = arg->nodesetval;
6810 if (ns != NULL) {
6811 for (i=0;i<ns->nodeNr;i++) {
6812 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6813 if (str2 != NULL) {
6814 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6815 xmlFree(str2);
6816 xmlXPathNumberFunction(ctxt, 1);
6817 val = valuePop(ctxt);
6818 v = val->floatval;
6819 xmlXPathReleaseObject(ctxt->context, val);
6820 if (!xmlXPathIsNaN(v)) {
6821 if ((!neq) && (v==f)) {
6822 ret = 1;
6823 break;
6824 } else if ((neq) && (v!=f)) {
6825 ret = 1;
6826 break;
6827 }
6828 } else { /* NaN is unequal to any value */
6829 if (neq)
6830 ret = 1;
6831 }
6832 }
6833 }
6834 }
6835
6836 return(ret);
6837}
6838
6839
6857static int
6858xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6859 int i, j;
6860 unsigned int *hashs1;
6861 unsigned int *hashs2;
6862 xmlChar **values1;
6863 xmlChar **values2;
6864 int ret = 0;
6865 xmlNodeSetPtr ns1;
6866 xmlNodeSetPtr ns2;
6867
6868 if ((arg1 == NULL) ||
6869 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6870 return(0);
6871 if ((arg2 == NULL) ||
6872 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6873 return(0);
6874
6875 ns1 = arg1->nodesetval;
6876 ns2 = arg2->nodesetval;
6877
6878 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6879 return(0);
6880 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6881 return(0);
6882
6883 /*
6884 * for equal, check if there is a node pertaining to both sets
6885 */
6886 if (neq == 0)
6887 for (i = 0;i < ns1->nodeNr;i++)
6888 for (j = 0;j < ns2->nodeNr;j++)
6889 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6890 return(1);
6891
6892 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6893 if (values1 == NULL) {
6894 /* TODO: Propagate memory error. */
6895 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6896 return(0);
6897 }
6898 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6899 if (hashs1 == NULL) {
6900 /* TODO: Propagate memory error. */
6901 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6902 xmlFree(values1);
6903 return(0);
6904 }
6905 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6906 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6907 if (values2 == NULL) {
6908 /* TODO: Propagate memory error. */
6909 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6910 xmlFree(hashs1);
6911 xmlFree(values1);
6912 return(0);
6913 }
6914 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6915 if (hashs2 == NULL) {
6916 /* TODO: Propagate memory error. */
6917 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6918 xmlFree(hashs1);
6919 xmlFree(values1);
6920 xmlFree(values2);
6921 return(0);
6922 }
6923 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6924 for (i = 0;i < ns1->nodeNr;i++) {
6925 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6926 for (j = 0;j < ns2->nodeNr;j++) {
6927 if (i == 0)
6928 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6929 if (hashs1[i] != hashs2[j]) {
6930 if (neq) {
6931 ret = 1;
6932 break;
6933 }
6934 }
6935 else {
6936 if (values1[i] == NULL)
6937 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6938 if (values2[j] == NULL)
6939 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6940 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6941 if (ret)
6942 break;
6943 }
6944 }
6945 if (ret)
6946 break;
6947 }
6948 for (i = 0;i < ns1->nodeNr;i++)
6949 if (values1[i] != NULL)
6950 xmlFree(values1[i]);
6951 for (j = 0;j < ns2->nodeNr;j++)
6952 if (values2[j] != NULL)
6953 xmlFree(values2[j]);
6954 xmlFree(values1);
6955 xmlFree(values2);
6956 xmlFree(hashs1);
6957 xmlFree(hashs2);
6958 return(ret);
6959}
6960
6961static int
6962xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6963 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6964 int ret = 0;
6965 /*
6966 *At this point we are assured neither arg1 nor arg2
6967 *is a nodeset, so we can just pick the appropriate routine.
6968 */
6969 switch (arg1->type) {
6970 case XPATH_UNDEFINED:
6971#ifdef DEBUG_EXPR
6973 "Equal: undefined\n");
6974#endif
6975 break;
6976 case XPATH_BOOLEAN:
6977 switch (arg2->type) {
6978 case XPATH_UNDEFINED:
6979#ifdef DEBUG_EXPR
6981 "Equal: undefined\n");
6982#endif
6983 break;
6984 case XPATH_BOOLEAN:
6985#ifdef DEBUG_EXPR
6987 "Equal: %d boolean %d \n",
6988 arg1->boolval, arg2->boolval);
6989#endif
6990 ret = (arg1->boolval == arg2->boolval);
6991 break;
6992 case XPATH_NUMBER:
6993 ret = (arg1->boolval ==
6994 xmlXPathCastNumberToBoolean(arg2->floatval));
6995 break;
6996 case XPATH_STRING:
6997 if ((arg2->stringval == NULL) ||
6998 (arg2->stringval[0] == 0)) ret = 0;
6999 else
7000 ret = 1;
7001 ret = (arg1->boolval == ret);
7002 break;
7003 case XPATH_USERS:
7004#ifdef LIBXML_XPTR_LOCS_ENABLED
7005 case XPATH_POINT:
7006 case XPATH_RANGE:
7007 case XPATH_LOCATIONSET:
7008#endif /* LIBXML_XPTR_LOCS_ENABLED */
7009 TODO
7010 break;
7011 case XPATH_NODESET:
7012 case XPATH_XSLT_TREE:
7013 break;
7014 }
7015 break;
7016 case XPATH_NUMBER:
7017 switch (arg2->type) {
7018 case XPATH_UNDEFINED:
7019#ifdef DEBUG_EXPR
7021 "Equal: undefined\n");
7022#endif
7023 break;
7024 case XPATH_BOOLEAN:
7025 ret = (arg2->boolval==
7026 xmlXPathCastNumberToBoolean(arg1->floatval));
7027 break;
7028 case XPATH_STRING:
7029 valuePush(ctxt, arg2);
7030 xmlXPathNumberFunction(ctxt, 1);
7031 arg2 = valuePop(ctxt);
7032 /* Falls through. */
7033 case XPATH_NUMBER:
7034 /* Hand check NaN and Infinity equalities */
7035 if (xmlXPathIsNaN(arg1->floatval) ||
7036 xmlXPathIsNaN(arg2->floatval)) {
7037 ret = 0;
7038 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7039 if (xmlXPathIsInf(arg2->floatval) == 1)
7040 ret = 1;
7041 else
7042 ret = 0;
7043 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7044 if (xmlXPathIsInf(arg2->floatval) == -1)
7045 ret = 1;
7046 else
7047 ret = 0;
7048 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7049 if (xmlXPathIsInf(arg1->floatval) == 1)
7050 ret = 1;
7051 else
7052 ret = 0;
7053 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7054 if (xmlXPathIsInf(arg1->floatval) == -1)
7055 ret = 1;
7056 else
7057 ret = 0;
7058 } else {
7059 ret = (arg1->floatval == arg2->floatval);
7060 }
7061 break;
7062 case XPATH_USERS:
7063#ifdef LIBXML_XPTR_LOCS_ENABLED
7064 case XPATH_POINT:
7065 case XPATH_RANGE:
7066 case XPATH_LOCATIONSET:
7067#endif /* LIBXML_XPTR_LOCS_ENABLED */
7068 TODO
7069 break;
7070 case XPATH_NODESET:
7071 case XPATH_XSLT_TREE:
7072 break;
7073 }
7074 break;
7075 case XPATH_STRING:
7076 switch (arg2->type) {
7077 case XPATH_UNDEFINED:
7078#ifdef DEBUG_EXPR
7080 "Equal: undefined\n");
7081#endif
7082 break;
7083 case XPATH_BOOLEAN:
7084 if ((arg1->stringval == NULL) ||
7085 (arg1->stringval[0] == 0)) ret = 0;
7086 else
7087 ret = 1;
7088 ret = (arg2->boolval == ret);
7089 break;
7090 case XPATH_STRING:
7091 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7092 break;
7093 case XPATH_NUMBER:
7094 valuePush(ctxt, arg1);
7095 xmlXPathNumberFunction(ctxt, 1);
7096 arg1 = valuePop(ctxt);
7097 /* Hand check NaN and Infinity equalities */
7098 if (xmlXPathIsNaN(arg1->floatval) ||
7099 xmlXPathIsNaN(arg2->floatval)) {
7100 ret = 0;
7101 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7102 if (xmlXPathIsInf(arg2->floatval) == 1)
7103 ret = 1;
7104 else
7105 ret = 0;
7106 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7107 if (xmlXPathIsInf(arg2->floatval) == -1)
7108 ret = 1;
7109 else
7110 ret = 0;
7111 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7112 if (xmlXPathIsInf(arg1->floatval) == 1)
7113 ret = 1;
7114 else
7115 ret = 0;
7116 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7117 if (xmlXPathIsInf(arg1->floatval) == -1)
7118 ret = 1;
7119 else
7120 ret = 0;
7121 } else {
7122 ret = (arg1->floatval == arg2->floatval);
7123 }
7124 break;
7125 case XPATH_USERS:
7126#ifdef LIBXML_XPTR_LOCS_ENABLED
7127 case XPATH_POINT:
7128 case XPATH_RANGE:
7129 case XPATH_LOCATIONSET:
7130#endif /* LIBXML_XPTR_LOCS_ENABLED */
7131 TODO
7132 break;
7133 case XPATH_NODESET:
7134 case XPATH_XSLT_TREE:
7135 break;
7136 }
7137 break;
7138 case XPATH_USERS:
7139#ifdef LIBXML_XPTR_LOCS_ENABLED
7140 case XPATH_POINT:
7141 case XPATH_RANGE:
7142 case XPATH_LOCATIONSET:
7143#endif /* LIBXML_XPTR_LOCS_ENABLED */
7144 TODO
7145 break;
7146 case XPATH_NODESET:
7147 case XPATH_XSLT_TREE:
7148 break;
7149 }
7150 xmlXPathReleaseObject(ctxt->context, arg1);
7151 xmlXPathReleaseObject(ctxt->context, arg2);
7152 return(ret);
7153}
7154
7163int
7164xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7165 xmlXPathObjectPtr arg1, arg2, argtmp;
7166 int ret = 0;
7167
7168 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7169 arg2 = valuePop(ctxt);
7170 arg1 = valuePop(ctxt);
7171 if ((arg1 == NULL) || (arg2 == NULL)) {
7172 if (arg1 != NULL)
7173 xmlXPathReleaseObject(ctxt->context, arg1);
7174 else
7175 xmlXPathReleaseObject(ctxt->context, arg2);
7176 XP_ERROR0(XPATH_INVALID_OPERAND);
7177 }
7178
7179 if (arg1 == arg2) {
7180#ifdef DEBUG_EXPR
7182 "Equal: by pointer\n");
7183#endif
7184 xmlXPathFreeObject(arg1);
7185 return(1);
7186 }
7187
7188 /*
7189 *If either argument is a nodeset, it's a 'special case'
7190 */
7191 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7192 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7193 /*
7194 *Hack it to assure arg1 is the nodeset
7195 */
7196 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7197 argtmp = arg2;
7198 arg2 = arg1;
7199 arg1 = argtmp;
7200 }
7201 switch (arg2->type) {
7202 case XPATH_UNDEFINED:
7203#ifdef DEBUG_EXPR
7205 "Equal: undefined\n");
7206#endif
7207 break;
7208 case XPATH_NODESET:
7209 case XPATH_XSLT_TREE:
7210 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7211 break;
7212 case XPATH_BOOLEAN:
7213 if ((arg1->nodesetval == NULL) ||
7214 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7215 else
7216 ret = 1;
7217 ret = (ret == arg2->boolval);
7218 break;
7219 case XPATH_NUMBER:
7220 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7221 break;
7222 case XPATH_STRING:
7223 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7224 break;
7225 case XPATH_USERS:
7226#ifdef LIBXML_XPTR_LOCS_ENABLED
7227 case XPATH_POINT:
7228 case XPATH_RANGE:
7229 case XPATH_LOCATIONSET:
7230#endif /* LIBXML_XPTR_LOCS_ENABLED */
7231 TODO
7232 break;
7233 }
7234 xmlXPathReleaseObject(ctxt->context, arg1);
7235 xmlXPathReleaseObject(ctxt->context, arg2);
7236 return(ret);
7237 }
7238
7239 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7240}
7241
7250int
7251xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7252 xmlXPathObjectPtr arg1, arg2, argtmp;
7253 int ret = 0;
7254
7255 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7256 arg2 = valuePop(ctxt);
7257 arg1 = valuePop(ctxt);
7258 if ((arg1 == NULL) || (arg2 == NULL)) {
7259 if (arg1 != NULL)
7260 xmlXPathReleaseObject(ctxt->context, arg1);
7261 else
7262 xmlXPathReleaseObject(ctxt->context, arg2);
7263 XP_ERROR0(XPATH_INVALID_OPERAND);
7264 }
7265
7266 if (arg1 == arg2) {
7267#ifdef DEBUG_EXPR
7269 "NotEqual: by pointer\n");
7270#endif
7271 xmlXPathReleaseObject(ctxt->context, arg1);
7272 return(0);
7273 }
7274
7275 /*
7276 *If either argument is a nodeset, it's a 'special case'
7277 */
7278 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7279 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7280 /*
7281 *Hack it to assure arg1 is the nodeset
7282 */
7283 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7284 argtmp = arg2;
7285 arg2 = arg1;
7286 arg1 = argtmp;
7287 }
7288 switch (arg2->type) {
7289 case XPATH_UNDEFINED:
7290#ifdef DEBUG_EXPR
7292 "NotEqual: undefined\n");
7293#endif
7294 break;
7295 case XPATH_NODESET:
7296 case XPATH_XSLT_TREE:
7297 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7298 break;
7299 case XPATH_BOOLEAN:
7300 if ((arg1->nodesetval == NULL) ||
7301 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7302 else
7303 ret = 1;
7304 ret = (ret != arg2->boolval);
7305 break;
7306 case XPATH_NUMBER:
7307 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7308 break;
7309 case XPATH_STRING:
7310 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7311 break;
7312 case XPATH_USERS:
7313#ifdef LIBXML_XPTR_LOCS_ENABLED
7314 case XPATH_POINT:
7315 case XPATH_RANGE:
7316 case XPATH_LOCATIONSET:
7317#endif /* LIBXML_XPTR_LOCS_ENABLED */
7318 TODO
7319 break;
7320 }
7321 xmlXPathReleaseObject(ctxt->context, arg1);
7322 xmlXPathReleaseObject(ctxt->context, arg2);
7323 return(ret);
7324 }
7325
7326 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7327}
7328
7353int
7354xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7355 int ret = 0, arg1i = 0, arg2i = 0;
7356 xmlXPathObjectPtr arg1, arg2;
7357
7358 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7359 arg2 = valuePop(ctxt);
7360 arg1 = valuePop(ctxt);
7361 if ((arg1 == NULL) || (arg2 == NULL)) {
7362 if (arg1 != NULL)
7363 xmlXPathReleaseObject(ctxt->context, arg1);
7364 else
7365 xmlXPathReleaseObject(ctxt->context, arg2);
7366 XP_ERROR0(XPATH_INVALID_OPERAND);
7367 }
7368
7369 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7370 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7371 /*
7372 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7373 * are not freed from within this routine; they will be freed from the
7374 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7375 */
7376 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7377 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7378 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7379 } else {
7380 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7381 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7382 arg1, arg2);
7383 } else {
7384 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7385 arg2, arg1);
7386 }
7387 }
7388 return(ret);
7389 }
7390
7391 if (arg1->type != XPATH_NUMBER) {
7392 valuePush(ctxt, arg1);
7393 xmlXPathNumberFunction(ctxt, 1);
7394 arg1 = valuePop(ctxt);
7395 }
7396 if (arg1->type != XPATH_NUMBER) {
7397 xmlXPathFreeObject(arg1);
7398 xmlXPathFreeObject(arg2);
7399 XP_ERROR0(XPATH_INVALID_OPERAND);
7400 }
7401 if (arg2->type != XPATH_NUMBER) {
7402 valuePush(ctxt, arg2);
7403 xmlXPathNumberFunction(ctxt, 1);
7404 arg2 = valuePop(ctxt);
7405 }
7406 if (arg2->type != XPATH_NUMBER) {
7407 xmlXPathReleaseObject(ctxt->context, arg1);
7408 xmlXPathReleaseObject(ctxt->context, arg2);
7409 XP_ERROR0(XPATH_INVALID_OPERAND);
7410 }
7411 /*
7412 * Add tests for infinity and nan
7413 * => feedback on 3.4 for Inf and NaN
7414 */
7415 /* Hand check NaN and Infinity comparisons */
7416 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7417 ret=0;
7418 } else {
7419 arg1i=xmlXPathIsInf(arg1->floatval);
7420 arg2i=xmlXPathIsInf(arg2->floatval);
7421 if (inf && strict) {
7422 if ((arg1i == -1 && arg2i != -1) ||
7423 (arg2i == 1 && arg1i != 1)) {
7424 ret = 1;
7425 } else if (arg1i == 0 && arg2i == 0) {
7426 ret = (arg1->floatval < arg2->floatval);
7427 } else {
7428 ret = 0;
7429 }
7430 }
7431 else if (inf && !strict) {
7432 if (arg1i == -1 || arg2i == 1) {
7433 ret = 1;
7434 } else if (arg1i == 0 && arg2i == 0) {
7435 ret = (arg1->floatval <= arg2->floatval);
7436 } else {
7437 ret = 0;
7438 }
7439 }
7440 else if (!inf && strict) {
7441 if ((arg1i == 1 && arg2i != 1) ||
7442 (arg2i == -1 && arg1i != -1)) {
7443 ret = 1;
7444 } else if (arg1i == 0 && arg2i == 0) {
7445 ret = (arg1->floatval > arg2->floatval);
7446 } else {
7447 ret = 0;
7448 }
7449 }
7450 else if (!inf && !strict) {
7451 if (arg1i == 1 || arg2i == -1) {
7452 ret = 1;
7453 } else if (arg1i == 0 && arg2i == 0) {
7454 ret = (arg1->floatval >= arg2->floatval);
7455 } else {
7456 ret = 0;
7457 }
7458 }
7459 }
7460 xmlXPathReleaseObject(ctxt->context, arg1);
7461 xmlXPathReleaseObject(ctxt->context, arg2);
7462 return(ret);
7463}
7464
7473void
7474xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7475 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7476 CAST_TO_NUMBER;
7477 CHECK_TYPE(XPATH_NUMBER);
7478 ctxt->value->floatval = -ctxt->value->floatval;
7479}
7480
7489void
7490xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7491 xmlXPathObjectPtr arg;
7492 double val;
7493
7494 arg = valuePop(ctxt);
7495 if (arg == NULL)
7496 XP_ERROR(XPATH_INVALID_OPERAND);
7497 val = xmlXPathCastToNumber(arg);
7498 xmlXPathReleaseObject(ctxt->context, arg);
7499 CAST_TO_NUMBER;
7500 CHECK_TYPE(XPATH_NUMBER);
7501 ctxt->value->floatval += val;
7502}
7503
7512void
7513xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7514 xmlXPathObjectPtr arg;
7515 double val;
7516
7517 arg = valuePop(ctxt);
7518 if (arg == NULL)
7519 XP_ERROR(XPATH_INVALID_OPERAND);
7520 val = xmlXPathCastToNumber(arg);
7521 xmlXPathReleaseObject(ctxt->context, arg);
7522 CAST_TO_NUMBER;
7523 CHECK_TYPE(XPATH_NUMBER);
7524 ctxt->value->floatval -= val;
7525}
7526
7535void
7536xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7537 xmlXPathObjectPtr arg;
7538 double val;
7539
7540 arg = valuePop(ctxt);
7541 if (arg == NULL)
7542 XP_ERROR(XPATH_INVALID_OPERAND);
7543 val = xmlXPathCastToNumber(arg);
7544 xmlXPathReleaseObject(ctxt->context, arg);
7545 CAST_TO_NUMBER;
7546 CHECK_TYPE(XPATH_NUMBER);
7547 ctxt->value->floatval *= val;
7548}
7549
7558ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
7559void
7560xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7561 xmlXPathObjectPtr arg;
7562 double val;
7563
7564 arg = valuePop(ctxt);
7565 if (arg == NULL)
7566 XP_ERROR(XPATH_INVALID_OPERAND);
7567 val = xmlXPathCastToNumber(arg);
7568 xmlXPathReleaseObject(ctxt->context, arg);
7569 CAST_TO_NUMBER;
7570 CHECK_TYPE(XPATH_NUMBER);
7571 ctxt->value->floatval /= val;
7572}
7573
7582void
7583xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7584 xmlXPathObjectPtr arg;
7585 double arg1, arg2;
7586
7587 arg = valuePop(ctxt);
7588 if (arg == NULL)
7589 XP_ERROR(XPATH_INVALID_OPERAND);
7590 arg2 = xmlXPathCastToNumber(arg);
7591 xmlXPathReleaseObject(ctxt->context, arg);
7592 CAST_TO_NUMBER;
7593 CHECK_TYPE(XPATH_NUMBER);
7594 arg1 = ctxt->value->floatval;
7595 if (arg2 == 0)
7596 ctxt->value->floatval = xmlXPathNAN;
7597 else {
7598 ctxt->value->floatval = fmod(arg1, arg2);
7599 }
7600}
7601
7602/************************************************************************
7603 * *
7604 * The traversal functions *
7605 * *
7606 ************************************************************************/
7607
7608/*
7609 * A traversal function enumerates nodes along an axis.
7610 * Initially it must be called with NULL, and it indicates
7611 * termination on the axis by returning NULL.
7612 */
7613typedef xmlNodePtr (*xmlXPathTraversalFunction)
7614 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7615
7616/*
7617 * xmlXPathTraversalFunctionExt:
7618 * A traversal function enumerates nodes along an axis.
7619 * Initially it must be called with NULL, and it indicates
7620 * termination on the axis by returning NULL.
7621 * The context node of the traversal is specified via @contextNode.
7622 */
7623typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7624 (xmlNodePtr cur, xmlNodePtr contextNode);
7625
7626/*
7627 * xmlXPathNodeSetMergeFunction:
7628 * Used for merging node sets in xmlXPathCollectAndTest().
7629 */
7630typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7631 (xmlNodeSetPtr, xmlNodeSetPtr);
7632
7633
7645xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7646 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7647 if (cur == NULL)
7648 return(ctxt->context->node);
7649 return(NULL);
7650}
7651
7663xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7664 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7665 if (cur == NULL) {
7666 if (ctxt->context->node == NULL) return(NULL);
7667 switch (ctxt->context->node->type) {
7668 case XML_ELEMENT_NODE:
7669 case XML_TEXT_NODE:
7672 case XML_ENTITY_NODE:
7673 case XML_PI_NODE:
7674 case XML_COMMENT_NODE:
7675 case XML_NOTATION_NODE:
7676 case XML_DTD_NODE:
7677 return(ctxt->context->node->children);
7678 case XML_DOCUMENT_NODE:
7682 return(((xmlDocPtr) ctxt->context->node)->children);
7683 case XML_ELEMENT_DECL:
7684 case XML_ATTRIBUTE_DECL:
7685 case XML_ENTITY_DECL:
7686 case XML_ATTRIBUTE_NODE:
7687 case XML_NAMESPACE_DECL:
7688 case XML_XINCLUDE_START:
7689 case XML_XINCLUDE_END:
7690 return(NULL);
7691 }
7692 return(NULL);
7693 }
7694 if ((cur->type == XML_DOCUMENT_NODE) ||
7695 (cur->type == XML_HTML_DOCUMENT_NODE))
7696 return(NULL);
7697 return(cur->next);
7698}
7699
7710static xmlNodePtr
7711xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7712 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7713 if (cur == NULL) {
7714 cur = ctxt->context->node;
7715 if (cur == NULL) return(NULL);
7716 /*
7717 * Get the first element child.
7718 */
7719 switch (cur->type) {
7720 case XML_ELEMENT_NODE:
7722 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7723 case XML_ENTITY_NODE:
7724 cur = cur->children;
7725 if (cur != NULL) {
7726 if (cur->type == XML_ELEMENT_NODE)
7727 return(cur);
7728 do {
7729 cur = cur->next;
7730 } while ((cur != NULL) &&
7731 (cur->type != XML_ELEMENT_NODE));
7732 return(cur);
7733 }
7734 return(NULL);
7735 case XML_DOCUMENT_NODE:
7738 default:
7739 return(NULL);
7740 }
7741 return(NULL);
7742 }
7743 /*
7744 * Get the next sibling element node.
7745 */
7746 switch (cur->type) {
7747 case XML_ELEMENT_NODE:
7748 case XML_TEXT_NODE:
7750 case XML_ENTITY_NODE:
7752 case XML_PI_NODE:
7753 case XML_COMMENT_NODE:
7754 case XML_XINCLUDE_END:
7755 break;
7756 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7757 default:
7758 return(NULL);
7759 }
7760 if (cur->next != NULL) {
7761 if (cur->next->type == XML_ELEMENT_NODE)
7762 return(cur->next);
7763 cur = cur->next;
7764 do {
7765 cur = cur->next;
7766 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7767 return(cur);
7768 }
7769 return(NULL);
7770}
7771
7772#if 0
7785static xmlNodePtr
7786xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7787 xmlNodePtr contextNode)
7788{
7789 if (cur == NULL) {
7790 if (contextNode == NULL)
7791 return(NULL);
7792 switch (contextNode->type) {
7793 case XML_ELEMENT_NODE:
7794 case XML_XINCLUDE_START:
7796 case XML_DOCUMENT_NODE:
7798 return(contextNode);
7799 default:
7800 return(NULL);
7801 }
7802 return(NULL);
7803 } else {
7805
7806 while (cur != NULL) {
7807 switch (cur->type) {
7808 case XML_ELEMENT_NODE:
7809 /* TODO: OK to have XInclude here? */
7810 case XML_XINCLUDE_START:
7812 if (cur != start)
7813 return(cur);
7814 if (cur->children != NULL) {
7815 cur = cur->children;
7816 continue;
7817 }
7818 break;
7819 /* Not sure if we need those here. */
7820 case XML_DOCUMENT_NODE:
7822 if (cur != start)
7823 return(cur);
7825 default:
7826 break;
7827 }
7828
7829next_sibling:
7830 if ((cur == NULL) || (cur == contextNode))
7831 return(NULL);
7832 if (cur->next != NULL) {
7833 cur = cur->next;
7834 } else {
7835 cur = cur->parent;
7836 goto next_sibling;
7837 }
7838 }
7839 }
7840 return(NULL);
7841}
7842#endif
7843
7856xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7857 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7858 if (cur == NULL) {
7859 if (ctxt->context->node == NULL)
7860 return(NULL);
7861 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7862 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7863 return(NULL);
7864
7865 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7866 return(ctxt->context->doc->children);
7867 return(ctxt->context->node->children);
7868 }
7869
7870 if (cur->type == XML_NAMESPACE_DECL)
7871 return(NULL);
7872 if (cur->children != NULL) {
7873 /*
7874 * Do not descend on entities declarations
7875 */
7876 if (cur->children->type != XML_ENTITY_DECL) {
7877 cur = cur->children;
7878 /*
7879 * Skip DTDs
7880 */
7881 if (cur->type != XML_DTD_NODE)
7882 return(cur);
7883 }
7884 }
7885
7886 if (cur == ctxt->context->node) return(NULL);
7887
7888 while (cur->next != NULL) {
7889 cur = cur->next;
7890 if ((cur->type != XML_ENTITY_DECL) &&
7891 (cur->type != XML_DTD_NODE))
7892 return(cur);
7893 }
7894
7895 do {
7896 cur = cur->parent;
7897 if (cur == NULL) break;
7898 if (cur == ctxt->context->node) return(NULL);
7899 if (cur->next != NULL) {
7900 cur = cur->next;
7901 return(cur);
7902 }
7903 } while (cur != NULL);
7904 return(cur);
7905}
7906
7921xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7922 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7923 if (cur == NULL)
7924 return(ctxt->context->node);
7925
7926 if (ctxt->context->node == NULL)
7927 return(NULL);
7928 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7929 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7930 return(NULL);
7931
7932 return(xmlXPathNextDescendant(ctxt, cur));
7933}
7934
7946xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7947 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7948 /*
7949 * the parent of an attribute or namespace node is the element
7950 * to which the attribute or namespace node is attached
7951 * Namespace handling !!!
7952 */
7953 if (cur == NULL) {
7954 if (ctxt->context->node == NULL) return(NULL);
7955 switch (ctxt->context->node->type) {
7956 case XML_ELEMENT_NODE:
7957 case XML_TEXT_NODE:
7960 case XML_ENTITY_NODE:
7961 case XML_PI_NODE:
7962 case XML_COMMENT_NODE:
7963 case XML_NOTATION_NODE:
7964 case XML_DTD_NODE:
7965 case XML_ELEMENT_DECL:
7966 case XML_ATTRIBUTE_DECL:
7967 case XML_XINCLUDE_START:
7968 case XML_XINCLUDE_END:
7969 case XML_ENTITY_DECL:
7970 if (ctxt->context->node->parent == NULL)
7971 return((xmlNodePtr) ctxt->context->doc);
7972 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7973 ((ctxt->context->node->parent->name[0] == ' ') ||
7974 (xmlStrEqual(ctxt->context->node->parent->name,
7975 BAD_CAST "fake node libxslt"))))
7976 return(NULL);
7977 return(ctxt->context->node->parent);
7978 case XML_ATTRIBUTE_NODE: {
7979 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7980
7981 return(att->parent);
7982 }
7983 case XML_DOCUMENT_NODE:
7987 return(NULL);
7988 case XML_NAMESPACE_DECL: {
7989 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7990
7991 if ((ns->next != NULL) &&
7992 (ns->next->type != XML_NAMESPACE_DECL))
7993 return((xmlNodePtr) ns->next);
7994 return(NULL);
7995 }
7996 }
7997 }
7998 return(NULL);
7999}
8000
8016xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8017 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8018 /*
8019 * the parent of an attribute or namespace node is the element
8020 * to which the attribute or namespace node is attached
8021 * !!!!!!!!!!!!!
8022 */
8023 if (cur == NULL) {
8024 if (ctxt->context->node == NULL) return(NULL);
8025 switch (ctxt->context->node->type) {
8026 case XML_ELEMENT_NODE:
8027 case XML_TEXT_NODE:
8030 case XML_ENTITY_NODE:
8031 case XML_PI_NODE:
8032 case XML_COMMENT_NODE:
8033 case XML_DTD_NODE:
8034 case XML_ELEMENT_DECL:
8035 case XML_ATTRIBUTE_DECL:
8036 case XML_ENTITY_DECL:
8037 case XML_NOTATION_NODE:
8038 case XML_XINCLUDE_START:
8039 case XML_XINCLUDE_END:
8040 if (ctxt->context->node->parent == NULL)
8041 return((xmlNodePtr) ctxt->context->doc);
8042 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8043 ((ctxt->context->node->parent->name[0] == ' ') ||
8044 (xmlStrEqual(ctxt->context->node->parent->name,
8045 BAD_CAST "fake node libxslt"))))
8046 return(NULL);
8047 return(ctxt->context->node->parent);
8048 case XML_ATTRIBUTE_NODE: {
8049 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8050
8051 return(tmp->parent);
8052 }
8053 case XML_DOCUMENT_NODE:
8057 return(NULL);
8058 case XML_NAMESPACE_DECL: {
8059 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8060
8061 if ((ns->next != NULL) &&
8062 (ns->next->type != XML_NAMESPACE_DECL))
8063 return((xmlNodePtr) ns->next);
8064 /* Bad, how did that namespace end up here ? */
8065 return(NULL);
8066 }
8067 }
8068 return(NULL);
8069 }
8070 if (cur == ctxt->context->doc->children)
8071 return((xmlNodePtr) ctxt->context->doc);
8072 if (cur == (xmlNodePtr) ctxt->context->doc)
8073 return(NULL);
8074 switch (cur->type) {
8075 case XML_ELEMENT_NODE:
8076 case XML_TEXT_NODE:
8079 case XML_ENTITY_NODE:
8080 case XML_PI_NODE:
8081 case XML_COMMENT_NODE:
8082 case XML_NOTATION_NODE:
8083 case XML_DTD_NODE:
8084 case XML_ELEMENT_DECL:
8085 case XML_ATTRIBUTE_DECL:
8086 case XML_ENTITY_DECL:
8087 case XML_XINCLUDE_START:
8088 case XML_XINCLUDE_END:
8089 if (cur->parent == NULL)
8090 return(NULL);
8091 if ((cur->parent->type == XML_ELEMENT_NODE) &&
8092 ((cur->parent->name[0] == ' ') ||
8093 (xmlStrEqual(cur->parent->name,
8094 BAD_CAST "fake node libxslt"))))
8095 return(NULL);
8096 return(cur->parent);
8097 case XML_ATTRIBUTE_NODE: {
8098 xmlAttrPtr att = (xmlAttrPtr) cur;
8099
8100 return(att->parent);
8101 }
8102 case XML_NAMESPACE_DECL: {
8103 xmlNsPtr ns = (xmlNsPtr) cur;
8104
8105 if ((ns->next != NULL) &&
8106 (ns->next->type != XML_NAMESPACE_DECL))
8107 return((xmlNodePtr) ns->next);
8108 /* Bad, how did that namespace end up here ? */
8109 return(NULL);
8110 }
8111 case XML_DOCUMENT_NODE:
8115 return(NULL);
8116 }
8117 return(NULL);
8118}
8119
8134xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8135 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8136 if (cur == NULL)
8137 return(ctxt->context->node);
8138 return(xmlXPathNextAncestor(ctxt, cur));
8139}
8140
8153xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8154 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8155 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8156 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8157 return(NULL);
8158 if (cur == (xmlNodePtr) ctxt->context->doc)
8159 return(NULL);
8160 if (cur == NULL)
8161 return(ctxt->context->node->next);
8162 return(cur->next);
8163}
8164
8178xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8179 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8180 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8181 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8182 return(NULL);
8183 if (cur == (xmlNodePtr) ctxt->context->doc)
8184 return(NULL);
8185 if (cur == NULL)
8186 return(ctxt->context->node->prev);
8187 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8188 cur = cur->prev;
8189 if (cur == NULL)
8190 return(ctxt->context->node->prev);
8191 }
8192 return(cur->prev);
8193}
8194
8209xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8210 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8211 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8212 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8213 return(cur->children);
8214
8215 if (cur == NULL) {
8216 cur = ctxt->context->node;
8217 if (cur->type == XML_ATTRIBUTE_NODE) {
8218 cur = cur->parent;
8219 } else if (cur->type == XML_NAMESPACE_DECL) {
8220 xmlNsPtr ns = (xmlNsPtr) cur;
8221
8222 if ((ns->next == NULL) ||
8223 (ns->next->type == XML_NAMESPACE_DECL))
8224 return (NULL);
8225 cur = (xmlNodePtr) ns->next;
8226 }
8227 }
8228 if (cur == NULL) return(NULL) ; /* ERROR */
8229 if (cur->next != NULL) return(cur->next) ;
8230 do {
8231 cur = cur->parent;
8232 if (cur == NULL) break;
8233 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8234 if (cur->next != NULL) return(cur->next);
8235 } while (cur != NULL);
8236 return(cur);
8237}
8238
8239/*
8240 * xmlXPathIsAncestor:
8241 * @ancestor: the ancestor node
8242 * @node: the current node
8243 *
8244 * Check that @ancestor is a @node's ancestor
8245 *
8246 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8247 */
8248static int
8249xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8250 if ((ancestor == NULL) || (node == NULL)) return(0);
8251 if (node->type == XML_NAMESPACE_DECL)
8252 return(0);
8253 if (ancestor->type == XML_NAMESPACE_DECL)
8254 return(0);
8255 /* nodes need to be in the same document */
8256 if (ancestor->doc != node->doc) return(0);
8257 /* avoid searching if ancestor or node is the root node */
8258 if (ancestor == (xmlNodePtr) node->doc) return(1);
8259 if (node == (xmlNodePtr) ancestor->doc) return(0);
8260 while (node->parent != NULL) {
8261 if (node->parent == ancestor)
8262 return(1);
8263 node = node->parent;
8264 }
8265 return(0);
8266}
8267
8282xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8283{
8284 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8285 if (cur == NULL) {
8286 cur = ctxt->context->node;
8287 if (cur->type == XML_ATTRIBUTE_NODE) {
8288 cur = cur->parent;
8289 } else if (cur->type == XML_NAMESPACE_DECL) {
8290 xmlNsPtr ns = (xmlNsPtr) cur;
8291
8292 if ((ns->next == NULL) ||
8293 (ns->next->type == XML_NAMESPACE_DECL))
8294 return (NULL);
8295 cur = (xmlNodePtr) ns->next;
8296 }
8297 }
8298 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8299 return (NULL);
8300 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8301 cur = cur->prev;
8302 do {
8303 if (cur->prev != NULL) {
8304 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8305 return (cur);
8306 }
8307
8308 cur = cur->parent;
8309 if (cur == NULL)
8310 return (NULL);
8311 if (cur == ctxt->context->doc->children)
8312 return (NULL);
8313 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8314 return (cur);
8315}
8316
8332static xmlNodePtr
8333xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8335{
8336 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8337 if (cur == NULL) {
8338 cur = ctxt->context->node;
8339 if (cur == NULL)
8340 return (NULL);
8341 if (cur->type == XML_ATTRIBUTE_NODE) {
8342 cur = cur->parent;
8343 } else if (cur->type == XML_NAMESPACE_DECL) {
8344 xmlNsPtr ns = (xmlNsPtr) cur;
8345
8346 if ((ns->next == NULL) ||
8347 (ns->next->type == XML_NAMESPACE_DECL))
8348 return (NULL);
8349 cur = (xmlNodePtr) ns->next;
8350 }
8351 ctxt->ancestor = cur->parent;
8352 }
8353 if (cur->type == XML_NAMESPACE_DECL)
8354 return(NULL);
8355 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8356 cur = cur->prev;
8357 while (cur->prev == NULL) {
8358 cur = cur->parent;
8359 if (cur == NULL)
8360 return (NULL);
8361 if (cur == ctxt->context->doc->children)
8362 return (NULL);
8363 if (cur != ctxt->ancestor)
8364 return (cur);
8365 ctxt->ancestor = cur->parent;
8366 }
8367 cur = cur->prev;
8368 while (cur->last != NULL)
8369 cur = cur->last;
8370 return (cur);
8371}
8372
8388xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8389 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8390 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8391 if (cur == NULL) {
8392 if (ctxt->context->tmpNsList != NULL)
8393 xmlFree(ctxt->context->tmpNsList);
8394 ctxt->context->tmpNsList =
8395 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8396 ctxt->context->tmpNsNr = 0;
8397 if (ctxt->context->tmpNsList != NULL) {
8398 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8399 ctxt->context->tmpNsNr++;
8400 }
8401 }
8402 return((xmlNodePtr) xmlXPathXMLNamespace);
8403 }
8404 if (ctxt->context->tmpNsNr > 0) {
8405 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8406 } else {
8407 if (ctxt->context->tmpNsList != NULL)
8408 xmlFree(ctxt->context->tmpNsList);
8409 ctxt->context->tmpNsList = NULL;
8410 return(NULL);
8411 }
8412}
8413
8425xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8426 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8427 if (ctxt->context->node == NULL)
8428 return(NULL);
8429 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8430 return(NULL);
8431 if (cur == NULL) {
8432 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8433 return(NULL);
8434 return((xmlNodePtr)ctxt->context->node->properties);
8435 }
8436 return((xmlNodePtr)cur->next);
8437}
8438
8439/************************************************************************
8440 * *
8441 * NodeTest Functions *
8442 * *
8443 ************************************************************************/
8444
8445#define IS_FUNCTION 200
8446
8447
8448/************************************************************************
8449 * *
8450 * Implicit tree core function library *
8451 * *
8452 ************************************************************************/
8453
8460void
8461xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8462 if ((ctxt == NULL) || (ctxt->context == NULL))
8463 return;
8464 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8465 (xmlNodePtr) ctxt->context->doc));
8466}
8467
8468/************************************************************************
8469 * *
8470 * The explicit core function library *
8471 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8472 * *
8473 ************************************************************************/
8474
8475
8485void
8486xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8487 CHECK_ARITY(0);
8488 if (ctxt->context->contextSize >= 0) {
8489 valuePush(ctxt,
8490 xmlXPathCacheNewFloat(ctxt->context,
8491 (double) ctxt->context->contextSize));
8492#ifdef DEBUG_EXPR
8494 "last() : %d\n", ctxt->context->contextSize);
8495#endif
8496 } else {
8497 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8498 }
8499}
8500
8512void
8513xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8514 CHECK_ARITY(0);
8515 if (ctxt->context->proximityPosition >= 0) {
8516 valuePush(ctxt,
8517 xmlXPathCacheNewFloat(ctxt->context,
8518 (double) ctxt->context->proximityPosition));
8519#ifdef DEBUG_EXPR
8520 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8521 ctxt->context->proximityPosition);
8522#endif
8523 } else {
8524 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8525 }
8526}
8527
8536void
8537xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8538 xmlXPathObjectPtr cur;
8539
8540 CHECK_ARITY(1);
8541 if ((ctxt->value == NULL) ||
8542 ((ctxt->value->type != XPATH_NODESET) &&
8543 (ctxt->value->type != XPATH_XSLT_TREE)))
8544 XP_ERROR(XPATH_INVALID_TYPE);
8545 cur = valuePop(ctxt);
8546
8547 if ((cur == NULL) || (cur->nodesetval == NULL))
8548 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8549 else
8550 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8551 (double) cur->nodesetval->nodeNr));
8552 xmlXPathReleaseObject(ctxt->context, cur);
8553}
8554
8564static xmlNodeSetPtr
8565xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8566 xmlNodeSetPtr ret;
8567 const xmlChar *cur = ids;
8568 xmlChar *ID;
8571
8572 if (ids == NULL) return(NULL);
8573
8574 ret = xmlXPathNodeSetCreate(NULL);
8575 if (ret == NULL)
8576 return(ret);
8577
8578 while (IS_BLANK_CH(*cur)) cur++;
8579 while (*cur != 0) {
8580 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8581 cur++;
8582
8583 ID = xmlStrndup(ids, cur - ids);
8584 if (ID != NULL) {
8585 /*
8586 * We used to check the fact that the value passed
8587 * was an NCName, but this generated much troubles for
8588 * me and Aleksey Sanin, people blatantly violated that
8589 * constraint, like Visa3D spec.
8590 * if (xmlValidateNCName(ID, 1) == 0)
8591 */
8592 attr = xmlGetID(doc, ID);
8593 if (attr != NULL) {
8594 if (attr->type == XML_ATTRIBUTE_NODE)
8595 elem = attr->parent;
8596 else if (attr->type == XML_ELEMENT_NODE)
8597 elem = (xmlNodePtr) attr;
8598 else
8599 elem = NULL;
8600 /* TODO: Check memory error. */
8601 if (elem != NULL)
8602 xmlXPathNodeSetAdd(ret, elem);
8603 }
8604 xmlFree(ID);
8605 }
8606
8607 while (IS_BLANK_CH(*cur)) cur++;
8608 ids = cur;
8609 }
8610 return(ret);
8611}
8612
8631void
8632xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8633 xmlChar *tokens;
8634 xmlNodeSetPtr ret;
8635 xmlXPathObjectPtr obj;
8636
8637 CHECK_ARITY(1);
8638 obj = valuePop(ctxt);
8639 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8640 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8641 xmlNodeSetPtr ns;
8642 int i;
8643
8644 /* TODO: Check memory error. */
8645 ret = xmlXPathNodeSetCreate(NULL);
8646
8647 if (obj->nodesetval != NULL) {
8648 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8649 tokens =
8650 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8651 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8652 /* TODO: Check memory error. */
8653 ret = xmlXPathNodeSetMerge(ret, ns);
8654 xmlXPathFreeNodeSet(ns);
8655 if (tokens != NULL)
8656 xmlFree(tokens);
8657 }
8658 }
8659 xmlXPathReleaseObject(ctxt->context, obj);
8660 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8661 return;
8662 }
8663 obj = xmlXPathCacheConvertString(ctxt->context, obj);
8664 if (obj == NULL) return;
8665 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8666 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8667 xmlXPathReleaseObject(ctxt->context, obj);
8668 return;
8669}
8670
8684void
8685xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8686 xmlXPathObjectPtr cur;
8687
8688 if (ctxt == NULL) return;
8689
8690 if (nargs == 0) {
8691 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8692 ctxt->context->node));
8693 nargs = 1;
8694 }
8695
8696 CHECK_ARITY(1);
8697 if ((ctxt->value == NULL) ||
8698 ((ctxt->value->type != XPATH_NODESET) &&
8699 (ctxt->value->type != XPATH_XSLT_TREE)))
8700 XP_ERROR(XPATH_INVALID_TYPE);
8701 cur = valuePop(ctxt);
8702
8703 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8704 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8705 } else {
8706 int i = 0; /* Should be first in document order !!!!! */
8707 switch (cur->nodesetval->nodeTab[i]->type) {
8708 case XML_ELEMENT_NODE:
8709 case XML_ATTRIBUTE_NODE:
8710 case XML_PI_NODE:
8711 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8712 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8713 else
8714 valuePush(ctxt,
8715 xmlXPathCacheNewString(ctxt->context,
8716 cur->nodesetval->nodeTab[i]->name));
8717 break;
8718 case XML_NAMESPACE_DECL:
8719 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8720 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8721 break;
8722 default:
8723 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8724 }
8725 }
8726 xmlXPathReleaseObject(ctxt->context, cur);
8727}
8728
8743void
8744xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8745 xmlXPathObjectPtr cur;
8746
8747 if (ctxt == NULL) return;
8748
8749 if (nargs == 0) {
8750 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8751 ctxt->context->node));
8752 nargs = 1;
8753 }
8754 CHECK_ARITY(1);
8755 if ((ctxt->value == NULL) ||
8756 ((ctxt->value->type != XPATH_NODESET) &&
8757 (ctxt->value->type != XPATH_XSLT_TREE)))
8758 XP_ERROR(XPATH_INVALID_TYPE);
8759 cur = valuePop(ctxt);
8760
8761 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8762 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8763 } else {
8764 int i = 0; /* Should be first in document order !!!!! */
8765 switch (cur->nodesetval->nodeTab[i]->type) {
8766 case XML_ELEMENT_NODE:
8767 case XML_ATTRIBUTE_NODE:
8768 if (cur->nodesetval->nodeTab[i]->ns == NULL)
8769 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8770 else
8771 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8772 cur->nodesetval->nodeTab[i]->ns->href));
8773 break;
8774 default:
8775 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8776 }
8777 }
8778 xmlXPathReleaseObject(ctxt->context, cur);
8779}
8780
8803static void
8804xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8805{
8806 xmlXPathObjectPtr cur;
8807
8808 if (nargs == 0) {
8809 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8810 ctxt->context->node));
8811 nargs = 1;
8812 }
8813
8814 CHECK_ARITY(1);
8815 if ((ctxt->value == NULL) ||
8816 ((ctxt->value->type != XPATH_NODESET) &&
8817 (ctxt->value->type != XPATH_XSLT_TREE)))
8818 XP_ERROR(XPATH_INVALID_TYPE);
8819 cur = valuePop(ctxt);
8820
8821 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8822 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8823 } else {
8824 int i = 0; /* Should be first in document order !!!!! */
8825
8826 switch (cur->nodesetval->nodeTab[i]->type) {
8827 case XML_ELEMENT_NODE:
8828 case XML_ATTRIBUTE_NODE:
8829 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8830 valuePush(ctxt,
8831 xmlXPathCacheNewCString(ctxt->context, ""));
8832 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8833 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8834 valuePush(ctxt,
8835 xmlXPathCacheNewString(ctxt->context,
8836 cur->nodesetval->nodeTab[i]->name));
8837 } else {
8839
8840 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8841 cur->nodesetval->nodeTab[i]->ns->prefix,
8842 NULL, 0);
8843 if (fullname == cur->nodesetval->nodeTab[i]->name)
8844 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8845 if (fullname == NULL) {
8846 XP_ERROR(XPATH_MEMORY_ERROR);
8847 }
8848 valuePush(ctxt, xmlXPathCacheWrapString(
8849 ctxt->context, fullname));
8850 }
8851 break;
8852 default:
8853 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8854 cur->nodesetval->nodeTab[i]));
8855 xmlXPathLocalNameFunction(ctxt, 1);
8856 }
8857 }
8858 xmlXPathReleaseObject(ctxt->context, cur);
8859}
8860
8861
8898void
8899xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8900 xmlXPathObjectPtr cur;
8901
8902 if (ctxt == NULL) return;
8903 if (nargs == 0) {
8904 valuePush(ctxt,
8905 xmlXPathCacheWrapString(ctxt->context,
8906 xmlXPathCastNodeToString(ctxt->context->node)));
8907 return;
8908 }
8909
8910 CHECK_ARITY(1);
8911 cur = valuePop(ctxt);
8912 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8913 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8914}
8915
8928void
8929xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8930 xmlXPathObjectPtr cur;
8931
8932 if (nargs == 0) {
8933 if ((ctxt == NULL) || (ctxt->context == NULL))
8934 return;
8935 if (ctxt->context->node == NULL) {
8936 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8937 } else {
8939
8940 content = xmlXPathCastNodeToString(ctxt->context->node);
8941 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8944 }
8945 return;
8946 }
8947 CHECK_ARITY(1);
8948 CAST_TO_STRING;
8949 CHECK_TYPE(XPATH_STRING);
8950 cur = valuePop(ctxt);
8951 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8952 xmlUTF8Strlen(cur->stringval)));
8953 xmlXPathReleaseObject(ctxt->context, cur);
8954}
8955
8965void
8966xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8967 xmlXPathObjectPtr cur, newobj;
8968 xmlChar *tmp;
8969
8970 if (ctxt == NULL) return;
8971 if (nargs < 2) {
8972 CHECK_ARITY(2);
8973 }
8974
8975 CAST_TO_STRING;
8976 cur = valuePop(ctxt);
8977 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8978 xmlXPathReleaseObject(ctxt->context, cur);
8979 return;
8980 }
8981 nargs--;
8982
8983 while (nargs > 0) {
8984 CAST_TO_STRING;
8985 newobj = valuePop(ctxt);
8986 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8987 xmlXPathReleaseObject(ctxt->context, newobj);
8988 xmlXPathReleaseObject(ctxt->context, cur);
8989 XP_ERROR(XPATH_INVALID_TYPE);
8990 }
8991 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8992 newobj->stringval = cur->stringval;
8993 cur->stringval = tmp;
8994 xmlXPathReleaseObject(ctxt->context, newobj);
8995 nargs--;
8996 }
8997 valuePush(ctxt, cur);
8998}
8999
9010void
9011xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9012 xmlXPathObjectPtr hay, needle;
9013
9014 CHECK_ARITY(2);
9015 CAST_TO_STRING;
9016 CHECK_TYPE(XPATH_STRING);
9017 needle = valuePop(ctxt);
9018 CAST_TO_STRING;
9019 hay = valuePop(ctxt);
9020
9021 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9022 xmlXPathReleaseObject(ctxt->context, hay);
9023 xmlXPathReleaseObject(ctxt->context, needle);
9024 XP_ERROR(XPATH_INVALID_TYPE);
9025 }
9026 if (xmlStrstr(hay->stringval, needle->stringval))
9027 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9028 else
9029 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9030 xmlXPathReleaseObject(ctxt->context, hay);
9031 xmlXPathReleaseObject(ctxt->context, needle);
9032}
9033
9044void
9045xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9046 xmlXPathObjectPtr hay, needle;
9047 int n;
9048
9049 CHECK_ARITY(2);
9050 CAST_TO_STRING;
9051 CHECK_TYPE(XPATH_STRING);
9052 needle = valuePop(ctxt);
9053 CAST_TO_STRING;
9054 hay = valuePop(ctxt);
9055
9056 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9057 xmlXPathReleaseObject(ctxt->context, hay);
9058 xmlXPathReleaseObject(ctxt->context, needle);
9059 XP_ERROR(XPATH_INVALID_TYPE);
9060 }
9061 n = xmlStrlen(needle->stringval);
9062 if (xmlStrncmp(hay->stringval, needle->stringval, n))
9063 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9064 else
9065 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9066 xmlXPathReleaseObject(ctxt->context, hay);
9067 xmlXPathReleaseObject(ctxt->context, needle);
9068}
9069
9098void
9099xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9100 xmlXPathObjectPtr str, start, len;
9101 double le=0, in;
9102 int i = 1, j = INT_MAX;
9103
9104 if (nargs < 2) {
9105 CHECK_ARITY(2);
9106 }
9107 if (nargs > 3) {
9108 CHECK_ARITY(3);
9109 }
9110 /*
9111 * take care of possible last (position) argument
9112 */
9113 if (nargs == 3) {
9114 CAST_TO_NUMBER;
9115 CHECK_TYPE(XPATH_NUMBER);
9116 len = valuePop(ctxt);
9117 le = len->floatval;
9118 xmlXPathReleaseObject(ctxt->context, len);
9119 }
9120
9121 CAST_TO_NUMBER;
9122 CHECK_TYPE(XPATH_NUMBER);
9123 start = valuePop(ctxt);
9124 in = start->floatval;
9125 xmlXPathReleaseObject(ctxt->context, start);
9126 CAST_TO_STRING;
9127 CHECK_TYPE(XPATH_STRING);
9128 str = valuePop(ctxt);
9129
9130 if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9131 i = INT_MAX;
9132 } else if (in >= 1.0) {
9133 i = (int)in;
9134 if (in - floor(in) >= 0.5)
9135 i += 1;
9136 }
9137
9138 if (nargs == 3) {
9139 double rin, rle, end;
9140
9141 rin = floor(in);
9142 if (in - rin >= 0.5)
9143 rin += 1.0;
9144
9145 rle = floor(le);
9146 if (le - rle >= 0.5)
9147 rle += 1.0;
9148
9149 end = rin + rle;
9150 if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9151 j = 1;
9152 } else if (end < INT_MAX) {
9153 j = (int)end;
9154 }
9155 }
9156
9157 if (i < j) {
9158 xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
9159 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9160 xmlFree(ret);
9161 } else {
9162 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9163 }
9164
9165 xmlXPathReleaseObject(ctxt->context, str);
9166}
9167
9181void
9182xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9183 xmlXPathObjectPtr str;
9184 xmlXPathObjectPtr find;
9186 const xmlChar *point;
9187 int offset;
9188
9189 CHECK_ARITY(2);
9190 CAST_TO_STRING;
9191 find = valuePop(ctxt);
9192 CAST_TO_STRING;
9193 str = valuePop(ctxt);
9194
9195 target = xmlBufCreate();
9196 if (target) {
9197 point = xmlStrstr(str->stringval, find->stringval);
9198 if (point) {
9199 offset = (int)(point - str->stringval);
9200 xmlBufAdd(target, str->stringval, offset);
9201 }
9202 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9205 }
9206 xmlXPathReleaseObject(ctxt->context, str);
9207 xmlXPathReleaseObject(ctxt->context, find);
9208}
9209
9224void
9225xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9226 xmlXPathObjectPtr str;
9227 xmlXPathObjectPtr find;
9229 const xmlChar *point;
9230 int offset;
9231
9232 CHECK_ARITY(2);
9233 CAST_TO_STRING;
9234 find = valuePop(ctxt);
9235 CAST_TO_STRING;
9236 str = valuePop(ctxt);
9237
9238 target = xmlBufCreate();
9239 if (target) {
9240 point = xmlStrstr(str->stringval, find->stringval);
9241 if (point) {
9242 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9243 xmlBufAdd(target, &str->stringval[offset],
9244 xmlStrlen(str->stringval) - offset);
9245 }
9246 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9249 }
9250 xmlXPathReleaseObject(ctxt->context, str);
9251 xmlXPathReleaseObject(ctxt->context, find);
9252}
9253
9268void
9269xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9271 int blank;
9272
9273 if (ctxt == NULL) return;
9274 if (nargs == 0) {
9275 /* Use current context node */
9276 valuePush(ctxt,
9277 xmlXPathCacheWrapString(ctxt->context,
9278 xmlXPathCastNodeToString(ctxt->context->node)));
9279 nargs = 1;
9280 }
9281
9282 CHECK_ARITY(1);
9283 CAST_TO_STRING;
9284 CHECK_TYPE(XPATH_STRING);
9285 source = ctxt->value->stringval;
9286 if (source == NULL)
9287 return;
9288 target = source;
9289
9290 /* Skip leading whitespaces */
9291 while (IS_BLANK_CH(*source))
9292 source++;
9293
9294 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9295 blank = 0;
9296 while (*source) {
9297 if (IS_BLANK_CH(*source)) {
9298 blank = 1;
9299 } else {
9300 if (blank) {
9301 *target++ = 0x20;
9302 blank = 0;
9303 }
9304 *target++ = *source;
9305 }
9306 source++;
9307 }
9308 *target = 0;
9309}
9310
9332void
9333xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9334 xmlXPathObjectPtr str;
9335 xmlXPathObjectPtr from;
9336 xmlXPathObjectPtr to;
9338 int offset, max;
9339 xmlChar ch;
9340 const xmlChar *point;
9341 xmlChar *cptr;
9342
9343 CHECK_ARITY(3);
9344
9345 CAST_TO_STRING;
9346 to = valuePop(ctxt);
9347 CAST_TO_STRING;
9348 from = valuePop(ctxt);
9349 CAST_TO_STRING;
9350 str = valuePop(ctxt);
9351
9352 target = xmlBufCreate();
9353 if (target) {
9354 max = xmlUTF8Strlen(to->stringval);
9355 for (cptr = str->stringval; (ch=*cptr); ) {
9356 offset = xmlUTF8Strloc(from->stringval, cptr);
9357 if (offset >= 0) {
9358 if (offset < max) {
9359 point = xmlUTF8Strpos(to->stringval, offset);
9360 if (point)
9362 }
9363 } else
9364 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9365
9366 /* Step to next character in input */
9367 cptr++;
9368 if ( ch & 0x80 ) {
9369 /* if not simple ascii, verify proper format */
9370 if ( (ch & 0xc0) != 0xc0 ) {
9372 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9373 /* not asserting an XPath error is probably better */
9374 break;
9375 }
9376 /* then skip over remaining bytes for this char */
9377 while ( (ch <<= 1) & 0x80 )
9378 if ( (*cptr++ & 0xc0) != 0x80 ) {
9380 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9381 /* not asserting an XPath error is probably better */
9382 break;
9383 }
9384 if (ch & 0x80) /* must have had error encountered */
9385 break;
9386 }
9387 }
9388 }
9389 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9392 xmlXPathReleaseObject(ctxt->context, str);
9393 xmlXPathReleaseObject(ctxt->context, from);
9394 xmlXPathReleaseObject(ctxt->context, to);
9395}
9396
9410void
9411xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9412 xmlXPathObjectPtr cur;
9413
9414 CHECK_ARITY(1);
9415 cur = valuePop(ctxt);
9416 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9417 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9418 valuePush(ctxt, cur);
9419}
9420
9431void
9432xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9433 CHECK_ARITY(1);
9434 CAST_TO_BOOLEAN;
9435 CHECK_TYPE(XPATH_BOOLEAN);
9436 ctxt->value->boolval = ! ctxt->value->boolval;
9437}
9438
9447void
9448xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9449 CHECK_ARITY(0);
9450 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9451}
9452
9461void
9462xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9463 CHECK_ARITY(0);
9464 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9465}
9466
9488void
9489xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9490 xmlXPathObjectPtr val = NULL;
9491 const xmlChar *theLang = NULL;
9492 const xmlChar *lang;
9493 int ret = 0;
9494 int i;
9495
9496 CHECK_ARITY(1);
9497 CAST_TO_STRING;
9498 CHECK_TYPE(XPATH_STRING);
9499 val = valuePop(ctxt);
9500 lang = val->stringval;
9501 theLang = xmlNodeGetLang(ctxt->context->node);
9502 if ((theLang != NULL) && (lang != NULL)) {
9503 for (i = 0;lang[i] != 0;i++)
9504 if (toupper(lang[i]) != toupper(theLang[i]))
9505 goto not_equal;
9506 if ((theLang[i] == 0) || (theLang[i] == '-'))
9507 ret = 1;
9508 }
9509not_equal:
9510 if (theLang != NULL)
9511 xmlFree((void *)theLang);
9512
9513 xmlXPathReleaseObject(ctxt->context, val);
9514 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9515}
9516
9525void
9526xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9527 xmlXPathObjectPtr cur;
9528 double res;
9529
9530 if (ctxt == NULL) return;
9531 if (nargs == 0) {
9532 if (ctxt->context->node == NULL) {
9533 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9534 } else {
9535 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9536
9538 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9540 }
9541 return;
9542 }
9543
9544 CHECK_ARITY(1);
9545 cur = valuePop(ctxt);
9546 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9547}
9548
9559void
9560xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9561 xmlXPathObjectPtr cur;
9562 int i;
9563 double res = 0.0;
9564
9565 CHECK_ARITY(1);
9566 if ((ctxt->value == NULL) ||
9567 ((ctxt->value->type != XPATH_NODESET) &&
9568 (ctxt->value->type != XPATH_XSLT_TREE)))
9569 XP_ERROR(XPATH_INVALID_TYPE);
9570 cur = valuePop(ctxt);
9571
9572 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9573 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9574 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9575 }
9576 }
9577 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9578 xmlXPathReleaseObject(ctxt->context, cur);
9579}
9580
9591void
9592xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9593 CHECK_ARITY(1);
9594 CAST_TO_NUMBER;
9595 CHECK_TYPE(XPATH_NUMBER);
9596
9597 ctxt->value->floatval = floor(ctxt->value->floatval);
9598}
9599
9610void
9611xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9612 CHECK_ARITY(1);
9613 CAST_TO_NUMBER;
9614 CHECK_TYPE(XPATH_NUMBER);
9615
9616#ifdef _AIX
9617 /* Work around buggy ceil() function on AIX */
9618 ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
9619#else
9620 ctxt->value->floatval = ceil(ctxt->value->floatval);
9621#endif
9622}
9623
9635void
9636xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9637 double f;
9638
9639 CHECK_ARITY(1);
9640 CAST_TO_NUMBER;
9641 CHECK_TYPE(XPATH_NUMBER);
9642
9643 f = ctxt->value->floatval;
9644
9645 if ((f >= -0.5) && (f < 0.5)) {
9646 /* Handles negative zero. */
9647 ctxt->value->floatval *= 0.0;
9648 }
9649 else {
9650 double rounded = floor(f);
9651 if (f - rounded >= 0.5)
9652 rounded += 1.0;
9653 ctxt->value->floatval = rounded;
9654 }
9655}
9656
9657/************************************************************************
9658 * *
9659 * The Parser *
9660 * *
9661 ************************************************************************/
9662
9663/*
9664 * a few forward declarations since we use a recursive call based
9665 * implementation.
9666 */
9667static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9668static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9669static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9670static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9671static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9672 int qualified);
9673
9686static int
9687xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9688 unsigned char c;
9689 unsigned int val;
9690 const xmlChar *cur;
9691
9692 if (ctxt == NULL)
9693 return(0);
9694 cur = ctxt->cur;
9695
9696 /*
9697 * We are supposed to handle UTF8, check it's valid
9698 * From rfc2044: encoding of the Unicode values on UTF-8:
9699 *
9700 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9701 * 0000 0000-0000 007F 0xxxxxxx
9702 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9703 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9704 *
9705 * Check for the 0x110000 limit too
9706 */
9707 c = *cur;
9708 if (c & 0x80) {
9709 if ((cur[1] & 0xc0) != 0x80)
9710 goto encoding_error;
9711 if ((c & 0xe0) == 0xe0) {
9712
9713 if ((cur[2] & 0xc0) != 0x80)
9714 goto encoding_error;
9715 if ((c & 0xf0) == 0xf0) {
9716 if (((c & 0xf8) != 0xf0) ||
9717 ((cur[3] & 0xc0) != 0x80))
9718 goto encoding_error;
9719 /* 4-byte code */
9720 *len = 4;
9721 val = (cur[0] & 0x7) << 18;
9722 val |= (cur[1] & 0x3f) << 12;
9723 val |= (cur[2] & 0x3f) << 6;
9724 val |= cur[3] & 0x3f;
9725 } else {
9726 /* 3-byte code */
9727 *len = 3;
9728 val = (cur[0] & 0xf) << 12;
9729 val |= (cur[1] & 0x3f) << 6;
9730 val |= cur[2] & 0x3f;
9731 }
9732 } else {
9733 /* 2-byte code */
9734 *len = 2;
9735 val = (cur[0] & 0x1f) << 6;
9736 val |= cur[1] & 0x3f;
9737 }
9738 if (!IS_CHAR(val)) {
9739 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9740 }
9741 return(val);
9742 } else {
9743 /* 1-byte code */
9744 *len = 1;
9745 return((int) *cur);
9746 }
9747encoding_error:
9748 /*
9749 * If we detect an UTF8 error that probably means that the
9750 * input encoding didn't get properly advertised in the
9751 * declaration header. Report the error and switch the encoding
9752 * to ISO-Latin-1 (if you don't like this policy, just declare the
9753 * encoding !)
9754 */
9755 *len = 0;
9756 XP_ERROR0(XPATH_ENCODING_ERROR);
9757}
9758
9773xmlChar *
9774xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9775 const xmlChar *in;
9776 xmlChar *ret;
9777 int count = 0;
9778
9779 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9780 /*
9781 * Accelerator for simple ASCII names
9782 */
9783 in = ctxt->cur;
9784 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9785 ((*in >= 0x41) && (*in <= 0x5A)) ||
9786 (*in == '_')) {
9787 in++;
9788 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9789 ((*in >= 0x41) && (*in <= 0x5A)) ||
9790 ((*in >= 0x30) && (*in <= 0x39)) ||
9791 (*in == '_') || (*in == '.') ||
9792 (*in == '-'))
9793 in++;
9794 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9795 (*in == '[') || (*in == ']') || (*in == ':') ||
9796 (*in == '@') || (*in == '*')) {
9797 count = in - ctxt->cur;
9798 if (count == 0)
9799 return(NULL);
9800 ret = xmlStrndup(ctxt->cur, count);
9801 ctxt->cur = in;
9802 return(ret);
9803 }
9804 }
9805 return(xmlXPathParseNameComplex(ctxt, 0));
9806}
9807
9808
9826static xmlChar *
9827xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9828 xmlChar *ret = NULL;
9829
9830 *prefix = NULL;
9831 ret = xmlXPathParseNCName(ctxt);
9832 if (ret && CUR == ':') {
9833 *prefix = ret;
9834 NEXT;
9835 ret = xmlXPathParseNCName(ctxt);
9836 }
9837 return(ret);
9838}
9839
9854xmlChar *
9855xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9856 const xmlChar *in;
9857 xmlChar *ret;
9858 size_t count = 0;
9859
9860 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9861 /*
9862 * Accelerator for simple ASCII names
9863 */
9864 in = ctxt->cur;
9865 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9866 ((*in >= 0x41) && (*in <= 0x5A)) ||
9867 (*in == '_') || (*in == ':')) {
9868 in++;
9869 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9870 ((*in >= 0x41) && (*in <= 0x5A)) ||
9871 ((*in >= 0x30) && (*in <= 0x39)) ||
9872 (*in == '_') || (*in == '-') ||
9873 (*in == ':') || (*in == '.'))
9874 in++;
9875 if ((*in > 0) && (*in < 0x80)) {
9876 count = in - ctxt->cur;
9877 if (count > XML_MAX_NAME_LENGTH) {
9878 ctxt->cur = in;
9879 XP_ERRORNULL(XPATH_EXPR_ERROR);
9880 }
9881 ret = xmlStrndup(ctxt->cur, count);
9882 ctxt->cur = in;
9883 return(ret);
9884 }
9885 }
9886 return(xmlXPathParseNameComplex(ctxt, 1));
9887}
9888
9889static xmlChar *
9890xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9892 int len = 0, l;
9893 int c;
9894
9895 /*
9896 * Handler for more complex cases
9897 */
9898 c = CUR_CHAR(l);
9899 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9900 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9901 (c == '*') || /* accelerators */
9902 (!IS_LETTER(c) && (c != '_') &&
9903 ((!qualified) || (c != ':')))) {
9904 return(NULL);
9905 }
9906
9907 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9908 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9909 (c == '.') || (c == '-') ||
9910 (c == '_') || ((qualified) && (c == ':')) ||
9911 (IS_COMBINING(c)) ||
9912 (IS_EXTENDER(c)))) {
9913 COPY_BUF(l,buf,len,c);
9914 NEXTL(l);
9915 c = CUR_CHAR(l);
9916 if (len >= XML_MAX_NAMELEN) {
9917 /*
9918 * Okay someone managed to make a huge name, so he's ready to pay
9919 * for the processing speed.
9920 */
9921 xmlChar *buffer;
9922 int max = len * 2;
9923
9924 if (len > XML_MAX_NAME_LENGTH) {
9925 XP_ERRORNULL(XPATH_EXPR_ERROR);
9926 }
9927 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9928 if (buffer == NULL) {
9929 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9930 }
9931 memcpy(buffer, buf, len);
9932 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9933 (c == '.') || (c == '-') ||
9934 (c == '_') || ((qualified) && (c == ':')) ||
9935 (IS_COMBINING(c)) ||
9936 (IS_EXTENDER(c))) {
9937 if (len + 10 > max) {
9938 xmlChar *tmp;
9939 if (max > XML_MAX_NAME_LENGTH) {
9940 xmlFree(buffer);
9941 XP_ERRORNULL(XPATH_EXPR_ERROR);
9942 }
9943 max *= 2;
9944 tmp = (xmlChar *) xmlRealloc(buffer,
9945 max * sizeof(xmlChar));
9946 if (tmp == NULL) {
9947 xmlFree(buffer);
9948 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9949 }
9950 buffer = tmp;
9951 }
9953 NEXTL(l);
9954 c = CUR_CHAR(l);
9955 }
9956 buffer[len] = 0;
9957 return(buffer);
9958 }
9959 }
9960 if (len == 0)
9961 return(NULL);
9962 return(xmlStrndup(buf, len));
9963}
9964
9965#define MAX_FRAC 20
9966
9983double
9985 const xmlChar *cur = str;
9986 double ret;
9987 int ok = 0;
9988 int isneg = 0;
9989 int exponent = 0;
9990 int is_exponent_negative = 0;
9991#ifdef __GNUC__
9992 unsigned long tmp = 0;
9993 double temp;
9994#endif
9995 if (cur == NULL) return(0);
9996 while (IS_BLANK_CH(*cur)) cur++;
9997 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9998 return(xmlXPathNAN);
9999 }
10000 if (*cur == '-') {
10001 isneg = 1;
10002 cur++;
10003 }
10004
10005#ifdef __GNUC__
10006 /*
10007 * tmp/temp is a workaround against a gcc compiler bug
10008 * http://veillard.com/gcc.bug
10009 */
10010 ret = 0;
10011 while ((*cur >= '0') && (*cur <= '9')) {
10012 ret = ret * 10;
10013 tmp = (*cur - '0');
10014 ok = 1;
10015 cur++;
10016 temp = (double) tmp;
10017 ret = ret + temp;
10018 }
10019#else
10020 ret = 0;
10021 while ((*cur >= '0') && (*cur <= '9')) {
10022 ret = ret * 10 + (*cur - '0');
10023 ok = 1;
10024 cur++;
10025 }
10026#endif
10027
10028 if (*cur == '.') {
10029 int v, frac = 0, max;
10030 double fraction = 0;
10031
10032 cur++;
10033 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10034 return(xmlXPathNAN);
10035 }
10036 while (*cur == '0') {
10037 frac = frac + 1;
10038 cur++;
10039 }
10040 max = frac + MAX_FRAC;
10041 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10042 v = (*cur - '0');
10043 fraction = fraction * 10 + v;
10044 frac = frac + 1;
10045 cur++;
10046 }
10047 fraction /= pow(10.0, frac);
10048 ret = ret + fraction;
10049 while ((*cur >= '0') && (*cur <= '9'))
10050 cur++;
10051 }
10052 if ((*cur == 'e') || (*cur == 'E')) {
10053 cur++;
10054 if (*cur == '-') {
10055 is_exponent_negative = 1;
10056 cur++;
10057 } else if (*cur == '+') {
10058 cur++;
10059 }
10060 while ((*cur >= '0') && (*cur <= '9')) {
10061 if (exponent < 1000000)
10062 exponent = exponent * 10 + (*cur - '0');
10063 cur++;
10064 }
10065 }
10066 while (IS_BLANK_CH(*cur)) cur++;
10067 if (*cur != 0) return(xmlXPathNAN);
10068 if (isneg) ret = -ret;
10069 if (is_exponent_negative) exponent = -exponent;
10070 ret *= pow(10.0, (double)exponent);
10071 return(ret);
10072}
10073
10085static void
10086xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10087{
10088 double ret = 0.0;
10089 int ok = 0;
10090 int exponent = 0;
10091 int is_exponent_negative = 0;
10092 xmlXPathObjectPtr num;
10093#ifdef __GNUC__
10094 unsigned long tmp = 0;
10095 double temp;
10096#endif
10097
10098 CHECK_ERROR;
10099 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10100 XP_ERROR(XPATH_NUMBER_ERROR);
10101 }
10102#ifdef __GNUC__
10103 /*
10104 * tmp/temp is a workaround against a gcc compiler bug
10105 * http://veillard.com/gcc.bug
10106 */
10107 ret = 0;
10108 while ((CUR >= '0') && (CUR <= '9')) {
10109 ret = ret * 10;
10110 tmp = (CUR - '0');
10111 ok = 1;
10112 NEXT;
10113 temp = (double) tmp;
10114 ret = ret + temp;
10115 }
10116#else
10117 ret = 0;
10118 while ((CUR >= '0') && (CUR <= '9')) {
10119 ret = ret * 10 + (CUR - '0');
10120 ok = 1;
10121 NEXT;
10122 }
10123#endif
10124 if (CUR == '.') {
10125 int v, frac = 0, max;
10126 double fraction = 0;
10127
10128 NEXT;
10129 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10130 XP_ERROR(XPATH_NUMBER_ERROR);
10131 }
10132 while (CUR == '0') {
10133 frac = frac + 1;
10134 NEXT;
10135 }
10136 max = frac + MAX_FRAC;
10137 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10138 v = (CUR - '0');
10139 fraction = fraction * 10 + v;
10140 frac = frac + 1;
10141 NEXT;
10142 }
10143 fraction /= pow(10.0, frac);
10144 ret = ret + fraction;
10145 while ((CUR >= '0') && (CUR <= '9'))
10146 NEXT;
10147 }
10148 if ((CUR == 'e') || (CUR == 'E')) {
10149 NEXT;
10150 if (CUR == '-') {
10151 is_exponent_negative = 1;
10152 NEXT;
10153 } else if (CUR == '+') {
10154 NEXT;
10155 }
10156 while ((CUR >= '0') && (CUR <= '9')) {
10157 if (exponent < 1000000)
10158 exponent = exponent * 10 + (CUR - '0');
10159 NEXT;
10160 }
10161 if (is_exponent_negative)
10162 exponent = -exponent;
10163 ret *= pow(10.0, (double) exponent);
10164 }
10165 num = xmlXPathCacheNewFloat(ctxt->context, ret);
10166 if (num == NULL) {
10167 ctxt->error = XPATH_MEMORY_ERROR;
10168 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
10169 NULL) == -1) {
10170 xmlXPathReleaseObject(ctxt->context, num);
10171 }
10172}
10173
10185static xmlChar *
10186xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10187 const xmlChar *q;
10188 xmlChar *ret = NULL;
10189
10190 if (CUR == '"') {
10191 NEXT;
10192 q = CUR_PTR;
10193 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10194 NEXT;
10195 if (!IS_CHAR_CH(CUR)) {
10196 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10197 } else {
10198 ret = xmlStrndup(q, CUR_PTR - q);
10199 NEXT;
10200 }
10201 } else if (CUR == '\'') {
10202 NEXT;
10203 q = CUR_PTR;
10204 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10205 NEXT;
10206 if (!IS_CHAR_CH(CUR)) {
10207 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10208 } else {
10209 ret = xmlStrndup(q, CUR_PTR - q);
10210 NEXT;
10211 }
10212 } else {
10213 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10214 }
10215 return(ret);
10216}
10217
10229static void
10230xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10231 const xmlChar *q;
10232 xmlChar *ret = NULL;
10233 xmlXPathObjectPtr lit;
10234
10235 if (CUR == '"') {
10236 NEXT;
10237 q = CUR_PTR;
10238 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10239 NEXT;
10240 if (!IS_CHAR_CH(CUR)) {
10241 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10242 } else {
10243 ret = xmlStrndup(q, CUR_PTR - q);
10244 NEXT;
10245 }
10246 } else if (CUR == '\'') {
10247 NEXT;
10248 q = CUR_PTR;
10249 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10250 NEXT;
10251 if (!IS_CHAR_CH(CUR)) {
10252 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10253 } else {
10254 ret = xmlStrndup(q, CUR_PTR - q);
10255 NEXT;
10256 }
10257 } else {
10258 XP_ERROR(XPATH_START_LITERAL_ERROR);
10259 }
10260 if (ret == NULL) return;
10261 lit = xmlXPathCacheNewString(ctxt->context, ret);
10262 if (lit == NULL) {
10263 ctxt->error = XPATH_MEMORY_ERROR;
10264 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10265 NULL) == -1) {
10266 xmlXPathReleaseObject(ctxt->context, lit);
10267 }
10268 xmlFree(ret);
10269}
10270
10288static void
10289xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10290 xmlChar *name;
10291 xmlChar *prefix;
10292
10294 if (CUR != '$') {
10295 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10296 }
10297 NEXT;
10298 name = xmlXPathParseQName(ctxt, &prefix);
10299 if (name == NULL) {
10300 xmlFree(prefix);
10301 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10302 }
10303 ctxt->comp->last = -1;
10304 if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
10305 xmlFree(prefix);
10306 xmlFree(name);
10307 }
10309 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10310 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10311 }
10312}
10313
10327int
10328xmlXPathIsNodeType(const xmlChar *name) {
10329 if (name == NULL)
10330 return(0);
10331
10332 if (xmlStrEqual(name, BAD_CAST "node"))
10333 return(1);
10334 if (xmlStrEqual(name, BAD_CAST "text"))
10335 return(1);
10336 if (xmlStrEqual(name, BAD_CAST "comment"))
10337 return(1);
10338 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10339 return(1);
10340 return(0);
10341}
10342
10353static void
10354xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10355 xmlChar *name;
10356 xmlChar *prefix;
10357 int nbargs = 0;
10358 int sort = 1;
10359
10360 name = xmlXPathParseQName(ctxt, &prefix);
10361 if (name == NULL) {
10362 xmlFree(prefix);
10363 XP_ERROR(XPATH_EXPR_ERROR);
10364 }
10366#ifdef DEBUG_EXPR
10367 if (prefix == NULL)
10368 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10369 name);
10370 else
10371 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10372 prefix, name);
10373#endif
10374
10375 if (CUR != '(') {
10376 xmlFree(name);
10377 xmlFree(prefix);
10378 XP_ERROR(XPATH_EXPR_ERROR);
10379 }
10380 NEXT;
10382
10383 /*
10384 * Optimization for count(): we don't need the node-set to be sorted.
10385 */
10386 if ((prefix == NULL) && (name[0] == 'c') &&
10387 xmlStrEqual(name, BAD_CAST "count"))
10388 {
10389 sort = 0;
10390 }
10391 ctxt->comp->last = -1;
10392 if (CUR != ')') {
10393 while (CUR != 0) {
10394 int op1 = ctxt->comp->last;
10395 ctxt->comp->last = -1;
10396 xmlXPathCompileExpr(ctxt, sort);
10397 if (ctxt->error != XPATH_EXPRESSION_OK) {
10398 xmlFree(name);
10399 xmlFree(prefix);
10400 return;
10401 }
10402 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10403 nbargs++;
10404 if (CUR == ')') break;
10405 if (CUR != ',') {
10406 xmlFree(name);
10407 xmlFree(prefix);
10408 XP_ERROR(XPATH_EXPR_ERROR);
10409 }
10410 NEXT;
10412 }
10413 }
10414 if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
10415 xmlFree(prefix);
10416 xmlFree(name);
10417 }
10418 NEXT;
10420}
10421
10434static void
10435xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10437 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10438 else if (CUR == '(') {
10439 NEXT;
10441 xmlXPathCompileExpr(ctxt, 1);
10442 CHECK_ERROR;
10443 if (CUR != ')') {
10444 XP_ERROR(XPATH_EXPR_ERROR);
10445 }
10446 NEXT;
10448 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10449 xmlXPathCompNumber(ctxt);
10450 } else if ((CUR == '\'') || (CUR == '"')) {
10451 xmlXPathCompLiteral(ctxt);
10452 } else {
10453 xmlXPathCompFunctionCall(ctxt);
10454 }
10456}
10457
10473static void
10474xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10475 xmlXPathCompPrimaryExpr(ctxt);
10476 CHECK_ERROR;
10478
10479 while (CUR == '[') {
10480 xmlXPathCompPredicate(ctxt, 1);
10482 }
10483
10484
10485}
10486
10504static xmlChar *
10505xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10506 int l;
10507 int c;
10508 const xmlChar *cur;
10509 xmlChar *ret;
10510
10511 cur = ctxt->cur;
10512
10513 c = CUR_CHAR(l);
10514 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10515 (!IS_LETTER(c) && (c != '_') &&
10516 (c != ':'))) {
10517 return(NULL);
10518 }
10519
10520 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10521 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10522 (c == '.') || (c == '-') ||
10523 (c == '_') || (c == ':') ||
10524 (IS_COMBINING(c)) ||
10525 (IS_EXTENDER(c)))) {
10526 NEXTL(l);
10527 c = CUR_CHAR(l);
10528 }
10529 ret = xmlStrndup(cur, ctxt->cur - cur);
10530 ctxt->cur = cur;
10531 return(ret);
10532}
10533
10552static void
10553xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10554 int lc = 1; /* Should we branch to LocationPath ? */
10555 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10556
10558 if ((CUR == '$') || (CUR == '(') ||
10559 (IS_ASCII_DIGIT(CUR)) ||
10560 (CUR == '\'') || (CUR == '"') ||
10561 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10562 lc = 0;
10563 } else if (CUR == '*') {
10564 /* relative or absolute location path */
10565 lc = 1;
10566 } else if (CUR == '/') {
10567 /* relative or absolute location path */
10568 lc = 1;
10569 } else if (CUR == '@') {
10570 /* relative abbreviated attribute location path */
10571 lc = 1;
10572 } else if (CUR == '.') {
10573 /* relative abbreviated attribute location path */
10574 lc = 1;
10575 } else {
10576 /*
10577 * Problem is finding if we have a name here whether it's:
10578 * - a nodetype
10579 * - a function call in which case it's followed by '('
10580 * - an axis in which case it's followed by ':'
10581 * - a element name
10582 * We do an a priori analysis here rather than having to
10583 * maintain parsed token content through the recursive function
10584 * calls. This looks uglier but makes the code easier to
10585 * read/write/debug.
10586 */
10588 name = xmlXPathScanName(ctxt);
10589 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10590#ifdef DEBUG_STEP
10592 "PathExpr: Axis\n");
10593#endif
10594 lc = 1;
10595 xmlFree(name);
10596 } else if (name != NULL) {
10597 int len =xmlStrlen(name);
10598
10599
10600 while (NXT(len) != 0) {
10601 if (NXT(len) == '/') {
10602 /* element name */
10603#ifdef DEBUG_STEP
10605 "PathExpr: AbbrRelLocation\n");
10606#endif
10607 lc = 1;
10608 break;
10609 } else if (IS_BLANK_CH(NXT(len))) {
10610 /* ignore blanks */
10611 ;
10612 } else if (NXT(len) == ':') {
10613#ifdef DEBUG_STEP
10615 "PathExpr: AbbrRelLocation\n");
10616#endif
10617 lc = 1;
10618 break;
10619 } else if ((NXT(len) == '(')) {
10620 /* Node Type or Function */
10621 if (xmlXPathIsNodeType(name)) {
10622#ifdef DEBUG_STEP
10624 "PathExpr: Type search\n");
10625#endif
10626 lc = 1;
10627#ifdef LIBXML_XPTR_LOCS_ENABLED
10628 } else if (ctxt->xptr &&
10629 xmlStrEqual(name, BAD_CAST "range-to")) {
10630 lc = 1;
10631#endif
10632 } else {
10633#ifdef DEBUG_STEP
10635 "PathExpr: function call\n");
10636#endif
10637 lc = 0;
10638 }
10639 break;
10640 } else if ((NXT(len) == '[')) {
10641 /* element name */
10642#ifdef DEBUG_STEP
10644 "PathExpr: AbbrRelLocation\n");
10645#endif
10646 lc = 1;
10647 break;
10648 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10649 (NXT(len) == '=')) {
10650 lc = 1;
10651 break;
10652 } else {
10653 lc = 1;
10654 break;
10655 }
10656 len++;
10657 }
10658 if (NXT(len) == 0) {
10659#ifdef DEBUG_STEP
10661 "PathExpr: AbbrRelLocation\n");
10662#endif
10663 /* element name */
10664 lc = 1;
10665 }
10666 xmlFree(name);
10667 } else {
10668 /* make sure all cases are covered explicitly */
10669 XP_ERROR(XPATH_EXPR_ERROR);
10670 }
10671 }
10672
10673 if (lc) {
10674 if (CUR == '/') {
10675 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10676 } else {
10677 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10678 }
10679 xmlXPathCompLocationPath(ctxt);
10680 } else {
10681 xmlXPathCompFilterExpr(ctxt);
10682 CHECK_ERROR;
10683 if ((CUR == '/') && (NXT(1) == '/')) {
10684 SKIP(2);
10686
10687 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10688 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10689
10690 xmlXPathCompRelativeLocationPath(ctxt);
10691 } else if (CUR == '/') {
10692 xmlXPathCompRelativeLocationPath(ctxt);
10693 }
10694 }
10696}
10697
10708static void
10709xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10710 xmlXPathCompPathExpr(ctxt);
10711 CHECK_ERROR;
10713 while (CUR == '|') {
10714 int op1 = ctxt->comp->last;
10715 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10716
10717 NEXT;
10719 xmlXPathCompPathExpr(ctxt);
10720
10721 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10722
10724 }
10725}
10726
10737static void
10738xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10739 int minus = 0;
10740 int found = 0;
10741
10743 while (CUR == '-') {
10744 minus = 1 - minus;
10745 found = 1;
10746 NEXT;
10748 }
10749
10750 xmlXPathCompUnionExpr(ctxt);
10751 CHECK_ERROR;
10752 if (found) {
10753 if (minus)
10754 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10755 else
10756 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10757 }
10758}
10759
10773static void
10774xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10775 xmlXPathCompUnaryExpr(ctxt);
10776 CHECK_ERROR;
10778 while ((CUR == '*') ||
10779 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10780 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10781 int op = -1;
10782 int op1 = ctxt->comp->last;
10783
10784 if (CUR == '*') {
10785 op = 0;
10786 NEXT;
10787 } else if (CUR == 'd') {
10788 op = 1;
10789 SKIP(3);
10790 } else if (CUR == 'm') {
10791 op = 2;
10792 SKIP(3);
10793 }
10795 xmlXPathCompUnaryExpr(ctxt);
10796 CHECK_ERROR;
10797 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10799 }
10800}
10801
10813static void
10814xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10815
10816 xmlXPathCompMultiplicativeExpr(ctxt);
10817 CHECK_ERROR;
10819 while ((CUR == '+') || (CUR == '-')) {
10820 int plus;
10821 int op1 = ctxt->comp->last;
10822
10823 if (CUR == '+') plus = 1;
10824 else plus = 0;
10825 NEXT;
10827 xmlXPathCompMultiplicativeExpr(ctxt);
10828 CHECK_ERROR;
10829 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10831 }
10832}
10833
10852static void
10853xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10854 xmlXPathCompAdditiveExpr(ctxt);
10855 CHECK_ERROR;
10857 while ((CUR == '<') || (CUR == '>')) {
10858 int inf, strict;
10859 int op1 = ctxt->comp->last;
10860
10861 if (CUR == '<') inf = 1;
10862 else inf = 0;
10863 if (NXT(1) == '=') strict = 0;
10864 else strict = 1;
10865 NEXT;
10866 if (!strict) NEXT;
10868 xmlXPathCompAdditiveExpr(ctxt);
10869 CHECK_ERROR;
10870 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10872 }
10873}
10874
10891static void
10892xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10893 xmlXPathCompRelationalExpr(ctxt);
10894 CHECK_ERROR;
10896 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10897 int eq;
10898 int op1 = ctxt->comp->last;
10899
10900 if (CUR == '=') eq = 1;
10901 else eq = 0;
10902 NEXT;
10903 if (!eq) NEXT;
10905 xmlXPathCompRelationalExpr(ctxt);
10906 CHECK_ERROR;
10907 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10909 }
10910}
10911
10922static void
10923xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10924 xmlXPathCompEqualityExpr(ctxt);
10925 CHECK_ERROR;
10927 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10928 int op1 = ctxt->comp->last;
10929 SKIP(3);
10931 xmlXPathCompEqualityExpr(ctxt);
10932 CHECK_ERROR;
10933 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10935 }
10936}
10937
10948static void
10949xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10950 xmlXPathContextPtr xpctxt = ctxt->context;
10951
10952 if (xpctxt != NULL) {
10953 if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10954 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10955 /*
10956 * Parsing a single '(' pushes about 10 functions on the call stack
10957 * before recursing!
10958 */
10959 xpctxt->depth += 10;
10960 }
10961
10962 xmlXPathCompAndExpr(ctxt);
10963 CHECK_ERROR;
10965 while ((CUR == 'o') && (NXT(1) == 'r')) {
10966 int op1 = ctxt->comp->last;
10967 SKIP(2);
10969 xmlXPathCompAndExpr(ctxt);
10970 CHECK_ERROR;
10971 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10973 }
10974 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10975 /* more ops could be optimized too */
10976 /*
10977 * This is the main place to eliminate sorting for
10978 * operations which don't require a sorted node-set.
10979 * E.g. count().
10980 */
10981 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10982 }
10983
10984 if (xpctxt != NULL)
10985 xpctxt->depth -= 10;
10986}
10987
10998static void
10999xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11000 int op1 = ctxt->comp->last;
11001
11003 if (CUR != '[') {
11004 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11005 }
11006 NEXT;
11008
11009 ctxt->comp->last = -1;
11010 /*
11011 * This call to xmlXPathCompileExpr() will deactivate sorting
11012 * of the predicate result.
11013 * TODO: Sorting is still activated for filters, since I'm not
11014 * sure if needed. Normally sorting should not be needed, since
11015 * a filter can only diminish the number of items in a sequence,
11016 * but won't change its order; so if the initial sequence is sorted,
11017 * subsequent sorting is not needed.
11018 */
11019 if (! filter)
11020 xmlXPathCompileExpr(ctxt, 0);
11021 else
11022 xmlXPathCompileExpr(ctxt, 1);
11023 CHECK_ERROR;
11024
11025 if (CUR != ']') {
11026 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11027 }
11028
11029 if (filter)
11030 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11031 else
11032 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11033
11034 NEXT;
11036}
11037
11059static xmlChar *
11060xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11061 xmlXPathTypeVal *type, xmlChar **prefix,
11062 xmlChar *name) {
11063 int blanks;
11064
11065 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11066 STRANGE;
11067 return(NULL);
11068 }
11069 *type = (xmlXPathTypeVal) 0;
11070 *test = (xmlXPathTestVal) 0;
11071 *prefix = NULL;
11073
11074 if ((name == NULL) && (CUR == '*')) {
11075 /*
11076 * All elements
11077 */
11078 NEXT;
11079 *test = NODE_TEST_ALL;
11080 return(NULL);
11081 }
11082
11083 if (name == NULL)
11084 name = xmlXPathParseNCName(ctxt);
11085 if (name == NULL) {
11086 XP_ERRORNULL(XPATH_EXPR_ERROR);
11087 }
11088
11089 blanks = IS_BLANK_CH(CUR);
11091 if (CUR == '(') {
11092 NEXT;
11093 /*
11094 * NodeType or PI search
11095 */
11096 if (xmlStrEqual(name, BAD_CAST "comment"))
11097 *type = NODE_TYPE_COMMENT;
11098 else if (xmlStrEqual(name, BAD_CAST "node"))
11099 *type = NODE_TYPE_NODE;
11100 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11101 *type = NODE_TYPE_PI;
11102 else if (xmlStrEqual(name, BAD_CAST "text"))
11103 *type = NODE_TYPE_TEXT;
11104 else {
11105 if (name != NULL)
11106 xmlFree(name);
11107 XP_ERRORNULL(XPATH_EXPR_ERROR);
11108 }
11109
11110 *test = NODE_TEST_TYPE;
11111
11113 if (*type == NODE_TYPE_PI) {
11114 /*
11115 * Specific case: search a PI by name.
11116 */
11117 if (name != NULL)
11118 xmlFree(name);
11119 name = NULL;
11120 if (CUR != ')') {
11121 name = xmlXPathParseLiteral(ctxt);
11122 if (name == NULL) {
11123 XP_ERRORNULL(XPATH_EXPR_ERROR);
11124 }
11125 *test = NODE_TEST_PI;
11127 }
11128 }
11129 if (CUR != ')') {
11130 if (name != NULL)
11131 xmlFree(name);
11132 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11133 }
11134 NEXT;
11135 return(name);
11136 }
11137 *test = NODE_TEST_NAME;
11138 if ((!blanks) && (CUR == ':')) {
11139 NEXT;
11140
11141 /*
11142 * Since currently the parser context don't have a
11143 * namespace list associated:
11144 * The namespace name for this prefix can be computed
11145 * only at evaluation time. The compilation is done
11146 * outside of any context.
11147 */
11148#if 0
11149 *prefix = xmlXPathNsLookup(ctxt->context, name);
11150 if (name != NULL)
11151 xmlFree(name);
11152 if (*prefix == NULL) {
11153 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11154 }
11155#else
11156 *prefix = name;
11157#endif
11158
11159 if (CUR == '*') {
11160 /*
11161 * All elements
11162 */
11163 NEXT;
11164 *test = NODE_TEST_ALL;
11165 return(NULL);
11166 }
11167
11168 name = xmlXPathParseNCName(ctxt);
11169 if (name == NULL) {
11170 XP_ERRORNULL(XPATH_EXPR_ERROR);
11171 }
11172 }
11173 return(name);
11174}
11175
11196static xmlXPathAxisVal
11197xmlXPathIsAxisName(const xmlChar *name) {
11198 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11199 switch (name[0]) {
11200 case 'a':
11201 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11202 ret = AXIS_ANCESTOR;
11203 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11204 ret = AXIS_ANCESTOR_OR_SELF;
11205 if (xmlStrEqual(name, BAD_CAST "attribute"))
11207 break;
11208 case 'c':
11209 if (xmlStrEqual(name, BAD_CAST "child"))
11210 ret = AXIS_CHILD;
11211 break;
11212 case 'd':
11213 if (xmlStrEqual(name, BAD_CAST "descendant"))
11214 ret = AXIS_DESCENDANT;
11215 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11216 ret = AXIS_DESCENDANT_OR_SELF;
11217 break;
11218 case 'f':
11219 if (xmlStrEqual(name, BAD_CAST "following"))
11220 ret = AXIS_FOLLOWING;
11221 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11222 ret = AXIS_FOLLOWING_SIBLING;
11223 break;
11224 case 'n':
11225 if (xmlStrEqual(name, BAD_CAST "namespace"))
11226 ret = AXIS_NAMESPACE;
11227 break;
11228 case 'p':
11229 if (xmlStrEqual(name, BAD_CAST "parent"))
11230 ret = AXIS_PARENT;
11231 if (xmlStrEqual(name, BAD_CAST "preceding"))
11232 ret = AXIS_PRECEDING;
11233 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11234 ret = AXIS_PRECEDING_SIBLING;
11235 break;
11236 case 's':
11237 if (xmlStrEqual(name, BAD_CAST "self"))
11238 ret = AXIS_SELF;
11239 break;
11240 }
11241 return(ret);
11242}
11243
11276static void
11277xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11278#ifdef LIBXML_XPTR_LOCS_ENABLED
11279 int rangeto = 0;
11280 int op2 = -1;
11281#endif
11282
11284 if ((CUR == '.') && (NXT(1) == '.')) {
11285 SKIP(2);
11287 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11288 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11289 } else if (CUR == '.') {
11290 NEXT;
11292 } else {
11293 xmlChar *name = NULL;
11294 xmlChar *prefix = NULL;
11295 xmlXPathTestVal test = (xmlXPathTestVal) 0;
11296 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11297 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11298 int op1;
11299
11300 /*
11301 * The modification needed for XPointer change to the production
11302 */
11303#ifdef LIBXML_XPTR_LOCS_ENABLED
11304 if (ctxt->xptr) {
11305 name = xmlXPathParseNCName(ctxt);
11306 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11307 op2 = ctxt->comp->last;
11308 xmlFree(name);
11310 if (CUR != '(') {
11311 XP_ERROR(XPATH_EXPR_ERROR);
11312 }
11313 NEXT;
11315
11316 xmlXPathCompileExpr(ctxt, 1);
11317 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11318 CHECK_ERROR;
11319
11321 if (CUR != ')') {
11322 XP_ERROR(XPATH_EXPR_ERROR);
11323 }
11324 NEXT;
11325 rangeto = 1;
11326 goto eval_predicates;
11327 }
11328 }
11329#endif
11330 if (CUR == '*') {
11331 axis = AXIS_CHILD;
11332 } else {
11333 if (name == NULL)
11334 name = xmlXPathParseNCName(ctxt);
11335 if (name != NULL) {
11336 axis = xmlXPathIsAxisName(name);
11337 if (axis != 0) {
11339 if ((CUR == ':') && (NXT(1) == ':')) {
11340 SKIP(2);
11341 xmlFree(name);
11342 name = NULL;
11343 } else {
11344 /* an element name can conflict with an axis one :-\ */
11345 axis = AXIS_CHILD;
11346 }
11347 } else {
11348 axis = AXIS_CHILD;
11349 }
11350 } else if (CUR == '@') {
11351 NEXT;
11352 axis = AXIS_ATTRIBUTE;
11353 } else {
11354 axis = AXIS_CHILD;
11355 }
11356 }
11357
11358 if (ctxt->error != XPATH_EXPRESSION_OK) {
11359 xmlFree(name);
11360 return;
11361 }
11362
11363 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11364 if (test == 0)
11365 return;
11366
11367 if ((prefix != NULL) && (ctxt->context != NULL) &&
11368 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11369 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11370 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11371 }
11372 }
11373#ifdef DEBUG_STEP
11375 "Basis : computing new set\n");
11376#endif
11377
11378#ifdef DEBUG_STEP
11380 if (ctxt->value == NULL)
11382 else if (ctxt->value->nodesetval == NULL)
11384 else
11385 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11386#endif
11387
11388#ifdef LIBXML_XPTR_LOCS_ENABLED
11389eval_predicates:
11390#endif
11391 op1 = ctxt->comp->last;
11392 ctxt->comp->last = -1;
11393
11395 while (CUR == '[') {
11396 xmlXPathCompPredicate(ctxt, 0);
11397 }
11398
11399#ifdef LIBXML_XPTR_LOCS_ENABLED
11400 if (rangeto) {
11401 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11402 } else
11403#endif
11404 if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11405 test, type, (void *)prefix, (void *)name) == -1) {
11406 xmlFree(prefix);
11407 xmlFree(name);
11408 }
11409 }
11410#ifdef DEBUG_STEP
11412 if (ctxt->value == NULL)
11414 else if (ctxt->value->nodesetval == NULL)
11416 else
11417 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11418 ctxt->value->nodesetval);
11419#endif
11420}
11421
11433static void
11434xmlXPathCompRelativeLocationPath
11435(xmlXPathParserContextPtr ctxt) {
11437 if ((CUR == '/') && (NXT(1) == '/')) {
11438 SKIP(2);
11440 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11441 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11442 } else if (CUR == '/') {
11443 NEXT;
11445 }
11446 xmlXPathCompStep(ctxt);
11447 CHECK_ERROR;
11449 while (CUR == '/') {
11450 if ((CUR == '/') && (NXT(1) == '/')) {
11451 SKIP(2);
11453 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11454 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11455 xmlXPathCompStep(ctxt);
11456 } else if (CUR == '/') {
11457 NEXT;
11459 xmlXPathCompStep(ctxt);
11460 }
11462 }
11463}
11464
11486static void
11487xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11489 if (CUR != '/') {
11490 xmlXPathCompRelativeLocationPath(ctxt);
11491 } else {
11492 while (CUR == '/') {
11493 if ((CUR == '/') && (NXT(1) == '/')) {
11494 SKIP(2);
11496 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11497 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11498 xmlXPathCompRelativeLocationPath(ctxt);
11499 } else if (CUR == '/') {
11500 NEXT;
11502 if ((CUR != 0 ) &&
11503 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11504 (CUR == '@') || (CUR == '*')))
11505 xmlXPathCompRelativeLocationPath(ctxt);
11506 }
11507 CHECK_ERROR;
11508 }
11509 }
11510}
11511
11512/************************************************************************
11513 * *
11514 * XPath precompiled expression evaluation *
11515 * *
11516 ************************************************************************/
11517
11518static int
11519xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11520
11521#ifdef DEBUG_STEP
11522static void
11523xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11524 int nbNodes)
11525{
11527 switch (op->value) {
11528 case AXIS_ANCESTOR:
11529 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11530 break;
11531 case AXIS_ANCESTOR_OR_SELF:
11533 "axis 'ancestors-or-self' ");
11534 break;
11535 case AXIS_ATTRIBUTE:
11536 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11537 break;
11538 case AXIS_CHILD:
11539 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11540 break;
11541 case AXIS_DESCENDANT:
11542 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11543 break;
11544 case AXIS_DESCENDANT_OR_SELF:
11546 "axis 'descendant-or-self' ");
11547 break;
11548 case AXIS_FOLLOWING:
11549 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11550 break;
11551 case AXIS_FOLLOWING_SIBLING:
11553 "axis 'following-siblings' ");
11554 break;
11555 case AXIS_NAMESPACE:
11556 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11557 break;
11558 case AXIS_PARENT:
11559 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11560 break;
11561 case AXIS_PRECEDING:
11562 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11563 break;
11564 case AXIS_PRECEDING_SIBLING:
11566 "axis 'preceding-sibling' ");
11567 break;
11568 case AXIS_SELF:
11569 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11570 break;
11571 }
11573 " context contains %d nodes\n", nbNodes);
11574 switch (op->value2) {
11575 case NODE_TEST_NONE:
11577 " searching for none !!!\n");
11578 break;
11579 case NODE_TEST_TYPE:
11581 " searching for type %d\n", op->value3);
11582 break;
11583 case NODE_TEST_PI:
11585 " searching for PI !!!\n");
11586 break;
11587 case NODE_TEST_ALL:
11589 " searching for *\n");
11590 break;
11591 case NODE_TEST_NS:
11593 " searching for namespace %s\n",
11594 op->value5);
11595 break;
11596 case NODE_TEST_NAME:
11598 " searching for name %s\n", op->value5);
11599 if (op->value4)
11601 " with namespace %s\n", op->value4);
11602 break;
11603 }
11605}
11606#endif /* DEBUG_STEP */
11607
11621static void
11622xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11623 xmlNodeSetPtr set,
11624 int filterOpIndex,
11625 int minPos, int maxPos,
11626 int hasNsNodes)
11627{
11628 xmlXPathContextPtr xpctxt;
11629 xmlNodePtr oldnode;
11630 xmlDocPtr olddoc;
11631 xmlXPathStepOpPtr filterOp;
11632 int oldcs, oldpp;
11633 int i, j, pos;
11634
11635 if ((set == NULL) || (set->nodeNr == 0))
11636 return;
11637
11638 /*
11639 * Check if the node set contains a sufficient number of nodes for
11640 * the requested range.
11641 */
11642 if (set->nodeNr < minPos) {
11643 xmlXPathNodeSetClear(set, hasNsNodes);
11644 return;
11645 }
11646
11647 xpctxt = ctxt->context;
11648 oldnode = xpctxt->node;
11649 olddoc = xpctxt->doc;
11650 oldcs = xpctxt->contextSize;
11651 oldpp = xpctxt->proximityPosition;
11652 filterOp = &ctxt->comp->steps[filterOpIndex];
11653
11654 xpctxt->contextSize = set->nodeNr;
11655
11656 for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11657 xmlNodePtr node = set->nodeTab[i];
11658 int res;
11659
11660 xpctxt->node = node;
11661 xpctxt->proximityPosition = i + 1;
11662
11663 /*
11664 * Also set the xpath document in case things like
11665 * key() are evaluated in the predicate.
11666 *
11667 * TODO: Get real doc for namespace nodes.
11668 */
11669 if ((node->type != XML_NAMESPACE_DECL) &&
11670 (node->doc != NULL))
11671 xpctxt->doc = node->doc;
11672
11673 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11674
11675 if (ctxt->error != XPATH_EXPRESSION_OK)
11676 break;
11677 if (res < 0) {
11678 /* Shouldn't happen */
11679 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11680 break;
11681 }
11682
11683 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11684 if (i != j) {
11685 set->nodeTab[j] = node;
11686 set->nodeTab[i] = NULL;
11687 }
11688
11689 j += 1;
11690 } else {
11691 /* Remove the entry from the initial node set. */
11692 set->nodeTab[i] = NULL;
11693 if (node->type == XML_NAMESPACE_DECL)
11694 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11695 }
11696
11697 if (res != 0) {
11698 if (pos == maxPos) {
11699 i += 1;
11700 break;
11701 }
11702
11703 pos += 1;
11704 }
11705 }
11706
11707 /* Free remaining nodes. */
11708 if (hasNsNodes) {
11709 for (; i < set->nodeNr; i++) {
11710 xmlNodePtr node = set->nodeTab[i];
11711 if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11712 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11713 }
11714 }
11715
11716 set->nodeNr = j;
11717
11718 /* If too many elements were removed, shrink table to preserve memory. */
11719 if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11720 (set->nodeNr < set->nodeMax / 2)) {
11721 xmlNodePtr *tmp;
11722 int nodeMax = set->nodeNr;
11723
11724 if (nodeMax < XML_NODESET_DEFAULT)
11725 nodeMax = XML_NODESET_DEFAULT;
11726 tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11727 nodeMax * sizeof(xmlNodePtr));
11728 if (tmp == NULL) {
11729 xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11730 } else {
11731 set->nodeTab = tmp;
11732 set->nodeMax = nodeMax;
11733 }
11734 }
11735
11736 xpctxt->node = oldnode;
11737 xpctxt->doc = olddoc;
11738 xpctxt->contextSize = oldcs;
11739 xpctxt->proximityPosition = oldpp;
11740}
11741
11742#ifdef LIBXML_XPTR_LOCS_ENABLED
11755static void
11756xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11757 xmlLocationSetPtr locset,
11758 int filterOpIndex,
11759 int minPos, int maxPos)
11760{
11761 xmlXPathContextPtr xpctxt;
11762 xmlNodePtr oldnode;
11763 xmlDocPtr olddoc;
11764 xmlXPathStepOpPtr filterOp;
11765 int oldcs, oldpp;
11766 int i, j, pos;
11767
11768 if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11769 return;
11770
11771 xpctxt = ctxt->context;
11772 oldnode = xpctxt->node;
11773 olddoc = xpctxt->doc;
11774 oldcs = xpctxt->contextSize;
11775 oldpp = xpctxt->proximityPosition;
11776 filterOp = &ctxt->comp->steps[filterOpIndex];
11777
11778 xpctxt->contextSize = locset->locNr;
11779
11780 for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11781 xmlNodePtr contextNode = locset->locTab[i]->user;
11782 int res;
11783
11784 xpctxt->node = contextNode;
11785 xpctxt->proximityPosition = i + 1;
11786
11787 /*
11788 * Also set the xpath document in case things like
11789 * key() are evaluated in the predicate.
11790 *
11791 * TODO: Get real doc for namespace nodes.
11792 */
11793 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11794 (contextNode->doc != NULL))
11795 xpctxt->doc = contextNode->doc;
11796
11797 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11798
11799 if (ctxt->error != XPATH_EXPRESSION_OK)
11800 break;
11801 if (res < 0) {
11802 /* Shouldn't happen */
11803 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11804 break;
11805 }
11806
11807 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11808 if (i != j) {
11809 locset->locTab[j] = locset->locTab[i];
11810 locset->locTab[i] = NULL;
11811 }
11812
11813 j += 1;
11814 } else {
11815 /* Remove the entry from the initial location set. */
11816 xmlXPathFreeObject(locset->locTab[i]);
11817 locset->locTab[i] = NULL;
11818 }
11819
11820 if (res != 0) {
11821 if (pos == maxPos) {
11822 i += 1;
11823 break;
11824 }
11825
11826 pos += 1;
11827 }
11828 }
11829
11830 /* Free remaining nodes. */
11831 for (; i < locset->locNr; i++)
11832 xmlXPathFreeObject(locset->locTab[i]);
11833
11834 locset->locNr = j;
11835
11836 /* If too many elements were removed, shrink table to preserve memory. */
11837 if ((locset->locMax > XML_NODESET_DEFAULT) &&
11838 (locset->locNr < locset->locMax / 2)) {
11839 xmlXPathObjectPtr *tmp;
11840 int locMax = locset->locNr;
11841
11842 if (locMax < XML_NODESET_DEFAULT)
11843 locMax = XML_NODESET_DEFAULT;
11844 tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11845 locMax * sizeof(xmlXPathObjectPtr));
11846 if (tmp == NULL) {
11847 xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11848 } else {
11849 locset->locTab = tmp;
11850 locset->locMax = locMax;
11851 }
11852 }
11853
11854 xpctxt->node = oldnode;
11855 xpctxt->doc = olddoc;
11856 xpctxt->contextSize = oldcs;
11857 xpctxt->proximityPosition = oldpp;
11858}
11859#endif /* LIBXML_XPTR_LOCS_ENABLED */
11860
11874static void
11875xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11876 xmlXPathStepOpPtr op,
11877 xmlNodeSetPtr set,
11878 int minPos, int maxPos,
11879 int hasNsNodes)
11880{
11881 if (op->ch1 != -1) {
11882 xmlXPathCompExprPtr comp = ctxt->comp;
11883 /*
11884 * Process inner predicates first.
11885 */
11886 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11888 "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11889 XP_ERROR(XPATH_INVALID_OPERAND);
11890 }
11891 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11892 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11893 ctxt->context->depth += 1;
11894 xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11895 1, set->nodeNr, hasNsNodes);
11896 ctxt->context->depth -= 1;
11897 CHECK_ERROR;
11898 }
11899
11900 if (op->ch2 != -1)
11901 xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11902}
11903
11904static int
11905xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11906 xmlXPathStepOpPtr op,
11907 int *maxPos)
11908{
11909
11910 xmlXPathStepOpPtr exprOp;
11911
11912 /*
11913 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11914 */
11915
11916 /*
11917 * If not -1, then ch1 will point to:
11918 * 1) For predicates (XPATH_OP_PREDICATE):
11919 * - an inner predicate operator
11920 * 2) For filters (XPATH_OP_FILTER):
11921 * - an inner filter operator OR
11922 * - an expression selecting the node set.
11923 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11924 */
11925 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11926 return(0);
11927
11928 if (op->ch2 != -1) {
11929 exprOp = &ctxt->comp->steps[op->ch2];
11930 } else
11931 return(0);
11932
11933 if ((exprOp != NULL) &&
11934 (exprOp->op == XPATH_OP_VALUE) &&
11935 (exprOp->value4 != NULL) &&
11936 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11937 {
11938 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11939
11940 /*
11941 * We have a "[n]" predicate here.
11942 * TODO: Unfortunately this simplistic test here is not
11943 * able to detect a position() predicate in compound
11944 * expressions like "[@attr = 'a" and position() = 1],
11945 * and even not the usage of position() in
11946 * "[position() = 1]"; thus - obviously - a position-range,
11947 * like it "[position() < 5]", is also not detected.
11948 * Maybe we could rewrite the AST to ease the optimization.
11949 */
11950
11951 if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11952 *maxPos = (int) floatval;
11953 if (floatval == (double) *maxPos)
11954 return(1);
11955 }
11956 }
11957 return(0);
11958}
11959
11960static int
11961xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11962 xmlXPathStepOpPtr op,
11964 int toBool)
11965{
11966
11967#define XP_TEST_HIT \
11968 if (hasAxisRange != 0) { \
11969 if (++pos == maxPos) { \
11970 if (addNode(seq, cur) < 0) \
11971 ctxt->error = XPATH_MEMORY_ERROR; \
11972 goto axis_range_end; } \
11973 } else { \
11974 if (addNode(seq, cur) < 0) \
11975 ctxt->error = XPATH_MEMORY_ERROR; \
11976 if (breakOnFirstHit) goto first_hit; }
11977
11978#define XP_TEST_HIT_NS \
11979 if (hasAxisRange != 0) { \
11980 if (++pos == maxPos) { \
11981 hasNsNodes = 1; \
11982 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11983 ctxt->error = XPATH_MEMORY_ERROR; \
11984 goto axis_range_end; } \
11985 } else { \
11986 hasNsNodes = 1; \
11987 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11988 ctxt->error = XPATH_MEMORY_ERROR; \
11989 if (breakOnFirstHit) goto first_hit; }
11990
11991 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11992 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11993 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11994 const xmlChar *prefix = op->value4;
11995 const xmlChar *name = op->value5;
11996 const xmlChar *URI = NULL;
11997
11998#ifdef DEBUG_STEP
11999 int nbMatches = 0, prevMatches = 0;
12000#endif
12001 int total = 0, hasNsNodes = 0;
12002 /* The popped object holding the context nodes */
12003 xmlXPathObjectPtr obj;
12004 /* The set of context nodes for the node tests */
12005 xmlNodeSetPtr contextSeq;
12006 int contextIdx;
12007 xmlNodePtr contextNode;
12008 /* The final resulting node set wrt to all context nodes */
12009 xmlNodeSetPtr outSeq;
12010 /*
12011 * The temporary resulting node set wrt 1 context node.
12012 * Used to feed predicate evaluation.
12013 */
12014 xmlNodeSetPtr seq;
12016 /* First predicate operator */
12017 xmlXPathStepOpPtr predOp;
12018 int maxPos; /* The requested position() (when a "[n]" predicate) */
12019 int hasPredicateRange, hasAxisRange, pos;
12020 int breakOnFirstHit;
12021
12022 xmlXPathTraversalFunction next = NULL;
12023 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12024 xmlXPathNodeSetMergeFunction mergeAndClear;
12025 xmlNodePtr oldContextNode;
12026 xmlXPathContextPtr xpctxt = ctxt->context;
12027
12028
12029 CHECK_TYPE0(XPATH_NODESET);
12030 obj = valuePop(ctxt);
12031 /*
12032 * Setup namespaces.
12033 */
12034 if (prefix != NULL) {
12035 URI = xmlXPathNsLookup(xpctxt, prefix);
12036 if (URI == NULL) {
12037 xmlXPathReleaseObject(xpctxt, obj);
12038 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12039 }
12040 }
12041 /*
12042 * Setup axis.
12043 *
12044 * MAYBE FUTURE TODO: merging optimizations:
12045 * - If the nodes to be traversed wrt to the initial nodes and
12046 * the current axis cannot overlap, then we could avoid searching
12047 * for duplicates during the merge.
12048 * But the question is how/when to evaluate if they cannot overlap.
12049 * Example: if we know that for two initial nodes, the one is
12050 * not in the ancestor-or-self axis of the other, then we could safely
12051 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12052 * the descendant-or-self axis.
12053 */
12054 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12055 switch (axis) {
12056 case AXIS_ANCESTOR:
12057 first = NULL;
12058 next = xmlXPathNextAncestor;
12059 break;
12060 case AXIS_ANCESTOR_OR_SELF:
12061 first = NULL;
12062 next = xmlXPathNextAncestorOrSelf;
12063 break;
12064 case AXIS_ATTRIBUTE:
12065 first = NULL;
12066 last = NULL;
12067 next = xmlXPathNextAttribute;
12068 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12069 break;
12070 case AXIS_CHILD:
12071 last = NULL;
12072 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12073 (type == NODE_TYPE_NODE))
12074 {
12075 /*
12076 * Optimization if an element node type is 'element'.
12077 */
12078 next = xmlXPathNextChildElement;
12079 } else
12080 next = xmlXPathNextChild;
12081 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12082 break;
12083 case AXIS_DESCENDANT:
12084 last = NULL;
12085 next = xmlXPathNextDescendant;
12086 break;
12087 case AXIS_DESCENDANT_OR_SELF:
12088 last = NULL;
12089 next = xmlXPathNextDescendantOrSelf;
12090 break;
12091 case AXIS_FOLLOWING:
12092 last = NULL;
12093 next = xmlXPathNextFollowing;
12094 break;
12095 case AXIS_FOLLOWING_SIBLING:
12096 last = NULL;
12097 next = xmlXPathNextFollowingSibling;
12098 break;
12099 case AXIS_NAMESPACE:
12100 first = NULL;
12101 last = NULL;
12102 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12103 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12104 break;
12105 case AXIS_PARENT:
12106 first = NULL;
12107 next = xmlXPathNextParent;
12108 break;
12109 case AXIS_PRECEDING:
12110 first = NULL;
12111 next = xmlXPathNextPrecedingInternal;
12112 break;
12113 case AXIS_PRECEDING_SIBLING:
12114 first = NULL;
12115 next = xmlXPathNextPrecedingSibling;
12116 break;
12117 case AXIS_SELF:
12118 first = NULL;
12119 last = NULL;
12120 next = xmlXPathNextSelf;
12121 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12122 break;
12123 }
12124
12125#ifdef DEBUG_STEP
12126 xmlXPathDebugDumpStepAxis(op,
12127 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12128#endif
12129
12130 if (next == NULL) {
12131 xmlXPathReleaseObject(xpctxt, obj);
12132 return(0);
12133 }
12134 contextSeq = obj->nodesetval;
12135 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12136 xmlXPathReleaseObject(xpctxt, obj);
12137 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12138 return(0);
12139 }
12140 /*
12141 * Predicate optimization ---------------------------------------------
12142 * If this step has a last predicate, which contains a position(),
12143 * then we'll optimize (although not exactly "position()", but only
12144 * the short-hand form, i.e., "[n]".
12145 *
12146 * Example - expression "/foo[parent::bar][1]":
12147 *
12148 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12149 * ROOT -- op->ch1
12150 * PREDICATE -- op->ch2 (predOp)
12151 * PREDICATE -- predOp->ch1 = [parent::bar]
12152 * SORT
12153 * COLLECT 'parent' 'name' 'node' bar
12154 * NODE
12155 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12156 *
12157 */
12158 maxPos = 0;
12159 predOp = NULL;
12160 hasPredicateRange = 0;
12161 hasAxisRange = 0;
12162 if (op->ch2 != -1) {
12163 /*
12164 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12165 */
12166 predOp = &ctxt->comp->steps[op->ch2];
12167 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12168 if (predOp->ch1 != -1) {
12169 /*
12170 * Use the next inner predicate operator.
12171 */
12172 predOp = &ctxt->comp->steps[predOp->ch1];
12173 hasPredicateRange = 1;
12174 } else {
12175 /*
12176 * There's no other predicate than the [n] predicate.
12177 */
12178 predOp = NULL;
12179 hasAxisRange = 1;
12180 }
12181 }
12182 }
12183 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12184 /*
12185 * Axis traversal -----------------------------------------------------
12186 */
12187 /*
12188 * 2.3 Node Tests
12189 * - For the attribute axis, the principal node type is attribute.
12190 * - For the namespace axis, the principal node type is namespace.
12191 * - For other axes, the principal node type is element.
12192 *
12193 * A node test * is true for any node of the
12194 * principal node type. For example, child::* will
12195 * select all element children of the context node
12196 */
12197 oldContextNode = xpctxt->node;
12198 addNode = xmlXPathNodeSetAddUnique;
12199 outSeq = NULL;
12200 seq = NULL;
12201 contextNode = NULL;
12202 contextIdx = 0;
12203
12204
12205 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12206 (ctxt->error == XPATH_EXPRESSION_OK)) {
12207 xpctxt->node = contextSeq->nodeTab[contextIdx++];
12208
12209 if (seq == NULL) {
12210 seq = xmlXPathNodeSetCreate(NULL);
12211 if (seq == NULL) {
12212 /* TODO: Propagate memory error. */
12213 total = 0;
12214 goto error;
12215 }
12216 }
12217 /*
12218 * Traverse the axis and test the nodes.
12219 */
12220 pos = 0;
12221 cur = NULL;
12222 hasNsNodes = 0;
12223 do {
12224 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12225 goto error;
12226
12227 cur = next(ctxt, cur);
12228 if (cur == NULL)
12229 break;
12230
12231 /*
12232 * QUESTION TODO: What does the "first" and "last" stuff do?
12233 */
12234 if ((first != NULL) && (*first != NULL)) {
12235 if (*first == cur)
12236 break;
12237 if (((total % 256) == 0) &&
12239 (xmlXPathCmpNodesExt(*first, cur) >= 0))
12240#else
12241 (xmlXPathCmpNodes(*first, cur) >= 0))
12242#endif
12243 {
12244 break;
12245 }
12246 }
12247 if ((last != NULL) && (*last != NULL)) {
12248 if (*last == cur)
12249 break;
12250 if (((total % 256) == 0) &&
12252 (xmlXPathCmpNodesExt(cur, *last) >= 0))
12253#else
12254 (xmlXPathCmpNodes(cur, *last) >= 0))
12255#endif
12256 {
12257 break;
12258 }
12259 }
12260
12261 total++;
12262
12263#ifdef DEBUG_STEP
12265#endif
12266
12267 switch (test) {
12268 case NODE_TEST_NONE:
12269 total = 0;
12270 STRANGE
12271 goto error;
12272 case NODE_TEST_TYPE:
12273 if (type == NODE_TYPE_NODE) {
12274 switch (cur->type) {
12275 case XML_DOCUMENT_NODE:
12277 case XML_ELEMENT_NODE:
12278 case XML_ATTRIBUTE_NODE:
12279 case XML_PI_NODE:
12280 case XML_COMMENT_NODE:
12282 case XML_TEXT_NODE:
12283 XP_TEST_HIT
12284 break;
12285 case XML_NAMESPACE_DECL: {
12286 if (axis == AXIS_NAMESPACE) {
12287 XP_TEST_HIT_NS
12288 } else {
12289 hasNsNodes = 1;
12290 XP_TEST_HIT
12291 }
12292 break;
12293 }
12294 default:
12295 break;
12296 }
12297 } else if (cur->type == (xmlElementType) type) {
12298 if (cur->type == XML_NAMESPACE_DECL)
12299 XP_TEST_HIT_NS
12300 else
12301 XP_TEST_HIT
12302 } else if ((type == NODE_TYPE_TEXT) &&
12303 (cur->type == XML_CDATA_SECTION_NODE))
12304 {
12305 XP_TEST_HIT
12306 }
12307 break;
12308 case NODE_TEST_PI:
12309 if ((cur->type == XML_PI_NODE) &&
12310 ((name == NULL) || xmlStrEqual(name, cur->name)))
12311 {
12312 XP_TEST_HIT
12313 }
12314 break;
12315 case NODE_TEST_ALL:
12316 if (axis == AXIS_ATTRIBUTE) {
12317 if (cur->type == XML_ATTRIBUTE_NODE)
12318 {
12319 if (prefix == NULL)
12320 {
12321 XP_TEST_HIT
12322 } else if ((cur->ns != NULL) &&
12323 (xmlStrEqual(URI, cur->ns->href)))
12324 {
12325 XP_TEST_HIT
12326 }
12327 }
12328 } else if (axis == AXIS_NAMESPACE) {
12329 if (cur->type == XML_NAMESPACE_DECL)
12330 {
12331 XP_TEST_HIT_NS
12332 }
12333 } else {
12334 if (cur->type == XML_ELEMENT_NODE) {
12335 if (prefix == NULL)
12336 {
12337 XP_TEST_HIT
12338
12339 } else if ((cur->ns != NULL) &&
12340 (xmlStrEqual(URI, cur->ns->href)))
12341 {
12342 XP_TEST_HIT
12343 }
12344 }
12345 }
12346 break;
12347 case NODE_TEST_NS:{
12348 TODO;
12349 break;
12350 }
12351 case NODE_TEST_NAME:
12352 if (axis == AXIS_ATTRIBUTE) {
12353 if (cur->type != XML_ATTRIBUTE_NODE)
12354 break;
12355 } else if (axis == AXIS_NAMESPACE) {
12356 if (cur->type != XML_NAMESPACE_DECL)
12357 break;
12358 } else {
12359 if (cur->type != XML_ELEMENT_NODE)
12360 break;
12361 }
12362 switch (cur->type) {
12363 case XML_ELEMENT_NODE:
12364 if (xmlStrEqual(name, cur->name)) {
12365 if (prefix == NULL) {
12366 if (cur->ns == NULL)
12367 {
12368 XP_TEST_HIT
12369 }
12370 } else {
12371 if ((cur->ns != NULL) &&
12372 (xmlStrEqual(URI, cur->ns->href)))
12373 {
12374 XP_TEST_HIT
12375 }
12376 }
12377 }
12378 break;
12379 case XML_ATTRIBUTE_NODE:{
12381
12382 if (xmlStrEqual(name, attr->name)) {
12383 if (prefix == NULL) {
12384 if ((attr->ns == NULL) ||
12385 (attr->ns->prefix == NULL))
12386 {
12387 XP_TEST_HIT
12388 }
12389 } else {
12390 if ((attr->ns != NULL) &&
12391 (xmlStrEqual(URI,
12392 attr->ns->href)))
12393 {
12394 XP_TEST_HIT
12395 }
12396 }
12397 }
12398 break;
12399 }
12400 case XML_NAMESPACE_DECL:
12401 if (cur->type == XML_NAMESPACE_DECL) {
12402 xmlNsPtr ns = (xmlNsPtr) cur;
12403
12404 if ((ns->prefix != NULL) && (name != NULL)
12405 && (xmlStrEqual(ns->prefix, name)))
12406 {
12407 XP_TEST_HIT_NS
12408 }
12409 }
12410 break;
12411 default:
12412 break;
12413 }
12414 break;
12415 } /* switch(test) */
12416 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12417
12418 goto apply_predicates;
12419
12420axis_range_end: /* ----------------------------------------------------- */
12421 /*
12422 * We have a "/foo[n]", and position() = n was reached.
12423 * Note that we can have as well "/foo/::parent::foo[1]", so
12424 * a duplicate-aware merge is still needed.
12425 * Merge with the result.
12426 */
12427 if (outSeq == NULL) {
12428 outSeq = seq;
12429 seq = NULL;
12430 } else
12431 /* TODO: Check memory error. */
12432 outSeq = mergeAndClear(outSeq, seq);
12433 /*
12434 * Break if only a true/false result was requested.
12435 */
12436 if (toBool)
12437 break;
12438 continue;
12439
12440first_hit: /* ---------------------------------------------------------- */
12441 /*
12442 * Break if only a true/false result was requested and
12443 * no predicates existed and a node test succeeded.
12444 */
12445 if (outSeq == NULL) {
12446 outSeq = seq;
12447 seq = NULL;
12448 } else
12449 /* TODO: Check memory error. */
12450 outSeq = mergeAndClear(outSeq, seq);
12451 break;
12452
12453#ifdef DEBUG_STEP
12454 if (seq != NULL)
12455 nbMatches += seq->nodeNr;
12456#endif
12457
12458apply_predicates: /* --------------------------------------------------- */
12459 if (ctxt->error != XPATH_EXPRESSION_OK)
12460 goto error;
12461
12462 /*
12463 * Apply predicates.
12464 */
12465 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12466 /*
12467 * E.g. when we have a "/foo[some expression][n]".
12468 */
12469 /*
12470 * QUESTION TODO: The old predicate evaluation took into
12471 * account location-sets.
12472 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12473 * Do we expect such a set here?
12474 * All what I learned now from the evaluation semantics
12475 * does not indicate that a location-set will be processed
12476 * here, so this looks OK.
12477 */
12478 /*
12479 * Iterate over all predicates, starting with the outermost
12480 * predicate.
12481 * TODO: Problem: we cannot execute the inner predicates first
12482 * since we cannot go back *up* the operator tree!
12483 * Options we have:
12484 * 1) Use of recursive functions (like is it currently done
12485 * via xmlXPathCompOpEval())
12486 * 2) Add a predicate evaluation information stack to the
12487 * context struct
12488 * 3) Change the way the operators are linked; we need a
12489 * "parent" field on xmlXPathStepOp
12490 *
12491 * For the moment, I'll try to solve this with a recursive
12492 * function: xmlXPathCompOpEvalPredicate().
12493 */
12494 if (hasPredicateRange != 0)
12495 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12496 hasNsNodes);
12497 else
12498 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12499 hasNsNodes);
12500
12501 if (ctxt->error != XPATH_EXPRESSION_OK) {
12502 total = 0;
12503 goto error;
12504 }
12505 }
12506
12507 if (seq->nodeNr > 0) {
12508 /*
12509 * Add to result set.
12510 */
12511 if (outSeq == NULL) {
12512 outSeq = seq;
12513 seq = NULL;
12514 } else {
12515 /* TODO: Check memory error. */
12516 outSeq = mergeAndClear(outSeq, seq);
12517 }
12518
12519 if (toBool)
12520 break;
12521 }
12522 }
12523
12524error:
12525 if ((obj->boolval) && (obj->user != NULL)) {
12526 /*
12527 * QUESTION TODO: What does this do and why?
12528 * TODO: Do we have to do this also for the "error"
12529 * cleanup further down?
12530 */
12531 ctxt->value->boolval = 1;
12532 ctxt->value->user = obj->user;
12533 obj->user = NULL;
12534 obj->boolval = 0;
12535 }
12536 xmlXPathReleaseObject(xpctxt, obj);
12537
12538 /*
12539 * Ensure we return at least an empty set.
12540 */
12541 if (outSeq == NULL) {
12542 if ((seq != NULL) && (seq->nodeNr == 0))
12543 outSeq = seq;
12544 else
12545 /* TODO: Check memory error. */
12546 outSeq = xmlXPathNodeSetCreate(NULL);
12547 }
12548 if ((seq != NULL) && (seq != outSeq)) {
12549 xmlXPathFreeNodeSet(seq);
12550 }
12551 /*
12552 * Hand over the result. Better to push the set also in
12553 * case of errors.
12554 */
12555 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12556 /*
12557 * Reset the context node.
12558 */
12559 xpctxt->node = oldContextNode;
12560 /*
12561 * When traversing the namespace axis in "toBool" mode, it's
12562 * possible that tmpNsList wasn't freed.
12563 */
12564 if (xpctxt->tmpNsList != NULL) {
12565 xmlFree(xpctxt->tmpNsList);
12566 xpctxt->tmpNsList = NULL;
12567 }
12568
12569#ifdef DEBUG_STEP
12571 "\nExamined %d nodes, found %d nodes at that step\n",
12572 total, nbMatches);
12573#endif
12574
12575 return(total);
12576}
12577
12578static int
12579xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12580 xmlXPathStepOpPtr op, xmlNodePtr * first);
12581
12593static int
12594xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12595 xmlXPathStepOpPtr op, xmlNodePtr * first)
12596{
12597 int total = 0, cur;
12598 xmlXPathCompExprPtr comp;
12599 xmlXPathObjectPtr arg1, arg2;
12600
12601 CHECK_ERROR0;
12602 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12603 return(0);
12604 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12605 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12606 ctxt->context->depth += 1;
12607 comp = ctxt->comp;
12608 switch (op->op) {
12609 case XPATH_OP_END:
12610 break;
12611 case XPATH_OP_UNION:
12612 total =
12613 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12614 first);
12615 CHECK_ERROR0;
12616 if ((ctxt->value != NULL)
12617 && (ctxt->value->type == XPATH_NODESET)
12618 && (ctxt->value->nodesetval != NULL)
12619 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12620 /*
12621 * limit tree traversing to first node in the result
12622 */
12623 /*
12624 * OPTIMIZE TODO: This implicitly sorts
12625 * the result, even if not needed. E.g. if the argument
12626 * of the count() function, no sorting is needed.
12627 * OPTIMIZE TODO: How do we know if the node-list wasn't
12628 * already sorted?
12629 */
12630 if (ctxt->value->nodesetval->nodeNr > 1)
12631 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12632 *first = ctxt->value->nodesetval->nodeTab[0];
12633 }
12634 cur =
12635 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12636 first);
12637 CHECK_ERROR0;
12638
12639 arg2 = valuePop(ctxt);
12640 arg1 = valuePop(ctxt);
12641 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12642 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12643 xmlXPathReleaseObject(ctxt->context, arg1);
12644 xmlXPathReleaseObject(ctxt->context, arg2);
12645 XP_ERROR0(XPATH_INVALID_TYPE);
12646 }
12647 if ((ctxt->context->opLimit != 0) &&
12648 (((arg1->nodesetval != NULL) &&
12649 (xmlXPathCheckOpLimit(ctxt,
12650 arg1->nodesetval->nodeNr) < 0)) ||
12651 ((arg2->nodesetval != NULL) &&
12652 (xmlXPathCheckOpLimit(ctxt,
12653 arg2->nodesetval->nodeNr) < 0)))) {
12654 xmlXPathReleaseObject(ctxt->context, arg1);
12655 xmlXPathReleaseObject(ctxt->context, arg2);
12656 break;
12657 }
12658
12659 /* TODO: Check memory error. */
12660 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12661 arg2->nodesetval);
12662 valuePush(ctxt, arg1);
12663 xmlXPathReleaseObject(ctxt->context, arg2);
12664 /* optimizer */
12665 if (total > cur)
12666 xmlXPathCompSwap(op);
12667 total += cur;
12668 break;
12669 case XPATH_OP_ROOT:
12670 xmlXPathRoot(ctxt);
12671 break;
12672 case XPATH_OP_NODE:
12673 if (op->ch1 != -1)
12674 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12675 CHECK_ERROR0;
12676 if (op->ch2 != -1)
12677 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12678 CHECK_ERROR0;
12679 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12680 ctxt->context->node));
12681 break;
12682 case XPATH_OP_COLLECT:{
12683 if (op->ch1 == -1)
12684 break;
12685
12686 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12687 CHECK_ERROR0;
12688
12689 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12690 break;
12691 }
12692 case XPATH_OP_VALUE:
12693 valuePush(ctxt,
12694 xmlXPathCacheObjectCopy(ctxt->context,
12695 (xmlXPathObjectPtr) op->value4));
12696 break;
12697 case XPATH_OP_SORT:
12698 if (op->ch1 != -1)
12699 total +=
12700 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12701 first);
12702 CHECK_ERROR0;
12703 if ((ctxt->value != NULL)
12704 && (ctxt->value->type == XPATH_NODESET)
12705 && (ctxt->value->nodesetval != NULL)
12706 && (ctxt->value->nodesetval->nodeNr > 1))
12707 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12708 break;
12709#ifdef XP_OPTIMIZED_FILTER_FIRST
12710 case XPATH_OP_FILTER:
12711 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12712 break;
12713#endif
12714 default:
12715 total += xmlXPathCompOpEval(ctxt, op);
12716 break;
12717 }
12718
12719 ctxt->context->depth -= 1;
12720 return(total);
12721}
12722
12734static int
12735xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12736 xmlNodePtr * last)
12737{
12738 int total = 0, cur;
12739 xmlXPathCompExprPtr comp;
12740 xmlXPathObjectPtr arg1, arg2;
12741
12742 CHECK_ERROR0;
12743 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12744 return(0);
12745 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12746 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12747 ctxt->context->depth += 1;
12748 comp = ctxt->comp;
12749 switch (op->op) {
12750 case XPATH_OP_END:
12751 break;
12752 case XPATH_OP_UNION:
12753 total =
12754 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12755 CHECK_ERROR0;
12756 if ((ctxt->value != NULL)
12757 && (ctxt->value->type == XPATH_NODESET)
12758 && (ctxt->value->nodesetval != NULL)
12759 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12760 /*
12761 * limit tree traversing to first node in the result
12762 */
12763 if (ctxt->value->nodesetval->nodeNr > 1)
12764 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12765 *last =
12766 ctxt->value->nodesetval->nodeTab[ctxt->value->
12767 nodesetval->nodeNr -
12768 1];
12769 }
12770 cur =
12771 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12772 CHECK_ERROR0;
12773 if ((ctxt->value != NULL)
12774 && (ctxt->value->type == XPATH_NODESET)
12775 && (ctxt->value->nodesetval != NULL)
12776 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12777 }
12778
12779 arg2 = valuePop(ctxt);
12780 arg1 = valuePop(ctxt);
12781 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12782 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12783 xmlXPathReleaseObject(ctxt->context, arg1);
12784 xmlXPathReleaseObject(ctxt->context, arg2);
12785 XP_ERROR0(XPATH_INVALID_TYPE);
12786 }
12787 if ((ctxt->context->opLimit != 0) &&
12788 (((arg1->nodesetval != NULL) &&
12789 (xmlXPathCheckOpLimit(ctxt,
12790 arg1->nodesetval->nodeNr) < 0)) ||
12791 ((arg2->nodesetval != NULL) &&
12792 (xmlXPathCheckOpLimit(ctxt,
12793 arg2->nodesetval->nodeNr) < 0)))) {
12794 xmlXPathReleaseObject(ctxt->context, arg1);
12795 xmlXPathReleaseObject(ctxt->context, arg2);
12796 break;
12797 }
12798
12799 /* TODO: Check memory error. */
12800 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12801 arg2->nodesetval);
12802 valuePush(ctxt, arg1);
12803 xmlXPathReleaseObject(ctxt->context, arg2);
12804 /* optimizer */
12805 if (total > cur)
12806 xmlXPathCompSwap(op);
12807 total += cur;
12808 break;
12809 case XPATH_OP_ROOT:
12810 xmlXPathRoot(ctxt);
12811 break;
12812 case XPATH_OP_NODE:
12813 if (op->ch1 != -1)
12814 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12815 CHECK_ERROR0;
12816 if (op->ch2 != -1)
12817 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12818 CHECK_ERROR0;
12819 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12820 ctxt->context->node));
12821 break;
12822 case XPATH_OP_COLLECT:{
12823 if (op->ch1 == -1)
12824 break;
12825
12826 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12827 CHECK_ERROR0;
12828
12829 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12830 break;
12831 }
12832 case XPATH_OP_VALUE:
12833 valuePush(ctxt,
12834 xmlXPathCacheObjectCopy(ctxt->context,
12835 (xmlXPathObjectPtr) op->value4));
12836 break;
12837 case XPATH_OP_SORT:
12838 if (op->ch1 != -1)
12839 total +=
12840 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12841 last);
12842 CHECK_ERROR0;
12843 if ((ctxt->value != NULL)
12844 && (ctxt->value->type == XPATH_NODESET)
12845 && (ctxt->value->nodesetval != NULL)
12846 && (ctxt->value->nodesetval->nodeNr > 1))
12847 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12848 break;
12849 default:
12850 total += xmlXPathCompOpEval(ctxt, op);
12851 break;
12852 }
12853
12854 ctxt->context->depth -= 1;
12855 return (total);
12856}
12857
12858#ifdef XP_OPTIMIZED_FILTER_FIRST
12859static int
12860xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12861 xmlXPathStepOpPtr op, xmlNodePtr * first)
12862{
12863 int total = 0;
12864 xmlXPathCompExprPtr comp;
12865 xmlNodeSetPtr set;
12866
12867 CHECK_ERROR0;
12868 comp = ctxt->comp;
12869 /*
12870 * Optimization for ()[last()] selection i.e. the last elem
12871 */
12872 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12873 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12874 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12875 int f = comp->steps[op->ch2].ch1;
12876
12877 if ((f != -1) &&
12878 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12879 (comp->steps[f].value5 == NULL) &&
12880 (comp->steps[f].value == 0) &&
12881 (comp->steps[f].value4 != NULL) &&
12883 (comp->steps[f].value4, BAD_CAST "last"))) {
12885
12886 total +=
12887 xmlXPathCompOpEvalLast(ctxt,
12888 &comp->steps[op->ch1],
12889 &last);
12890 CHECK_ERROR0;
12891 /*
12892 * The nodeset should be in document order,
12893 * Keep only the last value
12894 */
12895 if ((ctxt->value != NULL) &&
12896 (ctxt->value->type == XPATH_NODESET) &&
12897 (ctxt->value->nodesetval != NULL) &&
12898 (ctxt->value->nodesetval->nodeTab != NULL) &&
12899 (ctxt->value->nodesetval->nodeNr > 1)) {
12900 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12901 *first = *(ctxt->value->nodesetval->nodeTab);
12902 }
12903 return (total);
12904 }
12905 }
12906
12907 if (op->ch1 != -1)
12908 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12909 CHECK_ERROR0;
12910 if (op->ch2 == -1)
12911 return (total);
12912 if (ctxt->value == NULL)
12913 return (total);
12914
12915#ifdef LIBXML_XPTR_LOCS_ENABLED
12916 /*
12917 * Hum are we filtering the result of an XPointer expression
12918 */
12919 if (ctxt->value->type == XPATH_LOCATIONSET) {
12920 xmlLocationSetPtr locset = ctxt->value->user;
12921
12922 if (locset != NULL) {
12923 xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12924 if (locset->locNr > 0)
12925 *first = (xmlNodePtr) locset->locTab[0]->user;
12926 }
12927
12928 return (total);
12929 }
12930#endif /* LIBXML_XPTR_LOCS_ENABLED */
12931
12932 CHECK_TYPE0(XPATH_NODESET);
12933 set = ctxt->value->nodesetval;
12934 if (set != NULL) {
12935 xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12936 if (set->nodeNr > 0)
12937 *first = set->nodeTab[0];
12938 }
12939
12940 return (total);
12941}
12942#endif /* XP_OPTIMIZED_FILTER_FIRST */
12943
12952static int
12953xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12954{
12955 int total = 0;
12956 int equal, ret;
12957 xmlXPathCompExprPtr comp;
12958 xmlXPathObjectPtr arg1, arg2;
12959
12960 CHECK_ERROR0;
12961 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12962 return(0);
12963 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12964 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12965 ctxt->context->depth += 1;
12966 comp = ctxt->comp;
12967 switch (op->op) {
12968 case XPATH_OP_END:
12969 break;
12970 case XPATH_OP_AND:
12971 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12972 CHECK_ERROR0;
12973 xmlXPathBooleanFunction(ctxt, 1);
12974 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12975 break;
12976 arg2 = valuePop(ctxt);
12977 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12978 if (ctxt->error) {
12979 xmlXPathFreeObject(arg2);
12980 break;
12981 }
12982 xmlXPathBooleanFunction(ctxt, 1);
12983 if (ctxt->value != NULL)
12984 ctxt->value->boolval &= arg2->boolval;
12985 xmlXPathReleaseObject(ctxt->context, arg2);
12986 break;
12987 case XPATH_OP_OR:
12988 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12989 CHECK_ERROR0;
12990 xmlXPathBooleanFunction(ctxt, 1);
12991 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12992 break;
12993 arg2 = valuePop(ctxt);
12994 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12995 if (ctxt->error) {
12996 xmlXPathFreeObject(arg2);
12997 break;
12998 }
12999 xmlXPathBooleanFunction(ctxt, 1);
13000 if (ctxt->value != NULL)
13001 ctxt->value->boolval |= arg2->boolval;
13002 xmlXPathReleaseObject(ctxt->context, arg2);
13003 break;
13004 case XPATH_OP_EQUAL:
13005 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13006 CHECK_ERROR0;
13007 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13008 CHECK_ERROR0;
13009 if (op->value)
13010 equal = xmlXPathEqualValues(ctxt);
13011 else
13012 equal = xmlXPathNotEqualValues(ctxt);
13013 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13014 break;
13015 case XPATH_OP_CMP:
13016 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13017 CHECK_ERROR0;
13018 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13019 CHECK_ERROR0;
13020 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13021 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13022 break;
13023 case XPATH_OP_PLUS:
13024 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13025 CHECK_ERROR0;
13026 if (op->ch2 != -1) {
13027 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13028 }
13029 CHECK_ERROR0;
13030 if (op->value == 0)
13031 xmlXPathSubValues(ctxt);
13032 else if (op->value == 1)
13033 xmlXPathAddValues(ctxt);
13034 else if (op->value == 2)
13035 xmlXPathValueFlipSign(ctxt);
13036 else if (op->value == 3) {
13037 CAST_TO_NUMBER;
13038 CHECK_TYPE0(XPATH_NUMBER);
13039 }
13040 break;
13041 case XPATH_OP_MULT:
13042 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13043 CHECK_ERROR0;
13044 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13045 CHECK_ERROR0;
13046 if (op->value == 0)
13047 xmlXPathMultValues(ctxt);
13048 else if (op->value == 1)
13049 xmlXPathDivValues(ctxt);
13050 else if (op->value == 2)
13051 xmlXPathModValues(ctxt);
13052 break;
13053 case XPATH_OP_UNION:
13054 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13055 CHECK_ERROR0;
13056 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13057 CHECK_ERROR0;
13058
13059 arg2 = valuePop(ctxt);
13060 arg1 = valuePop(ctxt);
13061 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13062 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13063 xmlXPathReleaseObject(ctxt->context, arg1);
13064 xmlXPathReleaseObject(ctxt->context, arg2);
13065 XP_ERROR0(XPATH_INVALID_TYPE);
13066 }
13067 if ((ctxt->context->opLimit != 0) &&
13068 (((arg1->nodesetval != NULL) &&
13069 (xmlXPathCheckOpLimit(ctxt,
13070 arg1->nodesetval->nodeNr) < 0)) ||
13071 ((arg2->nodesetval != NULL) &&
13072 (xmlXPathCheckOpLimit(ctxt,
13073 arg2->nodesetval->nodeNr) < 0)))) {
13074 xmlXPathReleaseObject(ctxt->context, arg1);
13075 xmlXPathReleaseObject(ctxt->context, arg2);
13076 break;
13077 }
13078
13079 if ((arg1->nodesetval == NULL) ||
13080 ((arg2->nodesetval != NULL) &&
13081 (arg2->nodesetval->nodeNr != 0)))
13082 {
13083 /* TODO: Check memory error. */
13084 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13085 arg2->nodesetval);
13086 }
13087
13088 valuePush(ctxt, arg1);
13089 xmlXPathReleaseObject(ctxt->context, arg2);
13090 break;
13091 case XPATH_OP_ROOT:
13092 xmlXPathRoot(ctxt);
13093 break;
13094 case XPATH_OP_NODE:
13095 if (op->ch1 != -1)
13096 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13097 CHECK_ERROR0;
13098 if (op->ch2 != -1)
13099 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13100 CHECK_ERROR0;
13101 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13102 ctxt->context->node));
13103 break;
13104 case XPATH_OP_COLLECT:{
13105 if (op->ch1 == -1)
13106 break;
13107
13108 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13109 CHECK_ERROR0;
13110
13111 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13112 break;
13113 }
13114 case XPATH_OP_VALUE:
13115 valuePush(ctxt,
13116 xmlXPathCacheObjectCopy(ctxt->context,
13117 (xmlXPathObjectPtr) op->value4));
13118 break;
13119 case XPATH_OP_VARIABLE:{
13120 xmlXPathObjectPtr val;
13121
13122 if (op->ch1 != -1)
13123 total +=
13124 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13125 if (op->value5 == NULL) {
13126 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13127 if (val == NULL)
13128 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13129 valuePush(ctxt, val);
13130 } else {
13131 const xmlChar *URI;
13132
13133 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13134 if (URI == NULL) {
13136 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13137 (char *) op->value4, (char *)op->value5);
13138 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13139 break;
13140 }
13141 val = xmlXPathVariableLookupNS(ctxt->context,
13142 op->value4, URI);
13143 if (val == NULL)
13144 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13145 valuePush(ctxt, val);
13146 }
13147 break;
13148 }
13149 case XPATH_OP_FUNCTION:{
13150 xmlXPathFunction func;
13151 const xmlChar *oldFunc, *oldFuncURI;
13152 int i;
13153 int frame;
13154
13155 frame = xmlXPathSetFrame(ctxt);
13156 if (op->ch1 != -1) {
13157 total +=
13158 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13159 if (ctxt->error != XPATH_EXPRESSION_OK) {
13160 xmlXPathPopFrame(ctxt, frame);
13161 break;
13162 }
13163 }
13164 if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13166 "xmlXPathCompOpEval: parameter error\n");
13167 ctxt->error = XPATH_INVALID_OPERAND;
13168 xmlXPathPopFrame(ctxt, frame);
13169 break;
13170 }
13171 for (i = 0; i < op->value; i++) {
13172 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13174 "xmlXPathCompOpEval: parameter error\n");
13175 ctxt->error = XPATH_INVALID_OPERAND;
13176 xmlXPathPopFrame(ctxt, frame);
13177 break;
13178 }
13179 }
13180 if (op->cache != NULL)
13181 func = op->cache;
13182 else {
13183 const xmlChar *URI = NULL;
13184
13185 if (op->value5 == NULL)
13186 func =
13187 xmlXPathFunctionLookup(ctxt->context,
13188 op->value4);
13189 else {
13190 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13191 if (URI == NULL) {
13193 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13194 (char *)op->value4, (char *)op->value5);
13195 xmlXPathPopFrame(ctxt, frame);
13196 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13197 break;
13198 }
13199 func = xmlXPathFunctionLookupNS(ctxt->context,
13200 op->value4, URI);
13201 }
13202 if (func == NULL) {
13204 "xmlXPathCompOpEval: function %s not found\n",
13205 (char *)op->value4);
13206 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13207 }
13208 op->cache = func;
13209 op->cacheURI = (void *) URI;
13210 }
13211 oldFunc = ctxt->context->function;
13212 oldFuncURI = ctxt->context->functionURI;
13213 ctxt->context->function = op->value4;
13214 ctxt->context->functionURI = op->cacheURI;
13215 func(ctxt, op->value);
13216 ctxt->context->function = oldFunc;
13217 ctxt->context->functionURI = oldFuncURI;
13218 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13219 (ctxt->valueNr != ctxt->valueFrame + 1))
13220 XP_ERROR0(XPATH_STACK_ERROR);
13221 xmlXPathPopFrame(ctxt, frame);
13222 break;
13223 }
13224 case XPATH_OP_ARG:
13225 if (op->ch1 != -1) {
13226 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13227 CHECK_ERROR0;
13228 }
13229 if (op->ch2 != -1) {
13230 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13231 CHECK_ERROR0;
13232 }
13233 break;
13234 case XPATH_OP_PREDICATE:
13235 case XPATH_OP_FILTER:{
13236 xmlNodeSetPtr set;
13237
13238 /*
13239 * Optimization for ()[1] selection i.e. the first elem
13240 */
13241 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13243 /*
13244 * FILTER TODO: Can we assume that the inner processing
13245 * will result in an ordered list if we have an
13246 * XPATH_OP_FILTER?
13247 * What about an additional field or flag on
13248 * xmlXPathObject like @sorted ? This way we wouldn't need
13249 * to assume anything, so it would be more robust and
13250 * easier to optimize.
13251 */
13252 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13253 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13254#else
13255 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13256#endif
13257 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13258 xmlXPathObjectPtr val;
13259
13260 val = comp->steps[op->ch2].value4;
13261 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13262 (val->floatval == 1.0)) {
13264
13265 total +=
13266 xmlXPathCompOpEvalFirst(ctxt,
13267 &comp->steps[op->ch1],
13268 &first);
13269 CHECK_ERROR0;
13270 /*
13271 * The nodeset should be in document order,
13272 * Keep only the first value
13273 */
13274 if ((ctxt->value != NULL) &&
13275 (ctxt->value->type == XPATH_NODESET) &&
13276 (ctxt->value->nodesetval != NULL) &&
13277 (ctxt->value->nodesetval->nodeNr > 1))
13278 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13279 1, 1);
13280 break;
13281 }
13282 }
13283 /*
13284 * Optimization for ()[last()] selection i.e. the last elem
13285 */
13286 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13287 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13288 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13289 int f = comp->steps[op->ch2].ch1;
13290
13291 if ((f != -1) &&
13292 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13293 (comp->steps[f].value5 == NULL) &&
13294 (comp->steps[f].value == 0) &&
13295 (comp->steps[f].value4 != NULL) &&
13297 (comp->steps[f].value4, BAD_CAST "last"))) {
13299
13300 total +=
13301 xmlXPathCompOpEvalLast(ctxt,
13302 &comp->steps[op->ch1],
13303 &last);
13304 CHECK_ERROR0;
13305 /*
13306 * The nodeset should be in document order,
13307 * Keep only the last value
13308 */
13309 if ((ctxt->value != NULL) &&
13310 (ctxt->value->type == XPATH_NODESET) &&
13311 (ctxt->value->nodesetval != NULL) &&
13312 (ctxt->value->nodesetval->nodeTab != NULL) &&
13313 (ctxt->value->nodesetval->nodeNr > 1))
13314 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13315 break;
13316 }
13317 }
13318 /*
13319 * Process inner predicates first.
13320 * Example "index[parent::book][1]":
13321 * ...
13322 * PREDICATE <-- we are here "[1]"
13323 * PREDICATE <-- process "[parent::book]" first
13324 * SORT
13325 * COLLECT 'parent' 'name' 'node' book
13326 * NODE
13327 * ELEM Object is a number : 1
13328 */
13329 if (op->ch1 != -1)
13330 total +=
13331 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13332 CHECK_ERROR0;
13333 if (op->ch2 == -1)
13334 break;
13335 if (ctxt->value == NULL)
13336 break;
13337
13338#ifdef LIBXML_XPTR_LOCS_ENABLED
13339 /*
13340 * Hum are we filtering the result of an XPointer expression
13341 */
13342 if (ctxt->value->type == XPATH_LOCATIONSET) {
13343 xmlLocationSetPtr locset = ctxt->value->user;
13344 xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13345 1, locset->locNr);
13346 break;
13347 }
13348#endif /* LIBXML_XPTR_LOCS_ENABLED */
13349
13350 CHECK_TYPE0(XPATH_NODESET);
13351 set = ctxt->value->nodesetval;
13352 if (set != NULL)
13353 xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13354 1, set->nodeNr, 1);
13355 break;
13356 }
13357 case XPATH_OP_SORT:
13358 if (op->ch1 != -1)
13359 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13360 CHECK_ERROR0;
13361 if ((ctxt->value != NULL) &&
13362 (ctxt->value->type == XPATH_NODESET) &&
13363 (ctxt->value->nodesetval != NULL) &&
13364 (ctxt->value->nodesetval->nodeNr > 1))
13365 {
13366 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13367 }
13368 break;
13369#ifdef LIBXML_XPTR_LOCS_ENABLED
13370 case XPATH_OP_RANGETO:{
13371 xmlXPathObjectPtr range;
13372 xmlXPathObjectPtr res, obj;
13373 xmlXPathObjectPtr tmp;
13374 xmlLocationSetPtr newlocset = NULL;
13375 xmlLocationSetPtr oldlocset;
13376 xmlNodeSetPtr oldset;
13377 xmlNodePtr oldnode = ctxt->context->node;
13378 int oldcs = ctxt->context->contextSize;
13379 int oldpp = ctxt->context->proximityPosition;
13380 int i, j;
13381
13382 if (op->ch1 != -1) {
13383 total +=
13384 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13385 CHECK_ERROR0;
13386 }
13387 if (ctxt->value == NULL) {
13388 XP_ERROR0(XPATH_INVALID_OPERAND);
13389 }
13390 if (op->ch2 == -1)
13391 break;
13392
13393 if (ctxt->value->type == XPATH_LOCATIONSET) {
13394 /*
13395 * Extract the old locset, and then evaluate the result of the
13396 * expression for all the element in the locset. use it to grow
13397 * up a new locset.
13398 */
13399 CHECK_TYPE0(XPATH_LOCATIONSET);
13400
13401 if ((ctxt->value->user == NULL) ||
13402 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13403 break;
13404
13405 obj = valuePop(ctxt);
13406 oldlocset = obj->user;
13407
13408 newlocset = xmlXPtrLocationSetCreate(NULL);
13409
13410 for (i = 0; i < oldlocset->locNr; i++) {
13411 /*
13412 * Run the evaluation with a node list made of a
13413 * single item in the nodelocset.
13414 */
13415 ctxt->context->node = oldlocset->locTab[i]->user;
13416 ctxt->context->contextSize = oldlocset->locNr;
13417 ctxt->context->proximityPosition = i + 1;
13418 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13419 ctxt->context->node);
13420 valuePush(ctxt, tmp);
13421
13422 if (op->ch2 != -1)
13423 total +=
13424 xmlXPathCompOpEval(ctxt,
13425 &comp->steps[op->ch2]);
13426 if (ctxt->error != XPATH_EXPRESSION_OK) {
13427 xmlXPtrFreeLocationSet(newlocset);
13428 goto rangeto_error;
13429 }
13430
13431 res = valuePop(ctxt);
13432 if (res->type == XPATH_LOCATIONSET) {
13433 xmlLocationSetPtr rloc =
13434 (xmlLocationSetPtr)res->user;
13435 for (j=0; j<rloc->locNr; j++) {
13436 range = xmlXPtrNewRange(
13437 oldlocset->locTab[i]->user,
13438 oldlocset->locTab[i]->index,
13439 rloc->locTab[j]->user2,
13440 rloc->locTab[j]->index2);
13441 if (range != NULL) {
13442 xmlXPtrLocationSetAdd(newlocset, range);
13443 }
13444 }
13445 } else {
13446 range = xmlXPtrNewRangeNodeObject(
13447 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13448 if (range != NULL) {
13449 xmlXPtrLocationSetAdd(newlocset,range);
13450 }
13451 }
13452
13453 /*
13454 * Cleanup
13455 */
13456 if (res != NULL) {
13457 xmlXPathReleaseObject(ctxt->context, res);
13458 }
13459 if (ctxt->value == tmp) {
13460 res = valuePop(ctxt);
13461 xmlXPathReleaseObject(ctxt->context, res);
13462 }
13463 }
13464 } else { /* Not a location set */
13465 CHECK_TYPE0(XPATH_NODESET);
13466 obj = valuePop(ctxt);
13467 oldset = obj->nodesetval;
13468
13469 newlocset = xmlXPtrLocationSetCreate(NULL);
13470
13471 if (oldset != NULL) {
13472 for (i = 0; i < oldset->nodeNr; i++) {
13473 /*
13474 * Run the evaluation with a node list made of a single item
13475 * in the nodeset.
13476 */
13477 ctxt->context->node = oldset->nodeTab[i];
13478 /*
13479 * OPTIMIZE TODO: Avoid recreation for every iteration.
13480 */
13481 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13482 ctxt->context->node);
13483 valuePush(ctxt, tmp);
13484
13485 if (op->ch2 != -1)
13486 total +=
13487 xmlXPathCompOpEval(ctxt,
13488 &comp->steps[op->ch2]);
13489 if (ctxt->error != XPATH_EXPRESSION_OK) {
13490 xmlXPtrFreeLocationSet(newlocset);
13491 goto rangeto_error;
13492 }
13493
13494 res = valuePop(ctxt);
13495 range =
13496 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13497 res);
13498 if (range != NULL) {
13499 xmlXPtrLocationSetAdd(newlocset, range);
13500 }
13501
13502 /*
13503 * Cleanup
13504 */
13505 if (res != NULL) {
13506 xmlXPathReleaseObject(ctxt->context, res);
13507 }
13508 if (ctxt->value == tmp) {
13509 res = valuePop(ctxt);
13510 xmlXPathReleaseObject(ctxt->context, res);
13511 }
13512 }
13513 }
13514 }
13515
13516 /*
13517 * The result is used as the new evaluation set.
13518 */
13519 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13520rangeto_error:
13521 xmlXPathReleaseObject(ctxt->context, obj);
13522 ctxt->context->node = oldnode;
13523 ctxt->context->contextSize = oldcs;
13524 ctxt->context->proximityPosition = oldpp;
13525 break;
13526 }
13527#endif /* LIBXML_XPTR_LOCS_ENABLED */
13528 default:
13530 "XPath: unknown precompiled operation %d\n", op->op);
13531 ctxt->error = XPATH_INVALID_OPERAND;
13532 break;
13533 }
13534
13535 ctxt->context->depth -= 1;
13536 return (total);
13537}
13538
13547static int
13548xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13549 xmlXPathStepOpPtr op,
13550 int isPredicate)
13551{
13552 xmlXPathObjectPtr resObj = NULL;
13553
13554start:
13555 if (OP_LIMIT_EXCEEDED(ctxt, 1))
13556 return(0);
13557 /* comp = ctxt->comp; */
13558 switch (op->op) {
13559 case XPATH_OP_END:
13560 return (0);
13561 case XPATH_OP_VALUE:
13562 resObj = (xmlXPathObjectPtr) op->value4;
13563 if (isPredicate)
13564 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13565 return(xmlXPathCastToBoolean(resObj));
13566 case XPATH_OP_SORT:
13567 /*
13568 * We don't need sorting for boolean results. Skip this one.
13569 */
13570 if (op->ch1 != -1) {
13571 op = &ctxt->comp->steps[op->ch1];
13572 goto start;
13573 }
13574 return(0);
13575 case XPATH_OP_COLLECT:
13576 if (op->ch1 == -1)
13577 return(0);
13578
13579 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13580 if (ctxt->error != XPATH_EXPRESSION_OK)
13581 return(-1);
13582
13583 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13584 if (ctxt->error != XPATH_EXPRESSION_OK)
13585 return(-1);
13586
13587 resObj = valuePop(ctxt);
13588 if (resObj == NULL)
13589 return(-1);
13590 break;
13591 default:
13592 /*
13593 * Fallback to call xmlXPathCompOpEval().
13594 */
13595 xmlXPathCompOpEval(ctxt, op);
13596 if (ctxt->error != XPATH_EXPRESSION_OK)
13597 return(-1);
13598
13599 resObj = valuePop(ctxt);
13600 if (resObj == NULL)
13601 return(-1);
13602 break;
13603 }
13604
13605 if (resObj) {
13606 int res;
13607
13608 if (resObj->type == XPATH_BOOLEAN) {
13609 res = resObj->boolval;
13610 } else if (isPredicate) {
13611 /*
13612 * For predicates a result of type "number" is handled
13613 * differently:
13614 * SPEC XPath 1.0:
13615 * "If the result is a number, the result will be converted
13616 * to true if the number is equal to the context position
13617 * and will be converted to false otherwise;"
13618 */
13619 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13620 } else {
13621 res = xmlXPathCastToBoolean(resObj);
13622 }
13623 xmlXPathReleaseObject(ctxt->context, resObj);
13624 return(res);
13625 }
13626
13627 return(0);
13628}
13629
13630#ifdef XPATH_STREAMING
13637static int
13638xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13639 xmlXPathObjectPtr *resultSeq, int toBool)
13640{
13641 int max_depth, min_depth;
13642 int from_root;
13643 int ret, depth;
13644 int eval_all_nodes;
13646 xmlStreamCtxtPtr patstream = NULL;
13647
13648 int nb_nodes = 0;
13649
13650 if ((ctxt == NULL) || (comp == NULL))
13651 return(-1);
13652 max_depth = xmlPatternMaxDepth(comp);
13653 if (max_depth == -1)
13654 return(-1);
13655 if (max_depth == -2)
13656 max_depth = 10000;
13657 min_depth = xmlPatternMinDepth(comp);
13658 if (min_depth == -1)
13659 return(-1);
13660 from_root = xmlPatternFromRoot(comp);
13661 if (from_root < 0)
13662 return(-1);
13663#if 0
13664 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13665#endif
13666
13667 if (! toBool) {
13668 if (resultSeq == NULL)
13669 return(-1);
13670 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13671 if (*resultSeq == NULL)
13672 return(-1);
13673 }
13674
13675 /*
13676 * handle the special cases of "/" amd "." being matched
13677 */
13678 if (min_depth == 0) {
13679 if (from_root) {
13680 /* Select "/" */
13681 if (toBool)
13682 return(1);
13683 /* TODO: Check memory error. */
13684 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
13685 (xmlNodePtr) ctxt->doc);
13686 } else {
13687 /* Select "self::node()" */
13688 if (toBool)
13689 return(1);
13690 /* TODO: Check memory error. */
13691 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13692 }
13693 }
13694 if (max_depth == 0) {
13695 return(0);
13696 }
13697
13698 if (from_root) {
13699 cur = (xmlNodePtr)ctxt->doc;
13700 } else if (ctxt->node != NULL) {
13701 switch (ctxt->node->type) {
13702 case XML_ELEMENT_NODE:
13703 case XML_DOCUMENT_NODE:
13706 cur = ctxt->node;
13707 break;
13708 case XML_ATTRIBUTE_NODE:
13709 case XML_TEXT_NODE:
13712 case XML_ENTITY_NODE:
13713 case XML_PI_NODE:
13714 case XML_COMMENT_NODE:
13715 case XML_NOTATION_NODE:
13716 case XML_DTD_NODE:
13718 case XML_ELEMENT_DECL:
13719 case XML_ATTRIBUTE_DECL:
13720 case XML_ENTITY_DECL:
13721 case XML_NAMESPACE_DECL:
13722 case XML_XINCLUDE_START:
13723 case XML_XINCLUDE_END:
13724 break;
13725 }
13726 limit = cur;
13727 }
13728 if (cur == NULL) {
13729 return(0);
13730 }
13731
13732 patstream = xmlPatternGetStreamCtxt(comp);
13733 if (patstream == NULL) {
13734 /*
13735 * QUESTION TODO: Is this an error?
13736 */
13737 return(0);
13738 }
13739
13740 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13741
13742 if (from_root) {
13743 ret = xmlStreamPush(patstream, NULL, NULL);
13744 if (ret < 0) {
13745 } else if (ret == 1) {
13746 if (toBool)
13747 goto return_1;
13748 /* TODO: Check memory error. */
13749 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13750 }
13751 }
13752 depth = 0;
13753 goto scan_children;
13754next_node:
13755 do {
13756 if (ctxt->opLimit != 0) {
13757 if (ctxt->opCount >= ctxt->opLimit) {
13759 "XPath operation limit exceeded\n");
13760 xmlFreeStreamCtxt(patstream);
13761 return(-1);
13762 }
13763 ctxt->opCount++;
13764 }
13765
13766 nb_nodes++;
13767
13768 switch (cur->type) {
13769 case XML_ELEMENT_NODE:
13770 case XML_TEXT_NODE:
13772 case XML_COMMENT_NODE:
13773 case XML_PI_NODE:
13774 if (cur->type == XML_ELEMENT_NODE) {
13775 ret = xmlStreamPush(patstream, cur->name,
13776 (cur->ns ? cur->ns->href : NULL));
13777 } else if (eval_all_nodes)
13778 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13779 else
13780 break;
13781
13782 if (ret < 0) {
13783 /* NOP. */
13784 } else if (ret == 1) {
13785 if (toBool)
13786 goto return_1;
13787 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13788 < 0) {
13789 ctxt->lastError.domain = XML_FROM_XPATH;
13790 ctxt->lastError.code = XML_ERR_NO_MEMORY;
13791 }
13792 }
13793 if ((cur->children == NULL) || (depth >= max_depth)) {
13794 ret = xmlStreamPop(patstream);
13795 while (cur->next != NULL) {
13796 cur = cur->next;
13797 if ((cur->type != XML_ENTITY_DECL) &&
13798 (cur->type != XML_DTD_NODE))
13799 goto next_node;
13800 }
13801 }
13802 default:
13803 break;
13804 }
13805
13806scan_children:
13807 if (cur->type == XML_NAMESPACE_DECL) break;
13808 if ((cur->children != NULL) && (depth < max_depth)) {
13809 /*
13810 * Do not descend on entities declarations
13811 */
13812 if (cur->children->type != XML_ENTITY_DECL) {
13813 cur = cur->children;
13814 depth++;
13815 /*
13816 * Skip DTDs
13817 */
13818 if (cur->type != XML_DTD_NODE)
13819 continue;
13820 }
13821 }
13822
13823 if (cur == limit)
13824 break;
13825
13826 while (cur->next != NULL) {
13827 cur = cur->next;
13828 if ((cur->type != XML_ENTITY_DECL) &&
13829 (cur->type != XML_DTD_NODE))
13830 goto next_node;
13831 }
13832
13833 do {
13834 cur = cur->parent;
13835 depth--;
13836 if ((cur == NULL) || (cur == limit) ||
13837 (cur->type == XML_DOCUMENT_NODE))
13838 goto done;
13839 if (cur->type == XML_ELEMENT_NODE) {
13840 ret = xmlStreamPop(patstream);
13841 } else if ((eval_all_nodes) &&
13842 ((cur->type == XML_TEXT_NODE) ||
13843 (cur->type == XML_CDATA_SECTION_NODE) ||
13844 (cur->type == XML_COMMENT_NODE) ||
13845 (cur->type == XML_PI_NODE)))
13846 {
13847 ret = xmlStreamPop(patstream);
13848 }
13849 if (cur->next != NULL) {
13850 cur = cur->next;
13851 break;
13852 }
13853 } while (cur != NULL);
13854
13855 } while ((cur != NULL) && (depth >= 0));
13856
13857done:
13858
13859#if 0
13860 printf("stream eval: checked %d nodes selected %d\n",
13861 nb_nodes, retObj->nodesetval->nodeNr);
13862#endif
13863
13864 if (patstream)
13865 xmlFreeStreamCtxt(patstream);
13866 return(0);
13867
13868return_1:
13869 if (patstream)
13870 xmlFreeStreamCtxt(patstream);
13871 return(1);
13872}
13873#endif /* XPATH_STREAMING */
13874
13882static int
13883xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13884{
13885 xmlXPathCompExprPtr comp;
13886 int oldDepth;
13887
13888 if ((ctxt == NULL) || (ctxt->comp == NULL))
13889 return(-1);
13890
13891 if (ctxt->valueTab == NULL) {
13892 /* Allocate the value stack */
13893 ctxt->valueTab = (xmlXPathObjectPtr *)
13894 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13895 if (ctxt->valueTab == NULL) {
13896 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13897 return(-1);
13898 }
13899 ctxt->valueNr = 0;
13900 ctxt->valueMax = 10;
13901 ctxt->value = NULL;
13902 ctxt->valueFrame = 0;
13903 }
13904#ifdef XPATH_STREAMING
13905 if (ctxt->comp->stream) {
13906 int res;
13907
13908 if (toBool) {
13909 /*
13910 * Evaluation to boolean result.
13911 */
13912 res = xmlXPathRunStreamEval(ctxt->context,
13913 ctxt->comp->stream, NULL, 1);
13914 if (res != -1)
13915 return(res);
13916 } else {
13917 xmlXPathObjectPtr resObj = NULL;
13918
13919 /*
13920 * Evaluation to a sequence.
13921 */
13922 res = xmlXPathRunStreamEval(ctxt->context,
13923 ctxt->comp->stream, &resObj, 0);
13924
13925 if ((res != -1) && (resObj != NULL)) {
13926 valuePush(ctxt, resObj);
13927 return(0);
13928 }
13929 if (resObj != NULL)
13930 xmlXPathReleaseObject(ctxt->context, resObj);
13931 }
13932 /*
13933 * QUESTION TODO: This falls back to normal XPath evaluation
13934 * if res == -1. Is this intended?
13935 */
13936 }
13937#endif
13938 comp = ctxt->comp;
13939 if (comp->last < 0) {
13941 "xmlXPathRunEval: last is less than zero\n");
13942 return(-1);
13943 }
13944 oldDepth = ctxt->context->depth;
13945 if (toBool)
13946 return(xmlXPathCompOpEvalToBoolean(ctxt,
13947 &comp->steps[comp->last], 0));
13948 else
13949 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13950 ctxt->context->depth = oldDepth;
13951
13952 return(0);
13953}
13954
13955/************************************************************************
13956 * *
13957 * Public interfaces *
13958 * *
13959 ************************************************************************/
13960
13977int
13978xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13979 if ((ctxt == NULL) || (res == NULL)) return(0);
13980 switch (res->type) {
13981 case XPATH_BOOLEAN:
13982 return(res->boolval);
13983 case XPATH_NUMBER:
13984 return(res->floatval == ctxt->proximityPosition);
13985 case XPATH_NODESET:
13986 case XPATH_XSLT_TREE:
13987 if (res->nodesetval == NULL)
13988 return(0);
13989 return(res->nodesetval->nodeNr != 0);
13990 case XPATH_STRING:
13991 return((res->stringval != NULL) &&
13992 (xmlStrlen(res->stringval) != 0));
13993 default:
13994 STRANGE
13995 }
13996 return(0);
13997}
13998
14015int
14016xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14017 xmlXPathObjectPtr res) {
14018 if ((ctxt == NULL) || (res == NULL)) return(0);
14019 switch (res->type) {
14020 case XPATH_BOOLEAN:
14021 return(res->boolval);
14022 case XPATH_NUMBER:
14023#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14024 return((res->floatval == ctxt->context->proximityPosition) &&
14025 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14026#else
14027 return(res->floatval == ctxt->context->proximityPosition);
14028#endif
14029 case XPATH_NODESET:
14030 case XPATH_XSLT_TREE:
14031 if (res->nodesetval == NULL)
14032 return(0);
14033 return(res->nodesetval->nodeNr != 0);
14034 case XPATH_STRING:
14035 return((res->stringval != NULL) && (res->stringval[0] != 0));
14036#ifdef LIBXML_XPTR_LOCS_ENABLED
14037 case XPATH_LOCATIONSET:{
14038 xmlLocationSetPtr ptr = res->user;
14039 if (ptr == NULL)
14040 return(0);
14041 return (ptr->locNr != 0);
14042 }
14043#endif
14044 default:
14045 STRANGE
14046 }
14047 return(0);
14048}
14049
14050#ifdef XPATH_STREAMING
14060static xmlXPathCompExprPtr
14061xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14062 /*
14063 * Optimization: use streaming patterns when the XPath expression can
14064 * be compiled to a stream lookup
14065 */
14066 xmlPatternPtr stream;
14067 xmlXPathCompExprPtr comp;
14068 xmlDictPtr dict = NULL;
14069 const xmlChar **namespaces = NULL;
14070 xmlNsPtr ns;
14071 int i, j;
14072
14073 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14074 (!xmlStrchr(str, '@'))) {
14075 const xmlChar *tmp;
14076
14077 /*
14078 * We don't try to handle expressions using the verbose axis
14079 * specifiers ("::"), just the simplified form at this point.
14080 * Additionally, if there is no list of namespaces available and
14081 * there's a ":" in the expression, indicating a prefixed QName,
14082 * then we won't try to compile either. xmlPatterncompile() needs
14083 * to have a list of namespaces at compilation time in order to
14084 * compile prefixed name tests.
14085 */
14086 tmp = xmlStrchr(str, ':');
14087 if ((tmp != NULL) &&
14088 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14089 return(NULL);
14090
14091 if (ctxt != NULL) {
14092 dict = ctxt->dict;
14093 if (ctxt->nsNr > 0) {
14094 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14095 if (namespaces == NULL) {
14096 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14097 return(NULL);
14098 }
14099 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14100 ns = ctxt->namespaces[j];
14101 namespaces[i++] = ns->href;
14102 namespaces[i++] = ns->prefix;
14103 }
14104 namespaces[i++] = NULL;
14105 namespaces[i] = NULL;
14106 }
14107 }
14108
14109 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14110 if (namespaces != NULL) {
14111 xmlFree((xmlChar **)namespaces);
14112 }
14113 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14114 comp = xmlXPathNewCompExpr();
14115 if (comp == NULL) {
14116 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14117 return(NULL);
14118 }
14119 comp->stream = stream;
14120 comp->dict = dict;
14121 if (comp->dict)
14122 xmlDictReference(comp->dict);
14123 return(comp);
14124 }
14125 xmlFreePattern(stream);
14126 }
14127 return(NULL);
14128}
14129#endif /* XPATH_STREAMING */
14130
14131static void
14132xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14133 xmlXPathStepOpPtr op)
14134{
14135 xmlXPathCompExprPtr comp = pctxt->comp;
14136 xmlXPathContextPtr ctxt;
14137
14138 /*
14139 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14140 * internal representation.
14141 */
14142
14143 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14144 (op->ch1 != -1) &&
14145 (op->ch2 == -1 /* no predicate */))
14146 {
14147 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14148
14149 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14150 ((xmlXPathAxisVal) prevop->value ==
14151 AXIS_DESCENDANT_OR_SELF) &&
14152 (prevop->ch2 == -1) &&
14153 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14154 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14155 {
14156 /*
14157 * This is a "descendant-or-self::node()" without predicates.
14158 * Try to eliminate it.
14159 */
14160
14161 switch ((xmlXPathAxisVal) op->value) {
14162 case AXIS_CHILD:
14163 case AXIS_DESCENDANT:
14164 /*
14165 * Convert "descendant-or-self::node()/child::" or
14166 * "descendant-or-self::node()/descendant::" to
14167 * "descendant::"
14168 */
14169 op->ch1 = prevop->ch1;
14170 op->value = AXIS_DESCENDANT;
14171 break;
14172 case AXIS_SELF:
14173 case AXIS_DESCENDANT_OR_SELF:
14174 /*
14175 * Convert "descendant-or-self::node()/self::" or
14176 * "descendant-or-self::node()/descendant-or-self::" to
14177 * to "descendant-or-self::"
14178 */
14179 op->ch1 = prevop->ch1;
14180 op->value = AXIS_DESCENDANT_OR_SELF;
14181 break;
14182 default:
14183 break;
14184 }
14185 }
14186 }
14187
14188 /* OP_VALUE has invalid ch1. */
14189 if (op->op == XPATH_OP_VALUE)
14190 return;
14191
14192 /* Recurse */
14193 ctxt = pctxt->context;
14194 if (ctxt != NULL) {
14195 if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14196 return;
14197 ctxt->depth += 1;
14198 }
14199 if (op->ch1 != -1)
14200 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14201 if (op->ch2 != -1)
14202 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14203 if (ctxt != NULL)
14204 ctxt->depth -= 1;
14205}
14206
14217xmlXPathCompExprPtr
14218xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14219 xmlXPathParserContextPtr pctxt;
14220 xmlXPathCompExprPtr comp;
14221 int oldDepth = 0;
14222
14223#ifdef XPATH_STREAMING
14224 comp = xmlXPathTryStreamCompile(ctxt, str);
14225 if (comp != NULL)
14226 return(comp);
14227#endif
14228
14229 xmlInitParser();
14230
14231 pctxt = xmlXPathNewParserContext(str, ctxt);
14232 if (pctxt == NULL)
14233 return NULL;
14234 if (ctxt != NULL)
14235 oldDepth = ctxt->depth;
14236 xmlXPathCompileExpr(pctxt, 1);
14237 if (ctxt != NULL)
14238 ctxt->depth = oldDepth;
14239
14240 if( pctxt->error != XPATH_EXPRESSION_OK )
14241 {
14242 xmlXPathFreeParserContext(pctxt);
14243 return(NULL);
14244 }
14245
14246 if (*pctxt->cur != 0) {
14247 /*
14248 * aleksey: in some cases this line prints *second* error message
14249 * (see bug #78858) and probably this should be fixed.
14250 * However, we are not sure that all error messages are printed
14251 * out in other places. It's not critical so we leave it as-is for now
14252 */
14253 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14254 comp = NULL;
14255 } else {
14256 comp = pctxt->comp;
14257 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14258 if (ctxt != NULL)
14259 oldDepth = ctxt->depth;
14260 xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14261 if (ctxt != NULL)
14262 ctxt->depth = oldDepth;
14263 }
14264 pctxt->comp = NULL;
14265 }
14266 xmlXPathFreeParserContext(pctxt);
14267
14268 if (comp != NULL) {
14269 comp->expr = xmlStrdup(str);
14270#ifdef DEBUG_EVAL_COUNTS
14271 comp->string = xmlStrdup(str);
14272 comp->nb = 0;
14273#endif
14274 }
14275 return(comp);
14276}
14277
14287xmlXPathCompExprPtr
14288xmlXPathCompile(const xmlChar *str) {
14289 return(xmlXPathCtxtCompile(NULL, str));
14290}
14291
14305static int
14306xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14307 xmlXPathContextPtr ctxt,
14308 xmlXPathObjectPtr *resObjPtr,
14309 int toBool)
14310{
14311 xmlXPathParserContextPtr pctxt;
14312 xmlXPathObjectPtr resObj;
14313#ifndef LIBXML_THREAD_ENABLED
14314 static int reentance = 0;
14315#endif
14316 int res;
14317
14318 CHECK_CTXT_NEG(ctxt)
14319
14320 if (comp == NULL)
14321 return(-1);
14322 xmlInitParser();
14323
14324#ifndef LIBXML_THREAD_ENABLED
14325 reentance++;
14326 if (reentance > 1)
14327 xmlXPathDisableOptimizer = 1;
14328#endif
14329
14330#ifdef DEBUG_EVAL_COUNTS
14331 comp->nb++;
14332 if ((comp->string != NULL) && (comp->nb > 100)) {
14333 fprintf(stderr, "100 x %s\n", comp->string);
14334 comp->nb = 0;
14335 }
14336#endif
14337 pctxt = xmlXPathCompParserContext(comp, ctxt);
14338 res = xmlXPathRunEval(pctxt, toBool);
14339
14340 if (pctxt->error != XPATH_EXPRESSION_OK) {
14341 resObj = NULL;
14342 } else {
14343 resObj = valuePop(pctxt);
14344 if (resObj == NULL) {
14345 if (!toBool)
14347 "xmlXPathCompiledEval: No result on the stack.\n");
14348 } else if (pctxt->valueNr > 0) {
14350 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14351 pctxt->valueNr);
14352 }
14353 }
14354
14355 if (resObjPtr)
14356 *resObjPtr = resObj;
14357 else
14358 xmlXPathReleaseObject(ctxt, resObj);
14359
14360 pctxt->comp = NULL;
14361 xmlXPathFreeParserContext(pctxt);
14362#ifndef LIBXML_THREAD_ENABLED
14363 reentance--;
14364#endif
14365
14366 return(res);
14367}
14368
14379xmlXPathObjectPtr
14380xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14381{
14382 xmlXPathObjectPtr res = NULL;
14383
14384 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14385 return(res);
14386}
14387
14399int
14400xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14401 xmlXPathContextPtr ctxt)
14402{
14403 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14404}
14405
14413void
14414xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14415#ifdef XPATH_STREAMING
14416 xmlXPathCompExprPtr comp;
14417#endif
14418 int oldDepth = 0;
14419
14420 if (ctxt == NULL) return;
14421
14422#ifdef XPATH_STREAMING
14423 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14424 if (comp != NULL) {
14425 if (ctxt->comp != NULL)
14426 xmlXPathFreeCompExpr(ctxt->comp);
14427 ctxt->comp = comp;
14428 } else
14429#endif
14430 {
14431 if (ctxt->context != NULL)
14432 oldDepth = ctxt->context->depth;
14433 xmlXPathCompileExpr(ctxt, 1);
14434 if (ctxt->context != NULL)
14435 ctxt->context->depth = oldDepth;
14436 CHECK_ERROR;
14437
14438 /* Check for trailing characters. */
14439 if (*ctxt->cur != 0)
14440 XP_ERROR(XPATH_EXPR_ERROR);
14441
14442 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14443 if (ctxt->context != NULL)
14444 oldDepth = ctxt->context->depth;
14445 xmlXPathOptimizeExpression(ctxt,
14446 &ctxt->comp->steps[ctxt->comp->last]);
14447 if (ctxt->context != NULL)
14448 ctxt->context->depth = oldDepth;
14449 }
14450 }
14451
14452 xmlXPathRunEval(ctxt, 0);
14453}
14454
14465xmlXPathObjectPtr
14466xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14467 xmlXPathParserContextPtr ctxt;
14468 xmlXPathObjectPtr res;
14469
14470 CHECK_CTXT(ctx)
14471
14472 xmlInitParser();
14473
14474 ctxt = xmlXPathNewParserContext(str, ctx);
14475 if (ctxt == NULL)
14476 return NULL;
14477 xmlXPathEvalExpr(ctxt);
14478
14479 if (ctxt->error != XPATH_EXPRESSION_OK) {
14480 res = NULL;
14481 } else {
14482 res = valuePop(ctxt);
14483 if (res == NULL) {
14485 "xmlXPathCompiledEval: No result on the stack.\n");
14486 } else if (ctxt->valueNr > 0) {
14488 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14489 ctxt->valueNr);
14490 }
14491 }
14492
14493 xmlXPathFreeParserContext(ctxt);
14494 return(res);
14495}
14496
14507int
14508xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14509 if ((node == NULL) || (ctx == NULL))
14510 return(-1);
14511
14512 if (node->doc == ctx->doc) {
14513 ctx->node = node;
14514 return(0);
14515 }
14516 return(-1);
14517}
14518
14531xmlXPathObjectPtr
14532xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14533 if (str == NULL)
14534 return(NULL);
14535 if (xmlXPathSetContextNode(node, ctx) < 0)
14536 return(NULL);
14537 return(xmlXPathEval(str, ctx));
14538}
14539
14550xmlXPathObjectPtr
14551xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14552 return(xmlXPathEval(str, ctxt));
14553}
14554
14555/************************************************************************
14556 * *
14557 * Extra functions not pertaining to the XPath spec *
14558 * *
14559 ************************************************************************/
14608static void
14609xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14610 xmlXPathObjectPtr str;
14611 int escape_reserved;
14613 xmlChar *cptr;
14614 xmlChar escape[4];
14615
14616 CHECK_ARITY(2);
14617
14618 escape_reserved = xmlXPathPopBoolean(ctxt);
14619
14620 CAST_TO_STRING;
14621 str = valuePop(ctxt);
14622
14623 target = xmlBufCreate();
14624
14625 escape[0] = '%';
14626 escape[3] = 0;
14627
14628 if (target) {
14629 for (cptr = str->stringval; *cptr; cptr++) {
14630 if ((*cptr >= 'A' && *cptr <= 'Z') ||
14631 (*cptr >= 'a' && *cptr <= 'z') ||
14632 (*cptr >= '0' && *cptr <= '9') ||
14633 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14634 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14635 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14636 (*cptr == '%' &&
14637 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14638 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14639 (cptr[1] >= '0' && cptr[1] <= '9')) &&
14640 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14641 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14642 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14643 (!escape_reserved &&
14644 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14645 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14646 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14647 *cptr == ','))) {
14648 xmlBufAdd(target, cptr, 1);
14649 } else {
14650 if ((*cptr >> 4) < 10)
14651 escape[1] = '0' + (*cptr >> 4);
14652 else
14653 escape[1] = 'A' - 10 + (*cptr >> 4);
14654 if ((*cptr & 0xF) < 10)
14655 escape[2] = '0' + (*cptr & 0xF);
14656 else
14657 escape[2] = 'A' - 10 + (*cptr & 0xF);
14658
14659 xmlBufAdd(target, &escape[0], 3);
14660 }
14661 }
14662 }
14663 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14666 xmlXPathReleaseObject(ctxt->context, str);
14667}
14668
14675void
14676xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14677{
14678 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14679 xmlXPathBooleanFunction);
14680 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14681 xmlXPathCeilingFunction);
14682 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14683 xmlXPathCountFunction);
14684 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14685 xmlXPathConcatFunction);
14686 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14687 xmlXPathContainsFunction);
14688 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14689 xmlXPathIdFunction);
14690 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14691 xmlXPathFalseFunction);
14692 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14693 xmlXPathFloorFunction);
14694 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14695 xmlXPathLastFunction);
14696 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14697 xmlXPathLangFunction);
14698 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14699 xmlXPathLocalNameFunction);
14700 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14701 xmlXPathNotFunction);
14702 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14703 xmlXPathNameFunction);
14704 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14705 xmlXPathNamespaceURIFunction);
14706 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14707 xmlXPathNormalizeFunction);
14708 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14709 xmlXPathNumberFunction);
14710 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14711 xmlXPathPositionFunction);
14712 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14713 xmlXPathRoundFunction);
14714 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14715 xmlXPathStringFunction);
14716 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14717 xmlXPathStringLengthFunction);
14718 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14719 xmlXPathStartsWithFunction);
14720 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14721 xmlXPathSubstringFunction);
14722 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14723 xmlXPathSubstringBeforeFunction);
14724 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14725 xmlXPathSubstringAfterFunction);
14726 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14727 xmlXPathSumFunction);
14728 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14729 xmlXPathTrueFunction);
14730 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14731 xmlXPathTranslateFunction);
14732
14733 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14734 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14735 xmlXPathEscapeUriFunction);
14736}
14737
14738#endif /* LIBXML_XPATH_ENABLED */
_STLP_MOVE_TO_STD_NAMESPACE void sort(_RandomAccessIter __first, _RandomAccessIter __last)
Definition: _algo.c:993
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
int toupper(int c)
Definition: utclib.c:881
#define ok(value,...)
Definition: atltest.h:57
#define skip(...)
Definition: atltest.h:64
struct _root root
void xmlBufFree(xmlBufPtr buf)
Definition: buf.c:322
xmlBufPtr xmlBufCreate(void)
Definition: buf.c:122
int xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len)
Definition: buf.c:821
r l[0]
Definition: byte_order.h:168
Definition: list.h:37
size_type size() const
Definition: _list.h:379
Definition: _set.h:50
static TAGID TAGID find
Definition: db.cpp:155
#define NULL
Definition: types.h:112
@ AXIS_CHILD
Definition: pattern.c:46
@ AXIS_ATTRIBUTE
Definition: pattern.c:47
#define SKIP_BLANKS
Definition: pattern.c:1175
#define SKIP(val)
Definition: pattern.c:1171
#define NXT(val)
Definition: pattern.c:1172
#define CUR_PTR
Definition: pattern.c:1173
#define CUR
Definition: pattern.c:1170
UINT op
Definition: effect.c:236
#define frac(x)
Definition: texture.c:364
content
Definition: atl_ax.c:994
static WCHAR no[MAX_STRING_RESOURCE_LEN]
Definition: object.c:2340
BOOL next_node(stream_t *stream, strbuf_t *buf)
Definition: stream.c:140
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
switch(r->id)
Definition: btrfs.c:3046
__kernel_ptrdiff_t ptrdiff_t
Definition: linux.h:247
POINTL point
Definition: edittest.c:50
double log10(double x)
Definition: freeldr.c:124
double pow(double x, double y)
Definition: freeldr.c:112
#define printf
Definition: freeldr.h:97
#define NEXT(n, i)
FxCollectionEntry * cur
size_t total
#define DBL_DIG
Definition: gcc_float.h:57
GLuint start
Definition: gl.h:1545
GLint GLint GLsizei GLsizei GLsizei depth
Definition: gl.h:1546
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
const GLdouble * v
Definition: gl.h:2040
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLdouble s
Definition: gl.h:2039
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
GLuint GLuint end
Definition: gl.h:1545
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLdouble GLdouble GLdouble GLdouble q
Definition: gl.h:2063
GLsizeiptr size
Definition: glext.h:5919
GLenum func
Definition: glext.h:6028
GLdouble n
Definition: glext.h:7729
GLuint res
Definition: glext.h:9613
GLuint * ids
Definition: glext.h:5907
GLuint buffer
Definition: glext.h:5915
GLuint GLuint GLuint GLuint arg1
Definition: glext.h:9513
const GLubyte * c
Definition: glext.h:8905
GLdouble GLdouble GLdouble GLdouble top
Definition: glext.h:10859
GLuint GLuint GLuint GLuint GLuint GLuint GLuint arg2
Definition: glext.h:9514
GLfloat f
Definition: glext.h:7540
GLint limit
Definition: glext.h:10326
GLenum GLint * range
Definition: glext.h:7539
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLuint in
Definition: glext.h:9616
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glext.h:7005
const GLint * first
Definition: glext.h:5794
GLuint GLfloat * val
Definition: glext.h:7180
GLuint GLuint num
Definition: glext.h:9618
GLenum GLsizei len
Definition: glext.h:6722
GLintptr offset
Definition: glext.h:5920
GLenum target
Definition: glext.h:7315
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
#define ATTRIBUTE_UNUSED
Definition: i386-dis.c:36
@ extra
Definition: id3.c:95
#define INT_MIN
Definition: limits.h:39
#define INT_MAX
Definition: limits.h:40
_Check_return_ _CRT_JIT_INTRINSIC double __cdecl fabs(_In_ double x)
Definition: fabs.c:17
_Check_return_ double __cdecl fmod(_In_ double x, _In_ double y)
_Check_return_ _CRTIMP double __cdecl floor(_In_ double x)
_Check_return_ _CRTIMP double __cdecl ceil(_In_ double x)
#define stdout
Definition: stdio.h:99
#define stderr
Definition: stdio.h:100
_Check_return_opt_ _CRTIMP int __cdecl fprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format,...)
#define f
Definition: ke_i.h:83
#define c
Definition: ke_i.h:80
#define ATTRIBUTE_NO_SANITIZE(arg)
Definition: libxml.h:74
#define XML_POP_WARNINGS
Definition: libxml.h:67
#define XML_IGNORE_PEDANTIC_WARNINGS
Definition: libxml.h:66
if(dx< 0)
Definition: linetemp.h:194
#define isinf(x)
Definition: mingw_math.h:94
#define isnan(x)
Definition: mingw_math.h:133
double __cdecl copysign(double, double)
#define error(str)
Definition: mkdosfs.c:1605
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
#define for
Definition: utility.h:88
char string[160]
Definition: util.h:11
static PVOID ptr
Definition: dispmode.c:27
#define NAN
Definition: mesh.c:39
const char * fullname
Definition: shader.c:1766
static unsigned int number
Definition: dsound.c:1479
static UINT UINT last
Definition: font.c:45
#define eq(received, expected, label, type)
Definition: locale.c:144
#define INFINITY
Definition: misc.c:36
static size_t elem
Definition: string.c:68
static const char mbstate_t *static wchar_t const char mbstate_t *static const wchar_t int *static double
Definition: string.c:80
static int strict
Definition: error.c:51
static DWORD DWORD DWORD DWORD * steps
Definition: cursoricon.c:1638
static ATOM item
Definition: dde.c:856
#define shift
Definition: input.c:1755
static WCHAR escape[]
Definition: url.c:36
#define real
static void set1(uint8 *data, int x, int y)
Definition: nanoxwin.c:811
static TCHAR * items[]
Definition: page1.c:45
#define IS_COMBINING(c)
#define XML_MAX_NAME_LENGTH
#define XML_MAX_NAMELEN
#define IS_DIGIT(c)
#define IS_CHAR(c)
#define IS_ASCII_DIGIT(c)
#define IS_EXTENDER(c)
#define IS_LETTER(c)
#define IS_ASCII_LETTER(c)
#define IS_CHAR_CH(c)
#define IS_BLANK_CH(c)
static unsigned __int64 next
Definition: rand_nt.c:6
#define equal(x, y)
Definition: reader.cc:56
#define test
Definition: rosglue.h:37
int n2
Definition: dwarfget.c:147
int n1
Definition: dwarfget.c:147
const WCHAR * str
static calc_node_t temp
Definition: rpn_ieee.c:38
#define ID
Definition: ruserpass.c:36
XMLPUBFUN const xmlChar *XMLCALL xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len)
Definition: dict.c:867
XMLPUBFUN void XMLCALL xmlDictFree(xmlDictPtr dict)
Definition: dict.c:802
XMLPUBFUN int XMLCALL xmlDictReference(xmlDictPtr dict)
Definition: dict.c:647
XMLPUBVAR xmlMallocFunc xmlMallocAtomic
Definition: globals.h:249
XMLPUBVAR xmlMallocFunc xmlMalloc
Definition: globals.h:248
XMLPUBVAR xmlFreeFunc xmlFree
Definition: globals.h:251
XMLPUBVAR void * xmlGenericErrorContext
Definition: globals.h:353
XMLPUBVAR xmlReallocFunc xmlRealloc
Definition: globals.h:250
XMLPUBVAR xmlGenericErrorFunc xmlGenericError
Definition: globals.h:337
XMLPUBFUN int XMLCALL xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name, const xmlChar *name2, void *userdata, xmlHashDeallocator f)
Definition: hash.c:445
XMLPUBFUN int XMLCALL xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name, const xmlChar *name2, void *userdata)
Definition: hash.c:406
XMLPUBFUN void XMLCALL xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f)
Definition: hash.c:322
XMLPUBFUN void *XMLCALL xmlHashLookup(xmlHashTablePtr table, const xmlChar *name)
Definition: hash.c:461
XMLPUBFUN int XMLCALL xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name, const xmlChar *name2, xmlHashDeallocator f)
Definition: hash.c:1071
XMLPUBFUN xmlHashTablePtr XMLCALL xmlHashCreate(int size)
Definition: hash.c:176
XMLPUBFUN int XMLCALL xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata)
Definition: hash.c:389
XMLPUBFUN int XMLCALL xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name, xmlHashDeallocator f)
Definition: hash.c:1052
XMLPUBFUN void *XMLCALL xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name, const xmlChar *name2)
Definition: hash.c:476
XMLPUBFUN void XMLCALL xmlHashDefaultDeallocator(void *entry, const xmlChar *name)
XMLPUBFUN int XMLCALL xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata, xmlHashDeallocator f)
Definition: hash.c:425
XMLPUBFUN void XMLCALL xmlInitParser(void)
Definition: parser.c:14676
XMLPUBFUN xmlNodePtr XMLCALL xmlAddChild(xmlNodePtr parent, xmlNodePtr cur)
XMLPUBFUN xmlChar *XMLCALL xmlNodeGetContent(const xmlNode *cur)
XMLPUBFUN xmlNodePtr XMLCALL xmlDocGetRootElement(const xmlDoc *doc)
XMLPUBFUN xmlChar *XMLCALL xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix, xmlChar *memory, int len)
xmlNode * xmlNodePtr
Definition: tree.h:488
XMLPUBFUN xmlDocPtr XMLCALL xmlNewDoc(const xmlChar *version)
xmlElementType
Definition: tree.h:159
@ XML_DOCUMENT_TYPE_NODE
Definition: tree.h:169
@ XML_ATTRIBUTE_NODE
Definition: tree.h:161
@ XML_ENTITY_DECL
Definition: tree.h:176
@ XML_DOCUMENT_NODE
Definition: tree.h:168
@ XML_CDATA_SECTION_NODE
Definition: tree.h:163
@ XML_TEXT_NODE
Definition: tree.h:162
@ XML_XINCLUDE_START
Definition: tree.h:178
@ XML_ENTITY_NODE
Definition: tree.h:165
@ XML_PI_NODE
Definition: tree.h:166
@ XML_XINCLUDE_END
Definition: tree.h:179
@ XML_DOCUMENT_FRAG_NODE
Definition: tree.h:170
@ XML_COMMENT_NODE
Definition: tree.h:167
@ XML_DTD_NODE
Definition: tree.h:173
@ XML_NAMESPACE_DECL
Definition: tree.h:177
@ XML_HTML_DOCUMENT_NODE
Definition: tree.h:172
@ XML_ELEMENT_NODE
Definition: tree.h:160
@ XML_ELEMENT_DECL
Definition: tree.h:174
@ XML_ENTITY_REF_NODE
Definition: tree.h:164
@ XML_NOTATION_NODE
Definition: tree.h:171
@ XML_ATTRIBUTE_DECL
Definition: tree.h:175
xmlAttr * xmlAttrPtr
Definition: tree.h:433
#define XML_XML_NAMESPACE
Definition: tree.h:140
XMLPUBFUN void XMLCALL xmlFreeNodeList(xmlNodePtr cur)
xmlNs * xmlNsPtr
Definition: tree.h:388
XMLPUBFUN xmlChar *XMLCALL xmlNodeGetLang(const xmlNode *cur)
XMLPUBFUN xmlChar *XMLCALL xmlBufContent(const xmlBuf *buf)
Definition: buf.c:553
XMLPUBFUN xmlNodePtr XMLCALL xmlDocCopyNode(xmlNodePtr node, xmlDocPtr doc, int recursive)
#define NEXTL(l)
Definition: parser.c:2156
#define COPY_BUF(l, b, i, v)
Definition: parser.c:2166
#define CUR_CHAR(l)
Definition: parser.c:2163
#define memset(x, y, z)
Definition: compat.h:39
#define finish()
Definition: seh0024.c:15
int zero
Definition: sehframes.cpp:29
CardRegion * from
Definition: spigame.cpp:19
Definition: tree.h:434
struct _xmlNode * parent
Definition: tree.h:440
Definition: buf.c:43
Definition: dict.c:111
struct _xmlDictEntry * dict
Definition: dict.c:114
Definition: tree.h:551
struct _xmlNode * children
Definition: tree.h:555
struct _xmlDoc * doc
Definition: tree.h:560
Definition: tree.h:489
xmlChar * content
Definition: tree.h:502
struct _xmlNode * children
Definition: tree.h:493
struct _xmlNode * next
Definition: tree.h:496
struct _xmlDoc * doc
Definition: tree.h:498
xmlElementType type
Definition: tree.h:491
struct _xmlNode * parent
Definition: tree.h:495
struct _xmlNode * prev
Definition: tree.h:497
Definition: tree.h:389
const xmlChar * prefix
Definition: tree.h:393
struct _xmlNs * next
Definition: tree.h:390
Definition: cookie.c:202
WCHAR * name
Definition: cookie.c:203
Definition: cache.c:49
char * value
Definition: compiler.c:67
Definition: query.h:87
Definition: fci.c:127
Definition: _hash_fun.h:40
Definition: parser.c:49
Definition: name.c:39
Definition: mxnamespace.c:45
BSTR prefix
Definition: mxnamespace.c:46
Definition: parse.h:23
Definition: reader.c:220
#define max(a, b)
Definition: svc.c:63
else
Definition: tritemp.h:161
Definition: dlist.c:348
Definition: pdh_main.c:94
XMLPUBFUN xmlAttrPtr XMLCALL xmlGetID(xmlDocPtr doc, const xmlChar *ID)
Definition: valid.c:2874
static const WCHAR lang[]
Definition: wbemdisp.c:287
int ret
void * arg
Definition: msvc.h:10
static int init
Definition: wintirpc.c:33
#define snprintf
Definition: wintirpc.h:48
@ XML_ERR_ERROR
Definition: xmlerror.h:27
@ XML_ERR_FATAL
Definition: xmlerror.h:28
@ XML_FROM_XPATH
Definition: xmlerror.h:49
XMLPUBFUN void XMLCALL xmlResetError(xmlErrorPtr err)
@ XML_XPATH_EXPRESSION_OK
Definition: xmlerror.h:387
@ XML_ERR_NO_MEMORY
Definition: xmlerror.h:102
XMLPUBFUN int XMLCALL xmlUTF8Strlen(const xmlChar *utf)
Definition: xmlstring.c:664
XMLPUBFUN const xmlChar *XMLCALL xmlStrchr(const xmlChar *str, xmlChar val)
Definition: xmlstring.c:325
XMLPUBFUN const xmlChar *XMLCALL xmlUTF8Strpos(const xmlChar *utf, int pos)
Definition: xmlstring.c:894
XMLPUBFUN xmlChar *XMLCALL xmlStrndup(const xmlChar *cur, int len)
Definition: xmlstring.c:42
XMLPUBFUN xmlChar *XMLCALL xmlUTF8Strsub(const xmlChar *utf, int start, int len)
Definition: xmlstring.c:964
XMLPUBFUN xmlChar *XMLCALL xmlStrcat(xmlChar *cur, const xmlChar *add)
Definition: xmlstring.c:524
XMLPUBFUN int XMLCALL xmlStrncmp(const xmlChar *str1, const xmlChar *str2, int len)
Definition: xmlstring.c:213
XMLPUBFUN const xmlChar *XMLCALL xmlStrstr(const xmlChar *str, const xmlChar *val)
Definition: xmlstring.c:345
XMLPUBFUN int XMLCALL xmlStrPrintf(xmlChar *buf, int len, const char *msg,...) LIBXML_ATTR_FORMAT(3
XMLPUBFUN xmlChar *XMLCALL xmlStrdup(const xmlChar *cur)
Definition: xmlstring.c:67
XMLPUBFUN int XMLCALL xmlUTF8Strsize(const xmlChar *utf, int len)
Definition: xmlstring.c:833
XMLPUBFUN int XMLCALL xmlUTF8Strloc(const xmlChar *utf, const xmlChar *utfchar)
Definition: xmlstring.c:926
#define BAD_CAST
Definition: xmlstring.h:35
XMLPUBFUN int XMLCALL xmlStrEqual(const xmlChar *str1, const xmlChar *str2)
Definition: xmlstring.c:160
XMLPUBFUN int XMLCALL xmlStrlen(const xmlChar *str)
Definition: xmlstring.c:426
unsigned char xmlChar
Definition: xmlstring.h:28
#define XP_OPTIMIZED_NON_ELEM_COMPARISON
Definition: xpath.c:81
static int wrap_cmp(xmlNodePtr x, xmlNodePtr y)
Definition: xpath.c:454
static int xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2)
Definition: xpath.c:156
#define XPATH_MAX_STACK_DEPTH
Definition: xpath.c:113
#define XPATH_MAX_STEPS
Definition: xpath.c:104
#define XPATH_MAX_NODESET_LENGTH
Definition: xpath.c:123
#define XP_OPTIMIZED_FILTER_FIRST
Definition: xpath.c:88
#define XPATH_MAX_RECURSION_DEPTH
Definition: xpath.c:133
#define TODO
Definition: xpath.c:58
double xmlXPathStringEvalNumber(const xmlChar *str)