1 /*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
11 * See Copyright for the status of this software
12 *
13 * Author: daniel@veillard.com
14 *
15 */
16
17 /* To avoid EBCDIC trouble when parsing on zOS */
18 #if defined(__MVS__)
19 #pragma convert("ISO8859-1")
20 #endif
21
22 #define IN_LIBXML
23 #include "libxml.h"
24
25 #include <limits.h>
26 #include <string.h>
27 #include <stddef.h>
28 #include <math.h>
29 #include <float.h>
30 #include <ctype.h>
31
32 #include <libxml/xmlmemory.h>
33 #include <libxml/tree.h>
34 #include <libxml/xpath.h>
35 #include <libxml/xpathInternals.h>
36 #include <libxml/parserInternals.h>
37 #include <libxml/hash.h>
38 #ifdef LIBXML_DEBUG_ENABLED
39 #include <libxml/debugXML.h>
40 #endif
41 #include <libxml/xmlerror.h>
42 #include <libxml/threads.h>
43 #ifdef LIBXML_PATTERN_ENABLED
44 #include <libxml/pattern.h>
45 #endif
46
47 #include "private/buf.h"
48 #include "private/error.h"
49 #include "private/xpath.h"
50
51 /* Disabled for now */
52 #if 0
53 #ifdef LIBXML_PATTERN_ENABLED
54 #define XPATH_STREAMING
55 #endif
56 #endif
57
58 /**
59 * WITH_TIM_SORT:
60 *
61 * Use the Timsort algorithm provided in timsort.h to sort
62 * nodeset as this is a great improvement over the old Shell sort
63 * used in xmlXPathNodeSetSort()
64 */
65 #define WITH_TIM_SORT
66
67 /*
68 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
69 * If defined, this will use xmlXPathCmpNodesExt() instead of
70 * xmlXPathCmpNodes(). The new function is optimized comparison of
71 * non-element nodes; actually it will speed up comparison only if
72 * xmlXPathOrderDocElems() was called in order to index the elements of
73 * a tree in document order; Libxslt does such an indexing, thus it will
74 * benefit from this optimization.
75 */
76 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
77
78 /*
79 * XP_OPTIMIZED_FILTER_FIRST:
80 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
81 * in a way, that it stop evaluation at the first node.
82 */
83 #define XP_OPTIMIZED_FILTER_FIRST
84
85 /*
86 * XPATH_MAX_STEPS:
87 * when compiling an XPath expression we arbitrary limit the maximum
88 * number of step operation in the compiled expression. 1000000 is
89 * an insanely large value which should never be reached under normal
90 * circumstances
91 */
92 #define XPATH_MAX_STEPS 1000000
93
94 /*
95 * XPATH_MAX_STACK_DEPTH:
96 * when evaluating an XPath expression we arbitrary limit the maximum
97 * number of object allowed to be pushed on the stack. 1000000 is
98 * an insanely large value which should never be reached under normal
99 * circumstances
100 */
101 #define XPATH_MAX_STACK_DEPTH 1000000
102
103 /*
104 * XPATH_MAX_NODESET_LENGTH:
105 * when evaluating an XPath expression nodesets are created and we
106 * arbitrary limit the maximum length of those node set. 10000000 is
107 * an insanely large value which should never be reached under normal
108 * circumstances, one would first need to construct an in memory tree
109 * with more than 10 millions nodes.
110 */
111 #define XPATH_MAX_NODESET_LENGTH 10000000
112
113 /*
114 * XPATH_MAX_RECRUSION_DEPTH:
115 * Maximum amount of nested functions calls when parsing or evaluating
116 * expressions
117 */
118 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
119 #define XPATH_MAX_RECURSION_DEPTH 500
120 #elif defined(_WIN32)
121 /* Windows typically limits stack size to 1MB. */
122 #define XPATH_MAX_RECURSION_DEPTH 1000
123 #else
124 #define XPATH_MAX_RECURSION_DEPTH 5000
125 #endif
126
127 /*
128 * TODO:
129 * There are a few spots where some tests are done which depend upon ascii
130 * data. These should be enhanced for full UTF8 support (see particularly
131 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
132 */
133
134 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
135
136 /************************************************************************
137 * *
138 * Floating point stuff *
139 * *
140 ************************************************************************/
141
142 double xmlXPathNAN = 0.0;
143 double xmlXPathPINF = 0.0;
144 double xmlXPathNINF = 0.0;
145
146 /**
147 * xmlXPathInit:
148 *
149 * DEPRECATED: Alias for xmlInitParser.
150 */
151 void
xmlXPathInit(void)152 xmlXPathInit(void) {
153 xmlInitParser();
154 }
155
156 /**
157 * xmlInitXPathInternal:
158 *
159 * Initialize the XPath environment
160 */
161 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
162 void
xmlInitXPathInternal(void)163 xmlInitXPathInternal(void) {
164 #if defined(NAN) && defined(INFINITY)
165 xmlXPathNAN = NAN;
166 xmlXPathPINF = INFINITY;
167 xmlXPathNINF = -INFINITY;
168 #else
169 /* MSVC doesn't allow division by zero in constant expressions. */
170 double zero = 0.0;
171 xmlXPathNAN = 0.0 / zero;
172 xmlXPathPINF = 1.0 / zero;
173 xmlXPathNINF = -xmlXPathPINF;
174 #endif
175 }
176
177 /**
178 * xmlXPathIsNaN:
179 * @val: a double value
180 *
181 * Checks whether a double is a NaN.
182 *
183 * Returns 1 if the value is a NaN, 0 otherwise
184 */
185 int
xmlXPathIsNaN(double val)186 xmlXPathIsNaN(double val) {
187 #ifdef isnan
188 return isnan(val);
189 #else
190 return !(val == val);
191 #endif
192 }
193
194 /**
195 * xmlXPathIsInf:
196 * @val: a double value
197 *
198 * Checks whether a double is an infinity.
199 *
200 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
201 */
202 int
xmlXPathIsInf(double val)203 xmlXPathIsInf(double val) {
204 #ifdef isinf
205 return isinf(val) ? (val > 0 ? 1 : -1) : 0;
206 #else
207 if (val >= xmlXPathPINF)
208 return 1;
209 if (val <= -xmlXPathPINF)
210 return -1;
211 return 0;
212 #endif
213 }
214
215 #endif /* SCHEMAS or XPATH */
216
217 #ifdef LIBXML_XPATH_ENABLED
218
219 /*
220 * TODO: when compatibility allows remove all "fake node libxslt" strings
221 * the test should just be name[0] = ' '
222 */
223
224 static const xmlNs xmlXPathXMLNamespaceStruct = {
225 NULL,
226 XML_NAMESPACE_DECL,
227 XML_XML_NAMESPACE,
228 BAD_CAST "xml",
229 NULL,
230 NULL
231 };
232 static const xmlNs *const xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
233 #ifndef LIBXML_THREAD_ENABLED
234 /*
235 * Optimizer is disabled only when threaded apps are detected while
236 * the library ain't compiled for thread safety.
237 */
238 static int xmlXPathDisableOptimizer = 0;
239 #endif
240
241 static void
242 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes);
243
244 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
245 /**
246 * xmlXPathCmpNodesExt:
247 * @node1: the first node
248 * @node2: the second node
249 *
250 * Compare two nodes w.r.t document order.
251 * This one is optimized for handling of non-element nodes.
252 *
253 * Returns -2 in case of error 1 if first point < second point, 0 if
254 * it's the same node, -1 otherwise
255 */
256 static int
xmlXPathCmpNodesExt(xmlNodePtr node1,xmlNodePtr node2)257 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
258 int depth1, depth2;
259 int misc = 0, precedence1 = 0, precedence2 = 0;
260 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
261 xmlNodePtr cur, root;
262 ptrdiff_t l1, l2;
263
264 if ((node1 == NULL) || (node2 == NULL))
265 return(-2);
266
267 if (node1 == node2)
268 return(0);
269
270 /*
271 * a couple of optimizations which will avoid computations in most cases
272 */
273 switch (node1->type) {
274 case XML_ELEMENT_NODE:
275 if (node2->type == XML_ELEMENT_NODE) {
276 if ((0 > (ptrdiff_t) node1->content) &&
277 (0 > (ptrdiff_t) node2->content) &&
278 (node1->doc == node2->doc))
279 {
280 l1 = -((ptrdiff_t) node1->content);
281 l2 = -((ptrdiff_t) node2->content);
282 if (l1 < l2)
283 return(1);
284 if (l1 > l2)
285 return(-1);
286 } else
287 goto turtle_comparison;
288 }
289 break;
290 case XML_ATTRIBUTE_NODE:
291 precedence1 = 1; /* element is owner */
292 miscNode1 = node1;
293 node1 = node1->parent;
294 misc = 1;
295 break;
296 case XML_TEXT_NODE:
297 case XML_CDATA_SECTION_NODE:
298 case XML_COMMENT_NODE:
299 case XML_PI_NODE: {
300 miscNode1 = node1;
301 /*
302 * Find nearest element node.
303 */
304 if (node1->prev != NULL) {
305 do {
306 node1 = node1->prev;
307 if (node1->type == XML_ELEMENT_NODE) {
308 precedence1 = 3; /* element in prev-sibl axis */
309 break;
310 }
311 if (node1->prev == NULL) {
312 precedence1 = 2; /* element is parent */
313 /*
314 * URGENT TODO: Are there any cases, where the
315 * parent of such a node is not an element node?
316 */
317 node1 = node1->parent;
318 break;
319 }
320 } while (1);
321 } else {
322 precedence1 = 2; /* element is parent */
323 node1 = node1->parent;
324 }
325 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
326 (0 <= (ptrdiff_t) node1->content)) {
327 /*
328 * Fallback for whatever case.
329 */
330 node1 = miscNode1;
331 precedence1 = 0;
332 } else
333 misc = 1;
334 }
335 break;
336 case XML_NAMESPACE_DECL:
337 /*
338 * TODO: why do we return 1 for namespace nodes?
339 */
340 return(1);
341 default:
342 break;
343 }
344 switch (node2->type) {
345 case XML_ELEMENT_NODE:
346 break;
347 case XML_ATTRIBUTE_NODE:
348 precedence2 = 1; /* element is owner */
349 miscNode2 = node2;
350 node2 = node2->parent;
351 misc = 1;
352 break;
353 case XML_TEXT_NODE:
354 case XML_CDATA_SECTION_NODE:
355 case XML_COMMENT_NODE:
356 case XML_PI_NODE: {
357 miscNode2 = node2;
358 if (node2->prev != NULL) {
359 do {
360 node2 = node2->prev;
361 if (node2->type == XML_ELEMENT_NODE) {
362 precedence2 = 3; /* element in prev-sibl axis */
363 break;
364 }
365 if (node2->prev == NULL) {
366 precedence2 = 2; /* element is parent */
367 node2 = node2->parent;
368 break;
369 }
370 } while (1);
371 } else {
372 precedence2 = 2; /* element is parent */
373 node2 = node2->parent;
374 }
375 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
376 (0 <= (ptrdiff_t) node2->content))
377 {
378 node2 = miscNode2;
379 precedence2 = 0;
380 } else
381 misc = 1;
382 }
383 break;
384 case XML_NAMESPACE_DECL:
385 return(1);
386 default:
387 break;
388 }
389 if (misc) {
390 if (node1 == node2) {
391 if (precedence1 == precedence2) {
392 /*
393 * The ugly case; but normally there aren't many
394 * adjacent non-element nodes around.
395 */
396 cur = miscNode2->prev;
397 while (cur != NULL) {
398 if (cur == miscNode1)
399 return(1);
400 if (cur->type == XML_ELEMENT_NODE)
401 return(-1);
402 cur = cur->prev;
403 }
404 return (-1);
405 } else {
406 /*
407 * Evaluate based on higher precedence wrt to the element.
408 * TODO: This assumes attributes are sorted before content.
409 * Is this 100% correct?
410 */
411 if (precedence1 < precedence2)
412 return(1);
413 else
414 return(-1);
415 }
416 }
417 /*
418 * Special case: One of the helper-elements is contained by the other.
419 * <foo>
420 * <node2>
421 * <node1>Text-1(precedence1 == 2)</node1>
422 * </node2>
423 * Text-6(precedence2 == 3)
424 * </foo>
425 */
426 if ((precedence2 == 3) && (precedence1 > 1)) {
427 cur = node1->parent;
428 while (cur) {
429 if (cur == node2)
430 return(1);
431 cur = cur->parent;
432 }
433 }
434 if ((precedence1 == 3) && (precedence2 > 1)) {
435 cur = node2->parent;
436 while (cur) {
437 if (cur == node1)
438 return(-1);
439 cur = cur->parent;
440 }
441 }
442 }
443
444 /*
445 * Speedup using document order if available.
446 */
447 if ((node1->type == XML_ELEMENT_NODE) &&
448 (node2->type == XML_ELEMENT_NODE) &&
449 (0 > (ptrdiff_t) node1->content) &&
450 (0 > (ptrdiff_t) node2->content) &&
451 (node1->doc == node2->doc)) {
452
453 l1 = -((ptrdiff_t) node1->content);
454 l2 = -((ptrdiff_t) node2->content);
455 if (l1 < l2)
456 return(1);
457 if (l1 > l2)
458 return(-1);
459 }
460
461 turtle_comparison:
462
463 if (node1 == node2->prev)
464 return(1);
465 if (node1 == node2->next)
466 return(-1);
467 /*
468 * compute depth to root
469 */
470 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
471 if (cur->parent == node1)
472 return(1);
473 depth2++;
474 }
475 root = cur;
476 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
477 if (cur->parent == node2)
478 return(-1);
479 depth1++;
480 }
481 /*
482 * Distinct document (or distinct entities :-( ) case.
483 */
484 if (root != cur) {
485 return(-2);
486 }
487 /*
488 * get the nearest common ancestor.
489 */
490 while (depth1 > depth2) {
491 depth1--;
492 node1 = node1->parent;
493 }
494 while (depth2 > depth1) {
495 depth2--;
496 node2 = node2->parent;
497 }
498 while (node1->parent != node2->parent) {
499 node1 = node1->parent;
500 node2 = node2->parent;
501 /* should not happen but just in case ... */
502 if ((node1 == NULL) || (node2 == NULL))
503 return(-2);
504 }
505 /*
506 * Find who's first.
507 */
508 if (node1 == node2->prev)
509 return(1);
510 if (node1 == node2->next)
511 return(-1);
512 /*
513 * Speedup using document order if available.
514 */
515 if ((node1->type == XML_ELEMENT_NODE) &&
516 (node2->type == XML_ELEMENT_NODE) &&
517 (0 > (ptrdiff_t) node1->content) &&
518 (0 > (ptrdiff_t) node2->content) &&
519 (node1->doc == node2->doc)) {
520
521 l1 = -((ptrdiff_t) node1->content);
522 l2 = -((ptrdiff_t) node2->content);
523 if (l1 < l2)
524 return(1);
525 if (l1 > l2)
526 return(-1);
527 }
528
529 for (cur = node1->next;cur != NULL;cur = cur->next)
530 if (cur == node2)
531 return(1);
532 return(-1); /* assume there is no sibling list corruption */
533 }
534 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
535
536 /*
537 * Wrapper for the Timsort algorithm from timsort.h
538 */
539 #ifdef WITH_TIM_SORT
540 #define SORT_NAME libxml_domnode
541 #define SORT_TYPE xmlNodePtr
542 /**
543 * wrap_cmp:
544 * @x: a node
545 * @y: another node
546 *
547 * Comparison function for the Timsort implementation
548 *
549 * Returns -2 in case of error -1 if first point < second point, 0 if
550 * it's the same node, +1 otherwise
551 */
552 static
553 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
554 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
wrap_cmp(xmlNodePtr x,xmlNodePtr y)555 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
556 {
557 int res = xmlXPathCmpNodesExt(x, y);
558 return res == -2 ? res : -res;
559 }
560 #else
wrap_cmp(xmlNodePtr x,xmlNodePtr y)561 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
562 {
563 int res = xmlXPathCmpNodes(x, y);
564 return res == -2 ? res : -res;
565 }
566 #endif
567 #define SORT_CMP(x, y) (wrap_cmp(x, y))
568 #include "timsort.h"
569 #endif /* WITH_TIM_SORT */
570
571 /************************************************************************
572 * *
573 * Error handling routines *
574 * *
575 ************************************************************************/
576
577 /**
578 * XP_ERRORNULL:
579 * @X: the error code
580 *
581 * Macro to raise an XPath error and return NULL.
582 */
583 #define XP_ERRORNULL(X) \
584 { xmlXPathErr(ctxt, X); return(NULL); }
585
586 /*
587 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
588 */
589 static const char* const xmlXPathErrorMessages[] = {
590 "Ok\n",
591 "Number encoding\n",
592 "Unfinished literal\n",
593 "Start of literal\n",
594 "Expected $ for variable reference\n",
595 "Undefined variable\n",
596 "Invalid predicate\n",
597 "Invalid expression\n",
598 "Missing closing curly brace\n",
599 "Unregistered function\n",
600 "Invalid operand\n",
601 "Invalid type\n",
602 "Invalid number of arguments\n",
603 "Invalid context size\n",
604 "Invalid context position\n",
605 "Memory allocation error\n",
606 "Syntax error\n",
607 "Resource error\n",
608 "Sub resource error\n",
609 "Undefined namespace prefix\n",
610 "Encoding error\n",
611 "Char out of XML range\n",
612 "Invalid or incomplete context\n",
613 "Stack usage error\n",
614 "Forbidden variable\n",
615 "Operation limit exceeded\n",
616 "Recursion limit exceeded\n",
617 "?? Unknown error ??\n" /* Must be last in the list! */
618 };
619 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
620 sizeof(xmlXPathErrorMessages[0])) - 1)
621 /**
622 * xmlXPathErrMemory:
623 * @ctxt: an XPath context
624 *
625 * Handle a memory allocation failure.
626 */
627 void
xmlXPathErrMemory(xmlXPathContextPtr ctxt)628 xmlXPathErrMemory(xmlXPathContextPtr ctxt)
629 {
630 if (ctxt == NULL)
631 return;
632 xmlRaiseMemoryError(ctxt->error, NULL, ctxt->userData, XML_FROM_XPATH,
633 &ctxt->lastError);
634 }
635
636 /**
637 * xmlXPathPErrMemory:
638 * @ctxt: an XPath parser context
639 *
640 * Handle a memory allocation failure.
641 */
642 void
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt)643 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt)
644 {
645 if (ctxt == NULL)
646 return;
647 ctxt->error = XPATH_MEMORY_ERROR;
648 xmlXPathErrMemory(ctxt->context);
649 }
650
651 /**
652 * xmlXPathErr:
653 * @ctxt: a XPath parser context
654 * @code: the error code
655 *
656 * Handle an XPath error
657 */
658 void
xmlXPathErr(xmlXPathParserContextPtr ctxt,int code)659 xmlXPathErr(xmlXPathParserContextPtr ctxt, int code)
660 {
661 xmlStructuredErrorFunc schannel = NULL;
662 xmlGenericErrorFunc channel = NULL;
663 void *data = NULL;
664 xmlNodePtr node = NULL;
665 int res;
666
667 if (ctxt == NULL)
668 return;
669 if ((code < 0) || (code > MAXERRNO))
670 code = MAXERRNO;
671 /* Only report the first error */
672 if (ctxt->error != 0)
673 return;
674
675 ctxt->error = code;
676
677 if (ctxt->context != NULL) {
678 xmlErrorPtr err = &ctxt->context->lastError;
679
680 /* Don't overwrite memory error. */
681 if (err->code == XML_ERR_NO_MEMORY)
682 return;
683
684 /* cleanup current last error */
685 xmlResetError(err);
686
687 err->domain = XML_FROM_XPATH;
688 err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK;
689 err->level = XML_ERR_ERROR;
690 if (ctxt->base != NULL) {
691 err->str1 = (char *) xmlStrdup(ctxt->base);
692 if (err->str1 == NULL) {
693 xmlXPathPErrMemory(ctxt);
694 return;
695 }
696 }
697 err->int1 = ctxt->cur - ctxt->base;
698 err->node = ctxt->context->debugNode;
699
700 schannel = ctxt->context->error;
701 data = ctxt->context->userData;
702 node = ctxt->context->debugNode;
703 }
704
705 if (schannel == NULL) {
706 channel = xmlGenericError;
707 data = xmlGenericErrorContext;
708 }
709
710 res = __xmlRaiseError(schannel, channel, data, NULL, node, XML_FROM_XPATH,
711 code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
712 XML_ERR_ERROR, NULL, 0,
713 (const char *) ctxt->base, NULL, NULL,
714 ctxt->cur - ctxt->base, 0,
715 "%s", xmlXPathErrorMessages[code]);
716 if (res < 0)
717 xmlXPathPErrMemory(ctxt);
718 }
719
720 /**
721 * xmlXPatherror:
722 * @ctxt: the XPath Parser context
723 * @file: the file name
724 * @line: the line number
725 * @no: the error number
726 *
727 * Formats an error message.
728 */
729 void
xmlXPatherror(xmlXPathParserContextPtr ctxt,const char * file ATTRIBUTE_UNUSED,int line ATTRIBUTE_UNUSED,int no)730 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
731 int line ATTRIBUTE_UNUSED, int no) {
732 xmlXPathErr(ctxt, no);
733 }
734
735 /**
736 * xmlXPathCheckOpLimit:
737 * @ctxt: the XPath Parser context
738 * @opCount: the number of operations to be added
739 *
740 * Adds opCount to the running total of operations and returns -1 if the
741 * operation limit is exceeded. Returns 0 otherwise.
742 */
743 static int
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt,unsigned long opCount)744 xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
745 xmlXPathContextPtr xpctxt = ctxt->context;
746
747 if ((opCount > xpctxt->opLimit) ||
748 (xpctxt->opCount > xpctxt->opLimit - opCount)) {
749 xpctxt->opCount = xpctxt->opLimit;
750 xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
751 return(-1);
752 }
753
754 xpctxt->opCount += opCount;
755 return(0);
756 }
757
758 #define OP_LIMIT_EXCEEDED(ctxt, n) \
759 ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
760
761 /************************************************************************
762 * *
763 * Parser Types *
764 * *
765 ************************************************************************/
766
767 /*
768 * Types are private:
769 */
770
771 typedef enum {
772 XPATH_OP_END=0,
773 XPATH_OP_AND,
774 XPATH_OP_OR,
775 XPATH_OP_EQUAL,
776 XPATH_OP_CMP,
777 XPATH_OP_PLUS,
778 XPATH_OP_MULT,
779 XPATH_OP_UNION,
780 XPATH_OP_ROOT,
781 XPATH_OP_NODE,
782 XPATH_OP_COLLECT,
783 XPATH_OP_VALUE, /* 11 */
784 XPATH_OP_VARIABLE,
785 XPATH_OP_FUNCTION,
786 XPATH_OP_ARG,
787 XPATH_OP_PREDICATE,
788 XPATH_OP_FILTER, /* 16 */
789 XPATH_OP_SORT /* 17 */
790 } xmlXPathOp;
791
792 typedef enum {
793 AXIS_ANCESTOR = 1,
794 AXIS_ANCESTOR_OR_SELF,
795 AXIS_ATTRIBUTE,
796 AXIS_CHILD,
797 AXIS_DESCENDANT,
798 AXIS_DESCENDANT_OR_SELF,
799 AXIS_FOLLOWING,
800 AXIS_FOLLOWING_SIBLING,
801 AXIS_NAMESPACE,
802 AXIS_PARENT,
803 AXIS_PRECEDING,
804 AXIS_PRECEDING_SIBLING,
805 AXIS_SELF
806 } xmlXPathAxisVal;
807
808 typedef enum {
809 NODE_TEST_NONE = 0,
810 NODE_TEST_TYPE = 1,
811 NODE_TEST_PI = 2,
812 NODE_TEST_ALL = 3,
813 NODE_TEST_NS = 4,
814 NODE_TEST_NAME = 5
815 } xmlXPathTestVal;
816
817 typedef enum {
818 NODE_TYPE_NODE = 0,
819 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
820 NODE_TYPE_TEXT = XML_TEXT_NODE,
821 NODE_TYPE_PI = XML_PI_NODE
822 } xmlXPathTypeVal;
823
824 typedef struct _xmlXPathStepOp xmlXPathStepOp;
825 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
826 struct _xmlXPathStepOp {
827 xmlXPathOp op; /* The identifier of the operation */
828 int ch1; /* First child */
829 int ch2; /* Second child */
830 int value;
831 int value2;
832 int value3;
833 void *value4;
834 void *value5;
835 xmlXPathFunction cache;
836 void *cacheURI;
837 };
838
839 struct _xmlXPathCompExpr {
840 int nbStep; /* Number of steps in this expression */
841 int maxStep; /* Maximum number of steps allocated */
842 xmlXPathStepOp *steps; /* ops for computation of this expression */
843 int last; /* index of last step in expression */
844 xmlChar *expr; /* the expression being computed */
845 xmlDictPtr dict; /* the dictionary to use if any */
846 #ifdef XPATH_STREAMING
847 xmlPatternPtr stream;
848 #endif
849 };
850
851 /************************************************************************
852 * *
853 * Forward declarations *
854 * *
855 ************************************************************************/
856
857 static void
858 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
859 static int
860 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
861 xmlXPathStepOpPtr op, xmlNodePtr *first);
862 static int
863 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
864 xmlXPathStepOpPtr op,
865 int isPredicate);
866 static void
867 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
868
869 /************************************************************************
870 * *
871 * Parser Type functions *
872 * *
873 ************************************************************************/
874
875 /**
876 * xmlXPathNewCompExpr:
877 *
878 * Create a new Xpath component
879 *
880 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
881 */
882 static xmlXPathCompExprPtr
xmlXPathNewCompExpr(void)883 xmlXPathNewCompExpr(void) {
884 xmlXPathCompExprPtr cur;
885
886 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
887 if (cur == NULL)
888 return(NULL);
889 memset(cur, 0, sizeof(xmlXPathCompExpr));
890 cur->maxStep = 10;
891 cur->nbStep = 0;
892 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
893 sizeof(xmlXPathStepOp));
894 if (cur->steps == NULL) {
895 xmlFree(cur);
896 return(NULL);
897 }
898 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
899 cur->last = -1;
900 return(cur);
901 }
902
903 /**
904 * xmlXPathFreeCompExpr:
905 * @comp: an XPATH comp
906 *
907 * Free up the memory allocated by @comp
908 */
909 void
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)910 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
911 {
912 xmlXPathStepOpPtr op;
913 int i;
914
915 if (comp == NULL)
916 return;
917 if (comp->dict == NULL) {
918 for (i = 0; i < comp->nbStep; i++) {
919 op = &comp->steps[i];
920 if (op->value4 != NULL) {
921 if (op->op == XPATH_OP_VALUE)
922 xmlXPathFreeObject(op->value4);
923 else
924 xmlFree(op->value4);
925 }
926 if (op->value5 != NULL)
927 xmlFree(op->value5);
928 }
929 } else {
930 for (i = 0; i < comp->nbStep; i++) {
931 op = &comp->steps[i];
932 if (op->value4 != NULL) {
933 if (op->op == XPATH_OP_VALUE)
934 xmlXPathFreeObject(op->value4);
935 }
936 }
937 xmlDictFree(comp->dict);
938 }
939 if (comp->steps != NULL) {
940 xmlFree(comp->steps);
941 }
942 #ifdef XPATH_STREAMING
943 if (comp->stream != NULL) {
944 xmlFreePatternList(comp->stream);
945 }
946 #endif
947 if (comp->expr != NULL) {
948 xmlFree(comp->expr);
949 }
950
951 xmlFree(comp);
952 }
953
954 /**
955 * xmlXPathCompExprAdd:
956 * @comp: the compiled expression
957 * @ch1: first child index
958 * @ch2: second child index
959 * @op: an op
960 * @value: the first int value
961 * @value2: the second int value
962 * @value3: the third int value
963 * @value4: the first string value
964 * @value5: the second string value
965 *
966 * Add a step to an XPath Compiled Expression
967 *
968 * Returns -1 in case of failure, the index otherwise
969 */
970 static int
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt,int ch1,int ch2,xmlXPathOp op,int value,int value2,int value3,void * value4,void * value5)971 xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
972 xmlXPathOp op, int value,
973 int value2, int value3, void *value4, void *value5) {
974 xmlXPathCompExprPtr comp = ctxt->comp;
975 if (comp->nbStep >= comp->maxStep) {
976 xmlXPathStepOp *real;
977
978 if (comp->maxStep >= XPATH_MAX_STEPS) {
979 xmlXPathPErrMemory(ctxt);
980 return(-1);
981 }
982 comp->maxStep *= 2;
983 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
984 comp->maxStep * sizeof(xmlXPathStepOp));
985 if (real == NULL) {
986 comp->maxStep /= 2;
987 xmlXPathPErrMemory(ctxt);
988 return(-1);
989 }
990 comp->steps = real;
991 }
992 comp->last = comp->nbStep;
993 comp->steps[comp->nbStep].ch1 = ch1;
994 comp->steps[comp->nbStep].ch2 = ch2;
995 comp->steps[comp->nbStep].op = op;
996 comp->steps[comp->nbStep].value = value;
997 comp->steps[comp->nbStep].value2 = value2;
998 comp->steps[comp->nbStep].value3 = value3;
999 if ((comp->dict != NULL) &&
1000 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1001 (op == XPATH_OP_COLLECT))) {
1002 if (value4 != NULL) {
1003 comp->steps[comp->nbStep].value4 = (xmlChar *)
1004 (void *)xmlDictLookup(comp->dict, value4, -1);
1005 xmlFree(value4);
1006 } else
1007 comp->steps[comp->nbStep].value4 = NULL;
1008 if (value5 != NULL) {
1009 comp->steps[comp->nbStep].value5 = (xmlChar *)
1010 (void *)xmlDictLookup(comp->dict, value5, -1);
1011 xmlFree(value5);
1012 } else
1013 comp->steps[comp->nbStep].value5 = NULL;
1014 } else {
1015 comp->steps[comp->nbStep].value4 = value4;
1016 comp->steps[comp->nbStep].value5 = value5;
1017 }
1018 comp->steps[comp->nbStep].cache = NULL;
1019 return(comp->nbStep++);
1020 }
1021
1022 /**
1023 * xmlXPathCompSwap:
1024 * @comp: the compiled expression
1025 * @op: operation index
1026 *
1027 * Swaps 2 operations in the compiled expression
1028 */
1029 static void
xmlXPathCompSwap(xmlXPathStepOpPtr op)1030 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1031 int tmp;
1032
1033 #ifndef LIBXML_THREAD_ENABLED
1034 /*
1035 * Since this manipulates possibly shared variables, this is
1036 * disabled if one detects that the library is used in a multithreaded
1037 * application
1038 */
1039 if (xmlXPathDisableOptimizer)
1040 return;
1041 #endif
1042
1043 tmp = op->ch1;
1044 op->ch1 = op->ch2;
1045 op->ch2 = tmp;
1046 }
1047
1048 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1049 xmlXPathCompExprAdd(ctxt, (op1), (op2), \
1050 (op), (val), (val2), (val3), (val4), (val5))
1051 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1052 xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \
1053 (op), (val), (val2), (val3), (val4), (val5))
1054
1055 #define PUSH_LEAVE_EXPR(op, val, val2) \
1056 xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1057
1058 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
1059 xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1060
1061 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1062 xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
1063 (val), (val2), 0 ,NULL ,NULL)
1064
1065 /************************************************************************
1066 * *
1067 * XPath object cache structures *
1068 * *
1069 ************************************************************************/
1070
1071 /* #define XP_DEFAULT_CACHE_ON */
1072
1073 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1074 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1075 struct _xmlXPathContextCache {
1076 xmlXPathObjectPtr nodesetObjs; /* stringval points to next */
1077 xmlXPathObjectPtr miscObjs; /* stringval points to next */
1078 int numNodeset;
1079 int maxNodeset;
1080 int numMisc;
1081 int maxMisc;
1082 };
1083
1084 /************************************************************************
1085 * *
1086 * Debugging related functions *
1087 * *
1088 ************************************************************************/
1089
1090 #ifdef LIBXML_DEBUG_ENABLED
1091 static void
xmlXPathDebugDumpNode(FILE * output,xmlNodePtr cur,int depth)1092 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1093 int i;
1094 char shift[100];
1095
1096 for (i = 0;((i < depth) && (i < 25));i++)
1097 shift[2 * i] = shift[2 * i + 1] = ' ';
1098 shift[2 * i] = shift[2 * i + 1] = 0;
1099 if (cur == NULL) {
1100 fprintf(output, "%s", shift);
1101 fprintf(output, "Node is NULL !\n");
1102 return;
1103
1104 }
1105
1106 if ((cur->type == XML_DOCUMENT_NODE) ||
1107 (cur->type == XML_HTML_DOCUMENT_NODE)) {
1108 fprintf(output, "%s", shift);
1109 fprintf(output, " /\n");
1110 } else if (cur->type == XML_ATTRIBUTE_NODE)
1111 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1112 else
1113 xmlDebugDumpOneNode(output, cur, depth);
1114 }
1115 static void
xmlXPathDebugDumpNodeList(FILE * output,xmlNodePtr cur,int depth)1116 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1117 xmlNodePtr tmp;
1118 int i;
1119 char shift[100];
1120
1121 for (i = 0;((i < depth) && (i < 25));i++)
1122 shift[2 * i] = shift[2 * i + 1] = ' ';
1123 shift[2 * i] = shift[2 * i + 1] = 0;
1124 if (cur == NULL) {
1125 fprintf(output, "%s", shift);
1126 fprintf(output, "Node is NULL !\n");
1127 return;
1128
1129 }
1130
1131 while (cur != NULL) {
1132 tmp = cur;
1133 cur = cur->next;
1134 xmlDebugDumpOneNode(output, tmp, depth);
1135 }
1136 }
1137
1138 static void
xmlXPathDebugDumpNodeSet(FILE * output,xmlNodeSetPtr cur,int depth)1139 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1140 int i;
1141 char shift[100];
1142
1143 for (i = 0;((i < depth) && (i < 25));i++)
1144 shift[2 * i] = shift[2 * i + 1] = ' ';
1145 shift[2 * i] = shift[2 * i + 1] = 0;
1146
1147 if (cur == NULL) {
1148 fprintf(output, "%s", shift);
1149 fprintf(output, "NodeSet is NULL !\n");
1150 return;
1151
1152 }
1153
1154 if (cur != NULL) {
1155 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1156 for (i = 0;i < cur->nodeNr;i++) {
1157 fprintf(output, "%s", shift);
1158 fprintf(output, "%d", i + 1);
1159 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1160 }
1161 }
1162 }
1163
1164 static void
xmlXPathDebugDumpValueTree(FILE * output,xmlNodeSetPtr cur,int depth)1165 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1166 int i;
1167 char shift[100];
1168
1169 for (i = 0;((i < depth) && (i < 25));i++)
1170 shift[2 * i] = shift[2 * i + 1] = ' ';
1171 shift[2 * i] = shift[2 * i + 1] = 0;
1172
1173 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1174 fprintf(output, "%s", shift);
1175 fprintf(output, "Value Tree is NULL !\n");
1176 return;
1177
1178 }
1179
1180 fprintf(output, "%s", shift);
1181 fprintf(output, "%d", i + 1);
1182 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1183 }
1184
1185 /**
1186 * xmlXPathDebugDumpObject:
1187 * @output: the FILE * to dump the output
1188 * @cur: the object to inspect
1189 * @depth: indentation level
1190 *
1191 * Dump the content of the object for debugging purposes
1192 */
1193 void
xmlXPathDebugDumpObject(FILE * output,xmlXPathObjectPtr cur,int depth)1194 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1195 int i;
1196 char shift[100];
1197
1198 if (output == NULL) return;
1199
1200 for (i = 0;((i < depth) && (i < 25));i++)
1201 shift[2 * i] = shift[2 * i + 1] = ' ';
1202 shift[2 * i] = shift[2 * i + 1] = 0;
1203
1204
1205 fprintf(output, "%s", shift);
1206
1207 if (cur == NULL) {
1208 fprintf(output, "Object is empty (NULL)\n");
1209 return;
1210 }
1211 switch(cur->type) {
1212 case XPATH_UNDEFINED:
1213 fprintf(output, "Object is uninitialized\n");
1214 break;
1215 case XPATH_NODESET:
1216 fprintf(output, "Object is a Node Set :\n");
1217 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1218 break;
1219 case XPATH_XSLT_TREE:
1220 fprintf(output, "Object is an XSLT value tree :\n");
1221 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1222 break;
1223 case XPATH_BOOLEAN:
1224 fprintf(output, "Object is a Boolean : ");
1225 if (cur->boolval) fprintf(output, "true\n");
1226 else fprintf(output, "false\n");
1227 break;
1228 case XPATH_NUMBER:
1229 switch (xmlXPathIsInf(cur->floatval)) {
1230 case 1:
1231 fprintf(output, "Object is a number : Infinity\n");
1232 break;
1233 case -1:
1234 fprintf(output, "Object is a number : -Infinity\n");
1235 break;
1236 default:
1237 if (xmlXPathIsNaN(cur->floatval)) {
1238 fprintf(output, "Object is a number : NaN\n");
1239 } else if (cur->floatval == 0) {
1240 /* Omit sign for negative zero. */
1241 fprintf(output, "Object is a number : 0\n");
1242 } else {
1243 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1244 }
1245 }
1246 break;
1247 case XPATH_STRING:
1248 fprintf(output, "Object is a string : ");
1249 xmlDebugDumpString(output, cur->stringval);
1250 fprintf(output, "\n");
1251 break;
1252 case XPATH_USERS:
1253 fprintf(output, "Object is user defined\n");
1254 break;
1255 }
1256 }
1257
1258 static void
xmlXPathDebugDumpStepOp(FILE * output,xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op,int depth)1259 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1260 xmlXPathStepOpPtr op, int depth) {
1261 int i;
1262 char shift[100];
1263
1264 for (i = 0;((i < depth) && (i < 25));i++)
1265 shift[2 * i] = shift[2 * i + 1] = ' ';
1266 shift[2 * i] = shift[2 * i + 1] = 0;
1267
1268 fprintf(output, "%s", shift);
1269 if (op == NULL) {
1270 fprintf(output, "Step is NULL\n");
1271 return;
1272 }
1273 switch (op->op) {
1274 case XPATH_OP_END:
1275 fprintf(output, "END"); break;
1276 case XPATH_OP_AND:
1277 fprintf(output, "AND"); break;
1278 case XPATH_OP_OR:
1279 fprintf(output, "OR"); break;
1280 case XPATH_OP_EQUAL:
1281 if (op->value)
1282 fprintf(output, "EQUAL =");
1283 else
1284 fprintf(output, "EQUAL !=");
1285 break;
1286 case XPATH_OP_CMP:
1287 if (op->value)
1288 fprintf(output, "CMP <");
1289 else
1290 fprintf(output, "CMP >");
1291 if (!op->value2)
1292 fprintf(output, "=");
1293 break;
1294 case XPATH_OP_PLUS:
1295 if (op->value == 0)
1296 fprintf(output, "PLUS -");
1297 else if (op->value == 1)
1298 fprintf(output, "PLUS +");
1299 else if (op->value == 2)
1300 fprintf(output, "PLUS unary -");
1301 else if (op->value == 3)
1302 fprintf(output, "PLUS unary - -");
1303 break;
1304 case XPATH_OP_MULT:
1305 if (op->value == 0)
1306 fprintf(output, "MULT *");
1307 else if (op->value == 1)
1308 fprintf(output, "MULT div");
1309 else
1310 fprintf(output, "MULT mod");
1311 break;
1312 case XPATH_OP_UNION:
1313 fprintf(output, "UNION"); break;
1314 case XPATH_OP_ROOT:
1315 fprintf(output, "ROOT"); break;
1316 case XPATH_OP_NODE:
1317 fprintf(output, "NODE"); break;
1318 case XPATH_OP_SORT:
1319 fprintf(output, "SORT"); break;
1320 case XPATH_OP_COLLECT: {
1321 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1322 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1323 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1324 const xmlChar *prefix = op->value4;
1325 const xmlChar *name = op->value5;
1326
1327 fprintf(output, "COLLECT ");
1328 switch (axis) {
1329 case AXIS_ANCESTOR:
1330 fprintf(output, " 'ancestors' "); break;
1331 case AXIS_ANCESTOR_OR_SELF:
1332 fprintf(output, " 'ancestors-or-self' "); break;
1333 case AXIS_ATTRIBUTE:
1334 fprintf(output, " 'attributes' "); break;
1335 case AXIS_CHILD:
1336 fprintf(output, " 'child' "); break;
1337 case AXIS_DESCENDANT:
1338 fprintf(output, " 'descendant' "); break;
1339 case AXIS_DESCENDANT_OR_SELF:
1340 fprintf(output, " 'descendant-or-self' "); break;
1341 case AXIS_FOLLOWING:
1342 fprintf(output, " 'following' "); break;
1343 case AXIS_FOLLOWING_SIBLING:
1344 fprintf(output, " 'following-siblings' "); break;
1345 case AXIS_NAMESPACE:
1346 fprintf(output, " 'namespace' "); break;
1347 case AXIS_PARENT:
1348 fprintf(output, " 'parent' "); break;
1349 case AXIS_PRECEDING:
1350 fprintf(output, " 'preceding' "); break;
1351 case AXIS_PRECEDING_SIBLING:
1352 fprintf(output, " 'preceding-sibling' "); break;
1353 case AXIS_SELF:
1354 fprintf(output, " 'self' "); break;
1355 }
1356 switch (test) {
1357 case NODE_TEST_NONE:
1358 fprintf(output, "'none' "); break;
1359 case NODE_TEST_TYPE:
1360 fprintf(output, "'type' "); break;
1361 case NODE_TEST_PI:
1362 fprintf(output, "'PI' "); break;
1363 case NODE_TEST_ALL:
1364 fprintf(output, "'all' "); break;
1365 case NODE_TEST_NS:
1366 fprintf(output, "'namespace' "); break;
1367 case NODE_TEST_NAME:
1368 fprintf(output, "'name' "); break;
1369 }
1370 switch (type) {
1371 case NODE_TYPE_NODE:
1372 fprintf(output, "'node' "); break;
1373 case NODE_TYPE_COMMENT:
1374 fprintf(output, "'comment' "); break;
1375 case NODE_TYPE_TEXT:
1376 fprintf(output, "'text' "); break;
1377 case NODE_TYPE_PI:
1378 fprintf(output, "'PI' "); break;
1379 }
1380 if (prefix != NULL)
1381 fprintf(output, "%s:", prefix);
1382 if (name != NULL)
1383 fprintf(output, "%s", (const char *) name);
1384 break;
1385
1386 }
1387 case XPATH_OP_VALUE: {
1388 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1389
1390 fprintf(output, "ELEM ");
1391 xmlXPathDebugDumpObject(output, object, 0);
1392 goto finish;
1393 }
1394 case XPATH_OP_VARIABLE: {
1395 const xmlChar *prefix = op->value5;
1396 const xmlChar *name = op->value4;
1397
1398 if (prefix != NULL)
1399 fprintf(output, "VARIABLE %s:%s", prefix, name);
1400 else
1401 fprintf(output, "VARIABLE %s", name);
1402 break;
1403 }
1404 case XPATH_OP_FUNCTION: {
1405 int nbargs = op->value;
1406 const xmlChar *prefix = op->value5;
1407 const xmlChar *name = op->value4;
1408
1409 if (prefix != NULL)
1410 fprintf(output, "FUNCTION %s:%s(%d args)",
1411 prefix, name, nbargs);
1412 else
1413 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1414 break;
1415 }
1416 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1417 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1418 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1419 default:
1420 fprintf(output, "UNKNOWN %d\n", op->op); return;
1421 }
1422 fprintf(output, "\n");
1423 finish:
1424 if (op->ch1 >= 0)
1425 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1426 if (op->ch2 >= 0)
1427 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1428 }
1429
1430 /**
1431 * xmlXPathDebugDumpCompExpr:
1432 * @output: the FILE * for the output
1433 * @comp: the precompiled XPath expression
1434 * @depth: the indentation level.
1435 *
1436 * Dumps the tree of the compiled XPath expression.
1437 */
1438 void
xmlXPathDebugDumpCompExpr(FILE * output,xmlXPathCompExprPtr comp,int depth)1439 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1440 int depth) {
1441 int i;
1442 char shift[100];
1443
1444 if ((output == NULL) || (comp == NULL)) return;
1445
1446 for (i = 0;((i < depth) && (i < 25));i++)
1447 shift[2 * i] = shift[2 * i + 1] = ' ';
1448 shift[2 * i] = shift[2 * i + 1] = 0;
1449
1450 fprintf(output, "%s", shift);
1451
1452 #ifdef XPATH_STREAMING
1453 if (comp->stream) {
1454 fprintf(output, "Streaming Expression\n");
1455 } else
1456 #endif
1457 {
1458 fprintf(output, "Compiled Expression : %d elements\n",
1459 comp->nbStep);
1460 i = comp->last;
1461 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1462 }
1463 }
1464
1465 #endif /* LIBXML_DEBUG_ENABLED */
1466
1467 /************************************************************************
1468 * *
1469 * XPath object caching *
1470 * *
1471 ************************************************************************/
1472
1473 /**
1474 * xmlXPathNewCache:
1475 *
1476 * Create a new object cache
1477 *
1478 * Returns the xmlXPathCache just allocated.
1479 */
1480 static xmlXPathContextCachePtr
xmlXPathNewCache(void)1481 xmlXPathNewCache(void)
1482 {
1483 xmlXPathContextCachePtr ret;
1484
1485 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1486 if (ret == NULL)
1487 return(NULL);
1488 memset(ret, 0 , sizeof(xmlXPathContextCache));
1489 ret->maxNodeset = 100;
1490 ret->maxMisc = 100;
1491 return(ret);
1492 }
1493
1494 static void
xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)1495 xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)
1496 {
1497 while (list != NULL) {
1498 xmlXPathObjectPtr next;
1499
1500 next = (void *) list->stringval;
1501
1502 if (list->nodesetval != NULL) {
1503 if (list->nodesetval->nodeTab != NULL)
1504 xmlFree(list->nodesetval->nodeTab);
1505 xmlFree(list->nodesetval);
1506 }
1507 xmlFree(list);
1508
1509 list = next;
1510 }
1511 }
1512
1513 static void
xmlXPathFreeCache(xmlXPathContextCachePtr cache)1514 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1515 {
1516 if (cache == NULL)
1517 return;
1518 if (cache->nodesetObjs)
1519 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1520 if (cache->miscObjs)
1521 xmlXPathCacheFreeObjectList(cache->miscObjs);
1522 xmlFree(cache);
1523 }
1524
1525 /**
1526 * xmlXPathContextSetCache:
1527 *
1528 * @ctxt: the XPath context
1529 * @active: enables/disables (creates/frees) the cache
1530 * @value: a value with semantics dependent on @options
1531 * @options: options (currently only the value 0 is used)
1532 *
1533 * Creates/frees an object cache on the XPath context.
1534 * If activates XPath objects (xmlXPathObject) will be cached internally
1535 * to be reused.
1536 * @options:
1537 * 0: This will set the XPath object caching:
1538 * @value:
1539 * This will set the maximum number of XPath objects
1540 * to be cached per slot
1541 * There are two slots for node-set and misc objects.
1542 * Use <0 for the default number (100).
1543 * Other values for @options have currently no effect.
1544 *
1545 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1546 */
1547 int
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,int active,int value,int options)1548 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1549 int active,
1550 int value,
1551 int options)
1552 {
1553 if (ctxt == NULL)
1554 return(-1);
1555 if (active) {
1556 xmlXPathContextCachePtr cache;
1557
1558 if (ctxt->cache == NULL) {
1559 ctxt->cache = xmlXPathNewCache();
1560 if (ctxt->cache == NULL) {
1561 xmlXPathErrMemory(ctxt);
1562 return(-1);
1563 }
1564 }
1565 cache = (xmlXPathContextCachePtr) ctxt->cache;
1566 if (options == 0) {
1567 if (value < 0)
1568 value = 100;
1569 cache->maxNodeset = value;
1570 cache->maxMisc = value;
1571 }
1572 } else if (ctxt->cache != NULL) {
1573 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1574 ctxt->cache = NULL;
1575 }
1576 return(0);
1577 }
1578
1579 /**
1580 * xmlXPathCacheWrapNodeSet:
1581 * @pctxt: the XPath context
1582 * @val: the NodePtr value
1583 *
1584 * This is the cached version of xmlXPathWrapNodeSet().
1585 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1586 *
1587 * Returns the created or reused object.
1588 *
1589 * In case of error the node set is destroyed and NULL is returned.
1590 */
1591 static xmlXPathObjectPtr
xmlXPathCacheWrapNodeSet(xmlXPathParserContextPtr pctxt,xmlNodeSetPtr val)1592 xmlXPathCacheWrapNodeSet(xmlXPathParserContextPtr pctxt, xmlNodeSetPtr val)
1593 {
1594 xmlXPathObjectPtr ret;
1595 xmlXPathContextPtr ctxt = pctxt->context;
1596
1597 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1598 xmlXPathContextCachePtr cache =
1599 (xmlXPathContextCachePtr) ctxt->cache;
1600
1601 if (cache->miscObjs != NULL) {
1602 ret = cache->miscObjs;
1603 cache->miscObjs = (void *) ret->stringval;
1604 cache->numMisc -= 1;
1605 ret->stringval = NULL;
1606 ret->type = XPATH_NODESET;
1607 ret->nodesetval = val;
1608 return(ret);
1609 }
1610 }
1611
1612 ret = xmlXPathWrapNodeSet(val);
1613 if (ret == NULL)
1614 xmlXPathPErrMemory(pctxt);
1615 return(ret);
1616 }
1617
1618 /**
1619 * xmlXPathCacheWrapString:
1620 * @pctxt the XPath context
1621 * @val: the xmlChar * value
1622 *
1623 * This is the cached version of xmlXPathWrapString().
1624 * Wraps the @val string into an XPath object.
1625 *
1626 * Returns the created or reused object.
1627 */
1628 static xmlXPathObjectPtr
xmlXPathCacheWrapString(xmlXPathParserContextPtr pctxt,xmlChar * val)1629 xmlXPathCacheWrapString(xmlXPathParserContextPtr pctxt, xmlChar *val)
1630 {
1631 xmlXPathObjectPtr ret;
1632 xmlXPathContextPtr ctxt = pctxt->context;
1633
1634 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1635 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1636
1637 if (cache->miscObjs != NULL) {
1638 ret = cache->miscObjs;
1639 cache->miscObjs = (void *) ret->stringval;
1640 cache->numMisc -= 1;
1641 ret->type = XPATH_STRING;
1642 ret->stringval = val;
1643 return(ret);
1644 }
1645 }
1646
1647 ret = xmlXPathWrapString(val);
1648 if (ret == NULL)
1649 xmlXPathPErrMemory(pctxt);
1650 return(ret);
1651 }
1652
1653 /**
1654 * xmlXPathCacheNewNodeSet:
1655 * @pctxt the XPath context
1656 * @val: the NodePtr value
1657 *
1658 * This is the cached version of xmlXPathNewNodeSet().
1659 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
1660 * it with the single Node @val
1661 *
1662 * Returns the created or reused object.
1663 */
1664 static xmlXPathObjectPtr
xmlXPathCacheNewNodeSet(xmlXPathParserContextPtr pctxt,xmlNodePtr val)1665 xmlXPathCacheNewNodeSet(xmlXPathParserContextPtr pctxt, xmlNodePtr val)
1666 {
1667 xmlXPathObjectPtr ret;
1668 xmlXPathContextPtr ctxt = pctxt->context;
1669
1670 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1671 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1672
1673 if (cache->nodesetObjs != NULL) {
1674 /*
1675 * Use the nodeset-cache.
1676 */
1677 ret = cache->nodesetObjs;
1678 cache->nodesetObjs = (void *) ret->stringval;
1679 cache->numNodeset -= 1;
1680 ret->stringval = NULL;
1681 ret->type = XPATH_NODESET;
1682 ret->boolval = 0;
1683 if (val) {
1684 if ((ret->nodesetval->nodeMax == 0) ||
1685 (val->type == XML_NAMESPACE_DECL))
1686 {
1687 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val) < 0)
1688 xmlXPathPErrMemory(pctxt);
1689 } else {
1690 ret->nodesetval->nodeTab[0] = val;
1691 ret->nodesetval->nodeNr = 1;
1692 }
1693 }
1694 return(ret);
1695 } else if (cache->miscObjs != NULL) {
1696 xmlNodeSetPtr set;
1697 /*
1698 * Fallback to misc-cache.
1699 */
1700
1701 set = xmlXPathNodeSetCreate(val);
1702 if (set == NULL) {
1703 xmlXPathPErrMemory(pctxt);
1704 return(NULL);
1705 }
1706
1707 ret = cache->miscObjs;
1708 cache->miscObjs = (void *) ret->stringval;
1709 cache->numMisc -= 1;
1710 ret->stringval = NULL;
1711 ret->type = XPATH_NODESET;
1712 ret->boolval = 0;
1713 ret->nodesetval = set;
1714 return(ret);
1715 }
1716 }
1717 ret = xmlXPathNewNodeSet(val);
1718 if (ret == NULL)
1719 xmlXPathPErrMemory(pctxt);
1720 return(ret);
1721 }
1722
1723 /**
1724 * xmlXPathCacheNewString:
1725 * @pctxt the XPath context
1726 * @val: the xmlChar * value
1727 *
1728 * This is the cached version of xmlXPathNewString().
1729 * Acquire an xmlXPathObjectPtr of type string and of value @val
1730 *
1731 * Returns the created or reused object.
1732 */
1733 static xmlXPathObjectPtr
xmlXPathCacheNewString(xmlXPathParserContextPtr pctxt,const xmlChar * val)1734 xmlXPathCacheNewString(xmlXPathParserContextPtr pctxt, const xmlChar *val)
1735 {
1736 xmlXPathObjectPtr ret;
1737 xmlXPathContextPtr ctxt = pctxt->context;
1738
1739 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1740 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1741
1742 if (cache->miscObjs != NULL) {
1743 xmlChar *copy;
1744
1745 if (val == NULL)
1746 val = BAD_CAST "";
1747 copy = xmlStrdup(val);
1748 if (copy == NULL) {
1749 xmlXPathPErrMemory(pctxt);
1750 return(NULL);
1751 }
1752
1753 ret = cache->miscObjs;
1754 cache->miscObjs = (void *) ret->stringval;
1755 cache->numMisc -= 1;
1756 ret->type = XPATH_STRING;
1757 ret->stringval = copy;
1758 return(ret);
1759 }
1760 }
1761
1762 ret = xmlXPathNewString(val);
1763 if (ret == NULL)
1764 xmlXPathPErrMemory(pctxt);
1765 return(ret);
1766 }
1767
1768 /**
1769 * xmlXPathCacheNewCString:
1770 * @pctxt the XPath context
1771 * @val: the char * value
1772 *
1773 * This is the cached version of xmlXPathNewCString().
1774 * Acquire an xmlXPathObjectPtr of type string and of value @val
1775 *
1776 * Returns the created or reused object.
1777 */
1778 static xmlXPathObjectPtr
xmlXPathCacheNewCString(xmlXPathParserContextPtr pctxt,const char * val)1779 xmlXPathCacheNewCString(xmlXPathParserContextPtr pctxt, const char *val)
1780 {
1781 return xmlXPathCacheNewString(pctxt, BAD_CAST val);
1782 }
1783
1784 /**
1785 * xmlXPathCacheNewBoolean:
1786 * @pctxt the XPath context
1787 * @val: the boolean value
1788 *
1789 * This is the cached version of xmlXPathNewBoolean().
1790 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
1791 *
1792 * Returns the created or reused object.
1793 */
1794 static xmlXPathObjectPtr
xmlXPathCacheNewBoolean(xmlXPathParserContextPtr pctxt,int val)1795 xmlXPathCacheNewBoolean(xmlXPathParserContextPtr pctxt, int val)
1796 {
1797 xmlXPathObjectPtr ret;
1798 xmlXPathContextPtr ctxt = pctxt->context;
1799
1800 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1801 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1802
1803 if (cache->miscObjs != NULL) {
1804 ret = cache->miscObjs;
1805 cache->miscObjs = (void *) ret->stringval;
1806 cache->numMisc -= 1;
1807 ret->stringval = NULL;
1808 ret->type = XPATH_BOOLEAN;
1809 ret->boolval = (val != 0);
1810 return(ret);
1811 }
1812 }
1813
1814 ret = xmlXPathNewBoolean(val);
1815 if (ret == NULL)
1816 xmlXPathPErrMemory(pctxt);
1817 return(ret);
1818 }
1819
1820 /**
1821 * xmlXPathCacheNewFloat:
1822 * @pctxt the XPath context
1823 * @val: the double value
1824 *
1825 * This is the cached version of xmlXPathNewFloat().
1826 * Acquires an xmlXPathObjectPtr of type double and of value @val
1827 *
1828 * Returns the created or reused object.
1829 */
1830 static xmlXPathObjectPtr
xmlXPathCacheNewFloat(xmlXPathParserContextPtr pctxt,double val)1831 xmlXPathCacheNewFloat(xmlXPathParserContextPtr pctxt, double val)
1832 {
1833 xmlXPathObjectPtr ret;
1834 xmlXPathContextPtr ctxt = pctxt->context;
1835
1836 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1837 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1838
1839 if (cache->miscObjs != NULL) {
1840 ret = cache->miscObjs;
1841 cache->miscObjs = (void *) ret->stringval;
1842 cache->numMisc -= 1;
1843 ret->stringval = NULL;
1844 ret->type = XPATH_NUMBER;
1845 ret->floatval = val;
1846 return(ret);
1847 }
1848 }
1849
1850 ret = xmlXPathNewFloat(val);
1851 if (ret == NULL)
1852 xmlXPathPErrMemory(pctxt);
1853 return(ret);
1854 }
1855
1856 /**
1857 * xmlXPathCacheObjectCopy:
1858 * @pctxt the XPath context
1859 * @val: the original object
1860 *
1861 * This is the cached version of xmlXPathObjectCopy().
1862 * Acquire a copy of a given object
1863 *
1864 * Returns a created or reused created object.
1865 */
1866 static xmlXPathObjectPtr
xmlXPathCacheObjectCopy(xmlXPathParserContextPtr pctxt,xmlXPathObjectPtr val)1867 xmlXPathCacheObjectCopy(xmlXPathParserContextPtr pctxt, xmlXPathObjectPtr val)
1868 {
1869 xmlXPathObjectPtr ret;
1870 xmlXPathContextPtr ctxt = pctxt->context;
1871
1872 if (val == NULL)
1873 return(NULL);
1874
1875 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1876 switch (val->type) {
1877 case XPATH_NODESET: {
1878 xmlNodeSetPtr set;
1879
1880 set = xmlXPathNodeSetMerge(NULL, val->nodesetval);
1881 if (set == NULL) {
1882 xmlXPathPErrMemory(pctxt);
1883 return(NULL);
1884 }
1885 return(xmlXPathCacheWrapNodeSet(pctxt, set));
1886 }
1887 case XPATH_STRING:
1888 return(xmlXPathCacheNewString(pctxt, val->stringval));
1889 case XPATH_BOOLEAN:
1890 return(xmlXPathCacheNewBoolean(pctxt, val->boolval));
1891 case XPATH_NUMBER:
1892 return(xmlXPathCacheNewFloat(pctxt, val->floatval));
1893 default:
1894 break;
1895 }
1896 }
1897 ret = xmlXPathObjectCopy(val);
1898 if (ret == NULL)
1899 xmlXPathPErrMemory(pctxt);
1900 return(ret);
1901 }
1902
1903 /************************************************************************
1904 * *
1905 * Parser stacks related functions and macros *
1906 * *
1907 ************************************************************************/
1908
1909 /**
1910 * xmlXPathCastToNumberInternal:
1911 * @ctxt: parser context
1912 * @val: an XPath object
1913 *
1914 * Converts an XPath object to its number value
1915 *
1916 * Returns the number value
1917 */
1918 static double
xmlXPathCastToNumberInternal(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr val)1919 xmlXPathCastToNumberInternal(xmlXPathParserContextPtr ctxt,
1920 xmlXPathObjectPtr val) {
1921 double ret = 0.0;
1922
1923 if (val == NULL)
1924 return(xmlXPathNAN);
1925 switch (val->type) {
1926 case XPATH_UNDEFINED:
1927 ret = xmlXPathNAN;
1928 break;
1929 case XPATH_NODESET:
1930 case XPATH_XSLT_TREE: {
1931 xmlChar *str;
1932
1933 str = xmlXPathCastNodeSetToString(val->nodesetval);
1934 if (str == NULL) {
1935 xmlXPathPErrMemory(ctxt);
1936 ret = xmlXPathNAN;
1937 } else {
1938 ret = xmlXPathCastStringToNumber(str);
1939 xmlFree(str);
1940 }
1941 break;
1942 }
1943 case XPATH_STRING:
1944 ret = xmlXPathCastStringToNumber(val->stringval);
1945 break;
1946 case XPATH_NUMBER:
1947 ret = val->floatval;
1948 break;
1949 case XPATH_BOOLEAN:
1950 ret = xmlXPathCastBooleanToNumber(val->boolval);
1951 break;
1952 case XPATH_USERS:
1953 /* TODO */
1954 ret = xmlXPathNAN;
1955 break;
1956 }
1957 return(ret);
1958 }
1959
1960 /**
1961 * valuePop:
1962 * @ctxt: an XPath evaluation context
1963 *
1964 * Pops the top XPath object from the value stack
1965 *
1966 * Returns the XPath object just removed
1967 */
1968 xmlXPathObjectPtr
valuePop(xmlXPathParserContextPtr ctxt)1969 valuePop(xmlXPathParserContextPtr ctxt)
1970 {
1971 xmlXPathObjectPtr ret;
1972
1973 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
1974 return (NULL);
1975
1976 ctxt->valueNr--;
1977 if (ctxt->valueNr > 0)
1978 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1979 else
1980 ctxt->value = NULL;
1981 ret = ctxt->valueTab[ctxt->valueNr];
1982 ctxt->valueTab[ctxt->valueNr] = NULL;
1983 return (ret);
1984 }
1985 /**
1986 * valuePush:
1987 * @ctxt: an XPath evaluation context
1988 * @value: the XPath object
1989 *
1990 * Pushes a new XPath object on top of the value stack. If value is NULL,
1991 * a memory error is recorded in the parser context.
1992 *
1993 * Returns the number of items on the value stack, or -1 in case of error.
1994 *
1995 * The object is destroyed in case of error.
1996 */
1997 int
valuePush(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr value)1998 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1999 {
2000 if (ctxt == NULL) return(-1);
2001 if (value == NULL) {
2002 /*
2003 * A NULL value typically indicates that a memory allocation failed.
2004 */
2005 xmlXPathPErrMemory(ctxt);
2006 return(-1);
2007 }
2008 if (ctxt->valueNr >= ctxt->valueMax) {
2009 xmlXPathObjectPtr *tmp;
2010
2011 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2012 xmlXPathPErrMemory(ctxt);
2013 xmlXPathFreeObject(value);
2014 return (-1);
2015 }
2016 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2017 2 * ctxt->valueMax *
2018 sizeof(ctxt->valueTab[0]));
2019 if (tmp == NULL) {
2020 xmlXPathPErrMemory(ctxt);
2021 xmlXPathFreeObject(value);
2022 return (-1);
2023 }
2024 ctxt->valueMax *= 2;
2025 ctxt->valueTab = tmp;
2026 }
2027 ctxt->valueTab[ctxt->valueNr] = value;
2028 ctxt->value = value;
2029 return (ctxt->valueNr++);
2030 }
2031
2032 /**
2033 * xmlXPathPopBoolean:
2034 * @ctxt: an XPath parser context
2035 *
2036 * Pops a boolean from the stack, handling conversion if needed.
2037 * Check error with #xmlXPathCheckError.
2038 *
2039 * Returns the boolean
2040 */
2041 int
xmlXPathPopBoolean(xmlXPathParserContextPtr ctxt)2042 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2043 xmlXPathObjectPtr obj;
2044 int ret;
2045
2046 obj = valuePop(ctxt);
2047 if (obj == NULL) {
2048 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2049 return(0);
2050 }
2051 if (obj->type != XPATH_BOOLEAN)
2052 ret = xmlXPathCastToBoolean(obj);
2053 else
2054 ret = obj->boolval;
2055 xmlXPathReleaseObject(ctxt->context, obj);
2056 return(ret);
2057 }
2058
2059 /**
2060 * xmlXPathPopNumber:
2061 * @ctxt: an XPath parser context
2062 *
2063 * Pops a number from the stack, handling conversion if needed.
2064 * Check error with #xmlXPathCheckError.
2065 *
2066 * Returns the number
2067 */
2068 double
xmlXPathPopNumber(xmlXPathParserContextPtr ctxt)2069 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2070 xmlXPathObjectPtr obj;
2071 double ret;
2072
2073 obj = valuePop(ctxt);
2074 if (obj == NULL) {
2075 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2076 return(0);
2077 }
2078 if (obj->type != XPATH_NUMBER)
2079 ret = xmlXPathCastToNumberInternal(ctxt, obj);
2080 else
2081 ret = obj->floatval;
2082 xmlXPathReleaseObject(ctxt->context, obj);
2083 return(ret);
2084 }
2085
2086 /**
2087 * xmlXPathPopString:
2088 * @ctxt: an XPath parser context
2089 *
2090 * Pops a string from the stack, handling conversion if needed.
2091 * Check error with #xmlXPathCheckError.
2092 *
2093 * Returns the string
2094 */
2095 xmlChar *
xmlXPathPopString(xmlXPathParserContextPtr ctxt)2096 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2097 xmlXPathObjectPtr obj;
2098 xmlChar * ret;
2099
2100 obj = valuePop(ctxt);
2101 if (obj == NULL) {
2102 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2103 return(NULL);
2104 }
2105 ret = xmlXPathCastToString(obj);
2106 if (ret == NULL)
2107 xmlXPathPErrMemory(ctxt);
2108 xmlXPathReleaseObject(ctxt->context, obj);
2109 return(ret);
2110 }
2111
2112 /**
2113 * xmlXPathPopNodeSet:
2114 * @ctxt: an XPath parser context
2115 *
2116 * Pops a node-set from the stack, handling conversion if needed.
2117 * Check error with #xmlXPathCheckError.
2118 *
2119 * Returns the node-set
2120 */
2121 xmlNodeSetPtr
xmlXPathPopNodeSet(xmlXPathParserContextPtr ctxt)2122 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2123 xmlXPathObjectPtr obj;
2124 xmlNodeSetPtr ret;
2125
2126 if (ctxt == NULL) return(NULL);
2127 if (ctxt->value == NULL) {
2128 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2129 return(NULL);
2130 }
2131 if (!xmlXPathStackIsNodeSet(ctxt)) {
2132 xmlXPathSetTypeError(ctxt);
2133 return(NULL);
2134 }
2135 obj = valuePop(ctxt);
2136 ret = obj->nodesetval;
2137 #if 0
2138 /* to fix memory leak of not clearing obj->user */
2139 if (obj->boolval && obj->user != NULL)
2140 xmlFreeNodeList((xmlNodePtr) obj->user);
2141 #endif
2142 obj->nodesetval = NULL;
2143 xmlXPathReleaseObject(ctxt->context, obj);
2144 return(ret);
2145 }
2146
2147 /**
2148 * xmlXPathPopExternal:
2149 * @ctxt: an XPath parser context
2150 *
2151 * Pops an external object from the stack, handling conversion if needed.
2152 * Check error with #xmlXPathCheckError.
2153 *
2154 * Returns the object
2155 */
2156 void *
xmlXPathPopExternal(xmlXPathParserContextPtr ctxt)2157 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2158 xmlXPathObjectPtr obj;
2159 void * ret;
2160
2161 if ((ctxt == NULL) || (ctxt->value == NULL)) {
2162 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2163 return(NULL);
2164 }
2165 if (ctxt->value->type != XPATH_USERS) {
2166 xmlXPathSetTypeError(ctxt);
2167 return(NULL);
2168 }
2169 obj = valuePop(ctxt);
2170 ret = obj->user;
2171 obj->user = NULL;
2172 xmlXPathReleaseObject(ctxt->context, obj);
2173 return(ret);
2174 }
2175
2176 /*
2177 * Macros for accessing the content. Those should be used only by the parser,
2178 * and not exported.
2179 *
2180 * Dirty macros, i.e. one need to make assumption on the context to use them
2181 *
2182 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2183 * CUR returns the current xmlChar value, i.e. a 8 bit value
2184 * in ISO-Latin or UTF-8.
2185 * This should be used internally by the parser
2186 * only to compare to ASCII values otherwise it would break when
2187 * running with UTF-8 encoding.
2188 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2189 * to compare on ASCII based substring.
2190 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2191 * strings within the parser.
2192 * CURRENT Returns the current char value, with the full decoding of
2193 * UTF-8 if we are using this mode. It returns an int.
2194 * NEXT Skip to the next character, this does the proper decoding
2195 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2196 * It returns the pointer to the current xmlChar.
2197 */
2198
2199 #define CUR (*ctxt->cur)
2200 #define SKIP(val) ctxt->cur += (val)
2201 #define NXT(val) ctxt->cur[(val)]
2202 #define CUR_PTR ctxt->cur
2203 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2204
2205 #define COPY_BUF(l,b,i,v) \
2206 if (l == 1) b[i++] = v; \
2207 else i += xmlCopyChar(l,&b[i],v)
2208
2209 #define NEXTL(l) ctxt->cur += l
2210
2211 #define SKIP_BLANKS \
2212 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2213
2214 #define CURRENT (*ctxt->cur)
2215 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2216
2217
2218 #ifndef DBL_DIG
2219 #define DBL_DIG 16
2220 #endif
2221 #ifndef DBL_EPSILON
2222 #define DBL_EPSILON 1E-9
2223 #endif
2224
2225 #define UPPER_DOUBLE 1E9
2226 #define LOWER_DOUBLE 1E-5
2227 #define LOWER_DOUBLE_EXP 5
2228
2229 #define INTEGER_DIGITS DBL_DIG
2230 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2231 #define EXPONENT_DIGITS (3 + 2)
2232
2233 /**
2234 * xmlXPathFormatNumber:
2235 * @number: number to format
2236 * @buffer: output buffer
2237 * @buffersize: size of output buffer
2238 *
2239 * Convert the number into a string representation.
2240 */
2241 static void
xmlXPathFormatNumber(double number,char buffer[],int buffersize)2242 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2243 {
2244 switch (xmlXPathIsInf(number)) {
2245 case 1:
2246 if (buffersize > (int)sizeof("Infinity"))
2247 snprintf(buffer, buffersize, "Infinity");
2248 break;
2249 case -1:
2250 if (buffersize > (int)sizeof("-Infinity"))
2251 snprintf(buffer, buffersize, "-Infinity");
2252 break;
2253 default:
2254 if (xmlXPathIsNaN(number)) {
2255 if (buffersize > (int)sizeof("NaN"))
2256 snprintf(buffer, buffersize, "NaN");
2257 } else if (number == 0) {
2258 /* Omit sign for negative zero. */
2259 snprintf(buffer, buffersize, "0");
2260 } else if ((number > INT_MIN) && (number < INT_MAX) &&
2261 (number == (int) number)) {
2262 char work[30];
2263 char *ptr, *cur;
2264 int value = (int) number;
2265
2266 ptr = &buffer[0];
2267 if (value == 0) {
2268 *ptr++ = '0';
2269 } else {
2270 snprintf(work, 29, "%d", value);
2271 cur = &work[0];
2272 while ((*cur) && (ptr - buffer < buffersize)) {
2273 *ptr++ = *cur++;
2274 }
2275 }
2276 if (ptr - buffer < buffersize) {
2277 *ptr = 0;
2278 } else if (buffersize > 0) {
2279 ptr--;
2280 *ptr = 0;
2281 }
2282 } else {
2283 /*
2284 For the dimension of work,
2285 DBL_DIG is number of significant digits
2286 EXPONENT is only needed for "scientific notation"
2287 3 is sign, decimal point, and terminating zero
2288 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2289 Note that this dimension is slightly (a few characters)
2290 larger than actually necessary.
2291 */
2292 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2293 int integer_place, fraction_place;
2294 char *ptr;
2295 char *after_fraction;
2296 double absolute_value;
2297 int size;
2298
2299 absolute_value = fabs(number);
2300
2301 /*
2302 * First choose format - scientific or regular floating point.
2303 * In either case, result is in work, and after_fraction points
2304 * just past the fractional part.
2305 */
2306 if ( ((absolute_value > UPPER_DOUBLE) ||
2307 (absolute_value < LOWER_DOUBLE)) &&
2308 (absolute_value != 0.0) ) {
2309 /* Use scientific notation */
2310 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2311 fraction_place = DBL_DIG - 1;
2312 size = snprintf(work, sizeof(work),"%*.*e",
2313 integer_place, fraction_place, number);
2314 while ((size > 0) && (work[size] != 'e')) size--;
2315
2316 }
2317 else {
2318 /* Use regular notation */
2319 if (absolute_value > 0.0) {
2320 integer_place = (int)log10(absolute_value);
2321 if (integer_place > 0)
2322 fraction_place = DBL_DIG - integer_place - 1;
2323 else
2324 fraction_place = DBL_DIG - integer_place;
2325 } else {
2326 fraction_place = 1;
2327 }
2328 size = snprintf(work, sizeof(work), "%0.*f",
2329 fraction_place, number);
2330 }
2331
2332 /* Remove leading spaces sometimes inserted by snprintf */
2333 while (work[0] == ' ') {
2334 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2335 size--;
2336 }
2337
2338 /* Remove fractional trailing zeroes */
2339 after_fraction = work + size;
2340 ptr = after_fraction;
2341 while (*(--ptr) == '0')
2342 ;
2343 if (*ptr != '.')
2344 ptr++;
2345 while ((*ptr++ = *after_fraction++) != 0);
2346
2347 /* Finally copy result back to caller */
2348 size = strlen(work) + 1;
2349 if (size > buffersize) {
2350 work[buffersize - 1] = 0;
2351 size = buffersize;
2352 }
2353 memmove(buffer, work, size);
2354 }
2355 break;
2356 }
2357 }
2358
2359
2360 /************************************************************************
2361 * *
2362 * Routines to handle NodeSets *
2363 * *
2364 ************************************************************************/
2365
2366 /**
2367 * xmlXPathOrderDocElems:
2368 * @doc: an input document
2369 *
2370 * Call this routine to speed up XPath computation on static documents.
2371 * This stamps all the element nodes with the document order
2372 * Like for line information, the order is kept in the element->content
2373 * field, the value stored is actually - the node number (starting at -1)
2374 * to be able to differentiate from line numbers.
2375 *
2376 * Returns the number of elements found in the document or -1 in case
2377 * of error.
2378 */
2379 long
xmlXPathOrderDocElems(xmlDocPtr doc)2380 xmlXPathOrderDocElems(xmlDocPtr doc) {
2381 ptrdiff_t count = 0;
2382 xmlNodePtr cur;
2383
2384 if (doc == NULL)
2385 return(-1);
2386 cur = doc->children;
2387 while (cur != NULL) {
2388 if (cur->type == XML_ELEMENT_NODE) {
2389 cur->content = (void *) (-(++count));
2390 if (cur->children != NULL) {
2391 cur = cur->children;
2392 continue;
2393 }
2394 }
2395 if (cur->next != NULL) {
2396 cur = cur->next;
2397 continue;
2398 }
2399 do {
2400 cur = cur->parent;
2401 if (cur == NULL)
2402 break;
2403 if (cur == (xmlNodePtr) doc) {
2404 cur = NULL;
2405 break;
2406 }
2407 if (cur->next != NULL) {
2408 cur = cur->next;
2409 break;
2410 }
2411 } while (cur != NULL);
2412 }
2413 return(count);
2414 }
2415
2416 /**
2417 * xmlXPathCmpNodes:
2418 * @node1: the first node
2419 * @node2: the second node
2420 *
2421 * Compare two nodes w.r.t document order
2422 *
2423 * Returns -2 in case of error 1 if first point < second point, 0 if
2424 * it's the same node, -1 otherwise
2425 */
2426 int
xmlXPathCmpNodes(xmlNodePtr node1,xmlNodePtr node2)2427 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2428 int depth1, depth2;
2429 int attr1 = 0, attr2 = 0;
2430 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2431 xmlNodePtr cur, root;
2432
2433 if ((node1 == NULL) || (node2 == NULL))
2434 return(-2);
2435 /*
2436 * a couple of optimizations which will avoid computations in most cases
2437 */
2438 if (node1 == node2) /* trivial case */
2439 return(0);
2440 if (node1->type == XML_ATTRIBUTE_NODE) {
2441 attr1 = 1;
2442 attrNode1 = node1;
2443 node1 = node1->parent;
2444 }
2445 if (node2->type == XML_ATTRIBUTE_NODE) {
2446 attr2 = 1;
2447 attrNode2 = node2;
2448 node2 = node2->parent;
2449 }
2450 if (node1 == node2) {
2451 if (attr1 == attr2) {
2452 /* not required, but we keep attributes in order */
2453 if (attr1 != 0) {
2454 cur = attrNode2->prev;
2455 while (cur != NULL) {
2456 if (cur == attrNode1)
2457 return (1);
2458 cur = cur->prev;
2459 }
2460 return (-1);
2461 }
2462 return(0);
2463 }
2464 if (attr2 == 1)
2465 return(1);
2466 return(-1);
2467 }
2468 if ((node1->type == XML_NAMESPACE_DECL) ||
2469 (node2->type == XML_NAMESPACE_DECL))
2470 return(1);
2471 if (node1 == node2->prev)
2472 return(1);
2473 if (node1 == node2->next)
2474 return(-1);
2475
2476 /*
2477 * Speedup using document order if available.
2478 */
2479 if ((node1->type == XML_ELEMENT_NODE) &&
2480 (node2->type == XML_ELEMENT_NODE) &&
2481 (0 > (ptrdiff_t) node1->content) &&
2482 (0 > (ptrdiff_t) node2->content) &&
2483 (node1->doc == node2->doc)) {
2484 ptrdiff_t l1, l2;
2485
2486 l1 = -((ptrdiff_t) node1->content);
2487 l2 = -((ptrdiff_t) node2->content);
2488 if (l1 < l2)
2489 return(1);
2490 if (l1 > l2)
2491 return(-1);
2492 }
2493
2494 /*
2495 * compute depth to root
2496 */
2497 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2498 if (cur->parent == node1)
2499 return(1);
2500 depth2++;
2501 }
2502 root = cur;
2503 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2504 if (cur->parent == node2)
2505 return(-1);
2506 depth1++;
2507 }
2508 /*
2509 * Distinct document (or distinct entities :-( ) case.
2510 */
2511 if (root != cur) {
2512 return(-2);
2513 }
2514 /*
2515 * get the nearest common ancestor.
2516 */
2517 while (depth1 > depth2) {
2518 depth1--;
2519 node1 = node1->parent;
2520 }
2521 while (depth2 > depth1) {
2522 depth2--;
2523 node2 = node2->parent;
2524 }
2525 while (node1->parent != node2->parent) {
2526 node1 = node1->parent;
2527 node2 = node2->parent;
2528 /* should not happen but just in case ... */
2529 if ((node1 == NULL) || (node2 == NULL))
2530 return(-2);
2531 }
2532 /*
2533 * Find who's first.
2534 */
2535 if (node1 == node2->prev)
2536 return(1);
2537 if (node1 == node2->next)
2538 return(-1);
2539 /*
2540 * Speedup using document order if available.
2541 */
2542 if ((node1->type == XML_ELEMENT_NODE) &&
2543 (node2->type == XML_ELEMENT_NODE) &&
2544 (0 > (ptrdiff_t) node1->content) &&
2545 (0 > (ptrdiff_t) node2->content) &&
2546 (node1->doc == node2->doc)) {
2547 ptrdiff_t l1, l2;
2548
2549 l1 = -((ptrdiff_t) node1->content);
2550 l2 = -((ptrdiff_t) node2->content);
2551 if (l1 < l2)
2552 return(1);
2553 if (l1 > l2)
2554 return(-1);
2555 }
2556
2557 for (cur = node1->next;cur != NULL;cur = cur->next)
2558 if (cur == node2)
2559 return(1);
2560 return(-1); /* assume there is no sibling list corruption */
2561 }
2562
2563 /**
2564 * xmlXPathNodeSetSort:
2565 * @set: the node set
2566 *
2567 * Sort the node set in document order
2568 */
2569 void
xmlXPathNodeSetSort(xmlNodeSetPtr set)2570 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
2571 #ifndef WITH_TIM_SORT
2572 int i, j, incr, len;
2573 xmlNodePtr tmp;
2574 #endif
2575
2576 if (set == NULL)
2577 return;
2578
2579 #ifndef WITH_TIM_SORT
2580 /*
2581 * Use the old Shell's sort implementation to sort the node-set
2582 * Timsort ought to be quite faster
2583 */
2584 len = set->nodeNr;
2585 for (incr = len / 2; incr > 0; incr /= 2) {
2586 for (i = incr; i < len; i++) {
2587 j = i - incr;
2588 while (j >= 0) {
2589 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2590 if (xmlXPathCmpNodesExt(set->nodeTab[j],
2591 set->nodeTab[j + incr]) == -1)
2592 #else
2593 if (xmlXPathCmpNodes(set->nodeTab[j],
2594 set->nodeTab[j + incr]) == -1)
2595 #endif
2596 {
2597 tmp = set->nodeTab[j];
2598 set->nodeTab[j] = set->nodeTab[j + incr];
2599 set->nodeTab[j + incr] = tmp;
2600 j -= incr;
2601 } else
2602 break;
2603 }
2604 }
2605 }
2606 #else /* WITH_TIM_SORT */
2607 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2608 #endif /* WITH_TIM_SORT */
2609 }
2610
2611 #define XML_NODESET_DEFAULT 10
2612 /**
2613 * xmlXPathNodeSetDupNs:
2614 * @node: the parent node of the namespace XPath node
2615 * @ns: the libxml namespace declaration node.
2616 *
2617 * Namespace node in libxml don't match the XPath semantic. In a node set
2618 * the namespace nodes are duplicated and the next pointer is set to the
2619 * parent node in the XPath semantic.
2620 *
2621 * Returns the newly created object.
2622 */
2623 static xmlNodePtr
xmlXPathNodeSetDupNs(xmlNodePtr node,xmlNsPtr ns)2624 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2625 xmlNsPtr cur;
2626
2627 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2628 return(NULL);
2629 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
2630 return((xmlNodePtr) ns);
2631
2632 /*
2633 * Allocate a new Namespace and fill the fields.
2634 */
2635 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2636 if (cur == NULL)
2637 return(NULL);
2638 memset(cur, 0, sizeof(xmlNs));
2639 cur->type = XML_NAMESPACE_DECL;
2640 if (ns->href != NULL) {
2641 cur->href = xmlStrdup(ns->href);
2642 if (cur->href == NULL) {
2643 xmlFree(cur);
2644 return(NULL);
2645 }
2646 }
2647 if (ns->prefix != NULL) {
2648 cur->prefix = xmlStrdup(ns->prefix);
2649 if (cur->prefix == NULL) {
2650 xmlFree((xmlChar *) cur->href);
2651 xmlFree(cur);
2652 return(NULL);
2653 }
2654 }
2655 cur->next = (xmlNsPtr) node;
2656 return((xmlNodePtr) cur);
2657 }
2658
2659 /**
2660 * xmlXPathNodeSetFreeNs:
2661 * @ns: the XPath namespace node found in a nodeset.
2662 *
2663 * Namespace nodes in libxml don't match the XPath semantic. In a node set
2664 * the namespace nodes are duplicated and the next pointer is set to the
2665 * parent node in the XPath semantic. Check if such a node needs to be freed
2666 */
2667 void
xmlXPathNodeSetFreeNs(xmlNsPtr ns)2668 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
2669 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2670 return;
2671
2672 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2673 if (ns->href != NULL)
2674 xmlFree((xmlChar *)ns->href);
2675 if (ns->prefix != NULL)
2676 xmlFree((xmlChar *)ns->prefix);
2677 xmlFree(ns);
2678 }
2679 }
2680
2681 /**
2682 * xmlXPathNodeSetCreate:
2683 * @val: an initial xmlNodePtr, or NULL
2684 *
2685 * Create a new xmlNodeSetPtr of type double and of value @val
2686 *
2687 * Returns the newly created object.
2688 */
2689 xmlNodeSetPtr
xmlXPathNodeSetCreate(xmlNodePtr val)2690 xmlXPathNodeSetCreate(xmlNodePtr val) {
2691 xmlNodeSetPtr ret;
2692
2693 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2694 if (ret == NULL)
2695 return(NULL);
2696 memset(ret, 0 , sizeof(xmlNodeSet));
2697 if (val != NULL) {
2698 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2699 sizeof(xmlNodePtr));
2700 if (ret->nodeTab == NULL) {
2701 xmlFree(ret);
2702 return(NULL);
2703 }
2704 memset(ret->nodeTab, 0 ,
2705 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2706 ret->nodeMax = XML_NODESET_DEFAULT;
2707 if (val->type == XML_NAMESPACE_DECL) {
2708 xmlNsPtr ns = (xmlNsPtr) val;
2709 xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2710
2711 if (nsNode == NULL) {
2712 xmlXPathFreeNodeSet(ret);
2713 return(NULL);
2714 }
2715 ret->nodeTab[ret->nodeNr++] = nsNode;
2716 } else
2717 ret->nodeTab[ret->nodeNr++] = val;
2718 }
2719 return(ret);
2720 }
2721
2722 /**
2723 * xmlXPathNodeSetContains:
2724 * @cur: the node-set
2725 * @val: the node
2726 *
2727 * checks whether @cur contains @val
2728 *
2729 * Returns true (1) if @cur contains @val, false (0) otherwise
2730 */
2731 int
xmlXPathNodeSetContains(xmlNodeSetPtr cur,xmlNodePtr val)2732 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
2733 int i;
2734
2735 if ((cur == NULL) || (val == NULL)) return(0);
2736 if (val->type == XML_NAMESPACE_DECL) {
2737 for (i = 0; i < cur->nodeNr; i++) {
2738 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2739 xmlNsPtr ns1, ns2;
2740
2741 ns1 = (xmlNsPtr) val;
2742 ns2 = (xmlNsPtr) cur->nodeTab[i];
2743 if (ns1 == ns2)
2744 return(1);
2745 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
2746 (xmlStrEqual(ns1->prefix, ns2->prefix)))
2747 return(1);
2748 }
2749 }
2750 } else {
2751 for (i = 0; i < cur->nodeNr; i++) {
2752 if (cur->nodeTab[i] == val)
2753 return(1);
2754 }
2755 }
2756 return(0);
2757 }
2758
2759 /**
2760 * xmlXPathNodeSetAddNs:
2761 * @cur: the initial node set
2762 * @node: the hosting node
2763 * @ns: a the namespace node
2764 *
2765 * add a new namespace node to an existing NodeSet
2766 *
2767 * Returns 0 in case of success and -1 in case of error
2768 */
2769 int
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur,xmlNodePtr node,xmlNsPtr ns)2770 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
2771 int i;
2772 xmlNodePtr nsNode;
2773
2774 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
2775 (ns->type != XML_NAMESPACE_DECL) ||
2776 (node->type != XML_ELEMENT_NODE))
2777 return(-1);
2778
2779 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2780 /*
2781 * prevent duplicates
2782 */
2783 for (i = 0;i < cur->nodeNr;i++) {
2784 if ((cur->nodeTab[i] != NULL) &&
2785 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
2786 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
2787 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
2788 return(0);
2789 }
2790
2791 /*
2792 * grow the nodeTab if needed
2793 */
2794 if (cur->nodeMax == 0) {
2795 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2796 sizeof(xmlNodePtr));
2797 if (cur->nodeTab == NULL)
2798 return(-1);
2799 memset(cur->nodeTab, 0 ,
2800 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2801 cur->nodeMax = XML_NODESET_DEFAULT;
2802 } else if (cur->nodeNr == cur->nodeMax) {
2803 xmlNodePtr *temp;
2804
2805 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2806 return(-1);
2807 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2808 sizeof(xmlNodePtr));
2809 if (temp == NULL)
2810 return(-1);
2811 cur->nodeMax *= 2;
2812 cur->nodeTab = temp;
2813 }
2814 nsNode = xmlXPathNodeSetDupNs(node, ns);
2815 if(nsNode == NULL)
2816 return(-1);
2817 cur->nodeTab[cur->nodeNr++] = nsNode;
2818 return(0);
2819 }
2820
2821 /**
2822 * xmlXPathNodeSetAdd:
2823 * @cur: the initial node set
2824 * @val: a new xmlNodePtr
2825 *
2826 * add a new xmlNodePtr to an existing NodeSet
2827 *
2828 * Returns 0 in case of success, and -1 in case of error
2829 */
2830 int
xmlXPathNodeSetAdd(xmlNodeSetPtr cur,xmlNodePtr val)2831 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
2832 int i;
2833
2834 if ((cur == NULL) || (val == NULL)) return(-1);
2835
2836 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2837 /*
2838 * prevent duplicates
2839 */
2840 for (i = 0;i < cur->nodeNr;i++)
2841 if (cur->nodeTab[i] == val) return(0);
2842
2843 /*
2844 * grow the nodeTab if needed
2845 */
2846 if (cur->nodeMax == 0) {
2847 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2848 sizeof(xmlNodePtr));
2849 if (cur->nodeTab == NULL)
2850 return(-1);
2851 memset(cur->nodeTab, 0 ,
2852 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2853 cur->nodeMax = XML_NODESET_DEFAULT;
2854 } else if (cur->nodeNr == cur->nodeMax) {
2855 xmlNodePtr *temp;
2856
2857 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2858 return(-1);
2859 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2860 sizeof(xmlNodePtr));
2861 if (temp == NULL)
2862 return(-1);
2863 cur->nodeMax *= 2;
2864 cur->nodeTab = temp;
2865 }
2866 if (val->type == XML_NAMESPACE_DECL) {
2867 xmlNsPtr ns = (xmlNsPtr) val;
2868 xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2869
2870 if (nsNode == NULL)
2871 return(-1);
2872 cur->nodeTab[cur->nodeNr++] = nsNode;
2873 } else
2874 cur->nodeTab[cur->nodeNr++] = val;
2875 return(0);
2876 }
2877
2878 /**
2879 * xmlXPathNodeSetAddUnique:
2880 * @cur: the initial node set
2881 * @val: a new xmlNodePtr
2882 *
2883 * add a new xmlNodePtr to an existing NodeSet, optimized version
2884 * when we are sure the node is not already in the set.
2885 *
2886 * Returns 0 in case of success and -1 in case of failure
2887 */
2888 int
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur,xmlNodePtr val)2889 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
2890 if ((cur == NULL) || (val == NULL)) return(-1);
2891
2892 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2893 /*
2894 * grow the nodeTab if needed
2895 */
2896 if (cur->nodeMax == 0) {
2897 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2898 sizeof(xmlNodePtr));
2899 if (cur->nodeTab == NULL)
2900 return(-1);
2901 memset(cur->nodeTab, 0 ,
2902 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2903 cur->nodeMax = XML_NODESET_DEFAULT;
2904 } else if (cur->nodeNr == cur->nodeMax) {
2905 xmlNodePtr *temp;
2906
2907 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2908 return(-1);
2909 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2910 sizeof(xmlNodePtr));
2911 if (temp == NULL)
2912 return(-1);
2913 cur->nodeTab = temp;
2914 cur->nodeMax *= 2;
2915 }
2916 if (val->type == XML_NAMESPACE_DECL) {
2917 xmlNsPtr ns = (xmlNsPtr) val;
2918 xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2919
2920 if (nsNode == NULL)
2921 return(-1);
2922 cur->nodeTab[cur->nodeNr++] = nsNode;
2923 } else
2924 cur->nodeTab[cur->nodeNr++] = val;
2925 return(0);
2926 }
2927
2928 /**
2929 * xmlXPathNodeSetMerge:
2930 * @val1: the first NodeSet or NULL
2931 * @val2: the second NodeSet
2932 *
2933 * Merges two nodesets, all nodes from @val2 are added to @val1
2934 * if @val1 is NULL, a new set is created and copied from @val2
2935 *
2936 * Returns @val1 once extended or NULL in case of error.
2937 *
2938 * Frees @val1 in case of error.
2939 */
2940 xmlNodeSetPtr
xmlXPathNodeSetMerge(xmlNodeSetPtr val1,xmlNodeSetPtr val2)2941 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
2942 int i, j, initNr, skip;
2943 xmlNodePtr n1, n2;
2944
2945 if (val1 == NULL) {
2946 val1 = xmlXPathNodeSetCreate(NULL);
2947 if (val1 == NULL)
2948 return (NULL);
2949 }
2950 if (val2 == NULL)
2951 return(val1);
2952
2953 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2954 initNr = val1->nodeNr;
2955
2956 for (i = 0;i < val2->nodeNr;i++) {
2957 n2 = val2->nodeTab[i];
2958 /*
2959 * check against duplicates
2960 */
2961 skip = 0;
2962 for (j = 0; j < initNr; j++) {
2963 n1 = val1->nodeTab[j];
2964 if (n1 == n2) {
2965 skip = 1;
2966 break;
2967 } else if ((n1->type == XML_NAMESPACE_DECL) &&
2968 (n2->type == XML_NAMESPACE_DECL)) {
2969 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2970 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2971 ((xmlNsPtr) n2)->prefix)))
2972 {
2973 skip = 1;
2974 break;
2975 }
2976 }
2977 }
2978 if (skip)
2979 continue;
2980
2981 /*
2982 * grow the nodeTab if needed
2983 */
2984 if (val1->nodeMax == 0) {
2985 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2986 sizeof(xmlNodePtr));
2987 if (val1->nodeTab == NULL)
2988 goto error;
2989 memset(val1->nodeTab, 0 ,
2990 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2991 val1->nodeMax = XML_NODESET_DEFAULT;
2992 } else if (val1->nodeNr == val1->nodeMax) {
2993 xmlNodePtr *temp;
2994
2995 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2996 goto error;
2997 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
2998 sizeof(xmlNodePtr));
2999 if (temp == NULL)
3000 goto error;
3001 val1->nodeTab = temp;
3002 val1->nodeMax *= 2;
3003 }
3004 if (n2->type == XML_NAMESPACE_DECL) {
3005 xmlNsPtr ns = (xmlNsPtr) n2;
3006 xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3007
3008 if (nsNode == NULL)
3009 goto error;
3010 val1->nodeTab[val1->nodeNr++] = nsNode;
3011 } else
3012 val1->nodeTab[val1->nodeNr++] = n2;
3013 }
3014
3015 return(val1);
3016
3017 error:
3018 xmlXPathFreeNodeSet(val1);
3019 return(NULL);
3020 }
3021
3022
3023 /**
3024 * xmlXPathNodeSetMergeAndClear:
3025 * @set1: the first NodeSet or NULL
3026 * @set2: the second NodeSet
3027 *
3028 * Merges two nodesets, all nodes from @set2 are added to @set1.
3029 * Checks for duplicate nodes. Clears set2.
3030 *
3031 * Returns @set1 once extended or NULL in case of error.
3032 *
3033 * Frees @set1 in case of error.
3034 */
3035 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1,xmlNodeSetPtr set2)3036 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3037 {
3038 {
3039 int i, j, initNbSet1;
3040 xmlNodePtr n1, n2;
3041
3042 initNbSet1 = set1->nodeNr;
3043 for (i = 0;i < set2->nodeNr;i++) {
3044 n2 = set2->nodeTab[i];
3045 /*
3046 * Skip duplicates.
3047 */
3048 for (j = 0; j < initNbSet1; j++) {
3049 n1 = set1->nodeTab[j];
3050 if (n1 == n2) {
3051 goto skip_node;
3052 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3053 (n2->type == XML_NAMESPACE_DECL))
3054 {
3055 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3056 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3057 ((xmlNsPtr) n2)->prefix)))
3058 {
3059 /*
3060 * Free the namespace node.
3061 */
3062 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3063 goto skip_node;
3064 }
3065 }
3066 }
3067 /*
3068 * grow the nodeTab if needed
3069 */
3070 if (set1->nodeMax == 0) {
3071 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3072 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3073 if (set1->nodeTab == NULL)
3074 goto error;
3075 memset(set1->nodeTab, 0,
3076 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3077 set1->nodeMax = XML_NODESET_DEFAULT;
3078 } else if (set1->nodeNr >= set1->nodeMax) {
3079 xmlNodePtr *temp;
3080
3081 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
3082 goto error;
3083 temp = (xmlNodePtr *) xmlRealloc(
3084 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3085 if (temp == NULL)
3086 goto error;
3087 set1->nodeTab = temp;
3088 set1->nodeMax *= 2;
3089 }
3090 set1->nodeTab[set1->nodeNr++] = n2;
3091 skip_node:
3092 set2->nodeTab[i] = NULL;
3093 }
3094 }
3095 set2->nodeNr = 0;
3096 return(set1);
3097
3098 error:
3099 xmlXPathFreeNodeSet(set1);
3100 xmlXPathNodeSetClear(set2, 1);
3101 return(NULL);
3102 }
3103
3104 /**
3105 * xmlXPathNodeSetMergeAndClearNoDupls:
3106 * @set1: the first NodeSet or NULL
3107 * @set2: the second NodeSet
3108 *
3109 * Merges two nodesets, all nodes from @set2 are added to @set1.
3110 * Doesn't check for duplicate nodes. Clears set2.
3111 *
3112 * Returns @set1 once extended or NULL in case of error.
3113 *
3114 * Frees @set1 in case of error.
3115 */
3116 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1,xmlNodeSetPtr set2)3117 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3118 {
3119 {
3120 int i;
3121 xmlNodePtr n2;
3122
3123 for (i = 0;i < set2->nodeNr;i++) {
3124 n2 = set2->nodeTab[i];
3125 if (set1->nodeMax == 0) {
3126 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3127 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3128 if (set1->nodeTab == NULL)
3129 goto error;
3130 memset(set1->nodeTab, 0,
3131 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3132 set1->nodeMax = XML_NODESET_DEFAULT;
3133 } else if (set1->nodeNr >= set1->nodeMax) {
3134 xmlNodePtr *temp;
3135
3136 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
3137 goto error;
3138 temp = (xmlNodePtr *) xmlRealloc(
3139 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3140 if (temp == NULL)
3141 goto error;
3142 set1->nodeTab = temp;
3143 set1->nodeMax *= 2;
3144 }
3145 set1->nodeTab[set1->nodeNr++] = n2;
3146 set2->nodeTab[i] = NULL;
3147 }
3148 }
3149 set2->nodeNr = 0;
3150 return(set1);
3151
3152 error:
3153 xmlXPathFreeNodeSet(set1);
3154 xmlXPathNodeSetClear(set2, 1);
3155 return(NULL);
3156 }
3157
3158 /**
3159 * xmlXPathNodeSetDel:
3160 * @cur: the initial node set
3161 * @val: an xmlNodePtr
3162 *
3163 * Removes an xmlNodePtr from an existing NodeSet
3164 */
3165 void
xmlXPathNodeSetDel(xmlNodeSetPtr cur,xmlNodePtr val)3166 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3167 int i;
3168
3169 if (cur == NULL) return;
3170 if (val == NULL) return;
3171
3172 /*
3173 * find node in nodeTab
3174 */
3175 for (i = 0;i < cur->nodeNr;i++)
3176 if (cur->nodeTab[i] == val) break;
3177
3178 if (i >= cur->nodeNr) { /* not found */
3179 return;
3180 }
3181 if ((cur->nodeTab[i] != NULL) &&
3182 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
3183 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
3184 cur->nodeNr--;
3185 for (;i < cur->nodeNr;i++)
3186 cur->nodeTab[i] = cur->nodeTab[i + 1];
3187 cur->nodeTab[cur->nodeNr] = NULL;
3188 }
3189
3190 /**
3191 * xmlXPathNodeSetRemove:
3192 * @cur: the initial node set
3193 * @val: the index to remove
3194 *
3195 * Removes an entry from an existing NodeSet list.
3196 */
3197 void
xmlXPathNodeSetRemove(xmlNodeSetPtr cur,int val)3198 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
3199 if (cur == NULL) return;
3200 if (val >= cur->nodeNr) return;
3201 if ((cur->nodeTab[val] != NULL) &&
3202 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
3203 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
3204 cur->nodeNr--;
3205 for (;val < cur->nodeNr;val++)
3206 cur->nodeTab[val] = cur->nodeTab[val + 1];
3207 cur->nodeTab[cur->nodeNr] = NULL;
3208 }
3209
3210 /**
3211 * xmlXPathFreeNodeSet:
3212 * @obj: the xmlNodeSetPtr to free
3213 *
3214 * Free the NodeSet compound (not the actual nodes !).
3215 */
3216 void
xmlXPathFreeNodeSet(xmlNodeSetPtr obj)3217 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
3218 if (obj == NULL) return;
3219 if (obj->nodeTab != NULL) {
3220 int i;
3221
3222 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3223 for (i = 0;i < obj->nodeNr;i++)
3224 if ((obj->nodeTab[i] != NULL) &&
3225 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3226 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3227 xmlFree(obj->nodeTab);
3228 }
3229 xmlFree(obj);
3230 }
3231
3232 /**
3233 * xmlXPathNodeSetClearFromPos:
3234 * @set: the node set to be cleared
3235 * @pos: the start position to clear from
3236 *
3237 * Clears the list from temporary XPath objects (e.g. namespace nodes
3238 * are feed) starting with the entry at @pos, but does *not* free the list
3239 * itself. Sets the length of the list to @pos.
3240 */
3241 static void
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set,int pos,int hasNsNodes)3242 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
3243 {
3244 if ((set == NULL) || (pos >= set->nodeNr))
3245 return;
3246 else if ((hasNsNodes)) {
3247 int i;
3248 xmlNodePtr node;
3249
3250 for (i = pos; i < set->nodeNr; i++) {
3251 node = set->nodeTab[i];
3252 if ((node != NULL) &&
3253 (node->type == XML_NAMESPACE_DECL))
3254 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3255 }
3256 }
3257 set->nodeNr = pos;
3258 }
3259
3260 /**
3261 * xmlXPathNodeSetClear:
3262 * @set: the node set to clear
3263 *
3264 * Clears the list from all temporary XPath objects (e.g. namespace nodes
3265 * are feed), but does *not* free the list itself. Sets the length of the
3266 * list to 0.
3267 */
3268 static void
xmlXPathNodeSetClear(xmlNodeSetPtr set,int hasNsNodes)3269 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
3270 {
3271 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3272 }
3273
3274 /**
3275 * xmlXPathNodeSetKeepLast:
3276 * @set: the node set to be cleared
3277 *
3278 * Move the last node to the first position and clear temporary XPath objects
3279 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
3280 * to 1.
3281 */
3282 static void
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)3283 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
3284 {
3285 int i;
3286 xmlNodePtr node;
3287
3288 if ((set == NULL) || (set->nodeNr <= 1))
3289 return;
3290 for (i = 0; i < set->nodeNr - 1; i++) {
3291 node = set->nodeTab[i];
3292 if ((node != NULL) &&
3293 (node->type == XML_NAMESPACE_DECL))
3294 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3295 }
3296 set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
3297 set->nodeNr = 1;
3298 }
3299
3300 /**
3301 * xmlXPathNewNodeSet:
3302 * @val: the NodePtr value
3303 *
3304 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3305 * it with the single Node @val
3306 *
3307 * Returns the newly created object.
3308 */
3309 xmlXPathObjectPtr
xmlXPathNewNodeSet(xmlNodePtr val)3310 xmlXPathNewNodeSet(xmlNodePtr val) {
3311 xmlXPathObjectPtr ret;
3312
3313 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3314 if (ret == NULL)
3315 return(NULL);
3316 memset(ret, 0 , sizeof(xmlXPathObject));
3317 ret->type = XPATH_NODESET;
3318 ret->boolval = 0;
3319 ret->nodesetval = xmlXPathNodeSetCreate(val);
3320 if (ret->nodesetval == NULL) {
3321 xmlFree(ret);
3322 return(NULL);
3323 }
3324 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3325 return(ret);
3326 }
3327
3328 /**
3329 * xmlXPathNewValueTree:
3330 * @val: the NodePtr value
3331 *
3332 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
3333 * it with the tree root @val
3334 *
3335 * Returns the newly created object.
3336 */
3337 xmlXPathObjectPtr
xmlXPathNewValueTree(xmlNodePtr val)3338 xmlXPathNewValueTree(xmlNodePtr val) {
3339 xmlXPathObjectPtr ret;
3340
3341 ret = xmlXPathNewNodeSet(val);
3342 if (ret == NULL)
3343 return(NULL);
3344 ret->type = XPATH_XSLT_TREE;
3345
3346 return(ret);
3347 }
3348
3349 /**
3350 * xmlXPathNewNodeSetList:
3351 * @val: an existing NodeSet
3352 *
3353 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3354 * it with the Nodeset @val
3355 *
3356 * Returns the newly created object.
3357 */
3358 xmlXPathObjectPtr
xmlXPathNewNodeSetList(xmlNodeSetPtr val)3359 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
3360 {
3361 xmlXPathObjectPtr ret;
3362
3363 if (val == NULL)
3364 ret = NULL;
3365 else if (val->nodeTab == NULL)
3366 ret = xmlXPathNewNodeSet(NULL);
3367 else {
3368 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
3369 if (ret) {
3370 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val);
3371 if (ret->nodesetval == NULL) {
3372 xmlFree(ret);
3373 return(NULL);
3374 }
3375 }
3376 }
3377
3378 return (ret);
3379 }
3380
3381 /**
3382 * xmlXPathWrapNodeSet:
3383 * @val: the NodePtr value
3384 *
3385 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
3386 *
3387 * Returns the newly created object.
3388 *
3389 * In case of error the node set is destroyed and NULL is returned.
3390 */
3391 xmlXPathObjectPtr
xmlXPathWrapNodeSet(xmlNodeSetPtr val)3392 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
3393 xmlXPathObjectPtr ret;
3394
3395 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3396 if (ret == NULL) {
3397 xmlXPathFreeNodeSet(val);
3398 return(NULL);
3399 }
3400 memset(ret, 0 , sizeof(xmlXPathObject));
3401 ret->type = XPATH_NODESET;
3402 ret->nodesetval = val;
3403 return(ret);
3404 }
3405
3406 /**
3407 * xmlXPathFreeNodeSetList:
3408 * @obj: an existing NodeSetList object
3409 *
3410 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
3411 * the list contrary to xmlXPathFreeObject().
3412 */
3413 void
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj)3414 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
3415 if (obj == NULL) return;
3416 xmlFree(obj);
3417 }
3418
3419 /**
3420 * xmlXPathDifference:
3421 * @nodes1: a node-set
3422 * @nodes2: a node-set
3423 *
3424 * Implements the EXSLT - Sets difference() function:
3425 * node-set set:difference (node-set, node-set)
3426 *
3427 * Returns the difference between the two node sets, or nodes1 if
3428 * nodes2 is empty
3429 */
3430 xmlNodeSetPtr
xmlXPathDifference(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3431 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3432 xmlNodeSetPtr ret;
3433 int i, l1;
3434 xmlNodePtr cur;
3435
3436 if (xmlXPathNodeSetIsEmpty(nodes2))
3437 return(nodes1);
3438
3439 ret = xmlXPathNodeSetCreate(NULL);
3440 if (ret == NULL)
3441 return(NULL);
3442 if (xmlXPathNodeSetIsEmpty(nodes1))
3443 return(ret);
3444
3445 l1 = xmlXPathNodeSetGetLength(nodes1);
3446
3447 for (i = 0; i < l1; i++) {
3448 cur = xmlXPathNodeSetItem(nodes1, i);
3449 if (!xmlXPathNodeSetContains(nodes2, cur)) {
3450 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3451 xmlXPathFreeNodeSet(ret);
3452 return(NULL);
3453 }
3454 }
3455 }
3456 return(ret);
3457 }
3458
3459 /**
3460 * xmlXPathIntersection:
3461 * @nodes1: a node-set
3462 * @nodes2: a node-set
3463 *
3464 * Implements the EXSLT - Sets intersection() function:
3465 * node-set set:intersection (node-set, node-set)
3466 *
3467 * Returns a node set comprising the nodes that are within both the
3468 * node sets passed as arguments
3469 */
3470 xmlNodeSetPtr
xmlXPathIntersection(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3471 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3472 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
3473 int i, l1;
3474 xmlNodePtr cur;
3475
3476 if (ret == NULL)
3477 return(ret);
3478 if (xmlXPathNodeSetIsEmpty(nodes1))
3479 return(ret);
3480 if (xmlXPathNodeSetIsEmpty(nodes2))
3481 return(ret);
3482
3483 l1 = xmlXPathNodeSetGetLength(nodes1);
3484
3485 for (i = 0; i < l1; i++) {
3486 cur = xmlXPathNodeSetItem(nodes1, i);
3487 if (xmlXPathNodeSetContains(nodes2, cur)) {
3488 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3489 xmlXPathFreeNodeSet(ret);
3490 return(NULL);
3491 }
3492 }
3493 }
3494 return(ret);
3495 }
3496
3497 /**
3498 * xmlXPathDistinctSorted:
3499 * @nodes: a node-set, sorted by document order
3500 *
3501 * Implements the EXSLT - Sets distinct() function:
3502 * node-set set:distinct (node-set)
3503 *
3504 * Returns a subset of the nodes contained in @nodes, or @nodes if
3505 * it is empty
3506 */
3507 xmlNodeSetPtr
xmlXPathDistinctSorted(xmlNodeSetPtr nodes)3508 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
3509 xmlNodeSetPtr ret;
3510 xmlHashTablePtr hash;
3511 int i, l;
3512 xmlChar * strval;
3513 xmlNodePtr cur;
3514
3515 if (xmlXPathNodeSetIsEmpty(nodes))
3516 return(nodes);
3517
3518 ret = xmlXPathNodeSetCreate(NULL);
3519 if (ret == NULL)
3520 return(ret);
3521 l = xmlXPathNodeSetGetLength(nodes);
3522 hash = xmlHashCreate (l);
3523 for (i = 0; i < l; i++) {
3524 cur = xmlXPathNodeSetItem(nodes, i);
3525 strval = xmlXPathCastNodeToString(cur);
3526 if (xmlHashLookup(hash, strval) == NULL) {
3527 if (xmlHashAddEntry(hash, strval, strval) < 0) {
3528 xmlFree(strval);
3529 goto error;
3530 }
3531 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3532 goto error;
3533 } else {
3534 xmlFree(strval);
3535 }
3536 }
3537 xmlHashFree(hash, xmlHashDefaultDeallocator);
3538 return(ret);
3539
3540 error:
3541 xmlHashFree(hash, xmlHashDefaultDeallocator);
3542 xmlXPathFreeNodeSet(ret);
3543 return(NULL);
3544 }
3545
3546 /**
3547 * xmlXPathDistinct:
3548 * @nodes: a node-set
3549 *
3550 * Implements the EXSLT - Sets distinct() function:
3551 * node-set set:distinct (node-set)
3552 * @nodes is sorted by document order, then #exslSetsDistinctSorted
3553 * is called with the sorted node-set
3554 *
3555 * Returns a subset of the nodes contained in @nodes, or @nodes if
3556 * it is empty
3557 */
3558 xmlNodeSetPtr
xmlXPathDistinct(xmlNodeSetPtr nodes)3559 xmlXPathDistinct (xmlNodeSetPtr nodes) {
3560 if (xmlXPathNodeSetIsEmpty(nodes))
3561 return(nodes);
3562
3563 xmlXPathNodeSetSort(nodes);
3564 return(xmlXPathDistinctSorted(nodes));
3565 }
3566
3567 /**
3568 * xmlXPathHasSameNodes:
3569 * @nodes1: a node-set
3570 * @nodes2: a node-set
3571 *
3572 * Implements the EXSLT - Sets has-same-nodes function:
3573 * boolean set:has-same-node(node-set, node-set)
3574 *
3575 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
3576 * otherwise
3577 */
3578 int
xmlXPathHasSameNodes(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3579 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3580 int i, l;
3581 xmlNodePtr cur;
3582
3583 if (xmlXPathNodeSetIsEmpty(nodes1) ||
3584 xmlXPathNodeSetIsEmpty(nodes2))
3585 return(0);
3586
3587 l = xmlXPathNodeSetGetLength(nodes1);
3588 for (i = 0; i < l; i++) {
3589 cur = xmlXPathNodeSetItem(nodes1, i);
3590 if (xmlXPathNodeSetContains(nodes2, cur))
3591 return(1);
3592 }
3593 return(0);
3594 }
3595
3596 /**
3597 * xmlXPathNodeLeadingSorted:
3598 * @nodes: a node-set, sorted by document order
3599 * @node: a node
3600 *
3601 * Implements the EXSLT - Sets leading() function:
3602 * node-set set:leading (node-set, node-set)
3603 *
3604 * Returns the nodes in @nodes that precede @node in document order,
3605 * @nodes if @node is NULL or an empty node-set if @nodes
3606 * doesn't contain @node
3607 */
3608 xmlNodeSetPtr
xmlXPathNodeLeadingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)3609 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3610 int i, l;
3611 xmlNodePtr cur;
3612 xmlNodeSetPtr ret;
3613
3614 if (node == NULL)
3615 return(nodes);
3616
3617 ret = xmlXPathNodeSetCreate(NULL);
3618 if (ret == NULL)
3619 return(ret);
3620 if (xmlXPathNodeSetIsEmpty(nodes) ||
3621 (!xmlXPathNodeSetContains(nodes, node)))
3622 return(ret);
3623
3624 l = xmlXPathNodeSetGetLength(nodes);
3625 for (i = 0; i < l; i++) {
3626 cur = xmlXPathNodeSetItem(nodes, i);
3627 if (cur == node)
3628 break;
3629 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3630 xmlXPathFreeNodeSet(ret);
3631 return(NULL);
3632 }
3633 }
3634 return(ret);
3635 }
3636
3637 /**
3638 * xmlXPathNodeLeading:
3639 * @nodes: a node-set
3640 * @node: a node
3641 *
3642 * Implements the EXSLT - Sets leading() function:
3643 * node-set set:leading (node-set, node-set)
3644 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
3645 * is called.
3646 *
3647 * Returns the nodes in @nodes that precede @node in document order,
3648 * @nodes if @node is NULL or an empty node-set if @nodes
3649 * doesn't contain @node
3650 */
3651 xmlNodeSetPtr
xmlXPathNodeLeading(xmlNodeSetPtr nodes,xmlNodePtr node)3652 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
3653 xmlXPathNodeSetSort(nodes);
3654 return(xmlXPathNodeLeadingSorted(nodes, node));
3655 }
3656
3657 /**
3658 * xmlXPathLeadingSorted:
3659 * @nodes1: a node-set, sorted by document order
3660 * @nodes2: a node-set, sorted by document order
3661 *
3662 * Implements the EXSLT - Sets leading() function:
3663 * node-set set:leading (node-set, node-set)
3664 *
3665 * Returns the nodes in @nodes1 that precede the first node in @nodes2
3666 * in document order, @nodes1 if @nodes2 is NULL or empty or
3667 * an empty node-set if @nodes1 doesn't contain @nodes2
3668 */
3669 xmlNodeSetPtr
xmlXPathLeadingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3670 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3671 if (xmlXPathNodeSetIsEmpty(nodes2))
3672 return(nodes1);
3673 return(xmlXPathNodeLeadingSorted(nodes1,
3674 xmlXPathNodeSetItem(nodes2, 1)));
3675 }
3676
3677 /**
3678 * xmlXPathLeading:
3679 * @nodes1: a node-set
3680 * @nodes2: a node-set
3681 *
3682 * Implements the EXSLT - Sets leading() function:
3683 * node-set set:leading (node-set, node-set)
3684 * @nodes1 and @nodes2 are sorted by document order, then
3685 * #exslSetsLeadingSorted is called.
3686 *
3687 * Returns the nodes in @nodes1 that precede the first node in @nodes2
3688 * in document order, @nodes1 if @nodes2 is NULL or empty or
3689 * an empty node-set if @nodes1 doesn't contain @nodes2
3690 */
3691 xmlNodeSetPtr
xmlXPathLeading(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3692 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3693 if (xmlXPathNodeSetIsEmpty(nodes2))
3694 return(nodes1);
3695 if (xmlXPathNodeSetIsEmpty(nodes1))
3696 return(xmlXPathNodeSetCreate(NULL));
3697 xmlXPathNodeSetSort(nodes1);
3698 xmlXPathNodeSetSort(nodes2);
3699 return(xmlXPathNodeLeadingSorted(nodes1,
3700 xmlXPathNodeSetItem(nodes2, 1)));
3701 }
3702
3703 /**
3704 * xmlXPathNodeTrailingSorted:
3705 * @nodes: a node-set, sorted by document order
3706 * @node: a node
3707 *
3708 * Implements the EXSLT - Sets trailing() function:
3709 * node-set set:trailing (node-set, node-set)
3710 *
3711 * Returns the nodes in @nodes that follow @node in document order,
3712 * @nodes if @node is NULL or an empty node-set if @nodes
3713 * doesn't contain @node
3714 */
3715 xmlNodeSetPtr
xmlXPathNodeTrailingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)3716 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3717 int i, l;
3718 xmlNodePtr cur;
3719 xmlNodeSetPtr ret;
3720
3721 if (node == NULL)
3722 return(nodes);
3723
3724 ret = xmlXPathNodeSetCreate(NULL);
3725 if (ret == NULL)
3726 return(ret);
3727 if (xmlXPathNodeSetIsEmpty(nodes) ||
3728 (!xmlXPathNodeSetContains(nodes, node)))
3729 return(ret);
3730
3731 l = xmlXPathNodeSetGetLength(nodes);
3732 for (i = l - 1; i >= 0; i--) {
3733 cur = xmlXPathNodeSetItem(nodes, i);
3734 if (cur == node)
3735 break;
3736 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3737 xmlXPathFreeNodeSet(ret);
3738 return(NULL);
3739 }
3740 }
3741 xmlXPathNodeSetSort(ret); /* bug 413451 */
3742 return(ret);
3743 }
3744
3745 /**
3746 * xmlXPathNodeTrailing:
3747 * @nodes: a node-set
3748 * @node: a node
3749 *
3750 * Implements the EXSLT - Sets trailing() function:
3751 * node-set set:trailing (node-set, node-set)
3752 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
3753 * is called.
3754 *
3755 * Returns the nodes in @nodes that follow @node in document order,
3756 * @nodes if @node is NULL or an empty node-set if @nodes
3757 * doesn't contain @node
3758 */
3759 xmlNodeSetPtr
xmlXPathNodeTrailing(xmlNodeSetPtr nodes,xmlNodePtr node)3760 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
3761 xmlXPathNodeSetSort(nodes);
3762 return(xmlXPathNodeTrailingSorted(nodes, node));
3763 }
3764
3765 /**
3766 * xmlXPathTrailingSorted:
3767 * @nodes1: a node-set, sorted by document order
3768 * @nodes2: a node-set, sorted by document order
3769 *
3770 * Implements the EXSLT - Sets trailing() function:
3771 * node-set set:trailing (node-set, node-set)
3772 *
3773 * Returns the nodes in @nodes1 that follow the first node in @nodes2
3774 * in document order, @nodes1 if @nodes2 is NULL or empty or
3775 * an empty node-set if @nodes1 doesn't contain @nodes2
3776 */
3777 xmlNodeSetPtr
xmlXPathTrailingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3778 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3779 if (xmlXPathNodeSetIsEmpty(nodes2))
3780 return(nodes1);
3781 return(xmlXPathNodeTrailingSorted(nodes1,
3782 xmlXPathNodeSetItem(nodes2, 0)));
3783 }
3784
3785 /**
3786 * xmlXPathTrailing:
3787 * @nodes1: a node-set
3788 * @nodes2: a node-set
3789 *
3790 * Implements the EXSLT - Sets trailing() function:
3791 * node-set set:trailing (node-set, node-set)
3792 * @nodes1 and @nodes2 are sorted by document order, then
3793 * #xmlXPathTrailingSorted is called.
3794 *
3795 * Returns the nodes in @nodes1 that follow the first node in @nodes2
3796 * in document order, @nodes1 if @nodes2 is NULL or empty or
3797 * an empty node-set if @nodes1 doesn't contain @nodes2
3798 */
3799 xmlNodeSetPtr
xmlXPathTrailing(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3800 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3801 if (xmlXPathNodeSetIsEmpty(nodes2))
3802 return(nodes1);
3803 if (xmlXPathNodeSetIsEmpty(nodes1))
3804 return(xmlXPathNodeSetCreate(NULL));
3805 xmlXPathNodeSetSort(nodes1);
3806 xmlXPathNodeSetSort(nodes2);
3807 return(xmlXPathNodeTrailingSorted(nodes1,
3808 xmlXPathNodeSetItem(nodes2, 0)));
3809 }
3810
3811 /************************************************************************
3812 * *
3813 * Routines to handle extra functions *
3814 * *
3815 ************************************************************************/
3816
3817 /**
3818 * xmlXPathRegisterFunc:
3819 * @ctxt: the XPath context
3820 * @name: the function name
3821 * @f: the function implementation or NULL
3822 *
3823 * Register a new function. If @f is NULL it unregisters the function
3824 *
3825 * Returns 0 in case of success, -1 in case of error
3826 */
3827 int
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathFunction f)3828 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
3829 xmlXPathFunction f) {
3830 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
3831 }
3832
3833 /**
3834 * xmlXPathRegisterFuncNS:
3835 * @ctxt: the XPath context
3836 * @name: the function name
3837 * @ns_uri: the function namespace URI
3838 * @f: the function implementation or NULL
3839 *
3840 * Register a new function. If @f is NULL it unregisters the function
3841 *
3842 * Returns 0 in case of success, -1 in case of error
3843 */
3844 int
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathFunction f)3845 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3846 const xmlChar *ns_uri, xmlXPathFunction f) {
3847 int ret;
3848
3849 if (ctxt == NULL)
3850 return(-1);
3851 if (name == NULL)
3852 return(-1);
3853
3854 if (ctxt->funcHash == NULL)
3855 ctxt->funcHash = xmlHashCreate(0);
3856 if (ctxt->funcHash == NULL) {
3857 xmlXPathErrMemory(ctxt);
3858 return(-1);
3859 }
3860 if (f == NULL)
3861 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
3862 XML_IGNORE_FPTR_CAST_WARNINGS
3863 ret = xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f);
3864 XML_POP_WARNINGS
3865 if (ret < 0) {
3866 xmlXPathErrMemory(ctxt);
3867 return(-1);
3868 }
3869
3870 return(0);
3871 }
3872
3873 /**
3874 * xmlXPathRegisterFuncLookup:
3875 * @ctxt: the XPath context
3876 * @f: the lookup function
3877 * @funcCtxt: the lookup data
3878 *
3879 * Registers an external mechanism to do function lookup.
3880 */
3881 void
xmlXPathRegisterFuncLookup(xmlXPathContextPtr ctxt,xmlXPathFuncLookupFunc f,void * funcCtxt)3882 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
3883 xmlXPathFuncLookupFunc f,
3884 void *funcCtxt) {
3885 if (ctxt == NULL)
3886 return;
3887 ctxt->funcLookupFunc = f;
3888 ctxt->funcLookupData = funcCtxt;
3889 }
3890
3891 /**
3892 * xmlXPathFunctionLookup:
3893 * @ctxt: the XPath context
3894 * @name: the function name
3895 *
3896 * Search in the Function array of the context for the given
3897 * function.
3898 *
3899 * Returns the xmlXPathFunction or NULL if not found
3900 */
3901 xmlXPathFunction
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt,const xmlChar * name)3902 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
3903 if (ctxt == NULL)
3904 return (NULL);
3905
3906 if (ctxt->funcLookupFunc != NULL) {
3907 xmlXPathFunction ret;
3908 xmlXPathFuncLookupFunc f;
3909
3910 f = ctxt->funcLookupFunc;
3911 ret = f(ctxt->funcLookupData, name, NULL);
3912 if (ret != NULL)
3913 return(ret);
3914 }
3915 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
3916 }
3917
3918 /**
3919 * xmlXPathFunctionLookupNS:
3920 * @ctxt: the XPath context
3921 * @name: the function name
3922 * @ns_uri: the function namespace URI
3923 *
3924 * Search in the Function array of the context for the given
3925 * function.
3926 *
3927 * Returns the xmlXPathFunction or NULL if not found
3928 */
3929 xmlXPathFunction
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)3930 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3931 const xmlChar *ns_uri) {
3932 xmlXPathFunction ret;
3933
3934 if (ctxt == NULL)
3935 return(NULL);
3936 if (name == NULL)
3937 return(NULL);
3938
3939 if (ctxt->funcLookupFunc != NULL) {
3940 xmlXPathFuncLookupFunc f;
3941
3942 f = ctxt->funcLookupFunc;
3943 ret = f(ctxt->funcLookupData, name, ns_uri);
3944 if (ret != NULL)
3945 return(ret);
3946 }
3947
3948 if (ctxt->funcHash == NULL)
3949 return(NULL);
3950
3951 XML_IGNORE_FPTR_CAST_WARNINGS
3952 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
3953 XML_POP_WARNINGS
3954 return(ret);
3955 }
3956
3957 /**
3958 * xmlXPathRegisteredFuncsCleanup:
3959 * @ctxt: the XPath context
3960 *
3961 * Cleanup the XPath context data associated to registered functions
3962 */
3963 void
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt)3964 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
3965 if (ctxt == NULL)
3966 return;
3967
3968 xmlHashFree(ctxt->funcHash, NULL);
3969 ctxt->funcHash = NULL;
3970 }
3971
3972 /************************************************************************
3973 * *
3974 * Routines to handle Variables *
3975 * *
3976 ************************************************************************/
3977
3978 /**
3979 * xmlXPathRegisterVariable:
3980 * @ctxt: the XPath context
3981 * @name: the variable name
3982 * @value: the variable value or NULL
3983 *
3984 * Register a new variable value. If @value is NULL it unregisters
3985 * the variable
3986 *
3987 * Returns 0 in case of success, -1 in case of error
3988 */
3989 int
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathObjectPtr value)3990 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
3991 xmlXPathObjectPtr value) {
3992 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
3993 }
3994
3995 /**
3996 * xmlXPathRegisterVariableNS:
3997 * @ctxt: the XPath context
3998 * @name: the variable name
3999 * @ns_uri: the variable namespace URI
4000 * @value: the variable value or NULL
4001 *
4002 * Register a new variable value. If @value is NULL it unregisters
4003 * the variable
4004 *
4005 * Returns 0 in case of success, -1 in case of error
4006 */
4007 int
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathObjectPtr value)4008 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4009 const xmlChar *ns_uri,
4010 xmlXPathObjectPtr value) {
4011 if (ctxt == NULL)
4012 return(-1);
4013 if (name == NULL)
4014 return(-1);
4015
4016 if (ctxt->varHash == NULL)
4017 ctxt->varHash = xmlHashCreate(0);
4018 if (ctxt->varHash == NULL)
4019 return(-1);
4020 if (value == NULL)
4021 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4022 xmlXPathFreeObjectEntry));
4023 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4024 (void *) value, xmlXPathFreeObjectEntry));
4025 }
4026
4027 /**
4028 * xmlXPathRegisterVariableLookup:
4029 * @ctxt: the XPath context
4030 * @f: the lookup function
4031 * @data: the lookup data
4032 *
4033 * register an external mechanism to do variable lookup
4034 */
4035 void
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,xmlXPathVariableLookupFunc f,void * data)4036 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4037 xmlXPathVariableLookupFunc f, void *data) {
4038 if (ctxt == NULL)
4039 return;
4040 ctxt->varLookupFunc = f;
4041 ctxt->varLookupData = data;
4042 }
4043
4044 /**
4045 * xmlXPathVariableLookup:
4046 * @ctxt: the XPath context
4047 * @name: the variable name
4048 *
4049 * Search in the Variable array of the context for the given
4050 * variable value.
4051 *
4052 * Returns a copy of the value or NULL if not found
4053 */
4054 xmlXPathObjectPtr
xmlXPathVariableLookup(xmlXPathContextPtr ctxt,const xmlChar * name)4055 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4056 if (ctxt == NULL)
4057 return(NULL);
4058
4059 if (ctxt->varLookupFunc != NULL) {
4060 xmlXPathObjectPtr ret;
4061
4062 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4063 (ctxt->varLookupData, name, NULL);
4064 return(ret);
4065 }
4066 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4067 }
4068
4069 /**
4070 * xmlXPathVariableLookupNS:
4071 * @ctxt: the XPath context
4072 * @name: the variable name
4073 * @ns_uri: the variable namespace URI
4074 *
4075 * Search in the Variable array of the context for the given
4076 * variable value.
4077 *
4078 * Returns the a copy of the value or NULL if not found
4079 */
4080 xmlXPathObjectPtr
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4081 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4082 const xmlChar *ns_uri) {
4083 if (ctxt == NULL)
4084 return(NULL);
4085
4086 if (ctxt->varLookupFunc != NULL) {
4087 xmlXPathObjectPtr ret;
4088
4089 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4090 (ctxt->varLookupData, name, ns_uri);
4091 if (ret != NULL) return(ret);
4092 }
4093
4094 if (ctxt->varHash == NULL)
4095 return(NULL);
4096 if (name == NULL)
4097 return(NULL);
4098
4099 return(xmlXPathObjectCopy(xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4100 }
4101
4102 /**
4103 * xmlXPathRegisteredVariablesCleanup:
4104 * @ctxt: the XPath context
4105 *
4106 * Cleanup the XPath context data associated to registered variables
4107 */
4108 void
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt)4109 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4110 if (ctxt == NULL)
4111 return;
4112
4113 xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
4114 ctxt->varHash = NULL;
4115 }
4116
4117 /**
4118 * xmlXPathRegisterNs:
4119 * @ctxt: the XPath context
4120 * @prefix: the namespace prefix cannot be NULL or empty string
4121 * @ns_uri: the namespace name
4122 *
4123 * Register a new namespace. If @ns_uri is NULL it unregisters
4124 * the namespace
4125 *
4126 * Returns 0 in case of success, -1 in case of error
4127 */
4128 int
xmlXPathRegisterNs(xmlXPathContextPtr ctxt,const xmlChar * prefix,const xmlChar * ns_uri)4129 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4130 const xmlChar *ns_uri) {
4131 xmlChar *copy;
4132
4133 if (ctxt == NULL)
4134 return(-1);
4135 if (prefix == NULL)
4136 return(-1);
4137 if (prefix[0] == 0)
4138 return(-1);
4139
4140 if (ctxt->nsHash == NULL)
4141 ctxt->nsHash = xmlHashCreate(10);
4142 if (ctxt->nsHash == NULL) {
4143 xmlXPathErrMemory(ctxt);
4144 return(-1);
4145 }
4146 if (ns_uri == NULL)
4147 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
4148 xmlHashDefaultDeallocator));
4149
4150 copy = xmlStrdup(ns_uri);
4151 if (copy == NULL) {
4152 xmlXPathErrMemory(ctxt);
4153 return(-1);
4154 }
4155 if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
4156 xmlHashDefaultDeallocator) < 0) {
4157 xmlXPathErrMemory(ctxt);
4158 xmlFree(copy);
4159 return(-1);
4160 }
4161
4162 return(0);
4163 }
4164
4165 /**
4166 * xmlXPathNsLookup:
4167 * @ctxt: the XPath context
4168 * @prefix: the namespace prefix value
4169 *
4170 * Search in the namespace declaration array of the context for the given
4171 * namespace name associated to the given prefix
4172 *
4173 * Returns the value or NULL if not found
4174 */
4175 const xmlChar *
xmlXPathNsLookup(xmlXPathContextPtr ctxt,const xmlChar * prefix)4176 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
4177 if (ctxt == NULL)
4178 return(NULL);
4179 if (prefix == NULL)
4180 return(NULL);
4181
4182 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4183 return(XML_XML_NAMESPACE);
4184
4185 if (ctxt->namespaces != NULL) {
4186 int i;
4187
4188 for (i = 0;i < ctxt->nsNr;i++) {
4189 if ((ctxt->namespaces[i] != NULL) &&
4190 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4191 return(ctxt->namespaces[i]->href);
4192 }
4193 }
4194
4195 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4196 }
4197
4198 /**
4199 * xmlXPathRegisteredNsCleanup:
4200 * @ctxt: the XPath context
4201 *
4202 * Cleanup the XPath context data associated to registered variables
4203 */
4204 void
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt)4205 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
4206 if (ctxt == NULL)
4207 return;
4208
4209 xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4210 ctxt->nsHash = NULL;
4211 }
4212
4213 /************************************************************************
4214 * *
4215 * Routines to handle Values *
4216 * *
4217 ************************************************************************/
4218
4219 /* Allocations are terrible, one needs to optimize all this !!! */
4220
4221 /**
4222 * xmlXPathNewFloat:
4223 * @val: the double value
4224 *
4225 * Create a new xmlXPathObjectPtr of type double and of value @val
4226 *
4227 * Returns the newly created object.
4228 */
4229 xmlXPathObjectPtr
xmlXPathNewFloat(double val)4230 xmlXPathNewFloat(double val) {
4231 xmlXPathObjectPtr ret;
4232
4233 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4234 if (ret == NULL)
4235 return(NULL);
4236 memset(ret, 0 , sizeof(xmlXPathObject));
4237 ret->type = XPATH_NUMBER;
4238 ret->floatval = val;
4239 return(ret);
4240 }
4241
4242 /**
4243 * xmlXPathNewBoolean:
4244 * @val: the boolean value
4245 *
4246 * Create a new xmlXPathObjectPtr of type boolean and of value @val
4247 *
4248 * Returns the newly created object.
4249 */
4250 xmlXPathObjectPtr
xmlXPathNewBoolean(int val)4251 xmlXPathNewBoolean(int val) {
4252 xmlXPathObjectPtr ret;
4253
4254 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4255 if (ret == NULL)
4256 return(NULL);
4257 memset(ret, 0 , sizeof(xmlXPathObject));
4258 ret->type = XPATH_BOOLEAN;
4259 ret->boolval = (val != 0);
4260 return(ret);
4261 }
4262
4263 /**
4264 * xmlXPathNewString:
4265 * @val: the xmlChar * value
4266 *
4267 * Create a new xmlXPathObjectPtr of type string and of value @val
4268 *
4269 * Returns the newly created object.
4270 */
4271 xmlXPathObjectPtr
xmlXPathNewString(const xmlChar * val)4272 xmlXPathNewString(const xmlChar *val) {
4273 xmlXPathObjectPtr ret;
4274
4275 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4276 if (ret == NULL)
4277 return(NULL);
4278 memset(ret, 0 , sizeof(xmlXPathObject));
4279 ret->type = XPATH_STRING;
4280 if (val == NULL)
4281 val = BAD_CAST "";
4282 ret->stringval = xmlStrdup(val);
4283 if (ret->stringval == NULL) {
4284 xmlFree(ret);
4285 return(NULL);
4286 }
4287 return(ret);
4288 }
4289
4290 /**
4291 * xmlXPathWrapString:
4292 * @val: the xmlChar * value
4293 *
4294 * Wraps the @val string into an XPath object.
4295 *
4296 * Returns the newly created object.
4297 *
4298 * Frees @val in case of error.
4299 */
4300 xmlXPathObjectPtr
xmlXPathWrapString(xmlChar * val)4301 xmlXPathWrapString (xmlChar *val) {
4302 xmlXPathObjectPtr ret;
4303
4304 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4305 if (ret == NULL) {
4306 xmlFree(val);
4307 return(NULL);
4308 }
4309 memset(ret, 0 , sizeof(xmlXPathObject));
4310 ret->type = XPATH_STRING;
4311 ret->stringval = val;
4312 return(ret);
4313 }
4314
4315 /**
4316 * xmlXPathNewCString:
4317 * @val: the char * value
4318 *
4319 * Create a new xmlXPathObjectPtr of type string and of value @val
4320 *
4321 * Returns the newly created object.
4322 */
4323 xmlXPathObjectPtr
xmlXPathNewCString(const char * val)4324 xmlXPathNewCString(const char *val) {
4325 return(xmlXPathNewString(BAD_CAST val));
4326 }
4327
4328 /**
4329 * xmlXPathWrapCString:
4330 * @val: the char * value
4331 *
4332 * Wraps a string into an XPath object.
4333 *
4334 * Returns the newly created object.
4335 */
4336 xmlXPathObjectPtr
xmlXPathWrapCString(char * val)4337 xmlXPathWrapCString (char * val) {
4338 return(xmlXPathWrapString((xmlChar *)(val)));
4339 }
4340
4341 /**
4342 * xmlXPathWrapExternal:
4343 * @val: the user data
4344 *
4345 * Wraps the @val data into an XPath object.
4346 *
4347 * Returns the newly created object.
4348 */
4349 xmlXPathObjectPtr
xmlXPathWrapExternal(void * val)4350 xmlXPathWrapExternal (void *val) {
4351 xmlXPathObjectPtr ret;
4352
4353 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4354 if (ret == NULL)
4355 return(NULL);
4356 memset(ret, 0 , sizeof(xmlXPathObject));
4357 ret->type = XPATH_USERS;
4358 ret->user = val;
4359 return(ret);
4360 }
4361
4362 /**
4363 * xmlXPathObjectCopy:
4364 * @val: the original object
4365 *
4366 * allocate a new copy of a given object
4367 *
4368 * Returns the newly created object.
4369 */
4370 xmlXPathObjectPtr
xmlXPathObjectCopy(xmlXPathObjectPtr val)4371 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
4372 xmlXPathObjectPtr ret;
4373
4374 if (val == NULL)
4375 return(NULL);
4376
4377 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4378 if (ret == NULL)
4379 return(NULL);
4380 memcpy(ret, val , sizeof(xmlXPathObject));
4381 switch (val->type) {
4382 case XPATH_BOOLEAN:
4383 case XPATH_NUMBER:
4384 break;
4385 case XPATH_STRING:
4386 ret->stringval = xmlStrdup(val->stringval);
4387 if (ret->stringval == NULL) {
4388 xmlFree(ret);
4389 return(NULL);
4390 }
4391 break;
4392 case XPATH_XSLT_TREE:
4393 #if 0
4394 /*
4395 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
4396 this previous handling is no longer correct, and can cause some serious
4397 problems (ref. bug 145547)
4398 */
4399 if ((val->nodesetval != NULL) &&
4400 (val->nodesetval->nodeTab != NULL)) {
4401 xmlNodePtr cur, tmp;
4402 xmlDocPtr top;
4403
4404 ret->boolval = 1;
4405 top = xmlNewDoc(NULL);
4406 top->name = (char *)
4407 xmlStrdup(val->nodesetval->nodeTab[0]->name);
4408 ret->user = top;
4409 if (top != NULL) {
4410 top->doc = top;
4411 cur = val->nodesetval->nodeTab[0]->children;
4412 while (cur != NULL) {
4413 tmp = xmlDocCopyNode(cur, top, 1);
4414 xmlAddChild((xmlNodePtr) top, tmp);
4415 cur = cur->next;
4416 }
4417 }
4418
4419 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
4420 } else
4421 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
4422 /* Deallocate the copied tree value */
4423 break;
4424 #endif
4425 case XPATH_NODESET:
4426 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
4427 if (ret->nodesetval == NULL) {
4428 xmlFree(ret);
4429 return(NULL);
4430 }
4431 /* Do not deallocate the copied tree value */
4432 ret->boolval = 0;
4433 break;
4434 case XPATH_USERS:
4435 ret->user = val->user;
4436 break;
4437 default:
4438 xmlFree(ret);
4439 ret = NULL;
4440 break;
4441 }
4442 return(ret);
4443 }
4444
4445 /**
4446 * xmlXPathFreeObject:
4447 * @obj: the object to free
4448 *
4449 * Free up an xmlXPathObjectPtr object.
4450 */
4451 void
xmlXPathFreeObject(xmlXPathObjectPtr obj)4452 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
4453 if (obj == NULL) return;
4454 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4455 if (obj->nodesetval != NULL)
4456 xmlXPathFreeNodeSet(obj->nodesetval);
4457 } else if (obj->type == XPATH_STRING) {
4458 if (obj->stringval != NULL)
4459 xmlFree(obj->stringval);
4460 }
4461 xmlFree(obj);
4462 }
4463
4464 static void
xmlXPathFreeObjectEntry(void * obj,const xmlChar * name ATTRIBUTE_UNUSED)4465 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
4466 xmlXPathFreeObject((xmlXPathObjectPtr) obj);
4467 }
4468
4469 /**
4470 * xmlXPathReleaseObject:
4471 * @obj: the xmlXPathObjectPtr to free or to cache
4472 *
4473 * Depending on the state of the cache this frees the given
4474 * XPath object or stores it in the cache.
4475 */
4476 static void
xmlXPathReleaseObject(xmlXPathContextPtr ctxt,xmlXPathObjectPtr obj)4477 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
4478 {
4479 if (obj == NULL)
4480 return;
4481 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4482 xmlXPathFreeObject(obj);
4483 } else {
4484 xmlXPathContextCachePtr cache =
4485 (xmlXPathContextCachePtr) ctxt->cache;
4486
4487 switch (obj->type) {
4488 case XPATH_NODESET:
4489 case XPATH_XSLT_TREE:
4490 if (obj->nodesetval != NULL) {
4491 if ((obj->nodesetval->nodeMax <= 40) &&
4492 (cache->numNodeset < cache->maxNodeset)) {
4493 obj->stringval = (void *) cache->nodesetObjs;
4494 cache->nodesetObjs = obj;
4495 cache->numNodeset += 1;
4496 goto obj_cached;
4497 } else {
4498 xmlXPathFreeNodeSet(obj->nodesetval);
4499 obj->nodesetval = NULL;
4500 }
4501 }
4502 break;
4503 case XPATH_STRING:
4504 if (obj->stringval != NULL)
4505 xmlFree(obj->stringval);
4506 obj->stringval = NULL;
4507 break;
4508 case XPATH_BOOLEAN:
4509 case XPATH_NUMBER:
4510 break;
4511 default:
4512 goto free_obj;
4513 }
4514
4515 /*
4516 * Fallback to adding to the misc-objects slot.
4517 */
4518 if (cache->numMisc >= cache->maxMisc)
4519 goto free_obj;
4520 obj->stringval = (void *) cache->miscObjs;
4521 cache->miscObjs = obj;
4522 cache->numMisc += 1;
4523
4524 obj_cached:
4525 obj->boolval = 0;
4526 if (obj->nodesetval != NULL) {
4527 xmlNodeSetPtr tmpset = obj->nodesetval;
4528
4529 /*
4530 * Due to those nasty ns-nodes, we need to traverse
4531 * the list and free the ns-nodes.
4532 */
4533 if (tmpset->nodeNr > 0) {
4534 int i;
4535 xmlNodePtr node;
4536
4537 for (i = 0; i < tmpset->nodeNr; i++) {
4538 node = tmpset->nodeTab[i];
4539 if ((node != NULL) &&
4540 (node->type == XML_NAMESPACE_DECL))
4541 {
4542 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4543 }
4544 }
4545 }
4546 tmpset->nodeNr = 0;
4547 }
4548
4549 return;
4550
4551 free_obj:
4552 /*
4553 * Cache is full; free the object.
4554 */
4555 if (obj->nodesetval != NULL)
4556 xmlXPathFreeNodeSet(obj->nodesetval);
4557 xmlFree(obj);
4558 }
4559 return;
4560 }
4561
4562
4563 /************************************************************************
4564 * *
4565 * Type Casting Routines *
4566 * *
4567 ************************************************************************/
4568
4569 /**
4570 * xmlXPathCastBooleanToString:
4571 * @val: a boolean
4572 *
4573 * Converts a boolean to its string value.
4574 *
4575 * Returns a newly allocated string.
4576 */
4577 xmlChar *
xmlXPathCastBooleanToString(int val)4578 xmlXPathCastBooleanToString (int val) {
4579 xmlChar *ret;
4580 if (val)
4581 ret = xmlStrdup((const xmlChar *) "true");
4582 else
4583 ret = xmlStrdup((const xmlChar *) "false");
4584 return(ret);
4585 }
4586
4587 /**
4588 * xmlXPathCastNumberToString:
4589 * @val: a number
4590 *
4591 * Converts a number to its string value.
4592 *
4593 * Returns a newly allocated string.
4594 */
4595 xmlChar *
xmlXPathCastNumberToString(double val)4596 xmlXPathCastNumberToString (double val) {
4597 xmlChar *ret;
4598 switch (xmlXPathIsInf(val)) {
4599 case 1:
4600 ret = xmlStrdup((const xmlChar *) "Infinity");
4601 break;
4602 case -1:
4603 ret = xmlStrdup((const xmlChar *) "-Infinity");
4604 break;
4605 default:
4606 if (xmlXPathIsNaN(val)) {
4607 ret = xmlStrdup((const xmlChar *) "NaN");
4608 } else if (val == 0) {
4609 /* Omit sign for negative zero. */
4610 ret = xmlStrdup((const xmlChar *) "0");
4611 } else {
4612 /* could be improved */
4613 char buf[100];
4614 xmlXPathFormatNumber(val, buf, 99);
4615 buf[99] = 0;
4616 ret = xmlStrdup((const xmlChar *) buf);
4617 }
4618 }
4619 return(ret);
4620 }
4621
4622 /**
4623 * xmlXPathCastNodeToString:
4624 * @node: a node
4625 *
4626 * Converts a node to its string value.
4627 *
4628 * Returns a newly allocated string.
4629 */
4630 xmlChar *
xmlXPathCastNodeToString(xmlNodePtr node)4631 xmlXPathCastNodeToString (xmlNodePtr node) {
4632 return(xmlNodeGetContent(node));
4633 }
4634
4635 /**
4636 * xmlXPathCastNodeSetToString:
4637 * @ns: a node-set
4638 *
4639 * Converts a node-set to its string value.
4640 *
4641 * Returns a newly allocated string.
4642 */
4643 xmlChar *
xmlXPathCastNodeSetToString(xmlNodeSetPtr ns)4644 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
4645 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
4646 return(xmlStrdup((const xmlChar *) ""));
4647
4648 if (ns->nodeNr > 1)
4649 xmlXPathNodeSetSort(ns);
4650 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
4651 }
4652
4653 /**
4654 * xmlXPathCastToString:
4655 * @val: an XPath object
4656 *
4657 * Converts an existing object to its string() equivalent
4658 *
4659 * Returns the allocated string value of the object, NULL in case of error.
4660 * It's up to the caller to free the string memory with xmlFree().
4661 */
4662 xmlChar *
xmlXPathCastToString(xmlXPathObjectPtr val)4663 xmlXPathCastToString(xmlXPathObjectPtr val) {
4664 xmlChar *ret = NULL;
4665
4666 if (val == NULL)
4667 return(xmlStrdup((const xmlChar *) ""));
4668 switch (val->type) {
4669 case XPATH_UNDEFINED:
4670 ret = xmlStrdup((const xmlChar *) "");
4671 break;
4672 case XPATH_NODESET:
4673 case XPATH_XSLT_TREE:
4674 ret = xmlXPathCastNodeSetToString(val->nodesetval);
4675 break;
4676 case XPATH_STRING:
4677 return(xmlStrdup(val->stringval));
4678 case XPATH_BOOLEAN:
4679 ret = xmlXPathCastBooleanToString(val->boolval);
4680 break;
4681 case XPATH_NUMBER: {
4682 ret = xmlXPathCastNumberToString(val->floatval);
4683 break;
4684 }
4685 case XPATH_USERS:
4686 /* TODO */
4687 ret = xmlStrdup((const xmlChar *) "");
4688 break;
4689 }
4690 return(ret);
4691 }
4692
4693 /**
4694 * xmlXPathConvertString:
4695 * @val: an XPath object
4696 *
4697 * Converts an existing object to its string() equivalent
4698 *
4699 * Returns the new object, the old one is freed (or the operation
4700 * is done directly on @val)
4701 */
4702 xmlXPathObjectPtr
xmlXPathConvertString(xmlXPathObjectPtr val)4703 xmlXPathConvertString(xmlXPathObjectPtr val) {
4704 xmlChar *res = NULL;
4705
4706 if (val == NULL)
4707 return(xmlXPathNewCString(""));
4708
4709 switch (val->type) {
4710 case XPATH_UNDEFINED:
4711 break;
4712 case XPATH_NODESET:
4713 case XPATH_XSLT_TREE:
4714 res = xmlXPathCastNodeSetToString(val->nodesetval);
4715 break;
4716 case XPATH_STRING:
4717 return(val);
4718 case XPATH_BOOLEAN:
4719 res = xmlXPathCastBooleanToString(val->boolval);
4720 break;
4721 case XPATH_NUMBER:
4722 res = xmlXPathCastNumberToString(val->floatval);
4723 break;
4724 case XPATH_USERS:
4725 /* TODO */
4726 break;
4727 }
4728 xmlXPathFreeObject(val);
4729 if (res == NULL)
4730 return(xmlXPathNewCString(""));
4731 return(xmlXPathWrapString(res));
4732 }
4733
4734 /**
4735 * xmlXPathCastBooleanToNumber:
4736 * @val: a boolean
4737 *
4738 * Converts a boolean to its number value
4739 *
4740 * Returns the number value
4741 */
4742 double
xmlXPathCastBooleanToNumber(int val)4743 xmlXPathCastBooleanToNumber(int val) {
4744 if (val)
4745 return(1.0);
4746 return(0.0);
4747 }
4748
4749 /**
4750 * xmlXPathCastStringToNumber:
4751 * @val: a string
4752 *
4753 * Converts a string to its number value
4754 *
4755 * Returns the number value
4756 */
4757 double
xmlXPathCastStringToNumber(const xmlChar * val)4758 xmlXPathCastStringToNumber(const xmlChar * val) {
4759 return(xmlXPathStringEvalNumber(val));
4760 }
4761
4762 /**
4763 * xmlXPathNodeToNumberInternal:
4764 * @node: a node
4765 *
4766 * Converts a node to its number value
4767 *
4768 * Returns the number value
4769 */
4770 static double
xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr node)4771 xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt, xmlNodePtr node) {
4772 xmlChar *strval;
4773 double ret;
4774
4775 if (node == NULL)
4776 return(xmlXPathNAN);
4777 strval = xmlXPathCastNodeToString(node);
4778 if (strval == NULL) {
4779 xmlXPathPErrMemory(ctxt);
4780 return(xmlXPathNAN);
4781 }
4782 ret = xmlXPathCastStringToNumber(strval);
4783 xmlFree(strval);
4784
4785 return(ret);
4786 }
4787
4788 /**
4789 * xmlXPathCastNodeToNumber:
4790 * @node: a node
4791 *
4792 * Converts a node to its number value
4793 *
4794 * Returns the number value
4795 */
4796 double
xmlXPathCastNodeToNumber(xmlNodePtr node)4797 xmlXPathCastNodeToNumber (xmlNodePtr node) {
4798 return(xmlXPathNodeToNumberInternal(NULL, node));
4799 }
4800
4801 /**
4802 * xmlXPathCastNodeSetToNumber:
4803 * @ns: a node-set
4804 *
4805 * Converts a node-set to its number value
4806 *
4807 * Returns the number value
4808 */
4809 double
xmlXPathCastNodeSetToNumber(xmlNodeSetPtr ns)4810 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
4811 xmlChar *str;
4812 double ret;
4813
4814 if (ns == NULL)
4815 return(xmlXPathNAN);
4816 str = xmlXPathCastNodeSetToString(ns);
4817 ret = xmlXPathCastStringToNumber(str);
4818 xmlFree(str);
4819 return(ret);
4820 }
4821
4822 /**
4823 * xmlXPathCastToNumber:
4824 * @val: an XPath object
4825 *
4826 * Converts an XPath object to its number value
4827 *
4828 * Returns the number value
4829 */
4830 double
xmlXPathCastToNumber(xmlXPathObjectPtr val)4831 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
4832 return(xmlXPathCastToNumberInternal(NULL, val));
4833 }
4834
4835 /**
4836 * xmlXPathConvertNumber:
4837 * @val: an XPath object
4838 *
4839 * Converts an existing object to its number() equivalent
4840 *
4841 * Returns the new object, the old one is freed (or the operation
4842 * is done directly on @val)
4843 */
4844 xmlXPathObjectPtr
xmlXPathConvertNumber(xmlXPathObjectPtr val)4845 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
4846 xmlXPathObjectPtr ret;
4847
4848 if (val == NULL)
4849 return(xmlXPathNewFloat(0.0));
4850 if (val->type == XPATH_NUMBER)
4851 return(val);
4852 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
4853 xmlXPathFreeObject(val);
4854 return(ret);
4855 }
4856
4857 /**
4858 * xmlXPathCastNumberToBoolean:
4859 * @val: a number
4860 *
4861 * Converts a number to its boolean value
4862 *
4863 * Returns the boolean value
4864 */
4865 int
xmlXPathCastNumberToBoolean(double val)4866 xmlXPathCastNumberToBoolean (double val) {
4867 if (xmlXPathIsNaN(val) || (val == 0.0))
4868 return(0);
4869 return(1);
4870 }
4871
4872 /**
4873 * xmlXPathCastStringToBoolean:
4874 * @val: a string
4875 *
4876 * Converts a string to its boolean value
4877 *
4878 * Returns the boolean value
4879 */
4880 int
xmlXPathCastStringToBoolean(const xmlChar * val)4881 xmlXPathCastStringToBoolean (const xmlChar *val) {
4882 if ((val == NULL) || (xmlStrlen(val) == 0))
4883 return(0);
4884 return(1);
4885 }
4886
4887 /**
4888 * xmlXPathCastNodeSetToBoolean:
4889 * @ns: a node-set
4890 *
4891 * Converts a node-set to its boolean value
4892 *
4893 * Returns the boolean value
4894 */
4895 int
xmlXPathCastNodeSetToBoolean(xmlNodeSetPtr ns)4896 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
4897 if ((ns == NULL) || (ns->nodeNr == 0))
4898 return(0);
4899 return(1);
4900 }
4901
4902 /**
4903 * xmlXPathCastToBoolean:
4904 * @val: an XPath object
4905 *
4906 * Converts an XPath object to its boolean value
4907 *
4908 * Returns the boolean value
4909 */
4910 int
xmlXPathCastToBoolean(xmlXPathObjectPtr val)4911 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
4912 int ret = 0;
4913
4914 if (val == NULL)
4915 return(0);
4916 switch (val->type) {
4917 case XPATH_UNDEFINED:
4918 ret = 0;
4919 break;
4920 case XPATH_NODESET:
4921 case XPATH_XSLT_TREE:
4922 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
4923 break;
4924 case XPATH_STRING:
4925 ret = xmlXPathCastStringToBoolean(val->stringval);
4926 break;
4927 case XPATH_NUMBER:
4928 ret = xmlXPathCastNumberToBoolean(val->floatval);
4929 break;
4930 case XPATH_BOOLEAN:
4931 ret = val->boolval;
4932 break;
4933 case XPATH_USERS:
4934 /* TODO */
4935 ret = 0;
4936 break;
4937 }
4938 return(ret);
4939 }
4940
4941
4942 /**
4943 * xmlXPathConvertBoolean:
4944 * @val: an XPath object
4945 *
4946 * Converts an existing object to its boolean() equivalent
4947 *
4948 * Returns the new object, the old one is freed (or the operation
4949 * is done directly on @val)
4950 */
4951 xmlXPathObjectPtr
xmlXPathConvertBoolean(xmlXPathObjectPtr val)4952 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
4953 xmlXPathObjectPtr ret;
4954
4955 if (val == NULL)
4956 return(xmlXPathNewBoolean(0));
4957 if (val->type == XPATH_BOOLEAN)
4958 return(val);
4959 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
4960 xmlXPathFreeObject(val);
4961 return(ret);
4962 }
4963
4964 /************************************************************************
4965 * *
4966 * Routines to handle XPath contexts *
4967 * *
4968 ************************************************************************/
4969
4970 /**
4971 * xmlXPathNewContext:
4972 * @doc: the XML document
4973 *
4974 * Create a new xmlXPathContext
4975 *
4976 * Returns the xmlXPathContext just allocated. The caller will need to free it.
4977 */
4978 xmlXPathContextPtr
xmlXPathNewContext(xmlDocPtr doc)4979 xmlXPathNewContext(xmlDocPtr doc) {
4980 xmlXPathContextPtr ret;
4981
4982 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
4983 if (ret == NULL)
4984 return(NULL);
4985 memset(ret, 0 , sizeof(xmlXPathContext));
4986 ret->doc = doc;
4987 ret->node = NULL;
4988
4989 ret->varHash = NULL;
4990
4991 ret->nb_types = 0;
4992 ret->max_types = 0;
4993 ret->types = NULL;
4994
4995 ret->nb_axis = 0;
4996 ret->max_axis = 0;
4997 ret->axis = NULL;
4998
4999 ret->nsHash = NULL;
5000 ret->user = NULL;
5001
5002 ret->contextSize = -1;
5003 ret->proximityPosition = -1;
5004
5005 #ifdef XP_DEFAULT_CACHE_ON
5006 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
5007 xmlXPathFreeContext(ret);
5008 return(NULL);
5009 }
5010 #endif
5011
5012 xmlXPathRegisterAllFunctions(ret);
5013
5014 if (ret->lastError.code != XML_ERR_OK) {
5015 xmlXPathFreeContext(ret);
5016 return(NULL);
5017 }
5018
5019 return(ret);
5020 }
5021
5022 /**
5023 * xmlXPathFreeContext:
5024 * @ctxt: the context to free
5025 *
5026 * Free up an xmlXPathContext
5027 */
5028 void
xmlXPathFreeContext(xmlXPathContextPtr ctxt)5029 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
5030 if (ctxt == NULL) return;
5031
5032 if (ctxt->cache != NULL)
5033 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
5034 xmlXPathRegisteredNsCleanup(ctxt);
5035 xmlXPathRegisteredFuncsCleanup(ctxt);
5036 xmlXPathRegisteredVariablesCleanup(ctxt);
5037 xmlResetError(&ctxt->lastError);
5038 xmlFree(ctxt);
5039 }
5040
5041 /**
5042 * xmlXPathSetErrorHandler:
5043 * @ctxt: the XPath context
5044 * @handler: error handler
5045 * @data: user data which will be passed to the handler
5046 *
5047 * Register a callback function that will be called on errors and
5048 * warnings. If handler is NULL, the error handler will be deactivated.
5049 *
5050 * Available since 2.13.0.
5051 */
5052 void
xmlXPathSetErrorHandler(xmlXPathContextPtr ctxt,xmlStructuredErrorFunc handler,void * data)5053 xmlXPathSetErrorHandler(xmlXPathContextPtr ctxt,
5054 xmlStructuredErrorFunc handler, void *data) {
5055 if (ctxt == NULL)
5056 return;
5057
5058 ctxt->error = handler;
5059 ctxt->userData = data;
5060 }
5061
5062 /************************************************************************
5063 * *
5064 * Routines to handle XPath parser contexts *
5065 * *
5066 ************************************************************************/
5067
5068 /**
5069 * xmlXPathNewParserContext:
5070 * @str: the XPath expression
5071 * @ctxt: the XPath context
5072 *
5073 * Create a new xmlXPathParserContext
5074 *
5075 * Returns the xmlXPathParserContext just allocated.
5076 */
5077 xmlXPathParserContextPtr
xmlXPathNewParserContext(const xmlChar * str,xmlXPathContextPtr ctxt)5078 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
5079 xmlXPathParserContextPtr ret;
5080
5081 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5082 if (ret == NULL) {
5083 xmlXPathErrMemory(ctxt);
5084 return(NULL);
5085 }
5086 memset(ret, 0 , sizeof(xmlXPathParserContext));
5087 ret->cur = ret->base = str;
5088 ret->context = ctxt;
5089
5090 ret->comp = xmlXPathNewCompExpr();
5091 if (ret->comp == NULL) {
5092 xmlXPathErrMemory(ctxt);
5093 xmlFree(ret->valueTab);
5094 xmlFree(ret);
5095 return(NULL);
5096 }
5097 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
5098 ret->comp->dict = ctxt->dict;
5099 xmlDictReference(ret->comp->dict);
5100 }
5101
5102 return(ret);
5103 }
5104
5105 /**
5106 * xmlXPathCompParserContext:
5107 * @comp: the XPath compiled expression
5108 * @ctxt: the XPath context
5109 *
5110 * Create a new xmlXPathParserContext when processing a compiled expression
5111 *
5112 * Returns the xmlXPathParserContext just allocated.
5113 */
5114 static xmlXPathParserContextPtr
xmlXPathCompParserContext(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)5115 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
5116 xmlXPathParserContextPtr ret;
5117
5118 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5119 if (ret == NULL) {
5120 xmlXPathErrMemory(ctxt);
5121 return(NULL);
5122 }
5123 memset(ret, 0 , sizeof(xmlXPathParserContext));
5124
5125 /* Allocate the value stack */
5126 ret->valueTab = (xmlXPathObjectPtr *)
5127 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
5128 if (ret->valueTab == NULL) {
5129 xmlFree(ret);
5130 xmlXPathErrMemory(ctxt);
5131 return(NULL);
5132 }
5133 ret->valueNr = 0;
5134 ret->valueMax = 10;
5135 ret->value = NULL;
5136
5137 ret->context = ctxt;
5138 ret->comp = comp;
5139
5140 return(ret);
5141 }
5142
5143 /**
5144 * xmlXPathFreeParserContext:
5145 * @ctxt: the context to free
5146 *
5147 * Free up an xmlXPathParserContext
5148 */
5149 void
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt)5150 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
5151 int i;
5152
5153 if (ctxt->valueTab != NULL) {
5154 for (i = 0; i < ctxt->valueNr; i++) {
5155 if (ctxt->context)
5156 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
5157 else
5158 xmlXPathFreeObject(ctxt->valueTab[i]);
5159 }
5160 xmlFree(ctxt->valueTab);
5161 }
5162 if (ctxt->comp != NULL) {
5163 #ifdef XPATH_STREAMING
5164 if (ctxt->comp->stream != NULL) {
5165 xmlFreePatternList(ctxt->comp->stream);
5166 ctxt->comp->stream = NULL;
5167 }
5168 #endif
5169 xmlXPathFreeCompExpr(ctxt->comp);
5170 }
5171 xmlFree(ctxt);
5172 }
5173
5174 /************************************************************************
5175 * *
5176 * The implicit core function library *
5177 * *
5178 ************************************************************************/
5179
5180 /**
5181 * xmlXPathNodeValHash:
5182 * @node: a node pointer
5183 *
5184 * Function computing the beginning of the string value of the node,
5185 * used to speed up comparisons
5186 *
5187 * Returns an int usable as a hash
5188 */
5189 static unsigned int
xmlXPathNodeValHash(xmlNodePtr node)5190 xmlXPathNodeValHash(xmlNodePtr node) {
5191 int len = 2;
5192 const xmlChar * string = NULL;
5193 xmlNodePtr tmp = NULL;
5194 unsigned int ret = 0;
5195
5196 if (node == NULL)
5197 return(0);
5198
5199 if (node->type == XML_DOCUMENT_NODE) {
5200 tmp = xmlDocGetRootElement((xmlDocPtr) node);
5201 if (tmp == NULL)
5202 node = node->children;
5203 else
5204 node = tmp;
5205
5206 if (node == NULL)
5207 return(0);
5208 }
5209
5210 switch (node->type) {
5211 case XML_COMMENT_NODE:
5212 case XML_PI_NODE:
5213 case XML_CDATA_SECTION_NODE:
5214 case XML_TEXT_NODE:
5215 string = node->content;
5216 if (string == NULL)
5217 return(0);
5218 if (string[0] == 0)
5219 return(0);
5220 return(string[0] + (string[1] << 8));
5221 case XML_NAMESPACE_DECL:
5222 string = ((xmlNsPtr)node)->href;
5223 if (string == NULL)
5224 return(0);
5225 if (string[0] == 0)
5226 return(0);
5227 return(string[0] + (string[1] << 8));
5228 case XML_ATTRIBUTE_NODE:
5229 tmp = ((xmlAttrPtr) node)->children;
5230 break;
5231 case XML_ELEMENT_NODE:
5232 tmp = node->children;
5233 break;
5234 default:
5235 return(0);
5236 }
5237 while (tmp != NULL) {
5238 switch (tmp->type) {
5239 case XML_CDATA_SECTION_NODE:
5240 case XML_TEXT_NODE:
5241 string = tmp->content;
5242 break;
5243 default:
5244 string = NULL;
5245 break;
5246 }
5247 if ((string != NULL) && (string[0] != 0)) {
5248 if (len == 1) {
5249 return(ret + (string[0] << 8));
5250 }
5251 if (string[1] == 0) {
5252 len = 1;
5253 ret = string[0];
5254 } else {
5255 return(string[0] + (string[1] << 8));
5256 }
5257 }
5258 /*
5259 * Skip to next node
5260 */
5261 if ((tmp->children != NULL) &&
5262 (tmp->type != XML_DTD_NODE) &&
5263 (tmp->type != XML_ENTITY_REF_NODE) &&
5264 (tmp->children->type != XML_ENTITY_DECL)) {
5265 tmp = tmp->children;
5266 continue;
5267 }
5268 if (tmp == node)
5269 break;
5270
5271 if (tmp->next != NULL) {
5272 tmp = tmp->next;
5273 continue;
5274 }
5275
5276 do {
5277 tmp = tmp->parent;
5278 if (tmp == NULL)
5279 break;
5280 if (tmp == node) {
5281 tmp = NULL;
5282 break;
5283 }
5284 if (tmp->next != NULL) {
5285 tmp = tmp->next;
5286 break;
5287 }
5288 } while (tmp != NULL);
5289 }
5290 return(ret);
5291 }
5292
5293 /**
5294 * xmlXPathStringHash:
5295 * @string: a string
5296 *
5297 * Function computing the beginning of the string value of the node,
5298 * used to speed up comparisons
5299 *
5300 * Returns an int usable as a hash
5301 */
5302 static unsigned int
xmlXPathStringHash(const xmlChar * string)5303 xmlXPathStringHash(const xmlChar * string) {
5304 if (string == NULL)
5305 return(0);
5306 if (string[0] == 0)
5307 return(0);
5308 return(string[0] + (string[1] << 8));
5309 }
5310
5311 /**
5312 * xmlXPathCompareNodeSetFloat:
5313 * @ctxt: the XPath Parser context
5314 * @inf: less than (1) or greater than (0)
5315 * @strict: is the comparison strict
5316 * @arg: the node set
5317 * @f: the value
5318 *
5319 * Implement the compare operation between a nodeset and a number
5320 * @ns < @val (1, 1, ...
5321 * @ns <= @val (1, 0, ...
5322 * @ns > @val (0, 1, ...
5323 * @ns >= @val (0, 0, ...
5324 *
5325 * If one object to be compared is a node-set and the other is a number,
5326 * then the comparison will be true if and only if there is a node in the
5327 * node-set such that the result of performing the comparison on the number
5328 * to be compared and on the result of converting the string-value of that
5329 * node to a number using the number function is true.
5330 *
5331 * Returns 0 or 1 depending on the results of the test.
5332 */
5333 static int
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr f)5334 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
5335 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5336 int i, ret = 0;
5337 xmlNodeSetPtr ns;
5338 xmlChar *str2;
5339
5340 if ((f == NULL) || (arg == NULL) ||
5341 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5342 xmlXPathReleaseObject(ctxt->context, arg);
5343 xmlXPathReleaseObject(ctxt->context, f);
5344 return(0);
5345 }
5346 ns = arg->nodesetval;
5347 if (ns != NULL) {
5348 for (i = 0;i < ns->nodeNr;i++) {
5349 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5350 if (str2 != NULL) {
5351 valuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5352 xmlFree(str2);
5353 xmlXPathNumberFunction(ctxt, 1);
5354 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, f));
5355 ret = xmlXPathCompareValues(ctxt, inf, strict);
5356 if (ret)
5357 break;
5358 } else {
5359 xmlXPathPErrMemory(ctxt);
5360 }
5361 }
5362 }
5363 xmlXPathReleaseObject(ctxt->context, arg);
5364 xmlXPathReleaseObject(ctxt->context, f);
5365 return(ret);
5366 }
5367
5368 /**
5369 * xmlXPathCompareNodeSetString:
5370 * @ctxt: the XPath Parser context
5371 * @inf: less than (1) or greater than (0)
5372 * @strict: is the comparison strict
5373 * @arg: the node set
5374 * @s: the value
5375 *
5376 * Implement the compare operation between a nodeset and a string
5377 * @ns < @val (1, 1, ...
5378 * @ns <= @val (1, 0, ...
5379 * @ns > @val (0, 1, ...
5380 * @ns >= @val (0, 0, ...
5381 *
5382 * If one object to be compared is a node-set and the other is a string,
5383 * then the comparison will be true if and only if there is a node in
5384 * the node-set such that the result of performing the comparison on the
5385 * string-value of the node and the other string is true.
5386 *
5387 * Returns 0 or 1 depending on the results of the test.
5388 */
5389 static int
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr s)5390 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
5391 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5392 int i, ret = 0;
5393 xmlNodeSetPtr ns;
5394 xmlChar *str2;
5395
5396 if ((s == NULL) || (arg == NULL) ||
5397 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5398 xmlXPathReleaseObject(ctxt->context, arg);
5399 xmlXPathReleaseObject(ctxt->context, s);
5400 return(0);
5401 }
5402 ns = arg->nodesetval;
5403 if (ns != NULL) {
5404 for (i = 0;i < ns->nodeNr;i++) {
5405 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5406 if (str2 != NULL) {
5407 valuePush(ctxt,
5408 xmlXPathCacheNewString(ctxt, str2));
5409 xmlFree(str2);
5410 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, s));
5411 ret = xmlXPathCompareValues(ctxt, inf, strict);
5412 if (ret)
5413 break;
5414 } else {
5415 xmlXPathPErrMemory(ctxt);
5416 }
5417 }
5418 }
5419 xmlXPathReleaseObject(ctxt->context, arg);
5420 xmlXPathReleaseObject(ctxt->context, s);
5421 return(ret);
5422 }
5423
5424 /**
5425 * xmlXPathCompareNodeSets:
5426 * @inf: less than (1) or greater than (0)
5427 * @strict: is the comparison strict
5428 * @arg1: the first node set object
5429 * @arg2: the second node set object
5430 *
5431 * Implement the compare operation on nodesets:
5432 *
5433 * If both objects to be compared are node-sets, then the comparison
5434 * will be true if and only if there is a node in the first node-set
5435 * and a node in the second node-set such that the result of performing
5436 * the comparison on the string-values of the two nodes is true.
5437 * ....
5438 * When neither object to be compared is a node-set and the operator
5439 * is <=, <, >= or >, then the objects are compared by converting both
5440 * objects to numbers and comparing the numbers according to IEEE 754.
5441 * ....
5442 * The number function converts its argument to a number as follows:
5443 * - a string that consists of optional whitespace followed by an
5444 * optional minus sign followed by a Number followed by whitespace
5445 * is converted to the IEEE 754 number that is nearest (according
5446 * to the IEEE 754 round-to-nearest rule) to the mathematical value
5447 * represented by the string; any other string is converted to NaN
5448 *
5449 * Conclusion all nodes need to be converted first to their string value
5450 * and then the comparison must be done when possible
5451 */
5452 static int
xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)5453 xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt, int inf, int strict,
5454 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5455 int i, j, init = 0;
5456 double val1;
5457 double *values2;
5458 int ret = 0;
5459 xmlNodeSetPtr ns1;
5460 xmlNodeSetPtr ns2;
5461
5462 if ((arg1 == NULL) ||
5463 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5464 xmlXPathFreeObject(arg2);
5465 return(0);
5466 }
5467 if ((arg2 == NULL) ||
5468 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
5469 xmlXPathFreeObject(arg1);
5470 xmlXPathFreeObject(arg2);
5471 return(0);
5472 }
5473
5474 ns1 = arg1->nodesetval;
5475 ns2 = arg2->nodesetval;
5476
5477 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5478 xmlXPathFreeObject(arg1);
5479 xmlXPathFreeObject(arg2);
5480 return(0);
5481 }
5482 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5483 xmlXPathFreeObject(arg1);
5484 xmlXPathFreeObject(arg2);
5485 return(0);
5486 }
5487
5488 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5489 if (values2 == NULL) {
5490 xmlXPathPErrMemory(ctxt);
5491 xmlXPathFreeObject(arg1);
5492 xmlXPathFreeObject(arg2);
5493 return(0);
5494 }
5495 for (i = 0;i < ns1->nodeNr;i++) {
5496 val1 = xmlXPathNodeToNumberInternal(ctxt, ns1->nodeTab[i]);
5497 if (xmlXPathIsNaN(val1))
5498 continue;
5499 for (j = 0;j < ns2->nodeNr;j++) {
5500 if (init == 0) {
5501 values2[j] = xmlXPathNodeToNumberInternal(ctxt,
5502 ns2->nodeTab[j]);
5503 }
5504 if (xmlXPathIsNaN(values2[j]))
5505 continue;
5506 if (inf && strict)
5507 ret = (val1 < values2[j]);
5508 else if (inf && !strict)
5509 ret = (val1 <= values2[j]);
5510 else if (!inf && strict)
5511 ret = (val1 > values2[j]);
5512 else if (!inf && !strict)
5513 ret = (val1 >= values2[j]);
5514 if (ret)
5515 break;
5516 }
5517 if (ret)
5518 break;
5519 init = 1;
5520 }
5521 xmlFree(values2);
5522 xmlXPathFreeObject(arg1);
5523 xmlXPathFreeObject(arg2);
5524 return(ret);
5525 }
5526
5527 /**
5528 * xmlXPathCompareNodeSetValue:
5529 * @ctxt: the XPath Parser context
5530 * @inf: less than (1) or greater than (0)
5531 * @strict: is the comparison strict
5532 * @arg: the node set
5533 * @val: the value
5534 *
5535 * Implement the compare operation between a nodeset and a value
5536 * @ns < @val (1, 1, ...
5537 * @ns <= @val (1, 0, ...
5538 * @ns > @val (0, 1, ...
5539 * @ns >= @val (0, 0, ...
5540 *
5541 * If one object to be compared is a node-set and the other is a boolean,
5542 * then the comparison will be true if and only if the result of performing
5543 * the comparison on the boolean and on the result of converting
5544 * the node-set to a boolean using the boolean function is true.
5545 *
5546 * Returns 0 or 1 depending on the results of the test.
5547 */
5548 static int
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr val)5549 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
5550 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
5551 if ((val == NULL) || (arg == NULL) ||
5552 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5553 return(0);
5554
5555 switch(val->type) {
5556 case XPATH_NUMBER:
5557 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
5558 case XPATH_NODESET:
5559 case XPATH_XSLT_TREE:
5560 return(xmlXPathCompareNodeSets(ctxt, inf, strict, arg, val));
5561 case XPATH_STRING:
5562 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
5563 case XPATH_BOOLEAN:
5564 valuePush(ctxt, arg);
5565 xmlXPathBooleanFunction(ctxt, 1);
5566 valuePush(ctxt, val);
5567 return(xmlXPathCompareValues(ctxt, inf, strict));
5568 default:
5569 xmlXPathReleaseObject(ctxt->context, arg);
5570 xmlXPathReleaseObject(ctxt->context, val);
5571 XP_ERROR0(XPATH_INVALID_TYPE);
5572 }
5573 return(0);
5574 }
5575
5576 /**
5577 * xmlXPathEqualNodeSetString:
5578 * @arg: the nodeset object argument
5579 * @str: the string to compare to.
5580 * @neq: flag to show whether for '=' (0) or '!=' (1)
5581 *
5582 * Implement the equal operation on XPath objects content: @arg1 == @arg2
5583 * If one object to be compared is a node-set and the other is a string,
5584 * then the comparison will be true if and only if there is a node in
5585 * the node-set such that the result of performing the comparison on the
5586 * string-value of the node and the other string is true.
5587 *
5588 * Returns 0 or 1 depending on the results of the test.
5589 */
5590 static int
xmlXPathEqualNodeSetString(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,const xmlChar * str,int neq)5591 xmlXPathEqualNodeSetString(xmlXPathParserContextPtr ctxt,
5592 xmlXPathObjectPtr arg, const xmlChar * str, int neq)
5593 {
5594 int i;
5595 xmlNodeSetPtr ns;
5596 xmlChar *str2;
5597 unsigned int hash;
5598
5599 if ((str == NULL) || (arg == NULL) ||
5600 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5601 return (0);
5602 ns = arg->nodesetval;
5603 /*
5604 * A NULL nodeset compared with a string is always false
5605 * (since there is no node equal, and no node not equal)
5606 */
5607 if ((ns == NULL) || (ns->nodeNr <= 0) )
5608 return (0);
5609 hash = xmlXPathStringHash(str);
5610 for (i = 0; i < ns->nodeNr; i++) {
5611 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
5612 str2 = xmlNodeGetContent(ns->nodeTab[i]);
5613 if (str2 == NULL) {
5614 xmlXPathPErrMemory(ctxt);
5615 return(0);
5616 }
5617 if (xmlStrEqual(str, str2)) {
5618 xmlFree(str2);
5619 if (neq)
5620 continue;
5621 return (1);
5622 } else if (neq) {
5623 xmlFree(str2);
5624 return (1);
5625 }
5626 xmlFree(str2);
5627 } else if (neq)
5628 return (1);
5629 }
5630 return (0);
5631 }
5632
5633 /**
5634 * xmlXPathEqualNodeSetFloat:
5635 * @arg: the nodeset object argument
5636 * @f: the float to compare to
5637 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
5638 *
5639 * Implement the equal operation on XPath objects content: @arg1 == @arg2
5640 * If one object to be compared is a node-set and the other is a number,
5641 * then the comparison will be true if and only if there is a node in
5642 * the node-set such that the result of performing the comparison on the
5643 * number to be compared and on the result of converting the string-value
5644 * of that node to a number using the number function is true.
5645 *
5646 * Returns 0 or 1 depending on the results of the test.
5647 */
5648 static int
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,double f,int neq)5649 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
5650 xmlXPathObjectPtr arg, double f, int neq) {
5651 int i, ret=0;
5652 xmlNodeSetPtr ns;
5653 xmlChar *str2;
5654 xmlXPathObjectPtr val;
5655 double v;
5656
5657 if ((arg == NULL) ||
5658 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5659 return(0);
5660
5661 ns = arg->nodesetval;
5662 if (ns != NULL) {
5663 for (i=0;i<ns->nodeNr;i++) {
5664 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5665 if (str2 != NULL) {
5666 valuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5667 xmlFree(str2);
5668 xmlXPathNumberFunction(ctxt, 1);
5669 CHECK_ERROR0;
5670 val = valuePop(ctxt);
5671 v = val->floatval;
5672 xmlXPathReleaseObject(ctxt->context, val);
5673 if (!xmlXPathIsNaN(v)) {
5674 if ((!neq) && (v==f)) {
5675 ret = 1;
5676 break;
5677 } else if ((neq) && (v!=f)) {
5678 ret = 1;
5679 break;
5680 }
5681 } else { /* NaN is unequal to any value */
5682 if (neq)
5683 ret = 1;
5684 }
5685 } else {
5686 xmlXPathPErrMemory(ctxt);
5687 }
5688 }
5689 }
5690
5691 return(ret);
5692 }
5693
5694
5695 /**
5696 * xmlXPathEqualNodeSets:
5697 * @arg1: first nodeset object argument
5698 * @arg2: second nodeset object argument
5699 * @neq: flag to show whether to test '=' (0) or '!=' (1)
5700 *
5701 * Implement the equal / not equal operation on XPath nodesets:
5702 * @arg1 == @arg2 or @arg1 != @arg2
5703 * If both objects to be compared are node-sets, then the comparison
5704 * will be true if and only if there is a node in the first node-set and
5705 * a node in the second node-set such that the result of performing the
5706 * comparison on the string-values of the two nodes is true.
5707 *
5708 * (needless to say, this is a costly operation)
5709 *
5710 * Returns 0 or 1 depending on the results of the test.
5711 */
5712 static int
xmlXPathEqualNodeSets(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2,int neq)5713 xmlXPathEqualNodeSets(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr arg1,
5714 xmlXPathObjectPtr arg2, int neq) {
5715 int i, j;
5716 unsigned int *hashs1;
5717 unsigned int *hashs2;
5718 xmlChar **values1;
5719 xmlChar **values2;
5720 int ret = 0;
5721 xmlNodeSetPtr ns1;
5722 xmlNodeSetPtr ns2;
5723
5724 if ((arg1 == NULL) ||
5725 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
5726 return(0);
5727 if ((arg2 == NULL) ||
5728 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
5729 return(0);
5730
5731 ns1 = arg1->nodesetval;
5732 ns2 = arg2->nodesetval;
5733
5734 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
5735 return(0);
5736 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
5737 return(0);
5738
5739 /*
5740 * for equal, check if there is a node pertaining to both sets
5741 */
5742 if (neq == 0)
5743 for (i = 0;i < ns1->nodeNr;i++)
5744 for (j = 0;j < ns2->nodeNr;j++)
5745 if (ns1->nodeTab[i] == ns2->nodeTab[j])
5746 return(1);
5747
5748 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
5749 if (values1 == NULL) {
5750 xmlXPathPErrMemory(ctxt);
5751 return(0);
5752 }
5753 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
5754 if (hashs1 == NULL) {
5755 xmlXPathPErrMemory(ctxt);
5756 xmlFree(values1);
5757 return(0);
5758 }
5759 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
5760 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
5761 if (values2 == NULL) {
5762 xmlXPathPErrMemory(ctxt);
5763 xmlFree(hashs1);
5764 xmlFree(values1);
5765 return(0);
5766 }
5767 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
5768 if (hashs2 == NULL) {
5769 xmlXPathPErrMemory(ctxt);
5770 xmlFree(hashs1);
5771 xmlFree(values1);
5772 xmlFree(values2);
5773 return(0);
5774 }
5775 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
5776 for (i = 0;i < ns1->nodeNr;i++) {
5777 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
5778 for (j = 0;j < ns2->nodeNr;j++) {
5779 if (i == 0)
5780 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
5781 if (hashs1[i] != hashs2[j]) {
5782 if (neq) {
5783 ret = 1;
5784 break;
5785 }
5786 }
5787 else {
5788 if (values1[i] == NULL) {
5789 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
5790 if (values1[i] == NULL)
5791 xmlXPathPErrMemory(ctxt);
5792 }
5793 if (values2[j] == NULL) {
5794 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
5795 if (values2[j] == NULL)
5796 xmlXPathPErrMemory(ctxt);
5797 }
5798 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
5799 if (ret)
5800 break;
5801 }
5802 }
5803 if (ret)
5804 break;
5805 }
5806 for (i = 0;i < ns1->nodeNr;i++)
5807 if (values1[i] != NULL)
5808 xmlFree(values1[i]);
5809 for (j = 0;j < ns2->nodeNr;j++)
5810 if (values2[j] != NULL)
5811 xmlFree(values2[j]);
5812 xmlFree(values1);
5813 xmlFree(values2);
5814 xmlFree(hashs1);
5815 xmlFree(hashs2);
5816 return(ret);
5817 }
5818
5819 static int
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)5820 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
5821 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5822 int ret = 0;
5823 /*
5824 *At this point we are assured neither arg1 nor arg2
5825 *is a nodeset, so we can just pick the appropriate routine.
5826 */
5827 switch (arg1->type) {
5828 case XPATH_UNDEFINED:
5829 break;
5830 case XPATH_BOOLEAN:
5831 switch (arg2->type) {
5832 case XPATH_UNDEFINED:
5833 break;
5834 case XPATH_BOOLEAN:
5835 ret = (arg1->boolval == arg2->boolval);
5836 break;
5837 case XPATH_NUMBER:
5838 ret = (arg1->boolval ==
5839 xmlXPathCastNumberToBoolean(arg2->floatval));
5840 break;
5841 case XPATH_STRING:
5842 if ((arg2->stringval == NULL) ||
5843 (arg2->stringval[0] == 0)) ret = 0;
5844 else
5845 ret = 1;
5846 ret = (arg1->boolval == ret);
5847 break;
5848 case XPATH_USERS:
5849 /* TODO */
5850 break;
5851 case XPATH_NODESET:
5852 case XPATH_XSLT_TREE:
5853 break;
5854 }
5855 break;
5856 case XPATH_NUMBER:
5857 switch (arg2->type) {
5858 case XPATH_UNDEFINED:
5859 break;
5860 case XPATH_BOOLEAN:
5861 ret = (arg2->boolval==
5862 xmlXPathCastNumberToBoolean(arg1->floatval));
5863 break;
5864 case XPATH_STRING:
5865 valuePush(ctxt, arg2);
5866 xmlXPathNumberFunction(ctxt, 1);
5867 arg2 = valuePop(ctxt);
5868 if (ctxt->error)
5869 break;
5870 /* Falls through. */
5871 case XPATH_NUMBER:
5872 /* Hand check NaN and Infinity equalities */
5873 if (xmlXPathIsNaN(arg1->floatval) ||
5874 xmlXPathIsNaN(arg2->floatval)) {
5875 ret = 0;
5876 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5877 if (xmlXPathIsInf(arg2->floatval) == 1)
5878 ret = 1;
5879 else
5880 ret = 0;
5881 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5882 if (xmlXPathIsInf(arg2->floatval) == -1)
5883 ret = 1;
5884 else
5885 ret = 0;
5886 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5887 if (xmlXPathIsInf(arg1->floatval) == 1)
5888 ret = 1;
5889 else
5890 ret = 0;
5891 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5892 if (xmlXPathIsInf(arg1->floatval) == -1)
5893 ret = 1;
5894 else
5895 ret = 0;
5896 } else {
5897 ret = (arg1->floatval == arg2->floatval);
5898 }
5899 break;
5900 case XPATH_USERS:
5901 /* TODO */
5902 break;
5903 case XPATH_NODESET:
5904 case XPATH_XSLT_TREE:
5905 break;
5906 }
5907 break;
5908 case XPATH_STRING:
5909 switch (arg2->type) {
5910 case XPATH_UNDEFINED:
5911 break;
5912 case XPATH_BOOLEAN:
5913 if ((arg1->stringval == NULL) ||
5914 (arg1->stringval[0] == 0)) ret = 0;
5915 else
5916 ret = 1;
5917 ret = (arg2->boolval == ret);
5918 break;
5919 case XPATH_STRING:
5920 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
5921 break;
5922 case XPATH_NUMBER:
5923 valuePush(ctxt, arg1);
5924 xmlXPathNumberFunction(ctxt, 1);
5925 arg1 = valuePop(ctxt);
5926 if (ctxt->error)
5927 break;
5928 /* Hand check NaN and Infinity equalities */
5929 if (xmlXPathIsNaN(arg1->floatval) ||
5930 xmlXPathIsNaN(arg2->floatval)) {
5931 ret = 0;
5932 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5933 if (xmlXPathIsInf(arg2->floatval) == 1)
5934 ret = 1;
5935 else
5936 ret = 0;
5937 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5938 if (xmlXPathIsInf(arg2->floatval) == -1)
5939 ret = 1;
5940 else
5941 ret = 0;
5942 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5943 if (xmlXPathIsInf(arg1->floatval) == 1)
5944 ret = 1;
5945 else
5946 ret = 0;
5947 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5948 if (xmlXPathIsInf(arg1->floatval) == -1)
5949 ret = 1;
5950 else
5951 ret = 0;
5952 } else {
5953 ret = (arg1->floatval == arg2->floatval);
5954 }
5955 break;
5956 case XPATH_USERS:
5957 /* TODO */
5958 break;
5959 case XPATH_NODESET:
5960 case XPATH_XSLT_TREE:
5961 break;
5962 }
5963 break;
5964 case XPATH_USERS:
5965 /* TODO */
5966 break;
5967 case XPATH_NODESET:
5968 case XPATH_XSLT_TREE:
5969 break;
5970 }
5971 xmlXPathReleaseObject(ctxt->context, arg1);
5972 xmlXPathReleaseObject(ctxt->context, arg2);
5973 return(ret);
5974 }
5975
5976 /**
5977 * xmlXPathEqualValues:
5978 * @ctxt: the XPath Parser context
5979 *
5980 * Implement the equal operation on XPath objects content: @arg1 == @arg2
5981 *
5982 * Returns 0 or 1 depending on the results of the test.
5983 */
5984 int
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt)5985 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
5986 xmlXPathObjectPtr arg1, arg2, argtmp;
5987 int ret = 0;
5988
5989 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5990 arg2 = valuePop(ctxt);
5991 arg1 = valuePop(ctxt);
5992 if ((arg1 == NULL) || (arg2 == NULL)) {
5993 if (arg1 != NULL)
5994 xmlXPathReleaseObject(ctxt->context, arg1);
5995 else
5996 xmlXPathReleaseObject(ctxt->context, arg2);
5997 XP_ERROR0(XPATH_INVALID_OPERAND);
5998 }
5999
6000 if (arg1 == arg2) {
6001 xmlXPathFreeObject(arg1);
6002 return(1);
6003 }
6004
6005 /*
6006 *If either argument is a nodeset, it's a 'special case'
6007 */
6008 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6009 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6010 /*
6011 *Hack it to assure arg1 is the nodeset
6012 */
6013 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6014 argtmp = arg2;
6015 arg2 = arg1;
6016 arg1 = argtmp;
6017 }
6018 switch (arg2->type) {
6019 case XPATH_UNDEFINED:
6020 break;
6021 case XPATH_NODESET:
6022 case XPATH_XSLT_TREE:
6023 ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 0);
6024 break;
6025 case XPATH_BOOLEAN:
6026 if ((arg1->nodesetval == NULL) ||
6027 (arg1->nodesetval->nodeNr == 0)) ret = 0;
6028 else
6029 ret = 1;
6030 ret = (ret == arg2->boolval);
6031 break;
6032 case XPATH_NUMBER:
6033 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
6034 break;
6035 case XPATH_STRING:
6036 ret = xmlXPathEqualNodeSetString(ctxt, arg1,
6037 arg2->stringval, 0);
6038 break;
6039 case XPATH_USERS:
6040 /* TODO */
6041 break;
6042 }
6043 xmlXPathReleaseObject(ctxt->context, arg1);
6044 xmlXPathReleaseObject(ctxt->context, arg2);
6045 return(ret);
6046 }
6047
6048 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6049 }
6050
6051 /**
6052 * xmlXPathNotEqualValues:
6053 * @ctxt: the XPath Parser context
6054 *
6055 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6056 *
6057 * Returns 0 or 1 depending on the results of the test.
6058 */
6059 int
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt)6060 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
6061 xmlXPathObjectPtr arg1, arg2, argtmp;
6062 int ret = 0;
6063
6064 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6065 arg2 = valuePop(ctxt);
6066 arg1 = valuePop(ctxt);
6067 if ((arg1 == NULL) || (arg2 == NULL)) {
6068 if (arg1 != NULL)
6069 xmlXPathReleaseObject(ctxt->context, arg1);
6070 else
6071 xmlXPathReleaseObject(ctxt->context, arg2);
6072 XP_ERROR0(XPATH_INVALID_OPERAND);
6073 }
6074
6075 if (arg1 == arg2) {
6076 xmlXPathReleaseObject(ctxt->context, arg1);
6077 return(0);
6078 }
6079
6080 /*
6081 *If either argument is a nodeset, it's a 'special case'
6082 */
6083 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6084 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6085 /*
6086 *Hack it to assure arg1 is the nodeset
6087 */
6088 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6089 argtmp = arg2;
6090 arg2 = arg1;
6091 arg1 = argtmp;
6092 }
6093 switch (arg2->type) {
6094 case XPATH_UNDEFINED:
6095 break;
6096 case XPATH_NODESET:
6097 case XPATH_XSLT_TREE:
6098 ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 1);
6099 break;
6100 case XPATH_BOOLEAN:
6101 if ((arg1->nodesetval == NULL) ||
6102 (arg1->nodesetval->nodeNr == 0)) ret = 0;
6103 else
6104 ret = 1;
6105 ret = (ret != arg2->boolval);
6106 break;
6107 case XPATH_NUMBER:
6108 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
6109 break;
6110 case XPATH_STRING:
6111 ret = xmlXPathEqualNodeSetString(ctxt, arg1,
6112 arg2->stringval, 1);
6113 break;
6114 case XPATH_USERS:
6115 /* TODO */
6116 break;
6117 }
6118 xmlXPathReleaseObject(ctxt->context, arg1);
6119 xmlXPathReleaseObject(ctxt->context, arg2);
6120 return(ret);
6121 }
6122
6123 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6124 }
6125
6126 /**
6127 * xmlXPathCompareValues:
6128 * @ctxt: the XPath Parser context
6129 * @inf: less than (1) or greater than (0)
6130 * @strict: is the comparison strict
6131 *
6132 * Implement the compare operation on XPath objects:
6133 * @arg1 < @arg2 (1, 1, ...
6134 * @arg1 <= @arg2 (1, 0, ...
6135 * @arg1 > @arg2 (0, 1, ...
6136 * @arg1 >= @arg2 (0, 0, ...
6137 *
6138 * When neither object to be compared is a node-set and the operator is
6139 * <=, <, >=, >, then the objects are compared by converted both objects
6140 * to numbers and comparing the numbers according to IEEE 754. The <
6141 * comparison will be true if and only if the first number is less than the
6142 * second number. The <= comparison will be true if and only if the first
6143 * number is less than or equal to the second number. The > comparison
6144 * will be true if and only if the first number is greater than the second
6145 * number. The >= comparison will be true if and only if the first number
6146 * is greater than or equal to the second number.
6147 *
6148 * Returns 1 if the comparison succeeded, 0 if it failed
6149 */
6150 int
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt,int inf,int strict)6151 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
6152 int ret = 0, arg1i = 0, arg2i = 0;
6153 xmlXPathObjectPtr arg1, arg2;
6154
6155 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6156 arg2 = valuePop(ctxt);
6157 arg1 = valuePop(ctxt);
6158 if ((arg1 == NULL) || (arg2 == NULL)) {
6159 if (arg1 != NULL)
6160 xmlXPathReleaseObject(ctxt->context, arg1);
6161 else
6162 xmlXPathReleaseObject(ctxt->context, arg2);
6163 XP_ERROR0(XPATH_INVALID_OPERAND);
6164 }
6165
6166 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6167 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6168 /*
6169 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
6170 * are not freed from within this routine; they will be freed from the
6171 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
6172 */
6173 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
6174 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
6175 ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
6176 } else {
6177 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6178 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
6179 arg1, arg2);
6180 } else {
6181 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
6182 arg2, arg1);
6183 }
6184 }
6185 return(ret);
6186 }
6187
6188 if (arg1->type != XPATH_NUMBER) {
6189 valuePush(ctxt, arg1);
6190 xmlXPathNumberFunction(ctxt, 1);
6191 arg1 = valuePop(ctxt);
6192 }
6193 if (arg2->type != XPATH_NUMBER) {
6194 valuePush(ctxt, arg2);
6195 xmlXPathNumberFunction(ctxt, 1);
6196 arg2 = valuePop(ctxt);
6197 }
6198 if (ctxt->error)
6199 goto error;
6200 /*
6201 * Add tests for infinity and nan
6202 * => feedback on 3.4 for Inf and NaN
6203 */
6204 /* Hand check NaN and Infinity comparisons */
6205 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
6206 ret=0;
6207 } else {
6208 arg1i=xmlXPathIsInf(arg1->floatval);
6209 arg2i=xmlXPathIsInf(arg2->floatval);
6210 if (inf && strict) {
6211 if ((arg1i == -1 && arg2i != -1) ||
6212 (arg2i == 1 && arg1i != 1)) {
6213 ret = 1;
6214 } else if (arg1i == 0 && arg2i == 0) {
6215 ret = (arg1->floatval < arg2->floatval);
6216 } else {
6217 ret = 0;
6218 }
6219 }
6220 else if (inf && !strict) {
6221 if (arg1i == -1 || arg2i == 1) {
6222 ret = 1;
6223 } else if (arg1i == 0 && arg2i == 0) {
6224 ret = (arg1->floatval <= arg2->floatval);
6225 } else {
6226 ret = 0;
6227 }
6228 }
6229 else if (!inf && strict) {
6230 if ((arg1i == 1 && arg2i != 1) ||
6231 (arg2i == -1 && arg1i != -1)) {
6232 ret = 1;
6233 } else if (arg1i == 0 && arg2i == 0) {
6234 ret = (arg1->floatval > arg2->floatval);
6235 } else {
6236 ret = 0;
6237 }
6238 }
6239 else if (!inf && !strict) {
6240 if (arg1i == 1 || arg2i == -1) {
6241 ret = 1;
6242 } else if (arg1i == 0 && arg2i == 0) {
6243 ret = (arg1->floatval >= arg2->floatval);
6244 } else {
6245 ret = 0;
6246 }
6247 }
6248 }
6249 error:
6250 xmlXPathReleaseObject(ctxt->context, arg1);
6251 xmlXPathReleaseObject(ctxt->context, arg2);
6252 return(ret);
6253 }
6254
6255 /**
6256 * xmlXPathValueFlipSign:
6257 * @ctxt: the XPath Parser context
6258 *
6259 * Implement the unary - operation on an XPath object
6260 * The numeric operators convert their operands to numbers as if
6261 * by calling the number function.
6262 */
6263 void
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt)6264 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
6265 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
6266 CAST_TO_NUMBER;
6267 CHECK_TYPE(XPATH_NUMBER);
6268 ctxt->value->floatval = -ctxt->value->floatval;
6269 }
6270
6271 /**
6272 * xmlXPathAddValues:
6273 * @ctxt: the XPath Parser context
6274 *
6275 * Implement the add operation on XPath objects:
6276 * The numeric operators convert their operands to numbers as if
6277 * by calling the number function.
6278 */
6279 void
xmlXPathAddValues(xmlXPathParserContextPtr ctxt)6280 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
6281 xmlXPathObjectPtr arg;
6282 double val;
6283
6284 arg = valuePop(ctxt);
6285 if (arg == NULL)
6286 XP_ERROR(XPATH_INVALID_OPERAND);
6287 val = xmlXPathCastToNumberInternal(ctxt, arg);
6288 xmlXPathReleaseObject(ctxt->context, arg);
6289 CAST_TO_NUMBER;
6290 CHECK_TYPE(XPATH_NUMBER);
6291 ctxt->value->floatval += val;
6292 }
6293
6294 /**
6295 * xmlXPathSubValues:
6296 * @ctxt: the XPath Parser context
6297 *
6298 * Implement the subtraction operation on XPath objects:
6299 * The numeric operators convert their operands to numbers as if
6300 * by calling the number function.
6301 */
6302 void
xmlXPathSubValues(xmlXPathParserContextPtr ctxt)6303 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
6304 xmlXPathObjectPtr arg;
6305 double val;
6306
6307 arg = valuePop(ctxt);
6308 if (arg == NULL)
6309 XP_ERROR(XPATH_INVALID_OPERAND);
6310 val = xmlXPathCastToNumberInternal(ctxt, arg);
6311 xmlXPathReleaseObject(ctxt->context, arg);
6312 CAST_TO_NUMBER;
6313 CHECK_TYPE(XPATH_NUMBER);
6314 ctxt->value->floatval -= val;
6315 }
6316
6317 /**
6318 * xmlXPathMultValues:
6319 * @ctxt: the XPath Parser context
6320 *
6321 * Implement the multiply operation on XPath objects:
6322 * The numeric operators convert their operands to numbers as if
6323 * by calling the number function.
6324 */
6325 void
xmlXPathMultValues(xmlXPathParserContextPtr ctxt)6326 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
6327 xmlXPathObjectPtr arg;
6328 double val;
6329
6330 arg = valuePop(ctxt);
6331 if (arg == NULL)
6332 XP_ERROR(XPATH_INVALID_OPERAND);
6333 val = xmlXPathCastToNumberInternal(ctxt, arg);
6334 xmlXPathReleaseObject(ctxt->context, arg);
6335 CAST_TO_NUMBER;
6336 CHECK_TYPE(XPATH_NUMBER);
6337 ctxt->value->floatval *= val;
6338 }
6339
6340 /**
6341 * xmlXPathDivValues:
6342 * @ctxt: the XPath Parser context
6343 *
6344 * Implement the div operation on XPath objects @arg1 / @arg2:
6345 * The numeric operators convert their operands to numbers as if
6346 * by calling the number function.
6347 */
6348 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
6349 void
xmlXPathDivValues(xmlXPathParserContextPtr ctxt)6350 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
6351 xmlXPathObjectPtr arg;
6352 double val;
6353
6354 arg = valuePop(ctxt);
6355 if (arg == NULL)
6356 XP_ERROR(XPATH_INVALID_OPERAND);
6357 val = xmlXPathCastToNumberInternal(ctxt, arg);
6358 xmlXPathReleaseObject(ctxt->context, arg);
6359 CAST_TO_NUMBER;
6360 CHECK_TYPE(XPATH_NUMBER);
6361 ctxt->value->floatval /= val;
6362 }
6363
6364 /**
6365 * xmlXPathModValues:
6366 * @ctxt: the XPath Parser context
6367 *
6368 * Implement the mod operation on XPath objects: @arg1 / @arg2
6369 * The numeric operators convert their operands to numbers as if
6370 * by calling the number function.
6371 */
6372 void
xmlXPathModValues(xmlXPathParserContextPtr ctxt)6373 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
6374 xmlXPathObjectPtr arg;
6375 double arg1, arg2;
6376
6377 arg = valuePop(ctxt);
6378 if (arg == NULL)
6379 XP_ERROR(XPATH_INVALID_OPERAND);
6380 arg2 = xmlXPathCastToNumberInternal(ctxt, arg);
6381 xmlXPathReleaseObject(ctxt->context, arg);
6382 CAST_TO_NUMBER;
6383 CHECK_TYPE(XPATH_NUMBER);
6384 arg1 = ctxt->value->floatval;
6385 if (arg2 == 0)
6386 ctxt->value->floatval = xmlXPathNAN;
6387 else {
6388 ctxt->value->floatval = fmod(arg1, arg2);
6389 }
6390 }
6391
6392 /************************************************************************
6393 * *
6394 * The traversal functions *
6395 * *
6396 ************************************************************************/
6397
6398 /*
6399 * A traversal function enumerates nodes along an axis.
6400 * Initially it must be called with NULL, and it indicates
6401 * termination on the axis by returning NULL.
6402 */
6403 typedef xmlNodePtr (*xmlXPathTraversalFunction)
6404 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
6405
6406 /*
6407 * xmlXPathTraversalFunctionExt:
6408 * A traversal function enumerates nodes along an axis.
6409 * Initially it must be called with NULL, and it indicates
6410 * termination on the axis by returning NULL.
6411 * The context node of the traversal is specified via @contextNode.
6412 */
6413 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
6414 (xmlNodePtr cur, xmlNodePtr contextNode);
6415
6416 /*
6417 * xmlXPathNodeSetMergeFunction:
6418 * Used for merging node sets in xmlXPathCollectAndTest().
6419 */
6420 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
6421 (xmlNodeSetPtr, xmlNodeSetPtr);
6422
6423
6424 /**
6425 * xmlXPathNextSelf:
6426 * @ctxt: the XPath Parser context
6427 * @cur: the current node in the traversal
6428 *
6429 * Traversal function for the "self" direction
6430 * The self axis contains just the context node itself
6431 *
6432 * Returns the next element following that axis
6433 */
6434 xmlNodePtr
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6435 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6436 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6437 if (cur == NULL)
6438 return(ctxt->context->node);
6439 return(NULL);
6440 }
6441
6442 /**
6443 * xmlXPathNextChild:
6444 * @ctxt: the XPath Parser context
6445 * @cur: the current node in the traversal
6446 *
6447 * Traversal function for the "child" direction
6448 * The child axis contains the children of the context node in document order.
6449 *
6450 * Returns the next element following that axis
6451 */
6452 xmlNodePtr
xmlXPathNextChild(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6453 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6454 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6455 if (cur == NULL) {
6456 if (ctxt->context->node == NULL) return(NULL);
6457 switch (ctxt->context->node->type) {
6458 case XML_ELEMENT_NODE:
6459 case XML_TEXT_NODE:
6460 case XML_CDATA_SECTION_NODE:
6461 case XML_ENTITY_REF_NODE:
6462 case XML_ENTITY_NODE:
6463 case XML_PI_NODE:
6464 case XML_COMMENT_NODE:
6465 case XML_NOTATION_NODE:
6466 case XML_DTD_NODE:
6467 return(ctxt->context->node->children);
6468 case XML_DOCUMENT_NODE:
6469 case XML_DOCUMENT_TYPE_NODE:
6470 case XML_DOCUMENT_FRAG_NODE:
6471 case XML_HTML_DOCUMENT_NODE:
6472 return(((xmlDocPtr) ctxt->context->node)->children);
6473 case XML_ELEMENT_DECL:
6474 case XML_ATTRIBUTE_DECL:
6475 case XML_ENTITY_DECL:
6476 case XML_ATTRIBUTE_NODE:
6477 case XML_NAMESPACE_DECL:
6478 case XML_XINCLUDE_START:
6479 case XML_XINCLUDE_END:
6480 return(NULL);
6481 }
6482 return(NULL);
6483 }
6484 if ((cur->type == XML_DOCUMENT_NODE) ||
6485 (cur->type == XML_HTML_DOCUMENT_NODE))
6486 return(NULL);
6487 return(cur->next);
6488 }
6489
6490 /**
6491 * xmlXPathNextChildElement:
6492 * @ctxt: the XPath Parser context
6493 * @cur: the current node in the traversal
6494 *
6495 * Traversal function for the "child" direction and nodes of type element.
6496 * The child axis contains the children of the context node in document order.
6497 *
6498 * Returns the next element following that axis
6499 */
6500 static xmlNodePtr
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6501 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6502 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6503 if (cur == NULL) {
6504 cur = ctxt->context->node;
6505 if (cur == NULL) return(NULL);
6506 /*
6507 * Get the first element child.
6508 */
6509 switch (cur->type) {
6510 case XML_ELEMENT_NODE:
6511 case XML_DOCUMENT_FRAG_NODE:
6512 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
6513 case XML_ENTITY_NODE:
6514 cur = cur->children;
6515 if (cur != NULL) {
6516 if (cur->type == XML_ELEMENT_NODE)
6517 return(cur);
6518 do {
6519 cur = cur->next;
6520 } while ((cur != NULL) &&
6521 (cur->type != XML_ELEMENT_NODE));
6522 return(cur);
6523 }
6524 return(NULL);
6525 case XML_DOCUMENT_NODE:
6526 case XML_HTML_DOCUMENT_NODE:
6527 return(xmlDocGetRootElement((xmlDocPtr) cur));
6528 default:
6529 return(NULL);
6530 }
6531 return(NULL);
6532 }
6533 /*
6534 * Get the next sibling element node.
6535 */
6536 switch (cur->type) {
6537 case XML_ELEMENT_NODE:
6538 case XML_TEXT_NODE:
6539 case XML_ENTITY_REF_NODE:
6540 case XML_ENTITY_NODE:
6541 case XML_CDATA_SECTION_NODE:
6542 case XML_PI_NODE:
6543 case XML_COMMENT_NODE:
6544 case XML_XINCLUDE_END:
6545 break;
6546 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
6547 default:
6548 return(NULL);
6549 }
6550 if (cur->next != NULL) {
6551 if (cur->next->type == XML_ELEMENT_NODE)
6552 return(cur->next);
6553 cur = cur->next;
6554 do {
6555 cur = cur->next;
6556 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
6557 return(cur);
6558 }
6559 return(NULL);
6560 }
6561
6562 #if 0
6563 /**
6564 * xmlXPathNextDescendantOrSelfElemParent:
6565 * @ctxt: the XPath Parser context
6566 * @cur: the current node in the traversal
6567 *
6568 * Traversal function for the "descendant-or-self" axis.
6569 * Additionally it returns only nodes which can be parents of
6570 * element nodes.
6571 *
6572 *
6573 * Returns the next element following that axis
6574 */
6575 static xmlNodePtr
6576 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
6577 xmlNodePtr contextNode)
6578 {
6579 if (cur == NULL) {
6580 if (contextNode == NULL)
6581 return(NULL);
6582 switch (contextNode->type) {
6583 case XML_ELEMENT_NODE:
6584 case XML_XINCLUDE_START:
6585 case XML_DOCUMENT_FRAG_NODE:
6586 case XML_DOCUMENT_NODE:
6587 case XML_HTML_DOCUMENT_NODE:
6588 return(contextNode);
6589 default:
6590 return(NULL);
6591 }
6592 return(NULL);
6593 } else {
6594 xmlNodePtr start = cur;
6595
6596 while (cur != NULL) {
6597 switch (cur->type) {
6598 case XML_ELEMENT_NODE:
6599 /* TODO: OK to have XInclude here? */
6600 case XML_XINCLUDE_START:
6601 case XML_DOCUMENT_FRAG_NODE:
6602 if (cur != start)
6603 return(cur);
6604 if (cur->children != NULL) {
6605 cur = cur->children;
6606 continue;
6607 }
6608 break;
6609 /* Not sure if we need those here. */
6610 case XML_DOCUMENT_NODE:
6611 case XML_HTML_DOCUMENT_NODE:
6612 if (cur != start)
6613 return(cur);
6614 return(xmlDocGetRootElement((xmlDocPtr) cur));
6615 default:
6616 break;
6617 }
6618
6619 next_sibling:
6620 if ((cur == NULL) || (cur == contextNode))
6621 return(NULL);
6622 if (cur->next != NULL) {
6623 cur = cur->next;
6624 } else {
6625 cur = cur->parent;
6626 goto next_sibling;
6627 }
6628 }
6629 }
6630 return(NULL);
6631 }
6632 #endif
6633
6634 /**
6635 * xmlXPathNextDescendant:
6636 * @ctxt: the XPath Parser context
6637 * @cur: the current node in the traversal
6638 *
6639 * Traversal function for the "descendant" direction
6640 * the descendant axis contains the descendants of the context node in document
6641 * order; a descendant is a child or a child of a child and so on.
6642 *
6643 * Returns the next element following that axis
6644 */
6645 xmlNodePtr
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6646 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6647 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6648 if (cur == NULL) {
6649 if (ctxt->context->node == NULL)
6650 return(NULL);
6651 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6652 (ctxt->context->node->type == XML_NAMESPACE_DECL))
6653 return(NULL);
6654
6655 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6656 return(ctxt->context->doc->children);
6657 return(ctxt->context->node->children);
6658 }
6659
6660 if (cur->type == XML_NAMESPACE_DECL)
6661 return(NULL);
6662 if (cur->children != NULL) {
6663 /*
6664 * Do not descend on entities declarations
6665 */
6666 if (cur->children->type != XML_ENTITY_DECL) {
6667 cur = cur->children;
6668 /*
6669 * Skip DTDs
6670 */
6671 if (cur->type != XML_DTD_NODE)
6672 return(cur);
6673 }
6674 }
6675
6676 if (cur == ctxt->context->node) return(NULL);
6677
6678 while (cur->next != NULL) {
6679 cur = cur->next;
6680 if ((cur->type != XML_ENTITY_DECL) &&
6681 (cur->type != XML_DTD_NODE))
6682 return(cur);
6683 }
6684
6685 do {
6686 cur = cur->parent;
6687 if (cur == NULL) break;
6688 if (cur == ctxt->context->node) return(NULL);
6689 if (cur->next != NULL) {
6690 cur = cur->next;
6691 return(cur);
6692 }
6693 } while (cur != NULL);
6694 return(cur);
6695 }
6696
6697 /**
6698 * xmlXPathNextDescendantOrSelf:
6699 * @ctxt: the XPath Parser context
6700 * @cur: the current node in the traversal
6701 *
6702 * Traversal function for the "descendant-or-self" direction
6703 * the descendant-or-self axis contains the context node and the descendants
6704 * of the context node in document order; thus the context node is the first
6705 * node on the axis, and the first child of the context node is the second node
6706 * on the axis
6707 *
6708 * Returns the next element following that axis
6709 */
6710 xmlNodePtr
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6711 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6712 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6713 if (cur == NULL)
6714 return(ctxt->context->node);
6715
6716 if (ctxt->context->node == NULL)
6717 return(NULL);
6718 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6719 (ctxt->context->node->type == XML_NAMESPACE_DECL))
6720 return(NULL);
6721
6722 return(xmlXPathNextDescendant(ctxt, cur));
6723 }
6724
6725 /**
6726 * xmlXPathNextParent:
6727 * @ctxt: the XPath Parser context
6728 * @cur: the current node in the traversal
6729 *
6730 * Traversal function for the "parent" direction
6731 * The parent axis contains the parent of the context node, if there is one.
6732 *
6733 * Returns the next element following that axis
6734 */
6735 xmlNodePtr
xmlXPathNextParent(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6736 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6737 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6738 /*
6739 * the parent of an attribute or namespace node is the element
6740 * to which the attribute or namespace node is attached
6741 * Namespace handling !!!
6742 */
6743 if (cur == NULL) {
6744 if (ctxt->context->node == NULL) return(NULL);
6745 switch (ctxt->context->node->type) {
6746 case XML_ELEMENT_NODE:
6747 case XML_TEXT_NODE:
6748 case XML_CDATA_SECTION_NODE:
6749 case XML_ENTITY_REF_NODE:
6750 case XML_ENTITY_NODE:
6751 case XML_PI_NODE:
6752 case XML_COMMENT_NODE:
6753 case XML_NOTATION_NODE:
6754 case XML_DTD_NODE:
6755 case XML_ELEMENT_DECL:
6756 case XML_ATTRIBUTE_DECL:
6757 case XML_XINCLUDE_START:
6758 case XML_XINCLUDE_END:
6759 case XML_ENTITY_DECL:
6760 if (ctxt->context->node->parent == NULL)
6761 return((xmlNodePtr) ctxt->context->doc);
6762 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6763 ((ctxt->context->node->parent->name[0] == ' ') ||
6764 (xmlStrEqual(ctxt->context->node->parent->name,
6765 BAD_CAST "fake node libxslt"))))
6766 return(NULL);
6767 return(ctxt->context->node->parent);
6768 case XML_ATTRIBUTE_NODE: {
6769 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
6770
6771 return(att->parent);
6772 }
6773 case XML_DOCUMENT_NODE:
6774 case XML_DOCUMENT_TYPE_NODE:
6775 case XML_DOCUMENT_FRAG_NODE:
6776 case XML_HTML_DOCUMENT_NODE:
6777 return(NULL);
6778 case XML_NAMESPACE_DECL: {
6779 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6780
6781 if ((ns->next != NULL) &&
6782 (ns->next->type != XML_NAMESPACE_DECL))
6783 return((xmlNodePtr) ns->next);
6784 return(NULL);
6785 }
6786 }
6787 }
6788 return(NULL);
6789 }
6790
6791 /**
6792 * xmlXPathNextAncestor:
6793 * @ctxt: the XPath Parser context
6794 * @cur: the current node in the traversal
6795 *
6796 * Traversal function for the "ancestor" direction
6797 * the ancestor axis contains the ancestors of the context node; the ancestors
6798 * of the context node consist of the parent of context node and the parent's
6799 * parent and so on; the nodes are ordered in reverse document order; thus the
6800 * parent is the first node on the axis, and the parent's parent is the second
6801 * node on the axis
6802 *
6803 * Returns the next element following that axis
6804 */
6805 xmlNodePtr
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6806 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6807 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6808 /*
6809 * the parent of an attribute or namespace node is the element
6810 * to which the attribute or namespace node is attached
6811 * !!!!!!!!!!!!!
6812 */
6813 if (cur == NULL) {
6814 if (ctxt->context->node == NULL) return(NULL);
6815 switch (ctxt->context->node->type) {
6816 case XML_ELEMENT_NODE:
6817 case XML_TEXT_NODE:
6818 case XML_CDATA_SECTION_NODE:
6819 case XML_ENTITY_REF_NODE:
6820 case XML_ENTITY_NODE:
6821 case XML_PI_NODE:
6822 case XML_COMMENT_NODE:
6823 case XML_DTD_NODE:
6824 case XML_ELEMENT_DECL:
6825 case XML_ATTRIBUTE_DECL:
6826 case XML_ENTITY_DECL:
6827 case XML_NOTATION_NODE:
6828 case XML_XINCLUDE_START:
6829 case XML_XINCLUDE_END:
6830 if (ctxt->context->node->parent == NULL)
6831 return((xmlNodePtr) ctxt->context->doc);
6832 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6833 ((ctxt->context->node->parent->name[0] == ' ') ||
6834 (xmlStrEqual(ctxt->context->node->parent->name,
6835 BAD_CAST "fake node libxslt"))))
6836 return(NULL);
6837 return(ctxt->context->node->parent);
6838 case XML_ATTRIBUTE_NODE: {
6839 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
6840
6841 return(tmp->parent);
6842 }
6843 case XML_DOCUMENT_NODE:
6844 case XML_DOCUMENT_TYPE_NODE:
6845 case XML_DOCUMENT_FRAG_NODE:
6846 case XML_HTML_DOCUMENT_NODE:
6847 return(NULL);
6848 case XML_NAMESPACE_DECL: {
6849 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6850
6851 if ((ns->next != NULL) &&
6852 (ns->next->type != XML_NAMESPACE_DECL))
6853 return((xmlNodePtr) ns->next);
6854 /* Bad, how did that namespace end up here ? */
6855 return(NULL);
6856 }
6857 }
6858 return(NULL);
6859 }
6860 if (cur == ctxt->context->doc->children)
6861 return((xmlNodePtr) ctxt->context->doc);
6862 if (cur == (xmlNodePtr) ctxt->context->doc)
6863 return(NULL);
6864 switch (cur->type) {
6865 case XML_ELEMENT_NODE:
6866 case XML_TEXT_NODE:
6867 case XML_CDATA_SECTION_NODE:
6868 case XML_ENTITY_REF_NODE:
6869 case XML_ENTITY_NODE:
6870 case XML_PI_NODE:
6871 case XML_COMMENT_NODE:
6872 case XML_NOTATION_NODE:
6873 case XML_DTD_NODE:
6874 case XML_ELEMENT_DECL:
6875 case XML_ATTRIBUTE_DECL:
6876 case XML_ENTITY_DECL:
6877 case XML_XINCLUDE_START:
6878 case XML_XINCLUDE_END:
6879 if (cur->parent == NULL)
6880 return(NULL);
6881 if ((cur->parent->type == XML_ELEMENT_NODE) &&
6882 ((cur->parent->name[0] == ' ') ||
6883 (xmlStrEqual(cur->parent->name,
6884 BAD_CAST "fake node libxslt"))))
6885 return(NULL);
6886 return(cur->parent);
6887 case XML_ATTRIBUTE_NODE: {
6888 xmlAttrPtr att = (xmlAttrPtr) cur;
6889
6890 return(att->parent);
6891 }
6892 case XML_NAMESPACE_DECL: {
6893 xmlNsPtr ns = (xmlNsPtr) cur;
6894
6895 if ((ns->next != NULL) &&
6896 (ns->next->type != XML_NAMESPACE_DECL))
6897 return((xmlNodePtr) ns->next);
6898 /* Bad, how did that namespace end up here ? */
6899 return(NULL);
6900 }
6901 case XML_DOCUMENT_NODE:
6902 case XML_DOCUMENT_TYPE_NODE:
6903 case XML_DOCUMENT_FRAG_NODE:
6904 case XML_HTML_DOCUMENT_NODE:
6905 return(NULL);
6906 }
6907 return(NULL);
6908 }
6909
6910 /**
6911 * xmlXPathNextAncestorOrSelf:
6912 * @ctxt: the XPath Parser context
6913 * @cur: the current node in the traversal
6914 *
6915 * Traversal function for the "ancestor-or-self" direction
6916 * he ancestor-or-self axis contains the context node and ancestors of
6917 * the context node in reverse document order; thus the context node is
6918 * the first node on the axis, and the context node's parent the second;
6919 * parent here is defined the same as with the parent axis.
6920 *
6921 * Returns the next element following that axis
6922 */
6923 xmlNodePtr
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6924 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6925 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6926 if (cur == NULL)
6927 return(ctxt->context->node);
6928 return(xmlXPathNextAncestor(ctxt, cur));
6929 }
6930
6931 /**
6932 * xmlXPathNextFollowingSibling:
6933 * @ctxt: the XPath Parser context
6934 * @cur: the current node in the traversal
6935 *
6936 * Traversal function for the "following-sibling" direction
6937 * The following-sibling axis contains the following siblings of the context
6938 * node in document order.
6939 *
6940 * Returns the next element following that axis
6941 */
6942 xmlNodePtr
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6943 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6944 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6945 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6946 (ctxt->context->node->type == XML_NAMESPACE_DECL))
6947 return(NULL);
6948 if (cur == (xmlNodePtr) ctxt->context->doc)
6949 return(NULL);
6950 if (cur == NULL)
6951 return(ctxt->context->node->next);
6952 return(cur->next);
6953 }
6954
6955 /**
6956 * xmlXPathNextPrecedingSibling:
6957 * @ctxt: the XPath Parser context
6958 * @cur: the current node in the traversal
6959 *
6960 * Traversal function for the "preceding-sibling" direction
6961 * The preceding-sibling axis contains the preceding siblings of the context
6962 * node in reverse document order; the first preceding sibling is first on the
6963 * axis; the sibling preceding that node is the second on the axis and so on.
6964 *
6965 * Returns the next element following that axis
6966 */
6967 xmlNodePtr
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6968 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6969 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6970 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6971 (ctxt->context->node->type == XML_NAMESPACE_DECL))
6972 return(NULL);
6973 if (cur == (xmlNodePtr) ctxt->context->doc)
6974 return(NULL);
6975 if (cur == NULL)
6976 return(ctxt->context->node->prev);
6977 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
6978 cur = cur->prev;
6979 if (cur == NULL)
6980 return(ctxt->context->node->prev);
6981 }
6982 return(cur->prev);
6983 }
6984
6985 /**
6986 * xmlXPathNextFollowing:
6987 * @ctxt: the XPath Parser context
6988 * @cur: the current node in the traversal
6989 *
6990 * Traversal function for the "following" direction
6991 * The following axis contains all nodes in the same document as the context
6992 * node that are after the context node in document order, excluding any
6993 * descendants and excluding attribute nodes and namespace nodes; the nodes
6994 * are ordered in document order
6995 *
6996 * Returns the next element following that axis
6997 */
6998 xmlNodePtr
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6999 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7000 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7001 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
7002 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
7003 return(cur->children);
7004
7005 if (cur == NULL) {
7006 cur = ctxt->context->node;
7007 if (cur->type == XML_ATTRIBUTE_NODE) {
7008 cur = cur->parent;
7009 } else if (cur->type == XML_NAMESPACE_DECL) {
7010 xmlNsPtr ns = (xmlNsPtr) cur;
7011
7012 if ((ns->next == NULL) ||
7013 (ns->next->type == XML_NAMESPACE_DECL))
7014 return (NULL);
7015 cur = (xmlNodePtr) ns->next;
7016 }
7017 }
7018 if (cur == NULL) return(NULL) ; /* ERROR */
7019 if (cur->next != NULL) return(cur->next) ;
7020 do {
7021 cur = cur->parent;
7022 if (cur == NULL) break;
7023 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
7024 if (cur->next != NULL) return(cur->next);
7025 } while (cur != NULL);
7026 return(cur);
7027 }
7028
7029 /*
7030 * xmlXPathIsAncestor:
7031 * @ancestor: the ancestor node
7032 * @node: the current node
7033 *
7034 * Check that @ancestor is a @node's ancestor
7035 *
7036 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
7037 */
7038 static int
xmlXPathIsAncestor(xmlNodePtr ancestor,xmlNodePtr node)7039 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
7040 if ((ancestor == NULL) || (node == NULL)) return(0);
7041 if (node->type == XML_NAMESPACE_DECL)
7042 return(0);
7043 if (ancestor->type == XML_NAMESPACE_DECL)
7044 return(0);
7045 /* nodes need to be in the same document */
7046 if (ancestor->doc != node->doc) return(0);
7047 /* avoid searching if ancestor or node is the root node */
7048 if (ancestor == (xmlNodePtr) node->doc) return(1);
7049 if (node == (xmlNodePtr) ancestor->doc) return(0);
7050 while (node->parent != NULL) {
7051 if (node->parent == ancestor)
7052 return(1);
7053 node = node->parent;
7054 }
7055 return(0);
7056 }
7057
7058 /**
7059 * xmlXPathNextPreceding:
7060 * @ctxt: the XPath Parser context
7061 * @cur: the current node in the traversal
7062 *
7063 * Traversal function for the "preceding" direction
7064 * the preceding axis contains all nodes in the same document as the context
7065 * node that are before the context node in document order, excluding any
7066 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7067 * ordered in reverse document order
7068 *
7069 * Returns the next element following that axis
7070 */
7071 xmlNodePtr
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7072 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
7073 {
7074 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7075 if (cur == NULL) {
7076 cur = ctxt->context->node;
7077 if (cur->type == XML_ATTRIBUTE_NODE) {
7078 cur = cur->parent;
7079 } else if (cur->type == XML_NAMESPACE_DECL) {
7080 xmlNsPtr ns = (xmlNsPtr) cur;
7081
7082 if ((ns->next == NULL) ||
7083 (ns->next->type == XML_NAMESPACE_DECL))
7084 return (NULL);
7085 cur = (xmlNodePtr) ns->next;
7086 }
7087 }
7088 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
7089 return (NULL);
7090 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7091 cur = cur->prev;
7092 do {
7093 if (cur->prev != NULL) {
7094 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
7095 return (cur);
7096 }
7097
7098 cur = cur->parent;
7099 if (cur == NULL)
7100 return (NULL);
7101 if (cur == ctxt->context->doc->children)
7102 return (NULL);
7103 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
7104 return (cur);
7105 }
7106
7107 /**
7108 * xmlXPathNextPrecedingInternal:
7109 * @ctxt: the XPath Parser context
7110 * @cur: the current node in the traversal
7111 *
7112 * Traversal function for the "preceding" direction
7113 * the preceding axis contains all nodes in the same document as the context
7114 * node that are before the context node in document order, excluding any
7115 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7116 * ordered in reverse document order
7117 * This is a faster implementation but internal only since it requires a
7118 * state kept in the parser context: ctxt->ancestor.
7119 *
7120 * Returns the next element following that axis
7121 */
7122 static xmlNodePtr
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7123 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
7124 xmlNodePtr cur)
7125 {
7126 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7127 if (cur == NULL) {
7128 cur = ctxt->context->node;
7129 if (cur == NULL)
7130 return (NULL);
7131 if (cur->type == XML_ATTRIBUTE_NODE) {
7132 cur = cur->parent;
7133 } else if (cur->type == XML_NAMESPACE_DECL) {
7134 xmlNsPtr ns = (xmlNsPtr) cur;
7135
7136 if ((ns->next == NULL) ||
7137 (ns->next->type == XML_NAMESPACE_DECL))
7138 return (NULL);
7139 cur = (xmlNodePtr) ns->next;
7140 }
7141 ctxt->ancestor = cur->parent;
7142 }
7143 if (cur->type == XML_NAMESPACE_DECL)
7144 return(NULL);
7145 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7146 cur = cur->prev;
7147 while (cur->prev == NULL) {
7148 cur = cur->parent;
7149 if (cur == NULL)
7150 return (NULL);
7151 if (cur == ctxt->context->doc->children)
7152 return (NULL);
7153 if (cur != ctxt->ancestor)
7154 return (cur);
7155 ctxt->ancestor = cur->parent;
7156 }
7157 cur = cur->prev;
7158 while (cur->last != NULL)
7159 cur = cur->last;
7160 return (cur);
7161 }
7162
7163 /**
7164 * xmlXPathNextNamespace:
7165 * @ctxt: the XPath Parser context
7166 * @cur: the current attribute in the traversal
7167 *
7168 * Traversal function for the "namespace" direction
7169 * the namespace axis contains the namespace nodes of the context node;
7170 * the order of nodes on this axis is implementation-defined; the axis will
7171 * be empty unless the context node is an element
7172 *
7173 * We keep the XML namespace node at the end of the list.
7174 *
7175 * Returns the next element following that axis
7176 */
7177 xmlNodePtr
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7178 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7179 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7180 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
7181 if (cur == NULL) {
7182 if (ctxt->context->tmpNsList != NULL)
7183 xmlFree(ctxt->context->tmpNsList);
7184 ctxt->context->tmpNsNr = 0;
7185 if (xmlGetNsListSafe(ctxt->context->doc, ctxt->context->node,
7186 &ctxt->context->tmpNsList) < 0) {
7187 xmlXPathPErrMemory(ctxt);
7188 return(NULL);
7189 }
7190 if (ctxt->context->tmpNsList != NULL) {
7191 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
7192 ctxt->context->tmpNsNr++;
7193 }
7194 }
7195 return((xmlNodePtr) xmlXPathXMLNamespace);
7196 }
7197 if (ctxt->context->tmpNsNr > 0) {
7198 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
7199 } else {
7200 if (ctxt->context->tmpNsList != NULL)
7201 xmlFree(ctxt->context->tmpNsList);
7202 ctxt->context->tmpNsList = NULL;
7203 return(NULL);
7204 }
7205 }
7206
7207 /**
7208 * xmlXPathNextAttribute:
7209 * @ctxt: the XPath Parser context
7210 * @cur: the current attribute in the traversal
7211 *
7212 * Traversal function for the "attribute" direction
7213 * TODO: support DTD inherited default attributes
7214 *
7215 * Returns the next element following that axis
7216 */
7217 xmlNodePtr
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7218 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7219 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7220 if (ctxt->context->node == NULL)
7221 return(NULL);
7222 if (ctxt->context->node->type != XML_ELEMENT_NODE)
7223 return(NULL);
7224 if (cur == NULL) {
7225 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7226 return(NULL);
7227 return((xmlNodePtr)ctxt->context->node->properties);
7228 }
7229 return((xmlNodePtr)cur->next);
7230 }
7231
7232 /************************************************************************
7233 * *
7234 * NodeTest Functions *
7235 * *
7236 ************************************************************************/
7237
7238 #define IS_FUNCTION 200
7239
7240
7241 /************************************************************************
7242 * *
7243 * Implicit tree core function library *
7244 * *
7245 ************************************************************************/
7246
7247 /**
7248 * xmlXPathRoot:
7249 * @ctxt: the XPath Parser context
7250 *
7251 * Initialize the context to the root of the document
7252 */
7253 void
xmlXPathRoot(xmlXPathParserContextPtr ctxt)7254 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
7255 if ((ctxt == NULL) || (ctxt->context == NULL))
7256 return;
7257 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7258 (xmlNodePtr) ctxt->context->doc));
7259 }
7260
7261 /************************************************************************
7262 * *
7263 * The explicit core function library *
7264 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
7265 * *
7266 ************************************************************************/
7267
7268
7269 /**
7270 * xmlXPathLastFunction:
7271 * @ctxt: the XPath Parser context
7272 * @nargs: the number of arguments
7273 *
7274 * Implement the last() XPath function
7275 * number last()
7276 * The last function returns the number of nodes in the context node list.
7277 */
7278 void
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt,int nargs)7279 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7280 CHECK_ARITY(0);
7281 if (ctxt->context->contextSize >= 0) {
7282 valuePush(ctxt,
7283 xmlXPathCacheNewFloat(ctxt, (double) ctxt->context->contextSize));
7284 } else {
7285 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
7286 }
7287 }
7288
7289 /**
7290 * xmlXPathPositionFunction:
7291 * @ctxt: the XPath Parser context
7292 * @nargs: the number of arguments
7293 *
7294 * Implement the position() XPath function
7295 * number position()
7296 * The position function returns the position of the context node in the
7297 * context node list. The first position is 1, and so the last position
7298 * will be equal to last().
7299 */
7300 void
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt,int nargs)7301 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7302 CHECK_ARITY(0);
7303 if (ctxt->context->proximityPosition >= 0) {
7304 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7305 (double) ctxt->context->proximityPosition));
7306 } else {
7307 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
7308 }
7309 }
7310
7311 /**
7312 * xmlXPathCountFunction:
7313 * @ctxt: the XPath Parser context
7314 * @nargs: the number of arguments
7315 *
7316 * Implement the count() XPath function
7317 * number count(node-set)
7318 */
7319 void
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt,int nargs)7320 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7321 xmlXPathObjectPtr cur;
7322
7323 CHECK_ARITY(1);
7324 if ((ctxt->value == NULL) ||
7325 ((ctxt->value->type != XPATH_NODESET) &&
7326 (ctxt->value->type != XPATH_XSLT_TREE)))
7327 XP_ERROR(XPATH_INVALID_TYPE);
7328 cur = valuePop(ctxt);
7329
7330 if ((cur == NULL) || (cur->nodesetval == NULL))
7331 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
7332 else
7333 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7334 (double) cur->nodesetval->nodeNr));
7335 xmlXPathReleaseObject(ctxt->context, cur);
7336 }
7337
7338 /**
7339 * xmlXPathGetElementsByIds:
7340 * @doc: the document
7341 * @ids: a whitespace separated list of IDs
7342 *
7343 * Selects elements by their unique ID.
7344 *
7345 * Returns a node-set of selected elements.
7346 */
7347 static xmlNodeSetPtr
xmlXPathGetElementsByIds(xmlDocPtr doc,const xmlChar * ids)7348 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
7349 xmlNodeSetPtr ret;
7350 const xmlChar *cur = ids;
7351 xmlChar *ID;
7352 xmlAttrPtr attr;
7353 xmlNodePtr elem = NULL;
7354
7355 if (ids == NULL) return(NULL);
7356
7357 ret = xmlXPathNodeSetCreate(NULL);
7358 if (ret == NULL)
7359 return(ret);
7360
7361 while (IS_BLANK_CH(*cur)) cur++;
7362 while (*cur != 0) {
7363 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
7364 cur++;
7365
7366 ID = xmlStrndup(ids, cur - ids);
7367 if (ID == NULL) {
7368 xmlXPathFreeNodeSet(ret);
7369 return(NULL);
7370 }
7371 /*
7372 * We used to check the fact that the value passed
7373 * was an NCName, but this generated much troubles for
7374 * me and Aleksey Sanin, people blatantly violated that
7375 * constraint, like Visa3D spec.
7376 * if (xmlValidateNCName(ID, 1) == 0)
7377 */
7378 attr = xmlGetID(doc, ID);
7379 xmlFree(ID);
7380 if (attr != NULL) {
7381 if (attr->type == XML_ATTRIBUTE_NODE)
7382 elem = attr->parent;
7383 else if (attr->type == XML_ELEMENT_NODE)
7384 elem = (xmlNodePtr) attr;
7385 else
7386 elem = NULL;
7387 if (elem != NULL) {
7388 if (xmlXPathNodeSetAdd(ret, elem) < 0) {
7389 xmlXPathFreeNodeSet(ret);
7390 return(NULL);
7391 }
7392 }
7393 }
7394
7395 while (IS_BLANK_CH(*cur)) cur++;
7396 ids = cur;
7397 }
7398 return(ret);
7399 }
7400
7401 /**
7402 * xmlXPathIdFunction:
7403 * @ctxt: the XPath Parser context
7404 * @nargs: the number of arguments
7405 *
7406 * Implement the id() XPath function
7407 * node-set id(object)
7408 * The id function selects elements by their unique ID
7409 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
7410 * then the result is the union of the result of applying id to the
7411 * string value of each of the nodes in the argument node-set. When the
7412 * argument to id is of any other type, the argument is converted to a
7413 * string as if by a call to the string function; the string is split
7414 * into a whitespace-separated list of tokens (whitespace is any sequence
7415 * of characters matching the production S); the result is a node-set
7416 * containing the elements in the same document as the context node that
7417 * have a unique ID equal to any of the tokens in the list.
7418 */
7419 void
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt,int nargs)7420 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7421 xmlChar *tokens;
7422 xmlNodeSetPtr ret;
7423 xmlXPathObjectPtr obj;
7424
7425 CHECK_ARITY(1);
7426 obj = valuePop(ctxt);
7427 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7428 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7429 xmlNodeSetPtr ns;
7430 int i;
7431
7432 ret = xmlXPathNodeSetCreate(NULL);
7433 if (ret == NULL)
7434 xmlXPathPErrMemory(ctxt);
7435
7436 if (obj->nodesetval != NULL) {
7437 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7438 tokens =
7439 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7440 if (tokens == NULL)
7441 xmlXPathPErrMemory(ctxt);
7442 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7443 if (ns == NULL)
7444 xmlXPathPErrMemory(ctxt);
7445 ret = xmlXPathNodeSetMerge(ret, ns);
7446 if (ret == NULL)
7447 xmlXPathPErrMemory(ctxt);
7448 xmlXPathFreeNodeSet(ns);
7449 if (tokens != NULL)
7450 xmlFree(tokens);
7451 }
7452 }
7453 xmlXPathReleaseObject(ctxt->context, obj);
7454 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7455 return;
7456 }
7457 tokens = xmlXPathCastToString(obj);
7458 if (tokens == NULL)
7459 xmlXPathPErrMemory(ctxt);
7460 xmlXPathReleaseObject(ctxt->context, obj);
7461 ret = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7462 if (ret == NULL)
7463 xmlXPathPErrMemory(ctxt);
7464 xmlFree(tokens);
7465 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7466 return;
7467 }
7468
7469 /**
7470 * xmlXPathLocalNameFunction:
7471 * @ctxt: the XPath Parser context
7472 * @nargs: the number of arguments
7473 *
7474 * Implement the local-name() XPath function
7475 * string local-name(node-set?)
7476 * The local-name function returns a string containing the local part
7477 * of the name of the node in the argument node-set that is first in
7478 * document order. If the node-set is empty or the first node has no
7479 * name, an empty string is returned. If the argument is omitted it
7480 * defaults to the context node.
7481 */
7482 void
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt,int nargs)7483 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7484 xmlXPathObjectPtr cur;
7485
7486 if (ctxt == NULL) return;
7487
7488 if (nargs == 0) {
7489 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7490 nargs = 1;
7491 }
7492
7493 CHECK_ARITY(1);
7494 if ((ctxt->value == NULL) ||
7495 ((ctxt->value->type != XPATH_NODESET) &&
7496 (ctxt->value->type != XPATH_XSLT_TREE)))
7497 XP_ERROR(XPATH_INVALID_TYPE);
7498 cur = valuePop(ctxt);
7499
7500 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7501 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7502 } else {
7503 int i = 0; /* Should be first in document order !!!!! */
7504 switch (cur->nodesetval->nodeTab[i]->type) {
7505 case XML_ELEMENT_NODE:
7506 case XML_ATTRIBUTE_NODE:
7507 case XML_PI_NODE:
7508 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7509 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7510 else
7511 valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7512 cur->nodesetval->nodeTab[i]->name));
7513 break;
7514 case XML_NAMESPACE_DECL:
7515 valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7516 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
7517 break;
7518 default:
7519 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7520 }
7521 }
7522 xmlXPathReleaseObject(ctxt->context, cur);
7523 }
7524
7525 /**
7526 * xmlXPathNamespaceURIFunction:
7527 * @ctxt: the XPath Parser context
7528 * @nargs: the number of arguments
7529 *
7530 * Implement the namespace-uri() XPath function
7531 * string namespace-uri(node-set?)
7532 * The namespace-uri function returns a string containing the
7533 * namespace URI of the expanded name of the node in the argument
7534 * node-set that is first in document order. If the node-set is empty,
7535 * the first node has no name, or the expanded name has no namespace
7536 * URI, an empty string is returned. If the argument is omitted it
7537 * defaults to the context node.
7538 */
7539 void
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt,int nargs)7540 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7541 xmlXPathObjectPtr cur;
7542
7543 if (ctxt == NULL) return;
7544
7545 if (nargs == 0) {
7546 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7547 nargs = 1;
7548 }
7549 CHECK_ARITY(1);
7550 if ((ctxt->value == NULL) ||
7551 ((ctxt->value->type != XPATH_NODESET) &&
7552 (ctxt->value->type != XPATH_XSLT_TREE)))
7553 XP_ERROR(XPATH_INVALID_TYPE);
7554 cur = valuePop(ctxt);
7555
7556 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7557 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7558 } else {
7559 int i = 0; /* Should be first in document order !!!!! */
7560 switch (cur->nodesetval->nodeTab[i]->type) {
7561 case XML_ELEMENT_NODE:
7562 case XML_ATTRIBUTE_NODE:
7563 if (cur->nodesetval->nodeTab[i]->ns == NULL)
7564 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7565 else
7566 valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7567 cur->nodesetval->nodeTab[i]->ns->href));
7568 break;
7569 default:
7570 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7571 }
7572 }
7573 xmlXPathReleaseObject(ctxt->context, cur);
7574 }
7575
7576 /**
7577 * xmlXPathNameFunction:
7578 * @ctxt: the XPath Parser context
7579 * @nargs: the number of arguments
7580 *
7581 * Implement the name() XPath function
7582 * string name(node-set?)
7583 * The name function returns a string containing a QName representing
7584 * the name of the node in the argument node-set that is first in document
7585 * order. The QName must represent the name with respect to the namespace
7586 * declarations in effect on the node whose name is being represented.
7587 * Typically, this will be the form in which the name occurred in the XML
7588 * source. This need not be the case if there are namespace declarations
7589 * in effect on the node that associate multiple prefixes with the same
7590 * namespace. However, an implementation may include information about
7591 * the original prefix in its representation of nodes; in this case, an
7592 * implementation can ensure that the returned string is always the same
7593 * as the QName used in the XML source. If the argument it omitted it
7594 * defaults to the context node.
7595 * Libxml keep the original prefix so the "real qualified name" used is
7596 * returned.
7597 */
7598 static void
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt,int nargs)7599 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
7600 {
7601 xmlXPathObjectPtr cur;
7602
7603 if (nargs == 0) {
7604 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7605 nargs = 1;
7606 }
7607
7608 CHECK_ARITY(1);
7609 if ((ctxt->value == NULL) ||
7610 ((ctxt->value->type != XPATH_NODESET) &&
7611 (ctxt->value->type != XPATH_XSLT_TREE)))
7612 XP_ERROR(XPATH_INVALID_TYPE);
7613 cur = valuePop(ctxt);
7614
7615 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7616 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7617 } else {
7618 int i = 0; /* Should be first in document order !!!!! */
7619
7620 switch (cur->nodesetval->nodeTab[i]->type) {
7621 case XML_ELEMENT_NODE:
7622 case XML_ATTRIBUTE_NODE:
7623 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7624 valuePush(ctxt,
7625 xmlXPathCacheNewCString(ctxt, ""));
7626 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
7627 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
7628 valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7629 cur->nodesetval->nodeTab[i]->name));
7630 } else {
7631 xmlChar *fullname;
7632
7633 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
7634 cur->nodesetval->nodeTab[i]->ns->prefix,
7635 NULL, 0);
7636 if (fullname == cur->nodesetval->nodeTab[i]->name)
7637 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
7638 if (fullname == NULL)
7639 xmlXPathPErrMemory(ctxt);
7640 valuePush(ctxt, xmlXPathCacheWrapString(ctxt, fullname));
7641 }
7642 break;
7643 default:
7644 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7645 cur->nodesetval->nodeTab[i]));
7646 xmlXPathLocalNameFunction(ctxt, 1);
7647 }
7648 }
7649 xmlXPathReleaseObject(ctxt->context, cur);
7650 }
7651
7652
7653 /**
7654 * xmlXPathStringFunction:
7655 * @ctxt: the XPath Parser context
7656 * @nargs: the number of arguments
7657 *
7658 * Implement the string() XPath function
7659 * string string(object?)
7660 * The string function converts an object to a string as follows:
7661 * - A node-set is converted to a string by returning the value of
7662 * the node in the node-set that is first in document order.
7663 * If the node-set is empty, an empty string is returned.
7664 * - A number is converted to a string as follows
7665 * + NaN is converted to the string NaN
7666 * + positive zero is converted to the string 0
7667 * + negative zero is converted to the string 0
7668 * + positive infinity is converted to the string Infinity
7669 * + negative infinity is converted to the string -Infinity
7670 * + if the number is an integer, the number is represented in
7671 * decimal form as a Number with no decimal point and no leading
7672 * zeros, preceded by a minus sign (-) if the number is negative
7673 * + otherwise, the number is represented in decimal form as a
7674 * Number including a decimal point with at least one digit
7675 * before the decimal point and at least one digit after the
7676 * decimal point, preceded by a minus sign (-) if the number
7677 * is negative; there must be no leading zeros before the decimal
7678 * point apart possibly from the one required digit immediately
7679 * before the decimal point; beyond the one required digit
7680 * after the decimal point there must be as many, but only as
7681 * many, more digits as are needed to uniquely distinguish the
7682 * number from all other IEEE 754 numeric values.
7683 * - The boolean false value is converted to the string false.
7684 * The boolean true value is converted to the string true.
7685 *
7686 * If the argument is omitted, it defaults to a node-set with the
7687 * context node as its only member.
7688 */
7689 void
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt,int nargs)7690 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7691 xmlXPathObjectPtr cur;
7692 xmlChar *stringval;
7693
7694 if (ctxt == NULL) return;
7695 if (nargs == 0) {
7696 stringval = xmlXPathCastNodeToString(ctxt->context->node);
7697 if (stringval == NULL)
7698 xmlXPathPErrMemory(ctxt);
7699 valuePush(ctxt, xmlXPathCacheWrapString(ctxt, stringval));
7700 return;
7701 }
7702
7703 CHECK_ARITY(1);
7704 cur = valuePop(ctxt);
7705 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7706 if (cur->type != XPATH_STRING) {
7707 stringval = xmlXPathCastToString(cur);
7708 if (stringval == NULL)
7709 xmlXPathPErrMemory(ctxt);
7710 xmlXPathReleaseObject(ctxt->context, cur);
7711 cur = xmlXPathCacheWrapString(ctxt, stringval);
7712 }
7713 valuePush(ctxt, cur);
7714 }
7715
7716 /**
7717 * xmlXPathStringLengthFunction:
7718 * @ctxt: the XPath Parser context
7719 * @nargs: the number of arguments
7720 *
7721 * Implement the string-length() XPath function
7722 * number string-length(string?)
7723 * The string-length returns the number of characters in the string
7724 * (see [3.6 Strings]). If the argument is omitted, it defaults to
7725 * the context node converted to a string, in other words the value
7726 * of the context node.
7727 */
7728 void
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt,int nargs)7729 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7730 xmlXPathObjectPtr cur;
7731
7732 if (nargs == 0) {
7733 if ((ctxt == NULL) || (ctxt->context == NULL))
7734 return;
7735 if (ctxt->context->node == NULL) {
7736 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0));
7737 } else {
7738 xmlChar *content;
7739
7740 content = xmlXPathCastNodeToString(ctxt->context->node);
7741 if (content == NULL)
7742 xmlXPathPErrMemory(ctxt);
7743 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7744 xmlUTF8Strlen(content)));
7745 xmlFree(content);
7746 }
7747 return;
7748 }
7749 CHECK_ARITY(1);
7750 CAST_TO_STRING;
7751 CHECK_TYPE(XPATH_STRING);
7752 cur = valuePop(ctxt);
7753 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7754 xmlUTF8Strlen(cur->stringval)));
7755 xmlXPathReleaseObject(ctxt->context, cur);
7756 }
7757
7758 /**
7759 * xmlXPathConcatFunction:
7760 * @ctxt: the XPath Parser context
7761 * @nargs: the number of arguments
7762 *
7763 * Implement the concat() XPath function
7764 * string concat(string, string, string*)
7765 * The concat function returns the concatenation of its arguments.
7766 */
7767 void
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt,int nargs)7768 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7769 xmlXPathObjectPtr cur, newobj;
7770 xmlChar *tmp;
7771
7772 if (ctxt == NULL) return;
7773 if (nargs < 2) {
7774 CHECK_ARITY(2);
7775 }
7776
7777 CAST_TO_STRING;
7778 cur = valuePop(ctxt);
7779 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
7780 xmlXPathReleaseObject(ctxt->context, cur);
7781 return;
7782 }
7783 nargs--;
7784
7785 while (nargs > 0) {
7786 CAST_TO_STRING;
7787 newobj = valuePop(ctxt);
7788 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
7789 xmlXPathReleaseObject(ctxt->context, newobj);
7790 xmlXPathReleaseObject(ctxt->context, cur);
7791 XP_ERROR(XPATH_INVALID_TYPE);
7792 }
7793 tmp = xmlStrcat(newobj->stringval, cur->stringval);
7794 if (tmp == NULL)
7795 xmlXPathPErrMemory(ctxt);
7796 newobj->stringval = cur->stringval;
7797 cur->stringval = tmp;
7798 xmlXPathReleaseObject(ctxt->context, newobj);
7799 nargs--;
7800 }
7801 valuePush(ctxt, cur);
7802 }
7803
7804 /**
7805 * xmlXPathContainsFunction:
7806 * @ctxt: the XPath Parser context
7807 * @nargs: the number of arguments
7808 *
7809 * Implement the contains() XPath function
7810 * boolean contains(string, string)
7811 * The contains function returns true if the first argument string
7812 * contains the second argument string, and otherwise returns false.
7813 */
7814 void
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt,int nargs)7815 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7816 xmlXPathObjectPtr hay, needle;
7817
7818 CHECK_ARITY(2);
7819 CAST_TO_STRING;
7820 CHECK_TYPE(XPATH_STRING);
7821 needle = valuePop(ctxt);
7822 CAST_TO_STRING;
7823 hay = valuePop(ctxt);
7824
7825 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7826 xmlXPathReleaseObject(ctxt->context, hay);
7827 xmlXPathReleaseObject(ctxt->context, needle);
7828 XP_ERROR(XPATH_INVALID_TYPE);
7829 }
7830 if (xmlStrstr(hay->stringval, needle->stringval))
7831 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7832 else
7833 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7834 xmlXPathReleaseObject(ctxt->context, hay);
7835 xmlXPathReleaseObject(ctxt->context, needle);
7836 }
7837
7838 /**
7839 * xmlXPathStartsWithFunction:
7840 * @ctxt: the XPath Parser context
7841 * @nargs: the number of arguments
7842 *
7843 * Implement the starts-with() XPath function
7844 * boolean starts-with(string, string)
7845 * The starts-with function returns true if the first argument string
7846 * starts with the second argument string, and otherwise returns false.
7847 */
7848 void
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt,int nargs)7849 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7850 xmlXPathObjectPtr hay, needle;
7851 int n;
7852
7853 CHECK_ARITY(2);
7854 CAST_TO_STRING;
7855 CHECK_TYPE(XPATH_STRING);
7856 needle = valuePop(ctxt);
7857 CAST_TO_STRING;
7858 hay = valuePop(ctxt);
7859
7860 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7861 xmlXPathReleaseObject(ctxt->context, hay);
7862 xmlXPathReleaseObject(ctxt->context, needle);
7863 XP_ERROR(XPATH_INVALID_TYPE);
7864 }
7865 n = xmlStrlen(needle->stringval);
7866 if (xmlStrncmp(hay->stringval, needle->stringval, n))
7867 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7868 else
7869 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7870 xmlXPathReleaseObject(ctxt->context, hay);
7871 xmlXPathReleaseObject(ctxt->context, needle);
7872 }
7873
7874 /**
7875 * xmlXPathSubstringFunction:
7876 * @ctxt: the XPath Parser context
7877 * @nargs: the number of arguments
7878 *
7879 * Implement the substring() XPath function
7880 * string substring(string, number, number?)
7881 * The substring function returns the substring of the first argument
7882 * starting at the position specified in the second argument with
7883 * length specified in the third argument. For example,
7884 * substring("12345",2,3) returns "234". If the third argument is not
7885 * specified, it returns the substring starting at the position specified
7886 * in the second argument and continuing to the end of the string. For
7887 * example, substring("12345",2) returns "2345". More precisely, each
7888 * character in the string (see [3.6 Strings]) is considered to have a
7889 * numeric position: the position of the first character is 1, the position
7890 * of the second character is 2 and so on. The returned substring contains
7891 * those characters for which the position of the character is greater than
7892 * or equal to the second argument and, if the third argument is specified,
7893 * less than the sum of the second and third arguments; the comparisons
7894 * and addition used for the above follow the standard IEEE 754 rules. Thus:
7895 * - substring("12345", 1.5, 2.6) returns "234"
7896 * - substring("12345", 0, 3) returns "12"
7897 * - substring("12345", 0 div 0, 3) returns ""
7898 * - substring("12345", 1, 0 div 0) returns ""
7899 * - substring("12345", -42, 1 div 0) returns "12345"
7900 * - substring("12345", -1 div 0, 1 div 0) returns ""
7901 */
7902 void
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt,int nargs)7903 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7904 xmlXPathObjectPtr str, start, len;
7905 double le=0, in;
7906 int i = 1, j = INT_MAX;
7907
7908 if (nargs < 2) {
7909 CHECK_ARITY(2);
7910 }
7911 if (nargs > 3) {
7912 CHECK_ARITY(3);
7913 }
7914 /*
7915 * take care of possible last (position) argument
7916 */
7917 if (nargs == 3) {
7918 CAST_TO_NUMBER;
7919 CHECK_TYPE(XPATH_NUMBER);
7920 len = valuePop(ctxt);
7921 le = len->floatval;
7922 xmlXPathReleaseObject(ctxt->context, len);
7923 }
7924
7925 CAST_TO_NUMBER;
7926 CHECK_TYPE(XPATH_NUMBER);
7927 start = valuePop(ctxt);
7928 in = start->floatval;
7929 xmlXPathReleaseObject(ctxt->context, start);
7930 CAST_TO_STRING;
7931 CHECK_TYPE(XPATH_STRING);
7932 str = valuePop(ctxt);
7933
7934 if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
7935 i = INT_MAX;
7936 } else if (in >= 1.0) {
7937 i = (int)in;
7938 if (in - floor(in) >= 0.5)
7939 i += 1;
7940 }
7941
7942 if (nargs == 3) {
7943 double rin, rle, end;
7944
7945 rin = floor(in);
7946 if (in - rin >= 0.5)
7947 rin += 1.0;
7948
7949 rle = floor(le);
7950 if (le - rle >= 0.5)
7951 rle += 1.0;
7952
7953 end = rin + rle;
7954 if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
7955 j = 1;
7956 } else if (end < INT_MAX) {
7957 j = (int)end;
7958 }
7959 }
7960
7961 i -= 1;
7962 j -= 1;
7963
7964 if ((i < j) && (i < xmlUTF8Strlen(str->stringval))) {
7965 xmlChar *ret = xmlUTF8Strsub(str->stringval, i, j - i);
7966 if (ret == NULL)
7967 xmlXPathPErrMemory(ctxt);
7968 valuePush(ctxt, xmlXPathCacheNewString(ctxt, ret));
7969 xmlFree(ret);
7970 } else {
7971 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7972 }
7973
7974 xmlXPathReleaseObject(ctxt->context, str);
7975 }
7976
7977 /**
7978 * xmlXPathSubstringBeforeFunction:
7979 * @ctxt: the XPath Parser context
7980 * @nargs: the number of arguments
7981 *
7982 * Implement the substring-before() XPath function
7983 * string substring-before(string, string)
7984 * The substring-before function returns the substring of the first
7985 * argument string that precedes the first occurrence of the second
7986 * argument string in the first argument string, or the empty string
7987 * if the first argument string does not contain the second argument
7988 * string. For example, substring-before("1999/04/01","/") returns 1999.
7989 */
7990 void
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt,int nargs)7991 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7992 xmlXPathObjectPtr str = NULL;
7993 xmlXPathObjectPtr find = NULL;
7994 const xmlChar *point;
7995 xmlChar *result;
7996
7997 CHECK_ARITY(2);
7998 CAST_TO_STRING;
7999 find = valuePop(ctxt);
8000 CAST_TO_STRING;
8001 str = valuePop(ctxt);
8002 if (ctxt->error != 0)
8003 goto error;
8004
8005 point = xmlStrstr(str->stringval, find->stringval);
8006 if (point == NULL) {
8007 result = xmlStrdup(BAD_CAST "");
8008 } else {
8009 result = xmlStrndup(str->stringval, point - str->stringval);
8010 }
8011 if (result == NULL) {
8012 xmlXPathPErrMemory(ctxt);
8013 goto error;
8014 }
8015 valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
8016
8017 error:
8018 xmlXPathReleaseObject(ctxt->context, str);
8019 xmlXPathReleaseObject(ctxt->context, find);
8020 }
8021
8022 /**
8023 * xmlXPathSubstringAfterFunction:
8024 * @ctxt: the XPath Parser context
8025 * @nargs: the number of arguments
8026 *
8027 * Implement the substring-after() XPath function
8028 * string substring-after(string, string)
8029 * The substring-after function returns the substring of the first
8030 * argument string that follows the first occurrence of the second
8031 * argument string in the first argument string, or the empty string
8032 * if the first argument string does not contain the second argument
8033 * string. For example, substring-after("1999/04/01","/") returns 04/01,
8034 * and substring-after("1999/04/01","19") returns 99/04/01.
8035 */
8036 void
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt,int nargs)8037 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8038 xmlXPathObjectPtr str = NULL;
8039 xmlXPathObjectPtr find = NULL;
8040 const xmlChar *point;
8041 xmlChar *result;
8042
8043 CHECK_ARITY(2);
8044 CAST_TO_STRING;
8045 find = valuePop(ctxt);
8046 CAST_TO_STRING;
8047 str = valuePop(ctxt);
8048 if (ctxt->error != 0)
8049 goto error;
8050
8051 point = xmlStrstr(str->stringval, find->stringval);
8052 if (point == NULL) {
8053 result = xmlStrdup(BAD_CAST "");
8054 } else {
8055 result = xmlStrdup(point + xmlStrlen(find->stringval));
8056 }
8057 if (result == NULL) {
8058 xmlXPathPErrMemory(ctxt);
8059 goto error;
8060 }
8061 valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
8062
8063 error:
8064 xmlXPathReleaseObject(ctxt->context, str);
8065 xmlXPathReleaseObject(ctxt->context, find);
8066 }
8067
8068 /**
8069 * xmlXPathNormalizeFunction:
8070 * @ctxt: the XPath Parser context
8071 * @nargs: the number of arguments
8072 *
8073 * Implement the normalize-space() XPath function
8074 * string normalize-space(string?)
8075 * The normalize-space function returns the argument string with white
8076 * space normalized by stripping leading and trailing whitespace
8077 * and replacing sequences of whitespace characters by a single
8078 * space. Whitespace characters are the same allowed by the S production
8079 * in XML. If the argument is omitted, it defaults to the context
8080 * node converted to a string, in other words the value of the context node.
8081 */
8082 void
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt,int nargs)8083 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8084 xmlChar *source, *target;
8085 int blank;
8086
8087 if (ctxt == NULL) return;
8088 if (nargs == 0) {
8089 /* Use current context node */
8090 source = xmlXPathCastNodeToString(ctxt->context->node);
8091 if (source == NULL)
8092 xmlXPathPErrMemory(ctxt);
8093 valuePush(ctxt, xmlXPathCacheWrapString(ctxt, source));
8094 nargs = 1;
8095 }
8096
8097 CHECK_ARITY(1);
8098 CAST_TO_STRING;
8099 CHECK_TYPE(XPATH_STRING);
8100 source = ctxt->value->stringval;
8101 if (source == NULL)
8102 return;
8103 target = source;
8104
8105 /* Skip leading whitespaces */
8106 while (IS_BLANK_CH(*source))
8107 source++;
8108
8109 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
8110 blank = 0;
8111 while (*source) {
8112 if (IS_BLANK_CH(*source)) {
8113 blank = 1;
8114 } else {
8115 if (blank) {
8116 *target++ = 0x20;
8117 blank = 0;
8118 }
8119 *target++ = *source;
8120 }
8121 source++;
8122 }
8123 *target = 0;
8124 }
8125
8126 /**
8127 * xmlXPathTranslateFunction:
8128 * @ctxt: the XPath Parser context
8129 * @nargs: the number of arguments
8130 *
8131 * Implement the translate() XPath function
8132 * string translate(string, string, string)
8133 * The translate function returns the first argument string with
8134 * occurrences of characters in the second argument string replaced
8135 * by the character at the corresponding position in the third argument
8136 * string. For example, translate("bar","abc","ABC") returns the string
8137 * BAr. If there is a character in the second argument string with no
8138 * character at a corresponding position in the third argument string
8139 * (because the second argument string is longer than the third argument
8140 * string), then occurrences of that character in the first argument
8141 * string are removed. For example, translate("--aaa--","abc-","ABC")
8142 * returns "AAA". If a character occurs more than once in second
8143 * argument string, then the first occurrence determines the replacement
8144 * character. If the third argument string is longer than the second
8145 * argument string, then excess characters are ignored.
8146 */
8147 void
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt,int nargs)8148 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8149 xmlXPathObjectPtr str = NULL;
8150 xmlXPathObjectPtr from = NULL;
8151 xmlXPathObjectPtr to = NULL;
8152 xmlBufPtr target;
8153 int offset, max;
8154 int ch;
8155 const xmlChar *point;
8156 xmlChar *cptr, *content;
8157
8158 CHECK_ARITY(3);
8159
8160 CAST_TO_STRING;
8161 to = valuePop(ctxt);
8162 CAST_TO_STRING;
8163 from = valuePop(ctxt);
8164 CAST_TO_STRING;
8165 str = valuePop(ctxt);
8166 if (ctxt->error != 0)
8167 goto error;
8168
8169 /*
8170 * Account for quadratic runtime
8171 */
8172 if (ctxt->context->opLimit != 0) {
8173 unsigned long f1 = xmlStrlen(from->stringval);
8174 unsigned long f2 = xmlStrlen(str->stringval);
8175
8176 if ((f1 > 0) && (f2 > 0)) {
8177 unsigned long p;
8178
8179 f1 = f1 / 10 + 1;
8180 f2 = f2 / 10 + 1;
8181 p = f1 > ULONG_MAX / f2 ? ULONG_MAX : f1 * f2;
8182 if (xmlXPathCheckOpLimit(ctxt, p) < 0)
8183 goto error;
8184 }
8185 }
8186
8187 target = xmlBufCreateSize(64);
8188 if (target == NULL) {
8189 xmlXPathPErrMemory(ctxt);
8190 goto error;
8191 }
8192
8193 max = xmlUTF8Strlen(to->stringval);
8194 for (cptr = str->stringval; (ch=*cptr); ) {
8195 offset = xmlUTF8Strloc(from->stringval, cptr);
8196 if (offset >= 0) {
8197 if (offset < max) {
8198 point = xmlUTF8Strpos(to->stringval, offset);
8199 if (point)
8200 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
8201 }
8202 } else
8203 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
8204
8205 /* Step to next character in input */
8206 cptr++;
8207 if ( ch & 0x80 ) {
8208 /* if not simple ascii, verify proper format */
8209 if ( (ch & 0xc0) != 0xc0 ) {
8210 xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
8211 break;
8212 }
8213 /* then skip over remaining bytes for this char */
8214 while ( (ch <<= 1) & 0x80 )
8215 if ( (*cptr++ & 0xc0) != 0x80 ) {
8216 xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
8217 break;
8218 }
8219 if (ch & 0x80) /* must have had error encountered */
8220 break;
8221 }
8222 }
8223
8224 content = xmlBufDetach(target);
8225 if (content == NULL)
8226 xmlXPathPErrMemory(ctxt);
8227 else
8228 valuePush(ctxt, xmlXPathCacheWrapString(ctxt, content));
8229 xmlBufFree(target);
8230 error:
8231 xmlXPathReleaseObject(ctxt->context, str);
8232 xmlXPathReleaseObject(ctxt->context, from);
8233 xmlXPathReleaseObject(ctxt->context, to);
8234 }
8235
8236 /**
8237 * xmlXPathBooleanFunction:
8238 * @ctxt: the XPath Parser context
8239 * @nargs: the number of arguments
8240 *
8241 * Implement the boolean() XPath function
8242 * boolean boolean(object)
8243 * The boolean function converts its argument to a boolean as follows:
8244 * - a number is true if and only if it is neither positive or
8245 * negative zero nor NaN
8246 * - a node-set is true if and only if it is non-empty
8247 * - a string is true if and only if its length is non-zero
8248 */
8249 void
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt,int nargs)8250 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8251 xmlXPathObjectPtr cur;
8252
8253 CHECK_ARITY(1);
8254 cur = valuePop(ctxt);
8255 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8256 if (cur->type != XPATH_BOOLEAN) {
8257 int boolval = xmlXPathCastToBoolean(cur);
8258
8259 xmlXPathReleaseObject(ctxt->context, cur);
8260 cur = xmlXPathCacheNewBoolean(ctxt, boolval);
8261 }
8262 valuePush(ctxt, cur);
8263 }
8264
8265 /**
8266 * xmlXPathNotFunction:
8267 * @ctxt: the XPath Parser context
8268 * @nargs: the number of arguments
8269 *
8270 * Implement the not() XPath function
8271 * boolean not(boolean)
8272 * The not function returns true if its argument is false,
8273 * and false otherwise.
8274 */
8275 void
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt,int nargs)8276 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8277 CHECK_ARITY(1);
8278 CAST_TO_BOOLEAN;
8279 CHECK_TYPE(XPATH_BOOLEAN);
8280 ctxt->value->boolval = ! ctxt->value->boolval;
8281 }
8282
8283 /**
8284 * xmlXPathTrueFunction:
8285 * @ctxt: the XPath Parser context
8286 * @nargs: the number of arguments
8287 *
8288 * Implement the true() XPath function
8289 * boolean true()
8290 */
8291 void
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt,int nargs)8292 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8293 CHECK_ARITY(0);
8294 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
8295 }
8296
8297 /**
8298 * xmlXPathFalseFunction:
8299 * @ctxt: the XPath Parser context
8300 * @nargs: the number of arguments
8301 *
8302 * Implement the false() XPath function
8303 * boolean false()
8304 */
8305 void
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt,int nargs)8306 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8307 CHECK_ARITY(0);
8308 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
8309 }
8310
8311 /**
8312 * xmlXPathLangFunction:
8313 * @ctxt: the XPath Parser context
8314 * @nargs: the number of arguments
8315 *
8316 * Implement the lang() XPath function
8317 * boolean lang(string)
8318 * The lang function returns true or false depending on whether the
8319 * language of the context node as specified by xml:lang attributes
8320 * is the same as or is a sublanguage of the language specified by
8321 * the argument string. The language of the context node is determined
8322 * by the value of the xml:lang attribute on the context node, or, if
8323 * the context node has no xml:lang attribute, by the value of the
8324 * xml:lang attribute on the nearest ancestor of the context node that
8325 * has an xml:lang attribute. If there is no such attribute, then lang
8326 * returns false. If there is such an attribute, then lang returns
8327 * true if the attribute value is equal to the argument ignoring case,
8328 * or if there is some suffix starting with - such that the attribute
8329 * value is equal to the argument ignoring that suffix of the attribute
8330 * value and ignoring case.
8331 */
8332 void
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt,int nargs)8333 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8334 xmlXPathObjectPtr val;
8335 xmlNodePtr cur;
8336 xmlChar *theLang;
8337 const xmlChar *lang;
8338 int ret = 0;
8339 int i;
8340
8341 CHECK_ARITY(1);
8342 CAST_TO_STRING;
8343 CHECK_TYPE(XPATH_STRING);
8344 val = valuePop(ctxt);
8345 lang = val->stringval;
8346 cur = ctxt->context->node;
8347 while (cur != NULL) {
8348 if (xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE,
8349 &theLang) < 0)
8350 xmlXPathPErrMemory(ctxt);
8351 if (theLang != NULL)
8352 break;
8353 cur = cur->parent;
8354 }
8355 if ((theLang != NULL) && (lang != NULL)) {
8356 for (i = 0;lang[i] != 0;i++)
8357 if (toupper(lang[i]) != toupper(theLang[i]))
8358 goto not_equal;
8359 if ((theLang[i] == 0) || (theLang[i] == '-'))
8360 ret = 1;
8361 }
8362 not_equal:
8363 if (theLang != NULL)
8364 xmlFree((void *)theLang);
8365
8366 xmlXPathReleaseObject(ctxt->context, val);
8367 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
8368 }
8369
8370 /**
8371 * xmlXPathNumberFunction:
8372 * @ctxt: the XPath Parser context
8373 * @nargs: the number of arguments
8374 *
8375 * Implement the number() XPath function
8376 * number number(object?)
8377 */
8378 void
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt,int nargs)8379 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8380 xmlXPathObjectPtr cur;
8381 double res;
8382
8383 if (ctxt == NULL) return;
8384 if (nargs == 0) {
8385 if (ctxt->context->node == NULL) {
8386 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
8387 } else {
8388 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
8389 if (content == NULL)
8390 xmlXPathPErrMemory(ctxt);
8391
8392 res = xmlXPathStringEvalNumber(content);
8393 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8394 xmlFree(content);
8395 }
8396 return;
8397 }
8398
8399 CHECK_ARITY(1);
8400 cur = valuePop(ctxt);
8401 if (cur->type != XPATH_NUMBER) {
8402 double floatval;
8403
8404 floatval = xmlXPathCastToNumberInternal(ctxt, cur);
8405 xmlXPathReleaseObject(ctxt->context, cur);
8406 cur = xmlXPathCacheNewFloat(ctxt, floatval);
8407 }
8408 valuePush(ctxt, cur);
8409 }
8410
8411 /**
8412 * xmlXPathSumFunction:
8413 * @ctxt: the XPath Parser context
8414 * @nargs: the number of arguments
8415 *
8416 * Implement the sum() XPath function
8417 * number sum(node-set)
8418 * The sum function returns the sum of the values of the nodes in
8419 * the argument node-set.
8420 */
8421 void
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt,int nargs)8422 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8423 xmlXPathObjectPtr cur;
8424 int i;
8425 double res = 0.0;
8426
8427 CHECK_ARITY(1);
8428 if ((ctxt->value == NULL) ||
8429 ((ctxt->value->type != XPATH_NODESET) &&
8430 (ctxt->value->type != XPATH_XSLT_TREE)))
8431 XP_ERROR(XPATH_INVALID_TYPE);
8432 cur = valuePop(ctxt);
8433
8434 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
8435 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
8436 res += xmlXPathNodeToNumberInternal(ctxt,
8437 cur->nodesetval->nodeTab[i]);
8438 }
8439 }
8440 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8441 xmlXPathReleaseObject(ctxt->context, cur);
8442 }
8443
8444 /**
8445 * xmlXPathFloorFunction:
8446 * @ctxt: the XPath Parser context
8447 * @nargs: the number of arguments
8448 *
8449 * Implement the floor() XPath function
8450 * number floor(number)
8451 * The floor function returns the largest (closest to positive infinity)
8452 * number that is not greater than the argument and that is an integer.
8453 */
8454 void
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt,int nargs)8455 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8456 CHECK_ARITY(1);
8457 CAST_TO_NUMBER;
8458 CHECK_TYPE(XPATH_NUMBER);
8459
8460 ctxt->value->floatval = floor(ctxt->value->floatval);
8461 }
8462
8463 /**
8464 * xmlXPathCeilingFunction:
8465 * @ctxt: the XPath Parser context
8466 * @nargs: the number of arguments
8467 *
8468 * Implement the ceiling() XPath function
8469 * number ceiling(number)
8470 * The ceiling function returns the smallest (closest to negative infinity)
8471 * number that is not less than the argument and that is an integer.
8472 */
8473 void
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt,int nargs)8474 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8475 CHECK_ARITY(1);
8476 CAST_TO_NUMBER;
8477 CHECK_TYPE(XPATH_NUMBER);
8478
8479 #ifdef _AIX
8480 /* Work around buggy ceil() function on AIX */
8481 ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
8482 #else
8483 ctxt->value->floatval = ceil(ctxt->value->floatval);
8484 #endif
8485 }
8486
8487 /**
8488 * xmlXPathRoundFunction:
8489 * @ctxt: the XPath Parser context
8490 * @nargs: the number of arguments
8491 *
8492 * Implement the round() XPath function
8493 * number round(number)
8494 * The round function returns the number that is closest to the
8495 * argument and that is an integer. If there are two such numbers,
8496 * then the one that is closest to positive infinity is returned.
8497 */
8498 void
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt,int nargs)8499 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8500 double f;
8501
8502 CHECK_ARITY(1);
8503 CAST_TO_NUMBER;
8504 CHECK_TYPE(XPATH_NUMBER);
8505
8506 f = ctxt->value->floatval;
8507
8508 if ((f >= -0.5) && (f < 0.5)) {
8509 /* Handles negative zero. */
8510 ctxt->value->floatval *= 0.0;
8511 }
8512 else {
8513 double rounded = floor(f);
8514 if (f - rounded >= 0.5)
8515 rounded += 1.0;
8516 ctxt->value->floatval = rounded;
8517 }
8518 }
8519
8520 /************************************************************************
8521 * *
8522 * The Parser *
8523 * *
8524 ************************************************************************/
8525
8526 /*
8527 * a few forward declarations since we use a recursive call based
8528 * implementation.
8529 */
8530 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
8531 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
8532 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
8533 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
8534 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
8535 int qualified);
8536
8537 /**
8538 * xmlXPathCurrentChar:
8539 * @ctxt: the XPath parser context
8540 * @cur: pointer to the beginning of the char
8541 * @len: pointer to the length of the char read
8542 *
8543 * The current char value, if using UTF-8 this may actually span multiple
8544 * bytes in the input buffer.
8545 *
8546 * Returns the current char value and its length
8547 */
8548
8549 static int
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt,int * len)8550 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
8551 unsigned char c;
8552 unsigned int val;
8553 const xmlChar *cur;
8554
8555 if (ctxt == NULL)
8556 return(0);
8557 cur = ctxt->cur;
8558
8559 /*
8560 * We are supposed to handle UTF8, check it's valid
8561 * From rfc2044: encoding of the Unicode values on UTF-8:
8562 *
8563 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
8564 * 0000 0000-0000 007F 0xxxxxxx
8565 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
8566 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
8567 *
8568 * Check for the 0x110000 limit too
8569 */
8570 c = *cur;
8571 if (c & 0x80) {
8572 if ((cur[1] & 0xc0) != 0x80)
8573 goto encoding_error;
8574 if ((c & 0xe0) == 0xe0) {
8575
8576 if ((cur[2] & 0xc0) != 0x80)
8577 goto encoding_error;
8578 if ((c & 0xf0) == 0xf0) {
8579 if (((c & 0xf8) != 0xf0) ||
8580 ((cur[3] & 0xc0) != 0x80))
8581 goto encoding_error;
8582 /* 4-byte code */
8583 *len = 4;
8584 val = (cur[0] & 0x7) << 18;
8585 val |= (cur[1] & 0x3f) << 12;
8586 val |= (cur[2] & 0x3f) << 6;
8587 val |= cur[3] & 0x3f;
8588 } else {
8589 /* 3-byte code */
8590 *len = 3;
8591 val = (cur[0] & 0xf) << 12;
8592 val |= (cur[1] & 0x3f) << 6;
8593 val |= cur[2] & 0x3f;
8594 }
8595 } else {
8596 /* 2-byte code */
8597 *len = 2;
8598 val = (cur[0] & 0x1f) << 6;
8599 val |= cur[1] & 0x3f;
8600 }
8601 if (!IS_CHAR(val)) {
8602 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
8603 }
8604 return(val);
8605 } else {
8606 /* 1-byte code */
8607 *len = 1;
8608 return(*cur);
8609 }
8610 encoding_error:
8611 /*
8612 * If we detect an UTF8 error that probably means that the
8613 * input encoding didn't get properly advertised in the
8614 * declaration header. Report the error and switch the encoding
8615 * to ISO-Latin-1 (if you don't like this policy, just declare the
8616 * encoding !)
8617 */
8618 *len = 0;
8619 XP_ERROR0(XPATH_ENCODING_ERROR);
8620 }
8621
8622 /**
8623 * xmlXPathParseNCName:
8624 * @ctxt: the XPath Parser context
8625 *
8626 * parse an XML namespace non qualified name.
8627 *
8628 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
8629 *
8630 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
8631 * CombiningChar | Extender
8632 *
8633 * Returns the namespace name or NULL
8634 */
8635
8636 xmlChar *
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt)8637 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
8638 const xmlChar *in;
8639 xmlChar *ret;
8640 int count = 0;
8641
8642 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8643 /*
8644 * Accelerator for simple ASCII names
8645 */
8646 in = ctxt->cur;
8647 if (((*in >= 0x61) && (*in <= 0x7A)) ||
8648 ((*in >= 0x41) && (*in <= 0x5A)) ||
8649 (*in == '_')) {
8650 in++;
8651 while (((*in >= 0x61) && (*in <= 0x7A)) ||
8652 ((*in >= 0x41) && (*in <= 0x5A)) ||
8653 ((*in >= 0x30) && (*in <= 0x39)) ||
8654 (*in == '_') || (*in == '.') ||
8655 (*in == '-'))
8656 in++;
8657 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
8658 (*in == '[') || (*in == ']') || (*in == ':') ||
8659 (*in == '@') || (*in == '*')) {
8660 count = in - ctxt->cur;
8661 if (count == 0)
8662 return(NULL);
8663 ret = xmlStrndup(ctxt->cur, count);
8664 if (ret == NULL)
8665 xmlXPathPErrMemory(ctxt);
8666 ctxt->cur = in;
8667 return(ret);
8668 }
8669 }
8670 return(xmlXPathParseNameComplex(ctxt, 0));
8671 }
8672
8673
8674 /**
8675 * xmlXPathParseQName:
8676 * @ctxt: the XPath Parser context
8677 * @prefix: a xmlChar **
8678 *
8679 * parse an XML qualified name
8680 *
8681 * [NS 5] QName ::= (Prefix ':')? LocalPart
8682 *
8683 * [NS 6] Prefix ::= NCName
8684 *
8685 * [NS 7] LocalPart ::= NCName
8686 *
8687 * Returns the function returns the local part, and prefix is updated
8688 * to get the Prefix if any.
8689 */
8690
8691 static xmlChar *
xmlXPathParseQName(xmlXPathParserContextPtr ctxt,xmlChar ** prefix)8692 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
8693 xmlChar *ret = NULL;
8694
8695 *prefix = NULL;
8696 ret = xmlXPathParseNCName(ctxt);
8697 if (ret && CUR == ':') {
8698 *prefix = ret;
8699 NEXT;
8700 ret = xmlXPathParseNCName(ctxt);
8701 }
8702 return(ret);
8703 }
8704
8705 /**
8706 * xmlXPathParseName:
8707 * @ctxt: the XPath Parser context
8708 *
8709 * parse an XML name
8710 *
8711 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8712 * CombiningChar | Extender
8713 *
8714 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8715 *
8716 * Returns the namespace name or NULL
8717 */
8718
8719 xmlChar *
xmlXPathParseName(xmlXPathParserContextPtr ctxt)8720 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
8721 const xmlChar *in;
8722 xmlChar *ret;
8723 size_t count = 0;
8724
8725 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8726 /*
8727 * Accelerator for simple ASCII names
8728 */
8729 in = ctxt->cur;
8730 if (((*in >= 0x61) && (*in <= 0x7A)) ||
8731 ((*in >= 0x41) && (*in <= 0x5A)) ||
8732 (*in == '_') || (*in == ':')) {
8733 in++;
8734 while (((*in >= 0x61) && (*in <= 0x7A)) ||
8735 ((*in >= 0x41) && (*in <= 0x5A)) ||
8736 ((*in >= 0x30) && (*in <= 0x39)) ||
8737 (*in == '_') || (*in == '-') ||
8738 (*in == ':') || (*in == '.'))
8739 in++;
8740 if ((*in > 0) && (*in < 0x80)) {
8741 count = in - ctxt->cur;
8742 if (count > XML_MAX_NAME_LENGTH) {
8743 ctxt->cur = in;
8744 XP_ERRORNULL(XPATH_EXPR_ERROR);
8745 }
8746 ret = xmlStrndup(ctxt->cur, count);
8747 if (ret == NULL)
8748 xmlXPathPErrMemory(ctxt);
8749 ctxt->cur = in;
8750 return(ret);
8751 }
8752 }
8753 return(xmlXPathParseNameComplex(ctxt, 1));
8754 }
8755
8756 static xmlChar *
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,int qualified)8757 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
8758 xmlChar *ret;
8759 xmlChar buf[XML_MAX_NAMELEN + 5];
8760 int len = 0, l;
8761 int c;
8762
8763 /*
8764 * Handler for more complex cases
8765 */
8766 c = CUR_CHAR(l);
8767 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8768 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
8769 (c == '*') || /* accelerators */
8770 (!IS_LETTER(c) && (c != '_') &&
8771 ((!qualified) || (c != ':')))) {
8772 return(NULL);
8773 }
8774
8775 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8776 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8777 (c == '.') || (c == '-') ||
8778 (c == '_') || ((qualified) && (c == ':')) ||
8779 (IS_COMBINING(c)) ||
8780 (IS_EXTENDER(c)))) {
8781 COPY_BUF(l,buf,len,c);
8782 NEXTL(l);
8783 c = CUR_CHAR(l);
8784 if (len >= XML_MAX_NAMELEN) {
8785 /*
8786 * Okay someone managed to make a huge name, so he's ready to pay
8787 * for the processing speed.
8788 */
8789 xmlChar *buffer;
8790 int max = len * 2;
8791
8792 if (len > XML_MAX_NAME_LENGTH) {
8793 XP_ERRORNULL(XPATH_EXPR_ERROR);
8794 }
8795 buffer = (xmlChar *) xmlMallocAtomic(max);
8796 if (buffer == NULL) {
8797 xmlXPathPErrMemory(ctxt);
8798 return(NULL);
8799 }
8800 memcpy(buffer, buf, len);
8801 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
8802 (c == '.') || (c == '-') ||
8803 (c == '_') || ((qualified) && (c == ':')) ||
8804 (IS_COMBINING(c)) ||
8805 (IS_EXTENDER(c))) {
8806 if (len + 10 > max) {
8807 xmlChar *tmp;
8808 if (max > XML_MAX_NAME_LENGTH) {
8809 xmlFree(buffer);
8810 XP_ERRORNULL(XPATH_EXPR_ERROR);
8811 }
8812 max *= 2;
8813 tmp = (xmlChar *) xmlRealloc(buffer, max);
8814 if (tmp == NULL) {
8815 xmlFree(buffer);
8816 xmlXPathPErrMemory(ctxt);
8817 return(NULL);
8818 }
8819 buffer = tmp;
8820 }
8821 COPY_BUF(l,buffer,len,c);
8822 NEXTL(l);
8823 c = CUR_CHAR(l);
8824 }
8825 buffer[len] = 0;
8826 return(buffer);
8827 }
8828 }
8829 if (len == 0)
8830 return(NULL);
8831 ret = xmlStrndup(buf, len);
8832 if (ret == NULL)
8833 xmlXPathPErrMemory(ctxt);
8834 return(ret);
8835 }
8836
8837 #define MAX_FRAC 20
8838
8839 /**
8840 * xmlXPathStringEvalNumber:
8841 * @str: A string to scan
8842 *
8843 * [30a] Float ::= Number ('e' Digits?)?
8844 *
8845 * [30] Number ::= Digits ('.' Digits?)?
8846 * | '.' Digits
8847 * [31] Digits ::= [0-9]+
8848 *
8849 * Compile a Number in the string
8850 * In complement of the Number expression, this function also handles
8851 * negative values : '-' Number.
8852 *
8853 * Returns the double value.
8854 */
8855 double
xmlXPathStringEvalNumber(const xmlChar * str)8856 xmlXPathStringEvalNumber(const xmlChar *str) {
8857 const xmlChar *cur = str;
8858 double ret;
8859 int ok = 0;
8860 int isneg = 0;
8861 int exponent = 0;
8862 int is_exponent_negative = 0;
8863 #ifdef __GNUC__
8864 unsigned long tmp = 0;
8865 double temp;
8866 #endif
8867 if (cur == NULL) return(0);
8868 while (IS_BLANK_CH(*cur)) cur++;
8869 if (*cur == '-') {
8870 isneg = 1;
8871 cur++;
8872 }
8873 if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
8874 return(xmlXPathNAN);
8875 }
8876
8877 #ifdef __GNUC__
8878 /*
8879 * tmp/temp is a workaround against a gcc compiler bug
8880 * http://veillard.com/gcc.bug
8881 */
8882 ret = 0;
8883 while ((*cur >= '0') && (*cur <= '9')) {
8884 ret = ret * 10;
8885 tmp = (*cur - '0');
8886 ok = 1;
8887 cur++;
8888 temp = (double) tmp;
8889 ret = ret + temp;
8890 }
8891 #else
8892 ret = 0;
8893 while ((*cur >= '0') && (*cur <= '9')) {
8894 ret = ret * 10 + (*cur - '0');
8895 ok = 1;
8896 cur++;
8897 }
8898 #endif
8899
8900 if (*cur == '.') {
8901 int v, frac = 0, max;
8902 double fraction = 0;
8903
8904 cur++;
8905 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
8906 return(xmlXPathNAN);
8907 }
8908 while (*cur == '0') {
8909 frac = frac + 1;
8910 cur++;
8911 }
8912 max = frac + MAX_FRAC;
8913 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
8914 v = (*cur - '0');
8915 fraction = fraction * 10 + v;
8916 frac = frac + 1;
8917 cur++;
8918 }
8919 fraction /= pow(10.0, frac);
8920 ret = ret + fraction;
8921 while ((*cur >= '0') && (*cur <= '9'))
8922 cur++;
8923 }
8924 if ((*cur == 'e') || (*cur == 'E')) {
8925 cur++;
8926 if (*cur == '-') {
8927 is_exponent_negative = 1;
8928 cur++;
8929 } else if (*cur == '+') {
8930 cur++;
8931 }
8932 while ((*cur >= '0') && (*cur <= '9')) {
8933 if (exponent < 1000000)
8934 exponent = exponent * 10 + (*cur - '0');
8935 cur++;
8936 }
8937 }
8938 while (IS_BLANK_CH(*cur)) cur++;
8939 if (*cur != 0) return(xmlXPathNAN);
8940 if (isneg) ret = -ret;
8941 if (is_exponent_negative) exponent = -exponent;
8942 ret *= pow(10.0, (double)exponent);
8943 return(ret);
8944 }
8945
8946 /**
8947 * xmlXPathCompNumber:
8948 * @ctxt: the XPath Parser context
8949 *
8950 * [30] Number ::= Digits ('.' Digits?)?
8951 * | '.' Digits
8952 * [31] Digits ::= [0-9]+
8953 *
8954 * Compile a Number, then push it on the stack
8955 *
8956 */
8957 static void
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)8958 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
8959 {
8960 double ret = 0.0;
8961 int ok = 0;
8962 int exponent = 0;
8963 int is_exponent_negative = 0;
8964 xmlXPathObjectPtr num;
8965 #ifdef __GNUC__
8966 unsigned long tmp = 0;
8967 double temp;
8968 #endif
8969
8970 CHECK_ERROR;
8971 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
8972 XP_ERROR(XPATH_NUMBER_ERROR);
8973 }
8974 #ifdef __GNUC__
8975 /*
8976 * tmp/temp is a workaround against a gcc compiler bug
8977 * http://veillard.com/gcc.bug
8978 */
8979 ret = 0;
8980 while ((CUR >= '0') && (CUR <= '9')) {
8981 ret = ret * 10;
8982 tmp = (CUR - '0');
8983 ok = 1;
8984 NEXT;
8985 temp = (double) tmp;
8986 ret = ret + temp;
8987 }
8988 #else
8989 ret = 0;
8990 while ((CUR >= '0') && (CUR <= '9')) {
8991 ret = ret * 10 + (CUR - '0');
8992 ok = 1;
8993 NEXT;
8994 }
8995 #endif
8996 if (CUR == '.') {
8997 int v, frac = 0, max;
8998 double fraction = 0;
8999
9000 NEXT;
9001 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
9002 XP_ERROR(XPATH_NUMBER_ERROR);
9003 }
9004 while (CUR == '0') {
9005 frac = frac + 1;
9006 NEXT;
9007 }
9008 max = frac + MAX_FRAC;
9009 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
9010 v = (CUR - '0');
9011 fraction = fraction * 10 + v;
9012 frac = frac + 1;
9013 NEXT;
9014 }
9015 fraction /= pow(10.0, frac);
9016 ret = ret + fraction;
9017 while ((CUR >= '0') && (CUR <= '9'))
9018 NEXT;
9019 }
9020 if ((CUR == 'e') || (CUR == 'E')) {
9021 NEXT;
9022 if (CUR == '-') {
9023 is_exponent_negative = 1;
9024 NEXT;
9025 } else if (CUR == '+') {
9026 NEXT;
9027 }
9028 while ((CUR >= '0') && (CUR <= '9')) {
9029 if (exponent < 1000000)
9030 exponent = exponent * 10 + (CUR - '0');
9031 NEXT;
9032 }
9033 if (is_exponent_negative)
9034 exponent = -exponent;
9035 ret *= pow(10.0, (double) exponent);
9036 }
9037 num = xmlXPathCacheNewFloat(ctxt, ret);
9038 if (num == NULL) {
9039 ctxt->error = XPATH_MEMORY_ERROR;
9040 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
9041 NULL) == -1) {
9042 xmlXPathReleaseObject(ctxt->context, num);
9043 }
9044 }
9045
9046 /**
9047 * xmlXPathParseLiteral:
9048 * @ctxt: the XPath Parser context
9049 *
9050 * Parse a Literal
9051 *
9052 * [29] Literal ::= '"' [^"]* '"'
9053 * | "'" [^']* "'"
9054 *
9055 * Returns the value found or NULL in case of error
9056 */
9057 static xmlChar *
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt)9058 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
9059 const xmlChar *q;
9060 xmlChar *ret = NULL;
9061 int quote;
9062
9063 if (CUR == '"') {
9064 quote = '"';
9065 } else if (CUR == '\'') {
9066 quote = '\'';
9067 } else {
9068 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
9069 }
9070
9071 NEXT;
9072 q = CUR_PTR;
9073 while (CUR != quote) {
9074 int ch;
9075 int len = 4;
9076
9077 if (CUR == 0)
9078 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
9079 ch = xmlGetUTF8Char(CUR_PTR, &len);
9080 if ((ch < 0) || (IS_CHAR(ch) == 0))
9081 XP_ERRORNULL(XPATH_INVALID_CHAR_ERROR);
9082 CUR_PTR += len;
9083 }
9084 ret = xmlStrndup(q, CUR_PTR - q);
9085 if (ret == NULL)
9086 xmlXPathPErrMemory(ctxt);
9087 NEXT;
9088 return(ret);
9089 }
9090
9091 /**
9092 * xmlXPathCompLiteral:
9093 * @ctxt: the XPath Parser context
9094 *
9095 * Parse a Literal and push it on the stack.
9096 *
9097 * [29] Literal ::= '"' [^"]* '"'
9098 * | "'" [^']* "'"
9099 *
9100 * TODO: xmlXPathCompLiteral memory allocation could be improved.
9101 */
9102 static void
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt)9103 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
9104 xmlChar *ret = NULL;
9105 xmlXPathObjectPtr lit;
9106
9107 ret = xmlXPathParseLiteral(ctxt);
9108 if (ret == NULL)
9109 return;
9110 lit = xmlXPathCacheNewString(ctxt, ret);
9111 if (lit == NULL) {
9112 ctxt->error = XPATH_MEMORY_ERROR;
9113 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
9114 NULL) == -1) {
9115 xmlXPathReleaseObject(ctxt->context, lit);
9116 }
9117 xmlFree(ret);
9118 }
9119
9120 /**
9121 * xmlXPathCompVariableReference:
9122 * @ctxt: the XPath Parser context
9123 *
9124 * Parse a VariableReference, evaluate it and push it on the stack.
9125 *
9126 * The variable bindings consist of a mapping from variable names
9127 * to variable values. The value of a variable is an object, which can be
9128 * of any of the types that are possible for the value of an expression,
9129 * and may also be of additional types not specified here.
9130 *
9131 * Early evaluation is possible since:
9132 * The variable bindings [...] used to evaluate a subexpression are
9133 * always the same as those used to evaluate the containing expression.
9134 *
9135 * [36] VariableReference ::= '$' QName
9136 */
9137 static void
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt)9138 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
9139 xmlChar *name;
9140 xmlChar *prefix;
9141
9142 SKIP_BLANKS;
9143 if (CUR != '$') {
9144 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9145 }
9146 NEXT;
9147 name = xmlXPathParseQName(ctxt, &prefix);
9148 if (name == NULL) {
9149 xmlFree(prefix);
9150 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9151 }
9152 ctxt->comp->last = -1;
9153 if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
9154 xmlFree(prefix);
9155 xmlFree(name);
9156 }
9157 SKIP_BLANKS;
9158 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
9159 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
9160 }
9161 }
9162
9163 /**
9164 * xmlXPathIsNodeType:
9165 * @name: a name string
9166 *
9167 * Is the name given a NodeType one.
9168 *
9169 * [38] NodeType ::= 'comment'
9170 * | 'text'
9171 * | 'processing-instruction'
9172 * | 'node'
9173 *
9174 * Returns 1 if true 0 otherwise
9175 */
9176 int
xmlXPathIsNodeType(const xmlChar * name)9177 xmlXPathIsNodeType(const xmlChar *name) {
9178 if (name == NULL)
9179 return(0);
9180
9181 if (xmlStrEqual(name, BAD_CAST "node"))
9182 return(1);
9183 if (xmlStrEqual(name, BAD_CAST "text"))
9184 return(1);
9185 if (xmlStrEqual(name, BAD_CAST "comment"))
9186 return(1);
9187 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9188 return(1);
9189 return(0);
9190 }
9191
9192 /**
9193 * xmlXPathCompFunctionCall:
9194 * @ctxt: the XPath Parser context
9195 *
9196 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
9197 * [17] Argument ::= Expr
9198 *
9199 * Compile a function call, the evaluation of all arguments are
9200 * pushed on the stack
9201 */
9202 static void
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt)9203 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
9204 xmlChar *name;
9205 xmlChar *prefix;
9206 int nbargs = 0;
9207 int sort = 1;
9208
9209 name = xmlXPathParseQName(ctxt, &prefix);
9210 if (name == NULL) {
9211 xmlFree(prefix);
9212 XP_ERROR(XPATH_EXPR_ERROR);
9213 }
9214 SKIP_BLANKS;
9215
9216 if (CUR != '(') {
9217 xmlFree(name);
9218 xmlFree(prefix);
9219 XP_ERROR(XPATH_EXPR_ERROR);
9220 }
9221 NEXT;
9222 SKIP_BLANKS;
9223
9224 /*
9225 * Optimization for count(): we don't need the node-set to be sorted.
9226 */
9227 if ((prefix == NULL) && (name[0] == 'c') &&
9228 xmlStrEqual(name, BAD_CAST "count"))
9229 {
9230 sort = 0;
9231 }
9232 ctxt->comp->last = -1;
9233 if (CUR != ')') {
9234 while (CUR != 0) {
9235 int op1 = ctxt->comp->last;
9236 ctxt->comp->last = -1;
9237 xmlXPathCompileExpr(ctxt, sort);
9238 if (ctxt->error != XPATH_EXPRESSION_OK) {
9239 xmlFree(name);
9240 xmlFree(prefix);
9241 return;
9242 }
9243 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
9244 nbargs++;
9245 if (CUR == ')') break;
9246 if (CUR != ',') {
9247 xmlFree(name);
9248 xmlFree(prefix);
9249 XP_ERROR(XPATH_EXPR_ERROR);
9250 }
9251 NEXT;
9252 SKIP_BLANKS;
9253 }
9254 }
9255 if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
9256 xmlFree(prefix);
9257 xmlFree(name);
9258 }
9259 NEXT;
9260 SKIP_BLANKS;
9261 }
9262
9263 /**
9264 * xmlXPathCompPrimaryExpr:
9265 * @ctxt: the XPath Parser context
9266 *
9267 * [15] PrimaryExpr ::= VariableReference
9268 * | '(' Expr ')'
9269 * | Literal
9270 * | Number
9271 * | FunctionCall
9272 *
9273 * Compile a primary expression.
9274 */
9275 static void
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt)9276 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
9277 SKIP_BLANKS;
9278 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
9279 else if (CUR == '(') {
9280 NEXT;
9281 SKIP_BLANKS;
9282 xmlXPathCompileExpr(ctxt, 1);
9283 CHECK_ERROR;
9284 if (CUR != ')') {
9285 XP_ERROR(XPATH_EXPR_ERROR);
9286 }
9287 NEXT;
9288 SKIP_BLANKS;
9289 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9290 xmlXPathCompNumber(ctxt);
9291 } else if ((CUR == '\'') || (CUR == '"')) {
9292 xmlXPathCompLiteral(ctxt);
9293 } else {
9294 xmlXPathCompFunctionCall(ctxt);
9295 }
9296 SKIP_BLANKS;
9297 }
9298
9299 /**
9300 * xmlXPathCompFilterExpr:
9301 * @ctxt: the XPath Parser context
9302 *
9303 * [20] FilterExpr ::= PrimaryExpr
9304 * | FilterExpr Predicate
9305 *
9306 * Compile a filter expression.
9307 * Square brackets are used to filter expressions in the same way that
9308 * they are used in location paths. It is an error if the expression to
9309 * be filtered does not evaluate to a node-set. The context node list
9310 * used for evaluating the expression in square brackets is the node-set
9311 * to be filtered listed in document order.
9312 */
9313
9314 static void
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt)9315 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
9316 xmlXPathCompPrimaryExpr(ctxt);
9317 CHECK_ERROR;
9318 SKIP_BLANKS;
9319
9320 while (CUR == '[') {
9321 xmlXPathCompPredicate(ctxt, 1);
9322 SKIP_BLANKS;
9323 }
9324
9325
9326 }
9327
9328 /**
9329 * xmlXPathScanName:
9330 * @ctxt: the XPath Parser context
9331 *
9332 * Trickery: parse an XML name but without consuming the input flow
9333 * Needed to avoid insanity in the parser state.
9334 *
9335 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9336 * CombiningChar | Extender
9337 *
9338 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9339 *
9340 * [6] Names ::= Name (S Name)*
9341 *
9342 * Returns the Name parsed or NULL
9343 */
9344
9345 static xmlChar *
xmlXPathScanName(xmlXPathParserContextPtr ctxt)9346 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
9347 int l;
9348 int c;
9349 const xmlChar *cur;
9350 xmlChar *ret;
9351
9352 cur = ctxt->cur;
9353
9354 c = CUR_CHAR(l);
9355 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9356 (!IS_LETTER(c) && (c != '_') &&
9357 (c != ':'))) {
9358 return(NULL);
9359 }
9360
9361 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9362 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9363 (c == '.') || (c == '-') ||
9364 (c == '_') || (c == ':') ||
9365 (IS_COMBINING(c)) ||
9366 (IS_EXTENDER(c)))) {
9367 NEXTL(l);
9368 c = CUR_CHAR(l);
9369 }
9370 ret = xmlStrndup(cur, ctxt->cur - cur);
9371 if (ret == NULL)
9372 xmlXPathPErrMemory(ctxt);
9373 ctxt->cur = cur;
9374 return(ret);
9375 }
9376
9377 /**
9378 * xmlXPathCompPathExpr:
9379 * @ctxt: the XPath Parser context
9380 *
9381 * [19] PathExpr ::= LocationPath
9382 * | FilterExpr
9383 * | FilterExpr '/' RelativeLocationPath
9384 * | FilterExpr '//' RelativeLocationPath
9385 *
9386 * Compile a path expression.
9387 * The / operator and // operators combine an arbitrary expression
9388 * and a relative location path. It is an error if the expression
9389 * does not evaluate to a node-set.
9390 * The / operator does composition in the same way as when / is
9391 * used in a location path. As in location paths, // is short for
9392 * /descendant-or-self::node()/.
9393 */
9394
9395 static void
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt)9396 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
9397 int lc = 1; /* Should we branch to LocationPath ? */
9398 xmlChar *name = NULL; /* we may have to preparse a name to find out */
9399
9400 SKIP_BLANKS;
9401 if ((CUR == '$') || (CUR == '(') ||
9402 (IS_ASCII_DIGIT(CUR)) ||
9403 (CUR == '\'') || (CUR == '"') ||
9404 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9405 lc = 0;
9406 } else if (CUR == '*') {
9407 /* relative or absolute location path */
9408 lc = 1;
9409 } else if (CUR == '/') {
9410 /* relative or absolute location path */
9411 lc = 1;
9412 } else if (CUR == '@') {
9413 /* relative abbreviated attribute location path */
9414 lc = 1;
9415 } else if (CUR == '.') {
9416 /* relative abbreviated attribute location path */
9417 lc = 1;
9418 } else {
9419 /*
9420 * Problem is finding if we have a name here whether it's:
9421 * - a nodetype
9422 * - a function call in which case it's followed by '('
9423 * - an axis in which case it's followed by ':'
9424 * - a element name
9425 * We do an a priori analysis here rather than having to
9426 * maintain parsed token content through the recursive function
9427 * calls. This looks uglier but makes the code easier to
9428 * read/write/debug.
9429 */
9430 SKIP_BLANKS;
9431 name = xmlXPathScanName(ctxt);
9432 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
9433 lc = 1;
9434 xmlFree(name);
9435 } else if (name != NULL) {
9436 int len =xmlStrlen(name);
9437
9438
9439 while (NXT(len) != 0) {
9440 if (NXT(len) == '/') {
9441 /* element name */
9442 lc = 1;
9443 break;
9444 } else if (IS_BLANK_CH(NXT(len))) {
9445 /* ignore blanks */
9446 ;
9447 } else if (NXT(len) == ':') {
9448 lc = 1;
9449 break;
9450 } else if ((NXT(len) == '(')) {
9451 /* Node Type or Function */
9452 if (xmlXPathIsNodeType(name)) {
9453 lc = 1;
9454 } else {
9455 lc = 0;
9456 }
9457 break;
9458 } else if ((NXT(len) == '[')) {
9459 /* element name */
9460 lc = 1;
9461 break;
9462 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
9463 (NXT(len) == '=')) {
9464 lc = 1;
9465 break;
9466 } else {
9467 lc = 1;
9468 break;
9469 }
9470 len++;
9471 }
9472 if (NXT(len) == 0) {
9473 /* element name */
9474 lc = 1;
9475 }
9476 xmlFree(name);
9477 } else {
9478 /* make sure all cases are covered explicitly */
9479 XP_ERROR(XPATH_EXPR_ERROR);
9480 }
9481 }
9482
9483 if (lc) {
9484 if (CUR == '/') {
9485 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
9486 } else {
9487 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9488 }
9489 xmlXPathCompLocationPath(ctxt);
9490 } else {
9491 xmlXPathCompFilterExpr(ctxt);
9492 CHECK_ERROR;
9493 if ((CUR == '/') && (NXT(1) == '/')) {
9494 SKIP(2);
9495 SKIP_BLANKS;
9496
9497 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9498 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9499
9500 xmlXPathCompRelativeLocationPath(ctxt);
9501 } else if (CUR == '/') {
9502 xmlXPathCompRelativeLocationPath(ctxt);
9503 }
9504 }
9505 SKIP_BLANKS;
9506 }
9507
9508 /**
9509 * xmlXPathCompUnionExpr:
9510 * @ctxt: the XPath Parser context
9511 *
9512 * [18] UnionExpr ::= PathExpr
9513 * | UnionExpr '|' PathExpr
9514 *
9515 * Compile an union expression.
9516 */
9517
9518 static void
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt)9519 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
9520 xmlXPathCompPathExpr(ctxt);
9521 CHECK_ERROR;
9522 SKIP_BLANKS;
9523 while (CUR == '|') {
9524 int op1 = ctxt->comp->last;
9525 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9526
9527 NEXT;
9528 SKIP_BLANKS;
9529 xmlXPathCompPathExpr(ctxt);
9530
9531 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
9532
9533 SKIP_BLANKS;
9534 }
9535 }
9536
9537 /**
9538 * xmlXPathCompUnaryExpr:
9539 * @ctxt: the XPath Parser context
9540 *
9541 * [27] UnaryExpr ::= UnionExpr
9542 * | '-' UnaryExpr
9543 *
9544 * Compile an unary expression.
9545 */
9546
9547 static void
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt)9548 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
9549 int minus = 0;
9550 int found = 0;
9551
9552 SKIP_BLANKS;
9553 while (CUR == '-') {
9554 minus = 1 - minus;
9555 found = 1;
9556 NEXT;
9557 SKIP_BLANKS;
9558 }
9559
9560 xmlXPathCompUnionExpr(ctxt);
9561 CHECK_ERROR;
9562 if (found) {
9563 if (minus)
9564 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
9565 else
9566 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
9567 }
9568 }
9569
9570 /**
9571 * xmlXPathCompMultiplicativeExpr:
9572 * @ctxt: the XPath Parser context
9573 *
9574 * [26] MultiplicativeExpr ::= UnaryExpr
9575 * | MultiplicativeExpr MultiplyOperator UnaryExpr
9576 * | MultiplicativeExpr 'div' UnaryExpr
9577 * | MultiplicativeExpr 'mod' UnaryExpr
9578 * [34] MultiplyOperator ::= '*'
9579 *
9580 * Compile an Additive expression.
9581 */
9582
9583 static void
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt)9584 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
9585 xmlXPathCompUnaryExpr(ctxt);
9586 CHECK_ERROR;
9587 SKIP_BLANKS;
9588 while ((CUR == '*') ||
9589 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
9590 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
9591 int op = -1;
9592 int op1 = ctxt->comp->last;
9593
9594 if (CUR == '*') {
9595 op = 0;
9596 NEXT;
9597 } else if (CUR == 'd') {
9598 op = 1;
9599 SKIP(3);
9600 } else if (CUR == 'm') {
9601 op = 2;
9602 SKIP(3);
9603 }
9604 SKIP_BLANKS;
9605 xmlXPathCompUnaryExpr(ctxt);
9606 CHECK_ERROR;
9607 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
9608 SKIP_BLANKS;
9609 }
9610 }
9611
9612 /**
9613 * xmlXPathCompAdditiveExpr:
9614 * @ctxt: the XPath Parser context
9615 *
9616 * [25] AdditiveExpr ::= MultiplicativeExpr
9617 * | AdditiveExpr '+' MultiplicativeExpr
9618 * | AdditiveExpr '-' MultiplicativeExpr
9619 *
9620 * Compile an Additive expression.
9621 */
9622
9623 static void
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt)9624 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
9625
9626 xmlXPathCompMultiplicativeExpr(ctxt);
9627 CHECK_ERROR;
9628 SKIP_BLANKS;
9629 while ((CUR == '+') || (CUR == '-')) {
9630 int plus;
9631 int op1 = ctxt->comp->last;
9632
9633 if (CUR == '+') plus = 1;
9634 else plus = 0;
9635 NEXT;
9636 SKIP_BLANKS;
9637 xmlXPathCompMultiplicativeExpr(ctxt);
9638 CHECK_ERROR;
9639 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
9640 SKIP_BLANKS;
9641 }
9642 }
9643
9644 /**
9645 * xmlXPathCompRelationalExpr:
9646 * @ctxt: the XPath Parser context
9647 *
9648 * [24] RelationalExpr ::= AdditiveExpr
9649 * | RelationalExpr '<' AdditiveExpr
9650 * | RelationalExpr '>' AdditiveExpr
9651 * | RelationalExpr '<=' AdditiveExpr
9652 * | RelationalExpr '>=' AdditiveExpr
9653 *
9654 * A <= B > C is allowed ? Answer from James, yes with
9655 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
9656 * which is basically what got implemented.
9657 *
9658 * Compile a Relational expression, then push the result
9659 * on the stack
9660 */
9661
9662 static void
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt)9663 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
9664 xmlXPathCompAdditiveExpr(ctxt);
9665 CHECK_ERROR;
9666 SKIP_BLANKS;
9667 while ((CUR == '<') || (CUR == '>')) {
9668 int inf, strict;
9669 int op1 = ctxt->comp->last;
9670
9671 if (CUR == '<') inf = 1;
9672 else inf = 0;
9673 if (NXT(1) == '=') strict = 0;
9674 else strict = 1;
9675 NEXT;
9676 if (!strict) NEXT;
9677 SKIP_BLANKS;
9678 xmlXPathCompAdditiveExpr(ctxt);
9679 CHECK_ERROR;
9680 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
9681 SKIP_BLANKS;
9682 }
9683 }
9684
9685 /**
9686 * xmlXPathCompEqualityExpr:
9687 * @ctxt: the XPath Parser context
9688 *
9689 * [23] EqualityExpr ::= RelationalExpr
9690 * | EqualityExpr '=' RelationalExpr
9691 * | EqualityExpr '!=' RelationalExpr
9692 *
9693 * A != B != C is allowed ? Answer from James, yes with
9694 * (RelationalExpr = RelationalExpr) = RelationalExpr
9695 * (RelationalExpr != RelationalExpr) != RelationalExpr
9696 * which is basically what got implemented.
9697 *
9698 * Compile an Equality expression.
9699 *
9700 */
9701 static void
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt)9702 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
9703 xmlXPathCompRelationalExpr(ctxt);
9704 CHECK_ERROR;
9705 SKIP_BLANKS;
9706 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
9707 int eq;
9708 int op1 = ctxt->comp->last;
9709
9710 if (CUR == '=') eq = 1;
9711 else eq = 0;
9712 NEXT;
9713 if (!eq) NEXT;
9714 SKIP_BLANKS;
9715 xmlXPathCompRelationalExpr(ctxt);
9716 CHECK_ERROR;
9717 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
9718 SKIP_BLANKS;
9719 }
9720 }
9721
9722 /**
9723 * xmlXPathCompAndExpr:
9724 * @ctxt: the XPath Parser context
9725 *
9726 * [22] AndExpr ::= EqualityExpr
9727 * | AndExpr 'and' EqualityExpr
9728 *
9729 * Compile an AND expression.
9730 *
9731 */
9732 static void
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt)9733 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
9734 xmlXPathCompEqualityExpr(ctxt);
9735 CHECK_ERROR;
9736 SKIP_BLANKS;
9737 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
9738 int op1 = ctxt->comp->last;
9739 SKIP(3);
9740 SKIP_BLANKS;
9741 xmlXPathCompEqualityExpr(ctxt);
9742 CHECK_ERROR;
9743 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
9744 SKIP_BLANKS;
9745 }
9746 }
9747
9748 /**
9749 * xmlXPathCompileExpr:
9750 * @ctxt: the XPath Parser context
9751 *
9752 * [14] Expr ::= OrExpr
9753 * [21] OrExpr ::= AndExpr
9754 * | OrExpr 'or' AndExpr
9755 *
9756 * Parse and compile an expression
9757 */
9758 static void
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt,int sort)9759 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
9760 xmlXPathContextPtr xpctxt = ctxt->context;
9761
9762 if (xpctxt != NULL) {
9763 if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
9764 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9765 /*
9766 * Parsing a single '(' pushes about 10 functions on the call stack
9767 * before recursing!
9768 */
9769 xpctxt->depth += 10;
9770 }
9771
9772 xmlXPathCompAndExpr(ctxt);
9773 CHECK_ERROR;
9774 SKIP_BLANKS;
9775 while ((CUR == 'o') && (NXT(1) == 'r')) {
9776 int op1 = ctxt->comp->last;
9777 SKIP(2);
9778 SKIP_BLANKS;
9779 xmlXPathCompAndExpr(ctxt);
9780 CHECK_ERROR;
9781 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
9782 SKIP_BLANKS;
9783 }
9784 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
9785 /* more ops could be optimized too */
9786 /*
9787 * This is the main place to eliminate sorting for
9788 * operations which don't require a sorted node-set.
9789 * E.g. count().
9790 */
9791 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
9792 }
9793
9794 if (xpctxt != NULL)
9795 xpctxt->depth -= 10;
9796 }
9797
9798 /**
9799 * xmlXPathCompPredicate:
9800 * @ctxt: the XPath Parser context
9801 * @filter: act as a filter
9802 *
9803 * [8] Predicate ::= '[' PredicateExpr ']'
9804 * [9] PredicateExpr ::= Expr
9805 *
9806 * Compile a predicate expression
9807 */
9808 static void
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt,int filter)9809 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
9810 int op1 = ctxt->comp->last;
9811
9812 SKIP_BLANKS;
9813 if (CUR != '[') {
9814 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9815 }
9816 NEXT;
9817 SKIP_BLANKS;
9818
9819 ctxt->comp->last = -1;
9820 /*
9821 * This call to xmlXPathCompileExpr() will deactivate sorting
9822 * of the predicate result.
9823 * TODO: Sorting is still activated for filters, since I'm not
9824 * sure if needed. Normally sorting should not be needed, since
9825 * a filter can only diminish the number of items in a sequence,
9826 * but won't change its order; so if the initial sequence is sorted,
9827 * subsequent sorting is not needed.
9828 */
9829 if (! filter)
9830 xmlXPathCompileExpr(ctxt, 0);
9831 else
9832 xmlXPathCompileExpr(ctxt, 1);
9833 CHECK_ERROR;
9834
9835 if (CUR != ']') {
9836 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9837 }
9838
9839 if (filter)
9840 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
9841 else
9842 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
9843
9844 NEXT;
9845 SKIP_BLANKS;
9846 }
9847
9848 /**
9849 * xmlXPathCompNodeTest:
9850 * @ctxt: the XPath Parser context
9851 * @test: pointer to a xmlXPathTestVal
9852 * @type: pointer to a xmlXPathTypeVal
9853 * @prefix: placeholder for a possible name prefix
9854 *
9855 * [7] NodeTest ::= NameTest
9856 * | NodeType '(' ')'
9857 * | 'processing-instruction' '(' Literal ')'
9858 *
9859 * [37] NameTest ::= '*'
9860 * | NCName ':' '*'
9861 * | QName
9862 * [38] NodeType ::= 'comment'
9863 * | 'text'
9864 * | 'processing-instruction'
9865 * | 'node'
9866 *
9867 * Returns the name found and updates @test, @type and @prefix appropriately
9868 */
9869 static xmlChar *
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt,xmlXPathTestVal * test,xmlXPathTypeVal * type,xmlChar ** prefix,xmlChar * name)9870 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
9871 xmlXPathTypeVal *type, xmlChar **prefix,
9872 xmlChar *name) {
9873 int blanks;
9874
9875 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
9876 return(NULL);
9877 }
9878 *type = (xmlXPathTypeVal) 0;
9879 *test = (xmlXPathTestVal) 0;
9880 *prefix = NULL;
9881 SKIP_BLANKS;
9882
9883 if ((name == NULL) && (CUR == '*')) {
9884 /*
9885 * All elements
9886 */
9887 NEXT;
9888 *test = NODE_TEST_ALL;
9889 return(NULL);
9890 }
9891
9892 if (name == NULL)
9893 name = xmlXPathParseNCName(ctxt);
9894 if (name == NULL) {
9895 XP_ERRORNULL(XPATH_EXPR_ERROR);
9896 }
9897
9898 blanks = IS_BLANK_CH(CUR);
9899 SKIP_BLANKS;
9900 if (CUR == '(') {
9901 NEXT;
9902 /*
9903 * NodeType or PI search
9904 */
9905 if (xmlStrEqual(name, BAD_CAST "comment"))
9906 *type = NODE_TYPE_COMMENT;
9907 else if (xmlStrEqual(name, BAD_CAST "node"))
9908 *type = NODE_TYPE_NODE;
9909 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9910 *type = NODE_TYPE_PI;
9911 else if (xmlStrEqual(name, BAD_CAST "text"))
9912 *type = NODE_TYPE_TEXT;
9913 else {
9914 if (name != NULL)
9915 xmlFree(name);
9916 XP_ERRORNULL(XPATH_EXPR_ERROR);
9917 }
9918
9919 *test = NODE_TEST_TYPE;
9920
9921 SKIP_BLANKS;
9922 if (*type == NODE_TYPE_PI) {
9923 /*
9924 * Specific case: search a PI by name.
9925 */
9926 if (name != NULL)
9927 xmlFree(name);
9928 name = NULL;
9929 if (CUR != ')') {
9930 name = xmlXPathParseLiteral(ctxt);
9931 *test = NODE_TEST_PI;
9932 SKIP_BLANKS;
9933 }
9934 }
9935 if (CUR != ')') {
9936 if (name != NULL)
9937 xmlFree(name);
9938 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
9939 }
9940 NEXT;
9941 return(name);
9942 }
9943 *test = NODE_TEST_NAME;
9944 if ((!blanks) && (CUR == ':')) {
9945 NEXT;
9946
9947 /*
9948 * Since currently the parser context don't have a
9949 * namespace list associated:
9950 * The namespace name for this prefix can be computed
9951 * only at evaluation time. The compilation is done
9952 * outside of any context.
9953 */
9954 #if 0
9955 *prefix = xmlXPathNsLookup(ctxt->context, name);
9956 if (name != NULL)
9957 xmlFree(name);
9958 if (*prefix == NULL) {
9959 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9960 }
9961 #else
9962 *prefix = name;
9963 #endif
9964
9965 if (CUR == '*') {
9966 /*
9967 * All elements
9968 */
9969 NEXT;
9970 *test = NODE_TEST_ALL;
9971 return(NULL);
9972 }
9973
9974 name = xmlXPathParseNCName(ctxt);
9975 if (name == NULL) {
9976 XP_ERRORNULL(XPATH_EXPR_ERROR);
9977 }
9978 }
9979 return(name);
9980 }
9981
9982 /**
9983 * xmlXPathIsAxisName:
9984 * @name: a preparsed name token
9985 *
9986 * [6] AxisName ::= 'ancestor'
9987 * | 'ancestor-or-self'
9988 * | 'attribute'
9989 * | 'child'
9990 * | 'descendant'
9991 * | 'descendant-or-self'
9992 * | 'following'
9993 * | 'following-sibling'
9994 * | 'namespace'
9995 * | 'parent'
9996 * | 'preceding'
9997 * | 'preceding-sibling'
9998 * | 'self'
9999 *
10000 * Returns the axis or 0
10001 */
10002 static xmlXPathAxisVal
xmlXPathIsAxisName(const xmlChar * name)10003 xmlXPathIsAxisName(const xmlChar *name) {
10004 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
10005 switch (name[0]) {
10006 case 'a':
10007 if (xmlStrEqual(name, BAD_CAST "ancestor"))
10008 ret = AXIS_ANCESTOR;
10009 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
10010 ret = AXIS_ANCESTOR_OR_SELF;
10011 if (xmlStrEqual(name, BAD_CAST "attribute"))
10012 ret = AXIS_ATTRIBUTE;
10013 break;
10014 case 'c':
10015 if (xmlStrEqual(name, BAD_CAST "child"))
10016 ret = AXIS_CHILD;
10017 break;
10018 case 'd':
10019 if (xmlStrEqual(name, BAD_CAST "descendant"))
10020 ret = AXIS_DESCENDANT;
10021 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
10022 ret = AXIS_DESCENDANT_OR_SELF;
10023 break;
10024 case 'f':
10025 if (xmlStrEqual(name, BAD_CAST "following"))
10026 ret = AXIS_FOLLOWING;
10027 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
10028 ret = AXIS_FOLLOWING_SIBLING;
10029 break;
10030 case 'n':
10031 if (xmlStrEqual(name, BAD_CAST "namespace"))
10032 ret = AXIS_NAMESPACE;
10033 break;
10034 case 'p':
10035 if (xmlStrEqual(name, BAD_CAST "parent"))
10036 ret = AXIS_PARENT;
10037 if (xmlStrEqual(name, BAD_CAST "preceding"))
10038 ret = AXIS_PRECEDING;
10039 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
10040 ret = AXIS_PRECEDING_SIBLING;
10041 break;
10042 case 's':
10043 if (xmlStrEqual(name, BAD_CAST "self"))
10044 ret = AXIS_SELF;
10045 break;
10046 }
10047 return(ret);
10048 }
10049
10050 /**
10051 * xmlXPathCompStep:
10052 * @ctxt: the XPath Parser context
10053 *
10054 * [4] Step ::= AxisSpecifier NodeTest Predicate*
10055 * | AbbreviatedStep
10056 *
10057 * [12] AbbreviatedStep ::= '.' | '..'
10058 *
10059 * [5] AxisSpecifier ::= AxisName '::'
10060 * | AbbreviatedAxisSpecifier
10061 *
10062 * [13] AbbreviatedAxisSpecifier ::= '@'?
10063 *
10064 * Modified for XPtr range support as:
10065 *
10066 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
10067 * | AbbreviatedStep
10068 * | 'range-to' '(' Expr ')' Predicate*
10069 *
10070 * Compile one step in a Location Path
10071 * A location step of . is short for self::node(). This is
10072 * particularly useful in conjunction with //. For example, the
10073 * location path .//para is short for
10074 * self::node()/descendant-or-self::node()/child::para
10075 * and so will select all para descendant elements of the context
10076 * node.
10077 * Similarly, a location step of .. is short for parent::node().
10078 * For example, ../title is short for parent::node()/child::title
10079 * and so will select the title children of the parent of the context
10080 * node.
10081 */
10082 static void
xmlXPathCompStep(xmlXPathParserContextPtr ctxt)10083 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
10084 SKIP_BLANKS;
10085 if ((CUR == '.') && (NXT(1) == '.')) {
10086 SKIP(2);
10087 SKIP_BLANKS;
10088 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
10089 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10090 } else if (CUR == '.') {
10091 NEXT;
10092 SKIP_BLANKS;
10093 } else {
10094 xmlChar *name = NULL;
10095 xmlChar *prefix = NULL;
10096 xmlXPathTestVal test = (xmlXPathTestVal) 0;
10097 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
10098 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
10099 int op1;
10100
10101 if (CUR == '*') {
10102 axis = AXIS_CHILD;
10103 } else {
10104 if (name == NULL)
10105 name = xmlXPathParseNCName(ctxt);
10106 if (name != NULL) {
10107 axis = xmlXPathIsAxisName(name);
10108 if (axis != 0) {
10109 SKIP_BLANKS;
10110 if ((CUR == ':') && (NXT(1) == ':')) {
10111 SKIP(2);
10112 xmlFree(name);
10113 name = NULL;
10114 } else {
10115 /* an element name can conflict with an axis one :-\ */
10116 axis = AXIS_CHILD;
10117 }
10118 } else {
10119 axis = AXIS_CHILD;
10120 }
10121 } else if (CUR == '@') {
10122 NEXT;
10123 axis = AXIS_ATTRIBUTE;
10124 } else {
10125 axis = AXIS_CHILD;
10126 }
10127 }
10128
10129 if (ctxt->error != XPATH_EXPRESSION_OK) {
10130 xmlFree(name);
10131 return;
10132 }
10133
10134 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
10135 if (test == 0)
10136 return;
10137
10138 if ((prefix != NULL) && (ctxt->context != NULL) &&
10139 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
10140 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
10141 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
10142 }
10143 }
10144
10145 op1 = ctxt->comp->last;
10146 ctxt->comp->last = -1;
10147
10148 SKIP_BLANKS;
10149 while (CUR == '[') {
10150 xmlXPathCompPredicate(ctxt, 0);
10151 }
10152
10153 if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
10154 test, type, (void *)prefix, (void *)name) == -1) {
10155 xmlFree(prefix);
10156 xmlFree(name);
10157 }
10158 }
10159 }
10160
10161 /**
10162 * xmlXPathCompRelativeLocationPath:
10163 * @ctxt: the XPath Parser context
10164 *
10165 * [3] RelativeLocationPath ::= Step
10166 * | RelativeLocationPath '/' Step
10167 * | AbbreviatedRelativeLocationPath
10168 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
10169 *
10170 * Compile a relative location path.
10171 */
10172 static void
xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt)10173 xmlXPathCompRelativeLocationPath
10174 (xmlXPathParserContextPtr ctxt) {
10175 SKIP_BLANKS;
10176 if ((CUR == '/') && (NXT(1) == '/')) {
10177 SKIP(2);
10178 SKIP_BLANKS;
10179 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10180 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10181 } else if (CUR == '/') {
10182 NEXT;
10183 SKIP_BLANKS;
10184 }
10185 xmlXPathCompStep(ctxt);
10186 CHECK_ERROR;
10187 SKIP_BLANKS;
10188 while (CUR == '/') {
10189 if ((CUR == '/') && (NXT(1) == '/')) {
10190 SKIP(2);
10191 SKIP_BLANKS;
10192 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10193 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10194 xmlXPathCompStep(ctxt);
10195 } else if (CUR == '/') {
10196 NEXT;
10197 SKIP_BLANKS;
10198 xmlXPathCompStep(ctxt);
10199 }
10200 SKIP_BLANKS;
10201 }
10202 }
10203
10204 /**
10205 * xmlXPathCompLocationPath:
10206 * @ctxt: the XPath Parser context
10207 *
10208 * [1] LocationPath ::= RelativeLocationPath
10209 * | AbsoluteLocationPath
10210 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
10211 * | AbbreviatedAbsoluteLocationPath
10212 * [10] AbbreviatedAbsoluteLocationPath ::=
10213 * '//' RelativeLocationPath
10214 *
10215 * Compile a location path
10216 *
10217 * // is short for /descendant-or-self::node()/. For example,
10218 * //para is short for /descendant-or-self::node()/child::para and
10219 * so will select any para element in the document (even a para element
10220 * that is a document element will be selected by //para since the
10221 * document element node is a child of the root node); div//para is
10222 * short for div/descendant-or-self::node()/child::para and so will
10223 * select all para descendants of div children.
10224 */
10225 static void
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt)10226 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
10227 SKIP_BLANKS;
10228 if (CUR != '/') {
10229 xmlXPathCompRelativeLocationPath(ctxt);
10230 } else {
10231 while (CUR == '/') {
10232 if ((CUR == '/') && (NXT(1) == '/')) {
10233 SKIP(2);
10234 SKIP_BLANKS;
10235 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10236 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10237 xmlXPathCompRelativeLocationPath(ctxt);
10238 } else if (CUR == '/') {
10239 NEXT;
10240 SKIP_BLANKS;
10241 if ((CUR != 0 ) &&
10242 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
10243 (CUR == '@') || (CUR == '*')))
10244 xmlXPathCompRelativeLocationPath(ctxt);
10245 }
10246 CHECK_ERROR;
10247 }
10248 }
10249 }
10250
10251 /************************************************************************
10252 * *
10253 * XPath precompiled expression evaluation *
10254 * *
10255 ************************************************************************/
10256
10257 static int
10258 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
10259
10260 /**
10261 * xmlXPathNodeSetFilter:
10262 * @ctxt: the XPath Parser context
10263 * @set: the node set to filter
10264 * @filterOpIndex: the index of the predicate/filter op
10265 * @minPos: minimum position in the filtered set (1-based)
10266 * @maxPos: maximum position in the filtered set (1-based)
10267 * @hasNsNodes: true if the node set may contain namespace nodes
10268 *
10269 * Filter a node set, keeping only nodes for which the predicate expression
10270 * matches. Afterwards, keep only nodes between minPos and maxPos in the
10271 * filtered result.
10272 */
10273 static void
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,xmlNodeSetPtr set,int filterOpIndex,int minPos,int maxPos,int hasNsNodes)10274 xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
10275 xmlNodeSetPtr set,
10276 int filterOpIndex,
10277 int minPos, int maxPos,
10278 int hasNsNodes)
10279 {
10280 xmlXPathContextPtr xpctxt;
10281 xmlNodePtr oldnode;
10282 xmlDocPtr olddoc;
10283 xmlXPathStepOpPtr filterOp;
10284 int oldcs, oldpp;
10285 int i, j, pos;
10286
10287 if ((set == NULL) || (set->nodeNr == 0))
10288 return;
10289
10290 /*
10291 * Check if the node set contains a sufficient number of nodes for
10292 * the requested range.
10293 */
10294 if (set->nodeNr < minPos) {
10295 xmlXPathNodeSetClear(set, hasNsNodes);
10296 return;
10297 }
10298
10299 xpctxt = ctxt->context;
10300 oldnode = xpctxt->node;
10301 olddoc = xpctxt->doc;
10302 oldcs = xpctxt->contextSize;
10303 oldpp = xpctxt->proximityPosition;
10304 filterOp = &ctxt->comp->steps[filterOpIndex];
10305
10306 xpctxt->contextSize = set->nodeNr;
10307
10308 for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
10309 xmlNodePtr node = set->nodeTab[i];
10310 int res;
10311
10312 xpctxt->node = node;
10313 xpctxt->proximityPosition = i + 1;
10314
10315 /*
10316 * Also set the xpath document in case things like
10317 * key() are evaluated in the predicate.
10318 *
10319 * TODO: Get real doc for namespace nodes.
10320 */
10321 if ((node->type != XML_NAMESPACE_DECL) &&
10322 (node->doc != NULL))
10323 xpctxt->doc = node->doc;
10324
10325 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
10326
10327 if (ctxt->error != XPATH_EXPRESSION_OK)
10328 break;
10329 if (res < 0) {
10330 /* Shouldn't happen */
10331 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
10332 break;
10333 }
10334
10335 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
10336 if (i != j) {
10337 set->nodeTab[j] = node;
10338 set->nodeTab[i] = NULL;
10339 }
10340
10341 j += 1;
10342 } else {
10343 /* Remove the entry from the initial node set. */
10344 set->nodeTab[i] = NULL;
10345 if (node->type == XML_NAMESPACE_DECL)
10346 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10347 }
10348
10349 if (res != 0) {
10350 if (pos == maxPos) {
10351 i += 1;
10352 break;
10353 }
10354
10355 pos += 1;
10356 }
10357 }
10358
10359 /* Free remaining nodes. */
10360 if (hasNsNodes) {
10361 for (; i < set->nodeNr; i++) {
10362 xmlNodePtr node = set->nodeTab[i];
10363 if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
10364 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10365 }
10366 }
10367
10368 set->nodeNr = j;
10369
10370 /* If too many elements were removed, shrink table to preserve memory. */
10371 if ((set->nodeMax > XML_NODESET_DEFAULT) &&
10372 (set->nodeNr < set->nodeMax / 2)) {
10373 xmlNodePtr *tmp;
10374 int nodeMax = set->nodeNr;
10375
10376 if (nodeMax < XML_NODESET_DEFAULT)
10377 nodeMax = XML_NODESET_DEFAULT;
10378 tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
10379 nodeMax * sizeof(xmlNodePtr));
10380 if (tmp == NULL) {
10381 xmlXPathPErrMemory(ctxt);
10382 } else {
10383 set->nodeTab = tmp;
10384 set->nodeMax = nodeMax;
10385 }
10386 }
10387
10388 xpctxt->node = oldnode;
10389 xpctxt->doc = olddoc;
10390 xpctxt->contextSize = oldcs;
10391 xpctxt->proximityPosition = oldpp;
10392 }
10393
10394 /**
10395 * xmlXPathCompOpEvalPredicate:
10396 * @ctxt: the XPath Parser context
10397 * @op: the predicate op
10398 * @set: the node set to filter
10399 * @minPos: minimum position in the filtered set (1-based)
10400 * @maxPos: maximum position in the filtered set (1-based)
10401 * @hasNsNodes: true if the node set may contain namespace nodes
10402 *
10403 * Filter a node set, keeping only nodes for which the sequence of predicate
10404 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
10405 * in the filtered result.
10406 */
10407 static void
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int minPos,int maxPos,int hasNsNodes)10408 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
10409 xmlXPathStepOpPtr op,
10410 xmlNodeSetPtr set,
10411 int minPos, int maxPos,
10412 int hasNsNodes)
10413 {
10414 if (op->ch1 != -1) {
10415 xmlXPathCompExprPtr comp = ctxt->comp;
10416 /*
10417 * Process inner predicates first.
10418 */
10419 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
10420 XP_ERROR(XPATH_INVALID_OPERAND);
10421 }
10422 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10423 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10424 ctxt->context->depth += 1;
10425 xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
10426 1, set->nodeNr, hasNsNodes);
10427 ctxt->context->depth -= 1;
10428 CHECK_ERROR;
10429 }
10430
10431 if (op->ch2 != -1)
10432 xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
10433 }
10434
10435 static int
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int * maxPos)10436 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
10437 xmlXPathStepOpPtr op,
10438 int *maxPos)
10439 {
10440
10441 xmlXPathStepOpPtr exprOp;
10442
10443 /*
10444 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
10445 */
10446
10447 /*
10448 * If not -1, then ch1 will point to:
10449 * 1) For predicates (XPATH_OP_PREDICATE):
10450 * - an inner predicate operator
10451 * 2) For filters (XPATH_OP_FILTER):
10452 * - an inner filter operator OR
10453 * - an expression selecting the node set.
10454 * E.g. "key('a', 'b')" or "(//foo | //bar)".
10455 */
10456 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
10457 return(0);
10458
10459 if (op->ch2 != -1) {
10460 exprOp = &ctxt->comp->steps[op->ch2];
10461 } else
10462 return(0);
10463
10464 if ((exprOp != NULL) &&
10465 (exprOp->op == XPATH_OP_VALUE) &&
10466 (exprOp->value4 != NULL) &&
10467 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
10468 {
10469 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
10470
10471 /*
10472 * We have a "[n]" predicate here.
10473 * TODO: Unfortunately this simplistic test here is not
10474 * able to detect a position() predicate in compound
10475 * expressions like "[@attr = 'a" and position() = 1],
10476 * and even not the usage of position() in
10477 * "[position() = 1]"; thus - obviously - a position-range,
10478 * like it "[position() < 5]", is also not detected.
10479 * Maybe we could rewrite the AST to ease the optimization.
10480 */
10481
10482 if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
10483 *maxPos = (int) floatval;
10484 if (floatval == (double) *maxPos)
10485 return(1);
10486 }
10487 }
10488 return(0);
10489 }
10490
10491 static int
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first,xmlNodePtr * last,int toBool)10492 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
10493 xmlXPathStepOpPtr op,
10494 xmlNodePtr * first, xmlNodePtr * last,
10495 int toBool)
10496 {
10497
10498 #define XP_TEST_HIT \
10499 if (hasAxisRange != 0) { \
10500 if (++pos == maxPos) { \
10501 if (addNode(seq, cur) < 0) \
10502 xmlXPathPErrMemory(ctxt); \
10503 goto axis_range_end; } \
10504 } else { \
10505 if (addNode(seq, cur) < 0) \
10506 xmlXPathPErrMemory(ctxt); \
10507 if (breakOnFirstHit) goto first_hit; }
10508
10509 #define XP_TEST_HIT_NS \
10510 if (hasAxisRange != 0) { \
10511 if (++pos == maxPos) { \
10512 hasNsNodes = 1; \
10513 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
10514 xmlXPathPErrMemory(ctxt); \
10515 goto axis_range_end; } \
10516 } else { \
10517 hasNsNodes = 1; \
10518 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
10519 xmlXPathPErrMemory(ctxt); \
10520 if (breakOnFirstHit) goto first_hit; }
10521
10522 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
10523 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
10524 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
10525 const xmlChar *prefix = op->value4;
10526 const xmlChar *name = op->value5;
10527 const xmlChar *URI = NULL;
10528
10529 int total = 0, hasNsNodes = 0;
10530 /* The popped object holding the context nodes */
10531 xmlXPathObjectPtr obj;
10532 /* The set of context nodes for the node tests */
10533 xmlNodeSetPtr contextSeq;
10534 int contextIdx;
10535 xmlNodePtr contextNode;
10536 /* The final resulting node set wrt to all context nodes */
10537 xmlNodeSetPtr outSeq;
10538 /*
10539 * The temporary resulting node set wrt 1 context node.
10540 * Used to feed predicate evaluation.
10541 */
10542 xmlNodeSetPtr seq;
10543 xmlNodePtr cur;
10544 /* First predicate operator */
10545 xmlXPathStepOpPtr predOp;
10546 int maxPos; /* The requested position() (when a "[n]" predicate) */
10547 int hasPredicateRange, hasAxisRange, pos;
10548 int breakOnFirstHit;
10549
10550 xmlXPathTraversalFunction next = NULL;
10551 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
10552 xmlXPathNodeSetMergeFunction mergeAndClear;
10553 xmlNodePtr oldContextNode;
10554 xmlXPathContextPtr xpctxt = ctxt->context;
10555
10556
10557 CHECK_TYPE0(XPATH_NODESET);
10558 obj = valuePop(ctxt);
10559 /*
10560 * Setup namespaces.
10561 */
10562 if (prefix != NULL) {
10563 URI = xmlXPathNsLookup(xpctxt, prefix);
10564 if (URI == NULL) {
10565 xmlXPathReleaseObject(xpctxt, obj);
10566 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10567 }
10568 }
10569 /*
10570 * Setup axis.
10571 *
10572 * MAYBE FUTURE TODO: merging optimizations:
10573 * - If the nodes to be traversed wrt to the initial nodes and
10574 * the current axis cannot overlap, then we could avoid searching
10575 * for duplicates during the merge.
10576 * But the question is how/when to evaluate if they cannot overlap.
10577 * Example: if we know that for two initial nodes, the one is
10578 * not in the ancestor-or-self axis of the other, then we could safely
10579 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
10580 * the descendant-or-self axis.
10581 */
10582 mergeAndClear = xmlXPathNodeSetMergeAndClear;
10583 switch (axis) {
10584 case AXIS_ANCESTOR:
10585 first = NULL;
10586 next = xmlXPathNextAncestor;
10587 break;
10588 case AXIS_ANCESTOR_OR_SELF:
10589 first = NULL;
10590 next = xmlXPathNextAncestorOrSelf;
10591 break;
10592 case AXIS_ATTRIBUTE:
10593 first = NULL;
10594 last = NULL;
10595 next = xmlXPathNextAttribute;
10596 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10597 break;
10598 case AXIS_CHILD:
10599 last = NULL;
10600 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
10601 (type == NODE_TYPE_NODE))
10602 {
10603 /*
10604 * Optimization if an element node type is 'element'.
10605 */
10606 next = xmlXPathNextChildElement;
10607 } else
10608 next = xmlXPathNextChild;
10609 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10610 break;
10611 case AXIS_DESCENDANT:
10612 last = NULL;
10613 next = xmlXPathNextDescendant;
10614 break;
10615 case AXIS_DESCENDANT_OR_SELF:
10616 last = NULL;
10617 next = xmlXPathNextDescendantOrSelf;
10618 break;
10619 case AXIS_FOLLOWING:
10620 last = NULL;
10621 next = xmlXPathNextFollowing;
10622 break;
10623 case AXIS_FOLLOWING_SIBLING:
10624 last = NULL;
10625 next = xmlXPathNextFollowingSibling;
10626 break;
10627 case AXIS_NAMESPACE:
10628 first = NULL;
10629 last = NULL;
10630 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
10631 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10632 break;
10633 case AXIS_PARENT:
10634 first = NULL;
10635 next = xmlXPathNextParent;
10636 break;
10637 case AXIS_PRECEDING:
10638 first = NULL;
10639 next = xmlXPathNextPrecedingInternal;
10640 break;
10641 case AXIS_PRECEDING_SIBLING:
10642 first = NULL;
10643 next = xmlXPathNextPrecedingSibling;
10644 break;
10645 case AXIS_SELF:
10646 first = NULL;
10647 last = NULL;
10648 next = xmlXPathNextSelf;
10649 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10650 break;
10651 }
10652
10653 if (next == NULL) {
10654 xmlXPathReleaseObject(xpctxt, obj);
10655 return(0);
10656 }
10657 contextSeq = obj->nodesetval;
10658 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
10659 valuePush(ctxt, obj);
10660 return(0);
10661 }
10662 /*
10663 * Predicate optimization ---------------------------------------------
10664 * If this step has a last predicate, which contains a position(),
10665 * then we'll optimize (although not exactly "position()", but only
10666 * the short-hand form, i.e., "[n]".
10667 *
10668 * Example - expression "/foo[parent::bar][1]":
10669 *
10670 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
10671 * ROOT -- op->ch1
10672 * PREDICATE -- op->ch2 (predOp)
10673 * PREDICATE -- predOp->ch1 = [parent::bar]
10674 * SORT
10675 * COLLECT 'parent' 'name' 'node' bar
10676 * NODE
10677 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
10678 *
10679 */
10680 maxPos = 0;
10681 predOp = NULL;
10682 hasPredicateRange = 0;
10683 hasAxisRange = 0;
10684 if (op->ch2 != -1) {
10685 /*
10686 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
10687 */
10688 predOp = &ctxt->comp->steps[op->ch2];
10689 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
10690 if (predOp->ch1 != -1) {
10691 /*
10692 * Use the next inner predicate operator.
10693 */
10694 predOp = &ctxt->comp->steps[predOp->ch1];
10695 hasPredicateRange = 1;
10696 } else {
10697 /*
10698 * There's no other predicate than the [n] predicate.
10699 */
10700 predOp = NULL;
10701 hasAxisRange = 1;
10702 }
10703 }
10704 }
10705 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
10706 /*
10707 * Axis traversal -----------------------------------------------------
10708 */
10709 /*
10710 * 2.3 Node Tests
10711 * - For the attribute axis, the principal node type is attribute.
10712 * - For the namespace axis, the principal node type is namespace.
10713 * - For other axes, the principal node type is element.
10714 *
10715 * A node test * is true for any node of the
10716 * principal node type. For example, child::* will
10717 * select all element children of the context node
10718 */
10719 oldContextNode = xpctxt->node;
10720 addNode = xmlXPathNodeSetAddUnique;
10721 outSeq = NULL;
10722 seq = NULL;
10723 contextNode = NULL;
10724 contextIdx = 0;
10725
10726
10727 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
10728 (ctxt->error == XPATH_EXPRESSION_OK)) {
10729 xpctxt->node = contextSeq->nodeTab[contextIdx++];
10730
10731 if (seq == NULL) {
10732 seq = xmlXPathNodeSetCreate(NULL);
10733 if (seq == NULL) {
10734 xmlXPathPErrMemory(ctxt);
10735 total = 0;
10736 goto error;
10737 }
10738 }
10739 /*
10740 * Traverse the axis and test the nodes.
10741 */
10742 pos = 0;
10743 cur = NULL;
10744 hasNsNodes = 0;
10745 do {
10746 if (OP_LIMIT_EXCEEDED(ctxt, 1))
10747 goto error;
10748
10749 cur = next(ctxt, cur);
10750 if (cur == NULL)
10751 break;
10752
10753 /*
10754 * QUESTION TODO: What does the "first" and "last" stuff do?
10755 */
10756 if ((first != NULL) && (*first != NULL)) {
10757 if (*first == cur)
10758 break;
10759 if (((total % 256) == 0) &&
10760 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10761 (xmlXPathCmpNodesExt(*first, cur) >= 0))
10762 #else
10763 (xmlXPathCmpNodes(*first, cur) >= 0))
10764 #endif
10765 {
10766 break;
10767 }
10768 }
10769 if ((last != NULL) && (*last != NULL)) {
10770 if (*last == cur)
10771 break;
10772 if (((total % 256) == 0) &&
10773 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10774 (xmlXPathCmpNodesExt(cur, *last) >= 0))
10775 #else
10776 (xmlXPathCmpNodes(cur, *last) >= 0))
10777 #endif
10778 {
10779 break;
10780 }
10781 }
10782
10783 total++;
10784
10785 switch (test) {
10786 case NODE_TEST_NONE:
10787 total = 0;
10788 goto error;
10789 case NODE_TEST_TYPE:
10790 if (type == NODE_TYPE_NODE) {
10791 switch (cur->type) {
10792 case XML_DOCUMENT_NODE:
10793 case XML_HTML_DOCUMENT_NODE:
10794 case XML_ELEMENT_NODE:
10795 case XML_ATTRIBUTE_NODE:
10796 case XML_PI_NODE:
10797 case XML_COMMENT_NODE:
10798 case XML_CDATA_SECTION_NODE:
10799 case XML_TEXT_NODE:
10800 XP_TEST_HIT
10801 break;
10802 case XML_NAMESPACE_DECL: {
10803 if (axis == AXIS_NAMESPACE) {
10804 XP_TEST_HIT_NS
10805 } else {
10806 hasNsNodes = 1;
10807 XP_TEST_HIT
10808 }
10809 break;
10810 }
10811 default:
10812 break;
10813 }
10814 } else if (cur->type == (xmlElementType) type) {
10815 if (cur->type == XML_NAMESPACE_DECL)
10816 XP_TEST_HIT_NS
10817 else
10818 XP_TEST_HIT
10819 } else if ((type == NODE_TYPE_TEXT) &&
10820 (cur->type == XML_CDATA_SECTION_NODE))
10821 {
10822 XP_TEST_HIT
10823 }
10824 break;
10825 case NODE_TEST_PI:
10826 if ((cur->type == XML_PI_NODE) &&
10827 ((name == NULL) || xmlStrEqual(name, cur->name)))
10828 {
10829 XP_TEST_HIT
10830 }
10831 break;
10832 case NODE_TEST_ALL:
10833 if (axis == AXIS_ATTRIBUTE) {
10834 if (cur->type == XML_ATTRIBUTE_NODE)
10835 {
10836 if (prefix == NULL)
10837 {
10838 XP_TEST_HIT
10839 } else if ((cur->ns != NULL) &&
10840 (xmlStrEqual(URI, cur->ns->href)))
10841 {
10842 XP_TEST_HIT
10843 }
10844 }
10845 } else if (axis == AXIS_NAMESPACE) {
10846 if (cur->type == XML_NAMESPACE_DECL)
10847 {
10848 XP_TEST_HIT_NS
10849 }
10850 } else {
10851 if (cur->type == XML_ELEMENT_NODE) {
10852 if (prefix == NULL)
10853 {
10854 XP_TEST_HIT
10855
10856 } else if ((cur->ns != NULL) &&
10857 (xmlStrEqual(URI, cur->ns->href)))
10858 {
10859 XP_TEST_HIT
10860 }
10861 }
10862 }
10863 break;
10864 case NODE_TEST_NS:{
10865 /* TODO */
10866 break;
10867 }
10868 case NODE_TEST_NAME:
10869 if (axis == AXIS_ATTRIBUTE) {
10870 if (cur->type != XML_ATTRIBUTE_NODE)
10871 break;
10872 } else if (axis == AXIS_NAMESPACE) {
10873 if (cur->type != XML_NAMESPACE_DECL)
10874 break;
10875 } else {
10876 if (cur->type != XML_ELEMENT_NODE)
10877 break;
10878 }
10879 switch (cur->type) {
10880 case XML_ELEMENT_NODE:
10881 if (xmlStrEqual(name, cur->name)) {
10882 if (prefix == NULL) {
10883 if (cur->ns == NULL)
10884 {
10885 XP_TEST_HIT
10886 }
10887 } else {
10888 if ((cur->ns != NULL) &&
10889 (xmlStrEqual(URI, cur->ns->href)))
10890 {
10891 XP_TEST_HIT
10892 }
10893 }
10894 }
10895 break;
10896 case XML_ATTRIBUTE_NODE:{
10897 xmlAttrPtr attr = (xmlAttrPtr) cur;
10898
10899 if (xmlStrEqual(name, attr->name)) {
10900 if (prefix == NULL) {
10901 if ((attr->ns == NULL) ||
10902 (attr->ns->prefix == NULL))
10903 {
10904 XP_TEST_HIT
10905 }
10906 } else {
10907 if ((attr->ns != NULL) &&
10908 (xmlStrEqual(URI,
10909 attr->ns->href)))
10910 {
10911 XP_TEST_HIT
10912 }
10913 }
10914 }
10915 break;
10916 }
10917 case XML_NAMESPACE_DECL:
10918 if (cur->type == XML_NAMESPACE_DECL) {
10919 xmlNsPtr ns = (xmlNsPtr) cur;
10920
10921 if ((ns->prefix != NULL) && (name != NULL)
10922 && (xmlStrEqual(ns->prefix, name)))
10923 {
10924 XP_TEST_HIT_NS
10925 }
10926 }
10927 break;
10928 default:
10929 break;
10930 }
10931 break;
10932 } /* switch(test) */
10933 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
10934
10935 goto apply_predicates;
10936
10937 axis_range_end: /* ----------------------------------------------------- */
10938 /*
10939 * We have a "/foo[n]", and position() = n was reached.
10940 * Note that we can have as well "/foo/::parent::foo[1]", so
10941 * a duplicate-aware merge is still needed.
10942 * Merge with the result.
10943 */
10944 if (outSeq == NULL) {
10945 outSeq = seq;
10946 seq = NULL;
10947 } else {
10948 outSeq = mergeAndClear(outSeq, seq);
10949 if (outSeq == NULL)
10950 xmlXPathPErrMemory(ctxt);
10951 }
10952 /*
10953 * Break if only a true/false result was requested.
10954 */
10955 if (toBool)
10956 break;
10957 continue;
10958
10959 first_hit: /* ---------------------------------------------------------- */
10960 /*
10961 * Break if only a true/false result was requested and
10962 * no predicates existed and a node test succeeded.
10963 */
10964 if (outSeq == NULL) {
10965 outSeq = seq;
10966 seq = NULL;
10967 } else {
10968 outSeq = mergeAndClear(outSeq, seq);
10969 if (outSeq == NULL)
10970 xmlXPathPErrMemory(ctxt);
10971 }
10972 break;
10973
10974 apply_predicates: /* --------------------------------------------------- */
10975 if (ctxt->error != XPATH_EXPRESSION_OK)
10976 goto error;
10977
10978 /*
10979 * Apply predicates.
10980 */
10981 if ((predOp != NULL) && (seq->nodeNr > 0)) {
10982 /*
10983 * E.g. when we have a "/foo[some expression][n]".
10984 */
10985 /*
10986 * QUESTION TODO: The old predicate evaluation took into
10987 * account location-sets.
10988 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
10989 * Do we expect such a set here?
10990 * All what I learned now from the evaluation semantics
10991 * does not indicate that a location-set will be processed
10992 * here, so this looks OK.
10993 */
10994 /*
10995 * Iterate over all predicates, starting with the outermost
10996 * predicate.
10997 * TODO: Problem: we cannot execute the inner predicates first
10998 * since we cannot go back *up* the operator tree!
10999 * Options we have:
11000 * 1) Use of recursive functions (like is it currently done
11001 * via xmlXPathCompOpEval())
11002 * 2) Add a predicate evaluation information stack to the
11003 * context struct
11004 * 3) Change the way the operators are linked; we need a
11005 * "parent" field on xmlXPathStepOp
11006 *
11007 * For the moment, I'll try to solve this with a recursive
11008 * function: xmlXPathCompOpEvalPredicate().
11009 */
11010 if (hasPredicateRange != 0)
11011 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
11012 hasNsNodes);
11013 else
11014 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
11015 hasNsNodes);
11016
11017 if (ctxt->error != XPATH_EXPRESSION_OK) {
11018 total = 0;
11019 goto error;
11020 }
11021 }
11022
11023 if (seq->nodeNr > 0) {
11024 /*
11025 * Add to result set.
11026 */
11027 if (outSeq == NULL) {
11028 outSeq = seq;
11029 seq = NULL;
11030 } else {
11031 outSeq = mergeAndClear(outSeq, seq);
11032 if (outSeq == NULL)
11033 xmlXPathPErrMemory(ctxt);
11034 }
11035
11036 if (toBool)
11037 break;
11038 }
11039 }
11040
11041 error:
11042 if ((obj->boolval) && (obj->user != NULL)) {
11043 /*
11044 * QUESTION TODO: What does this do and why?
11045 * TODO: Do we have to do this also for the "error"
11046 * cleanup further down?
11047 */
11048 ctxt->value->boolval = 1;
11049 ctxt->value->user = obj->user;
11050 obj->user = NULL;
11051 obj->boolval = 0;
11052 }
11053 xmlXPathReleaseObject(xpctxt, obj);
11054
11055 /*
11056 * Ensure we return at least an empty set.
11057 */
11058 if (outSeq == NULL) {
11059 if ((seq != NULL) && (seq->nodeNr == 0)) {
11060 outSeq = seq;
11061 } else {
11062 outSeq = xmlXPathNodeSetCreate(NULL);
11063 if (outSeq == NULL)
11064 xmlXPathPErrMemory(ctxt);
11065 }
11066 }
11067 if ((seq != NULL) && (seq != outSeq)) {
11068 xmlXPathFreeNodeSet(seq);
11069 }
11070 /*
11071 * Hand over the result. Better to push the set also in
11072 * case of errors.
11073 */
11074 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, outSeq));
11075 /*
11076 * Reset the context node.
11077 */
11078 xpctxt->node = oldContextNode;
11079 /*
11080 * When traversing the namespace axis in "toBool" mode, it's
11081 * possible that tmpNsList wasn't freed.
11082 */
11083 if (xpctxt->tmpNsList != NULL) {
11084 xmlFree(xpctxt->tmpNsList);
11085 xpctxt->tmpNsList = NULL;
11086 }
11087
11088 return(total);
11089 }
11090
11091 static int
11092 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11093 xmlXPathStepOpPtr op, xmlNodePtr * first);
11094
11095 /**
11096 * xmlXPathCompOpEvalFirst:
11097 * @ctxt: the XPath parser context with the compiled expression
11098 * @op: an XPath compiled operation
11099 * @first: the first elem found so far
11100 *
11101 * Evaluate the Precompiled XPath operation searching only the first
11102 * element in document order
11103 *
11104 * Returns the number of examined objects.
11105 */
11106 static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)11107 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
11108 xmlXPathStepOpPtr op, xmlNodePtr * first)
11109 {
11110 int total = 0, cur;
11111 xmlXPathCompExprPtr comp;
11112 xmlXPathObjectPtr arg1, arg2;
11113
11114 CHECK_ERROR0;
11115 if (OP_LIMIT_EXCEEDED(ctxt, 1))
11116 return(0);
11117 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11118 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11119 ctxt->context->depth += 1;
11120 comp = ctxt->comp;
11121 switch (op->op) {
11122 case XPATH_OP_END:
11123 break;
11124 case XPATH_OP_UNION:
11125 total =
11126 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11127 first);
11128 CHECK_ERROR0;
11129 if ((ctxt->value != NULL)
11130 && (ctxt->value->type == XPATH_NODESET)
11131 && (ctxt->value->nodesetval != NULL)
11132 && (ctxt->value->nodesetval->nodeNr >= 1)) {
11133 /*
11134 * limit tree traversing to first node in the result
11135 */
11136 /*
11137 * OPTIMIZE TODO: This implicitly sorts
11138 * the result, even if not needed. E.g. if the argument
11139 * of the count() function, no sorting is needed.
11140 * OPTIMIZE TODO: How do we know if the node-list wasn't
11141 * already sorted?
11142 */
11143 if (ctxt->value->nodesetval->nodeNr > 1)
11144 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11145 *first = ctxt->value->nodesetval->nodeTab[0];
11146 }
11147 cur =
11148 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
11149 first);
11150 CHECK_ERROR0;
11151
11152 arg2 = valuePop(ctxt);
11153 arg1 = valuePop(ctxt);
11154 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11155 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11156 xmlXPathReleaseObject(ctxt->context, arg1);
11157 xmlXPathReleaseObject(ctxt->context, arg2);
11158 XP_ERROR0(XPATH_INVALID_TYPE);
11159 }
11160 if ((ctxt->context->opLimit != 0) &&
11161 (((arg1->nodesetval != NULL) &&
11162 (xmlXPathCheckOpLimit(ctxt,
11163 arg1->nodesetval->nodeNr) < 0)) ||
11164 ((arg2->nodesetval != NULL) &&
11165 (xmlXPathCheckOpLimit(ctxt,
11166 arg2->nodesetval->nodeNr) < 0)))) {
11167 xmlXPathReleaseObject(ctxt->context, arg1);
11168 xmlXPathReleaseObject(ctxt->context, arg2);
11169 break;
11170 }
11171
11172 if ((arg2->nodesetval != NULL) &&
11173 (arg2->nodesetval->nodeNr != 0)) {
11174 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11175 arg2->nodesetval);
11176 if (arg1->nodesetval == NULL)
11177 xmlXPathPErrMemory(ctxt);
11178 }
11179 valuePush(ctxt, arg1);
11180 xmlXPathReleaseObject(ctxt->context, arg2);
11181 /* optimizer */
11182 if (total > cur)
11183 xmlXPathCompSwap(op);
11184 total += cur;
11185 break;
11186 case XPATH_OP_ROOT:
11187 xmlXPathRoot(ctxt);
11188 break;
11189 case XPATH_OP_NODE:
11190 if (op->ch1 != -1)
11191 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11192 CHECK_ERROR0;
11193 if (op->ch2 != -1)
11194 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11195 CHECK_ERROR0;
11196 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11197 ctxt->context->node));
11198 break;
11199 case XPATH_OP_COLLECT:{
11200 if (op->ch1 == -1)
11201 break;
11202
11203 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11204 CHECK_ERROR0;
11205
11206 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
11207 break;
11208 }
11209 case XPATH_OP_VALUE:
11210 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11211 break;
11212 case XPATH_OP_SORT:
11213 if (op->ch1 != -1)
11214 total +=
11215 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11216 first);
11217 CHECK_ERROR0;
11218 if ((ctxt->value != NULL)
11219 && (ctxt->value->type == XPATH_NODESET)
11220 && (ctxt->value->nodesetval != NULL)
11221 && (ctxt->value->nodesetval->nodeNr > 1))
11222 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11223 break;
11224 #ifdef XP_OPTIMIZED_FILTER_FIRST
11225 case XPATH_OP_FILTER:
11226 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
11227 break;
11228 #endif
11229 default:
11230 total += xmlXPathCompOpEval(ctxt, op);
11231 break;
11232 }
11233
11234 ctxt->context->depth -= 1;
11235 return(total);
11236 }
11237
11238 /**
11239 * xmlXPathCompOpEvalLast:
11240 * @ctxt: the XPath parser context with the compiled expression
11241 * @op: an XPath compiled operation
11242 * @last: the last elem found so far
11243 *
11244 * Evaluate the Precompiled XPath operation searching only the last
11245 * element in document order
11246 *
11247 * Returns the number of nodes traversed
11248 */
11249 static int
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * last)11250 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
11251 xmlNodePtr * last)
11252 {
11253 int total = 0, cur;
11254 xmlXPathCompExprPtr comp;
11255 xmlXPathObjectPtr arg1, arg2;
11256
11257 CHECK_ERROR0;
11258 if (OP_LIMIT_EXCEEDED(ctxt, 1))
11259 return(0);
11260 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11261 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11262 ctxt->context->depth += 1;
11263 comp = ctxt->comp;
11264 switch (op->op) {
11265 case XPATH_OP_END:
11266 break;
11267 case XPATH_OP_UNION:
11268 total =
11269 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
11270 CHECK_ERROR0;
11271 if ((ctxt->value != NULL)
11272 && (ctxt->value->type == XPATH_NODESET)
11273 && (ctxt->value->nodesetval != NULL)
11274 && (ctxt->value->nodesetval->nodeNr >= 1)) {
11275 /*
11276 * limit tree traversing to first node in the result
11277 */
11278 if (ctxt->value->nodesetval->nodeNr > 1)
11279 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11280 *last =
11281 ctxt->value->nodesetval->nodeTab[ctxt->value->
11282 nodesetval->nodeNr -
11283 1];
11284 }
11285 cur =
11286 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
11287 CHECK_ERROR0;
11288 if ((ctxt->value != NULL)
11289 && (ctxt->value->type == XPATH_NODESET)
11290 && (ctxt->value->nodesetval != NULL)
11291 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
11292 }
11293
11294 arg2 = valuePop(ctxt);
11295 arg1 = valuePop(ctxt);
11296 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11297 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11298 xmlXPathReleaseObject(ctxt->context, arg1);
11299 xmlXPathReleaseObject(ctxt->context, arg2);
11300 XP_ERROR0(XPATH_INVALID_TYPE);
11301 }
11302 if ((ctxt->context->opLimit != 0) &&
11303 (((arg1->nodesetval != NULL) &&
11304 (xmlXPathCheckOpLimit(ctxt,
11305 arg1->nodesetval->nodeNr) < 0)) ||
11306 ((arg2->nodesetval != NULL) &&
11307 (xmlXPathCheckOpLimit(ctxt,
11308 arg2->nodesetval->nodeNr) < 0)))) {
11309 xmlXPathReleaseObject(ctxt->context, arg1);
11310 xmlXPathReleaseObject(ctxt->context, arg2);
11311 break;
11312 }
11313
11314 if ((arg2->nodesetval != NULL) &&
11315 (arg2->nodesetval->nodeNr != 0)) {
11316 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11317 arg2->nodesetval);
11318 if (arg1->nodesetval == NULL)
11319 xmlXPathPErrMemory(ctxt);
11320 }
11321 valuePush(ctxt, arg1);
11322 xmlXPathReleaseObject(ctxt->context, arg2);
11323 /* optimizer */
11324 if (total > cur)
11325 xmlXPathCompSwap(op);
11326 total += cur;
11327 break;
11328 case XPATH_OP_ROOT:
11329 xmlXPathRoot(ctxt);
11330 break;
11331 case XPATH_OP_NODE:
11332 if (op->ch1 != -1)
11333 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11334 CHECK_ERROR0;
11335 if (op->ch2 != -1)
11336 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11337 CHECK_ERROR0;
11338 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11339 ctxt->context->node));
11340 break;
11341 case XPATH_OP_COLLECT:{
11342 if (op->ch1 == -1)
11343 break;
11344
11345 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11346 CHECK_ERROR0;
11347
11348 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
11349 break;
11350 }
11351 case XPATH_OP_VALUE:
11352 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11353 break;
11354 case XPATH_OP_SORT:
11355 if (op->ch1 != -1)
11356 total +=
11357 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
11358 last);
11359 CHECK_ERROR0;
11360 if ((ctxt->value != NULL)
11361 && (ctxt->value->type == XPATH_NODESET)
11362 && (ctxt->value->nodesetval != NULL)
11363 && (ctxt->value->nodesetval->nodeNr > 1))
11364 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11365 break;
11366 default:
11367 total += xmlXPathCompOpEval(ctxt, op);
11368 break;
11369 }
11370
11371 ctxt->context->depth -= 1;
11372 return (total);
11373 }
11374
11375 #ifdef XP_OPTIMIZED_FILTER_FIRST
11376 static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)11377 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11378 xmlXPathStepOpPtr op, xmlNodePtr * first)
11379 {
11380 int total = 0;
11381 xmlXPathCompExprPtr comp;
11382 xmlXPathObjectPtr obj;
11383 xmlNodeSetPtr set;
11384
11385 CHECK_ERROR0;
11386 comp = ctxt->comp;
11387 /*
11388 * Optimization for ()[last()] selection i.e. the last elem
11389 */
11390 if ((op->ch1 != -1) && (op->ch2 != -1) &&
11391 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11392 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11393 int f = comp->steps[op->ch2].ch1;
11394
11395 if ((f != -1) &&
11396 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11397 (comp->steps[f].value5 == NULL) &&
11398 (comp->steps[f].value == 0) &&
11399 (comp->steps[f].value4 != NULL) &&
11400 (xmlStrEqual
11401 (comp->steps[f].value4, BAD_CAST "last"))) {
11402 xmlNodePtr last = NULL;
11403
11404 total +=
11405 xmlXPathCompOpEvalLast(ctxt,
11406 &comp->steps[op->ch1],
11407 &last);
11408 CHECK_ERROR0;
11409 /*
11410 * The nodeset should be in document order,
11411 * Keep only the last value
11412 */
11413 if ((ctxt->value != NULL) &&
11414 (ctxt->value->type == XPATH_NODESET) &&
11415 (ctxt->value->nodesetval != NULL) &&
11416 (ctxt->value->nodesetval->nodeTab != NULL) &&
11417 (ctxt->value->nodesetval->nodeNr > 1)) {
11418 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11419 *first = *(ctxt->value->nodesetval->nodeTab);
11420 }
11421 return (total);
11422 }
11423 }
11424
11425 if (op->ch1 != -1)
11426 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11427 CHECK_ERROR0;
11428 if (op->ch2 == -1)
11429 return (total);
11430 if (ctxt->value == NULL)
11431 return (total);
11432
11433 /*
11434 * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
11435 * the stack. We have to temporarily remove the nodeset object from the
11436 * stack to avoid freeing it prematurely.
11437 */
11438 CHECK_TYPE0(XPATH_NODESET);
11439 obj = valuePop(ctxt);
11440 set = obj->nodesetval;
11441 if (set != NULL) {
11442 xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
11443 if (set->nodeNr > 0)
11444 *first = set->nodeTab[0];
11445 }
11446 valuePush(ctxt, obj);
11447
11448 return (total);
11449 }
11450 #endif /* XP_OPTIMIZED_FILTER_FIRST */
11451
11452 /**
11453 * xmlXPathCompOpEval:
11454 * @ctxt: the XPath parser context with the compiled expression
11455 * @op: an XPath compiled operation
11456 *
11457 * Evaluate the Precompiled XPath operation
11458 * Returns the number of nodes traversed
11459 */
11460 static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op)11461 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
11462 {
11463 int total = 0;
11464 int equal, ret;
11465 xmlXPathCompExprPtr comp;
11466 xmlXPathObjectPtr arg1, arg2;
11467
11468 CHECK_ERROR0;
11469 if (OP_LIMIT_EXCEEDED(ctxt, 1))
11470 return(0);
11471 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11472 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11473 ctxt->context->depth += 1;
11474 comp = ctxt->comp;
11475 switch (op->op) {
11476 case XPATH_OP_END:
11477 break;
11478 case XPATH_OP_AND:
11479 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11480 CHECK_ERROR0;
11481 xmlXPathBooleanFunction(ctxt, 1);
11482 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
11483 break;
11484 arg2 = valuePop(ctxt);
11485 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11486 if (ctxt->error) {
11487 xmlXPathFreeObject(arg2);
11488 break;
11489 }
11490 xmlXPathBooleanFunction(ctxt, 1);
11491 if (ctxt->value != NULL)
11492 ctxt->value->boolval &= arg2->boolval;
11493 xmlXPathReleaseObject(ctxt->context, arg2);
11494 break;
11495 case XPATH_OP_OR:
11496 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11497 CHECK_ERROR0;
11498 xmlXPathBooleanFunction(ctxt, 1);
11499 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
11500 break;
11501 arg2 = valuePop(ctxt);
11502 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11503 if (ctxt->error) {
11504 xmlXPathFreeObject(arg2);
11505 break;
11506 }
11507 xmlXPathBooleanFunction(ctxt, 1);
11508 if (ctxt->value != NULL)
11509 ctxt->value->boolval |= arg2->boolval;
11510 xmlXPathReleaseObject(ctxt->context, arg2);
11511 break;
11512 case XPATH_OP_EQUAL:
11513 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11514 CHECK_ERROR0;
11515 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11516 CHECK_ERROR0;
11517 if (op->value)
11518 equal = xmlXPathEqualValues(ctxt);
11519 else
11520 equal = xmlXPathNotEqualValues(ctxt);
11521 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, equal));
11522 break;
11523 case XPATH_OP_CMP:
11524 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11525 CHECK_ERROR0;
11526 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11527 CHECK_ERROR0;
11528 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
11529 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
11530 break;
11531 case XPATH_OP_PLUS:
11532 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11533 CHECK_ERROR0;
11534 if (op->ch2 != -1) {
11535 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11536 }
11537 CHECK_ERROR0;
11538 if (op->value == 0)
11539 xmlXPathSubValues(ctxt);
11540 else if (op->value == 1)
11541 xmlXPathAddValues(ctxt);
11542 else if (op->value == 2)
11543 xmlXPathValueFlipSign(ctxt);
11544 else if (op->value == 3) {
11545 CAST_TO_NUMBER;
11546 CHECK_TYPE0(XPATH_NUMBER);
11547 }
11548 break;
11549 case XPATH_OP_MULT:
11550 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11551 CHECK_ERROR0;
11552 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11553 CHECK_ERROR0;
11554 if (op->value == 0)
11555 xmlXPathMultValues(ctxt);
11556 else if (op->value == 1)
11557 xmlXPathDivValues(ctxt);
11558 else if (op->value == 2)
11559 xmlXPathModValues(ctxt);
11560 break;
11561 case XPATH_OP_UNION:
11562 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11563 CHECK_ERROR0;
11564 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11565 CHECK_ERROR0;
11566
11567 arg2 = valuePop(ctxt);
11568 arg1 = valuePop(ctxt);
11569 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11570 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11571 xmlXPathReleaseObject(ctxt->context, arg1);
11572 xmlXPathReleaseObject(ctxt->context, arg2);
11573 XP_ERROR0(XPATH_INVALID_TYPE);
11574 }
11575 if ((ctxt->context->opLimit != 0) &&
11576 (((arg1->nodesetval != NULL) &&
11577 (xmlXPathCheckOpLimit(ctxt,
11578 arg1->nodesetval->nodeNr) < 0)) ||
11579 ((arg2->nodesetval != NULL) &&
11580 (xmlXPathCheckOpLimit(ctxt,
11581 arg2->nodesetval->nodeNr) < 0)))) {
11582 xmlXPathReleaseObject(ctxt->context, arg1);
11583 xmlXPathReleaseObject(ctxt->context, arg2);
11584 break;
11585 }
11586
11587 if (((arg2->nodesetval != NULL) &&
11588 (arg2->nodesetval->nodeNr != 0)))
11589 {
11590 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11591 arg2->nodesetval);
11592 if (arg1->nodesetval == NULL)
11593 xmlXPathPErrMemory(ctxt);
11594 }
11595
11596 valuePush(ctxt, arg1);
11597 xmlXPathReleaseObject(ctxt->context, arg2);
11598 break;
11599 case XPATH_OP_ROOT:
11600 xmlXPathRoot(ctxt);
11601 break;
11602 case XPATH_OP_NODE:
11603 if (op->ch1 != -1)
11604 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11605 CHECK_ERROR0;
11606 if (op->ch2 != -1)
11607 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11608 CHECK_ERROR0;
11609 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11610 ctxt->context->node));
11611 break;
11612 case XPATH_OP_COLLECT:{
11613 if (op->ch1 == -1)
11614 break;
11615
11616 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11617 CHECK_ERROR0;
11618
11619 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
11620 break;
11621 }
11622 case XPATH_OP_VALUE:
11623 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11624 break;
11625 case XPATH_OP_VARIABLE:{
11626 xmlXPathObjectPtr val;
11627
11628 if (op->ch1 != -1)
11629 total +=
11630 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11631 if (op->value5 == NULL) {
11632 val = xmlXPathVariableLookup(ctxt->context, op->value4);
11633 if (val == NULL)
11634 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
11635 valuePush(ctxt, val);
11636 } else {
11637 const xmlChar *URI;
11638
11639 URI = xmlXPathNsLookup(ctxt->context, op->value5);
11640 if (URI == NULL) {
11641 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11642 break;
11643 }
11644 val = xmlXPathVariableLookupNS(ctxt->context,
11645 op->value4, URI);
11646 if (val == NULL)
11647 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
11648 valuePush(ctxt, val);
11649 }
11650 break;
11651 }
11652 case XPATH_OP_FUNCTION:{
11653 xmlXPathFunction func;
11654 const xmlChar *oldFunc, *oldFuncURI;
11655 int i;
11656 int frame;
11657
11658 frame = ctxt->valueNr;
11659 if (op->ch1 != -1) {
11660 total +=
11661 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11662 if (ctxt->error != XPATH_EXPRESSION_OK)
11663 break;
11664 }
11665 if (ctxt->valueNr < frame + op->value)
11666 XP_ERROR0(XPATH_INVALID_OPERAND);
11667 for (i = 0; i < op->value; i++) {
11668 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL)
11669 XP_ERROR0(XPATH_INVALID_OPERAND);
11670 }
11671 if (op->cache != NULL)
11672 func = op->cache;
11673 else {
11674 const xmlChar *URI = NULL;
11675
11676 if (op->value5 == NULL)
11677 func =
11678 xmlXPathFunctionLookup(ctxt->context,
11679 op->value4);
11680 else {
11681 URI = xmlXPathNsLookup(ctxt->context, op->value5);
11682 if (URI == NULL)
11683 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11684 func = xmlXPathFunctionLookupNS(ctxt->context,
11685 op->value4, URI);
11686 }
11687 if (func == NULL)
11688 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
11689 op->cache = func;
11690 op->cacheURI = (void *) URI;
11691 }
11692 oldFunc = ctxt->context->function;
11693 oldFuncURI = ctxt->context->functionURI;
11694 ctxt->context->function = op->value4;
11695 ctxt->context->functionURI = op->cacheURI;
11696 func(ctxt, op->value);
11697 ctxt->context->function = oldFunc;
11698 ctxt->context->functionURI = oldFuncURI;
11699 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
11700 (ctxt->valueNr != frame + 1))
11701 XP_ERROR0(XPATH_STACK_ERROR);
11702 break;
11703 }
11704 case XPATH_OP_ARG:
11705 if (op->ch1 != -1) {
11706 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11707 CHECK_ERROR0;
11708 }
11709 if (op->ch2 != -1) {
11710 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11711 CHECK_ERROR0;
11712 }
11713 break;
11714 case XPATH_OP_PREDICATE:
11715 case XPATH_OP_FILTER:{
11716 xmlXPathObjectPtr obj;
11717 xmlNodeSetPtr set;
11718
11719 /*
11720 * Optimization for ()[1] selection i.e. the first elem
11721 */
11722 if ((op->ch1 != -1) && (op->ch2 != -1) &&
11723 #ifdef XP_OPTIMIZED_FILTER_FIRST
11724 /*
11725 * FILTER TODO: Can we assume that the inner processing
11726 * will result in an ordered list if we have an
11727 * XPATH_OP_FILTER?
11728 * What about an additional field or flag on
11729 * xmlXPathObject like @sorted ? This way we wouldn't need
11730 * to assume anything, so it would be more robust and
11731 * easier to optimize.
11732 */
11733 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
11734 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
11735 #else
11736 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11737 #endif
11738 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
11739 xmlXPathObjectPtr val;
11740
11741 val = comp->steps[op->ch2].value4;
11742 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
11743 (val->floatval == 1.0)) {
11744 xmlNodePtr first = NULL;
11745
11746 total +=
11747 xmlXPathCompOpEvalFirst(ctxt,
11748 &comp->steps[op->ch1],
11749 &first);
11750 CHECK_ERROR0;
11751 /*
11752 * The nodeset should be in document order,
11753 * Keep only the first value
11754 */
11755 if ((ctxt->value != NULL) &&
11756 (ctxt->value->type == XPATH_NODESET) &&
11757 (ctxt->value->nodesetval != NULL) &&
11758 (ctxt->value->nodesetval->nodeNr > 1))
11759 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
11760 1, 1);
11761 break;
11762 }
11763 }
11764 /*
11765 * Optimization for ()[last()] selection i.e. the last elem
11766 */
11767 if ((op->ch1 != -1) && (op->ch2 != -1) &&
11768 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11769 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11770 int f = comp->steps[op->ch2].ch1;
11771
11772 if ((f != -1) &&
11773 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11774 (comp->steps[f].value5 == NULL) &&
11775 (comp->steps[f].value == 0) &&
11776 (comp->steps[f].value4 != NULL) &&
11777 (xmlStrEqual
11778 (comp->steps[f].value4, BAD_CAST "last"))) {
11779 xmlNodePtr last = NULL;
11780
11781 total +=
11782 xmlXPathCompOpEvalLast(ctxt,
11783 &comp->steps[op->ch1],
11784 &last);
11785 CHECK_ERROR0;
11786 /*
11787 * The nodeset should be in document order,
11788 * Keep only the last value
11789 */
11790 if ((ctxt->value != NULL) &&
11791 (ctxt->value->type == XPATH_NODESET) &&
11792 (ctxt->value->nodesetval != NULL) &&
11793 (ctxt->value->nodesetval->nodeTab != NULL) &&
11794 (ctxt->value->nodesetval->nodeNr > 1))
11795 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11796 break;
11797 }
11798 }
11799 /*
11800 * Process inner predicates first.
11801 * Example "index[parent::book][1]":
11802 * ...
11803 * PREDICATE <-- we are here "[1]"
11804 * PREDICATE <-- process "[parent::book]" first
11805 * SORT
11806 * COLLECT 'parent' 'name' 'node' book
11807 * NODE
11808 * ELEM Object is a number : 1
11809 */
11810 if (op->ch1 != -1)
11811 total +=
11812 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11813 CHECK_ERROR0;
11814 if (op->ch2 == -1)
11815 break;
11816 if (ctxt->value == NULL)
11817 break;
11818
11819 /*
11820 * In case of errors, xmlXPathNodeSetFilter can pop additional
11821 * nodes from the stack. We have to temporarily remove the
11822 * nodeset object from the stack to avoid freeing it
11823 * prematurely.
11824 */
11825 CHECK_TYPE0(XPATH_NODESET);
11826 obj = valuePop(ctxt);
11827 set = obj->nodesetval;
11828 if (set != NULL)
11829 xmlXPathNodeSetFilter(ctxt, set, op->ch2,
11830 1, set->nodeNr, 1);
11831 valuePush(ctxt, obj);
11832 break;
11833 }
11834 case XPATH_OP_SORT:
11835 if (op->ch1 != -1)
11836 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11837 CHECK_ERROR0;
11838 if ((ctxt->value != NULL) &&
11839 (ctxt->value->type == XPATH_NODESET) &&
11840 (ctxt->value->nodesetval != NULL) &&
11841 (ctxt->value->nodesetval->nodeNr > 1))
11842 {
11843 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11844 }
11845 break;
11846 default:
11847 XP_ERROR0(XPATH_INVALID_OPERAND);
11848 break;
11849 }
11850
11851 ctxt->context->depth -= 1;
11852 return (total);
11853 }
11854
11855 /**
11856 * xmlXPathCompOpEvalToBoolean:
11857 * @ctxt: the XPath parser context
11858 *
11859 * Evaluates if the expression evaluates to true.
11860 *
11861 * Returns 1 if true, 0 if false and -1 on API or internal errors.
11862 */
11863 static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int isPredicate)11864 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
11865 xmlXPathStepOpPtr op,
11866 int isPredicate)
11867 {
11868 xmlXPathObjectPtr resObj = NULL;
11869
11870 start:
11871 if (OP_LIMIT_EXCEEDED(ctxt, 1))
11872 return(0);
11873 /* comp = ctxt->comp; */
11874 switch (op->op) {
11875 case XPATH_OP_END:
11876 return (0);
11877 case XPATH_OP_VALUE:
11878 resObj = (xmlXPathObjectPtr) op->value4;
11879 if (isPredicate)
11880 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
11881 return(xmlXPathCastToBoolean(resObj));
11882 case XPATH_OP_SORT:
11883 /*
11884 * We don't need sorting for boolean results. Skip this one.
11885 */
11886 if (op->ch1 != -1) {
11887 op = &ctxt->comp->steps[op->ch1];
11888 goto start;
11889 }
11890 return(0);
11891 case XPATH_OP_COLLECT:
11892 if (op->ch1 == -1)
11893 return(0);
11894
11895 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
11896 if (ctxt->error != XPATH_EXPRESSION_OK)
11897 return(-1);
11898
11899 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
11900 if (ctxt->error != XPATH_EXPRESSION_OK)
11901 return(-1);
11902
11903 resObj = valuePop(ctxt);
11904 if (resObj == NULL)
11905 return(-1);
11906 break;
11907 default:
11908 /*
11909 * Fallback to call xmlXPathCompOpEval().
11910 */
11911 xmlXPathCompOpEval(ctxt, op);
11912 if (ctxt->error != XPATH_EXPRESSION_OK)
11913 return(-1);
11914
11915 resObj = valuePop(ctxt);
11916 if (resObj == NULL)
11917 return(-1);
11918 break;
11919 }
11920
11921 if (resObj) {
11922 int res;
11923
11924 if (resObj->type == XPATH_BOOLEAN) {
11925 res = resObj->boolval;
11926 } else if (isPredicate) {
11927 /*
11928 * For predicates a result of type "number" is handled
11929 * differently:
11930 * SPEC XPath 1.0:
11931 * "If the result is a number, the result will be converted
11932 * to true if the number is equal to the context position
11933 * and will be converted to false otherwise;"
11934 */
11935 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
11936 } else {
11937 res = xmlXPathCastToBoolean(resObj);
11938 }
11939 xmlXPathReleaseObject(ctxt->context, resObj);
11940 return(res);
11941 }
11942
11943 return(0);
11944 }
11945
11946 #ifdef XPATH_STREAMING
11947 /**
11948 * xmlXPathRunStreamEval:
11949 * @pctxt: the XPath parser context with the compiled expression
11950 *
11951 * Evaluate the Precompiled Streamable XPath expression in the given context.
11952 */
11953 static int
xmlXPathRunStreamEval(xmlXPathParserContextPtr pctxt,xmlPatternPtr comp,xmlXPathObjectPtr * resultSeq,int toBool)11954 xmlXPathRunStreamEval(xmlXPathParserContextPtr pctxt, xmlPatternPtr comp,
11955 xmlXPathObjectPtr *resultSeq, int toBool)
11956 {
11957 int max_depth, min_depth;
11958 int from_root;
11959 int ret, depth;
11960 int eval_all_nodes;
11961 xmlNodePtr cur = NULL, limit = NULL;
11962 xmlStreamCtxtPtr patstream = NULL;
11963 xmlXPathContextPtr ctxt = pctxt->context;
11964
11965 if ((ctxt == NULL) || (comp == NULL))
11966 return(-1);
11967 max_depth = xmlPatternMaxDepth(comp);
11968 if (max_depth == -1)
11969 return(-1);
11970 if (max_depth == -2)
11971 max_depth = 10000;
11972 min_depth = xmlPatternMinDepth(comp);
11973 if (min_depth == -1)
11974 return(-1);
11975 from_root = xmlPatternFromRoot(comp);
11976 if (from_root < 0)
11977 return(-1);
11978 #if 0
11979 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
11980 #endif
11981
11982 if (! toBool) {
11983 if (resultSeq == NULL)
11984 return(-1);
11985 *resultSeq = xmlXPathCacheNewNodeSet(pctxt, NULL);
11986 if (*resultSeq == NULL)
11987 return(-1);
11988 }
11989
11990 /*
11991 * handle the special cases of "/" amd "." being matched
11992 */
11993 if (min_depth == 0) {
11994 int res;
11995
11996 if (from_root) {
11997 /* Select "/" */
11998 if (toBool)
11999 return(1);
12000 res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
12001 (xmlNodePtr) ctxt->doc);
12002 } else {
12003 /* Select "self::node()" */
12004 if (toBool)
12005 return(1);
12006 res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
12007 ctxt->node);
12008 }
12009
12010 if (res < 0)
12011 xmlXPathPErrMemory(pctxt);
12012 }
12013 if (max_depth == 0) {
12014 return(0);
12015 }
12016
12017 if (from_root) {
12018 cur = (xmlNodePtr)ctxt->doc;
12019 } else if (ctxt->node != NULL) {
12020 switch (ctxt->node->type) {
12021 case XML_ELEMENT_NODE:
12022 case XML_DOCUMENT_NODE:
12023 case XML_DOCUMENT_FRAG_NODE:
12024 case XML_HTML_DOCUMENT_NODE:
12025 cur = ctxt->node;
12026 break;
12027 case XML_ATTRIBUTE_NODE:
12028 case XML_TEXT_NODE:
12029 case XML_CDATA_SECTION_NODE:
12030 case XML_ENTITY_REF_NODE:
12031 case XML_ENTITY_NODE:
12032 case XML_PI_NODE:
12033 case XML_COMMENT_NODE:
12034 case XML_NOTATION_NODE:
12035 case XML_DTD_NODE:
12036 case XML_DOCUMENT_TYPE_NODE:
12037 case XML_ELEMENT_DECL:
12038 case XML_ATTRIBUTE_DECL:
12039 case XML_ENTITY_DECL:
12040 case XML_NAMESPACE_DECL:
12041 case XML_XINCLUDE_START:
12042 case XML_XINCLUDE_END:
12043 break;
12044 }
12045 limit = cur;
12046 }
12047 if (cur == NULL) {
12048 return(0);
12049 }
12050
12051 patstream = xmlPatternGetStreamCtxt(comp);
12052 if (patstream == NULL) {
12053 xmlXPathPErrMemory(pctxt);
12054 return(-1);
12055 }
12056
12057 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
12058
12059 if (from_root) {
12060 ret = xmlStreamPush(patstream, NULL, NULL);
12061 if (ret < 0) {
12062 } else if (ret == 1) {
12063 if (toBool)
12064 goto return_1;
12065 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) < 0)
12066 xmlXPathPErrMemory(pctxt);
12067 }
12068 }
12069 depth = 0;
12070 goto scan_children;
12071 next_node:
12072 do {
12073 if (ctxt->opLimit != 0) {
12074 if (ctxt->opCount >= ctxt->opLimit) {
12075 xmlXPathErr(ctxt, XPATH_RECURSION_LIMIT_EXCEEDED);
12076 xmlFreeStreamCtxt(patstream);
12077 return(-1);
12078 }
12079 ctxt->opCount++;
12080 }
12081
12082 switch (cur->type) {
12083 case XML_ELEMENT_NODE:
12084 case XML_TEXT_NODE:
12085 case XML_CDATA_SECTION_NODE:
12086 case XML_COMMENT_NODE:
12087 case XML_PI_NODE:
12088 if (cur->type == XML_ELEMENT_NODE) {
12089 ret = xmlStreamPush(patstream, cur->name,
12090 (cur->ns ? cur->ns->href : NULL));
12091 } else if (eval_all_nodes)
12092 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
12093 else
12094 break;
12095
12096 if (ret < 0) {
12097 xmlXPathPErrMemory(pctxt);
12098 } else if (ret == 1) {
12099 if (toBool)
12100 goto return_1;
12101 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
12102 cur) < 0)
12103 xmlXPathPErrMemory(pctxt);
12104 }
12105 if ((cur->children == NULL) || (depth >= max_depth)) {
12106 ret = xmlStreamPop(patstream);
12107 while (cur->next != NULL) {
12108 cur = cur->next;
12109 if ((cur->type != XML_ENTITY_DECL) &&
12110 (cur->type != XML_DTD_NODE))
12111 goto next_node;
12112 }
12113 }
12114 default:
12115 break;
12116 }
12117
12118 scan_children:
12119 if (cur->type == XML_NAMESPACE_DECL) break;
12120 if ((cur->children != NULL) && (depth < max_depth)) {
12121 /*
12122 * Do not descend on entities declarations
12123 */
12124 if (cur->children->type != XML_ENTITY_DECL) {
12125 cur = cur->children;
12126 depth++;
12127 /*
12128 * Skip DTDs
12129 */
12130 if (cur->type != XML_DTD_NODE)
12131 continue;
12132 }
12133 }
12134
12135 if (cur == limit)
12136 break;
12137
12138 while (cur->next != NULL) {
12139 cur = cur->next;
12140 if ((cur->type != XML_ENTITY_DECL) &&
12141 (cur->type != XML_DTD_NODE))
12142 goto next_node;
12143 }
12144
12145 do {
12146 cur = cur->parent;
12147 depth--;
12148 if ((cur == NULL) || (cur == limit) ||
12149 (cur->type == XML_DOCUMENT_NODE))
12150 goto done;
12151 if (cur->type == XML_ELEMENT_NODE) {
12152 ret = xmlStreamPop(patstream);
12153 } else if ((eval_all_nodes) &&
12154 ((cur->type == XML_TEXT_NODE) ||
12155 (cur->type == XML_CDATA_SECTION_NODE) ||
12156 (cur->type == XML_COMMENT_NODE) ||
12157 (cur->type == XML_PI_NODE)))
12158 {
12159 ret = xmlStreamPop(patstream);
12160 }
12161 if (cur->next != NULL) {
12162 cur = cur->next;
12163 break;
12164 }
12165 } while (cur != NULL);
12166
12167 } while ((cur != NULL) && (depth >= 0));
12168
12169 done:
12170
12171 if (patstream)
12172 xmlFreeStreamCtxt(patstream);
12173 return(0);
12174
12175 return_1:
12176 if (patstream)
12177 xmlFreeStreamCtxt(patstream);
12178 return(1);
12179 }
12180 #endif /* XPATH_STREAMING */
12181
12182 /**
12183 * xmlXPathRunEval:
12184 * @ctxt: the XPath parser context with the compiled expression
12185 * @toBool: evaluate to a boolean result
12186 *
12187 * Evaluate the Precompiled XPath expression in the given context.
12188 */
12189 static int
xmlXPathRunEval(xmlXPathParserContextPtr ctxt,int toBool)12190 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
12191 {
12192 xmlXPathCompExprPtr comp;
12193 int oldDepth;
12194
12195 if ((ctxt == NULL) || (ctxt->comp == NULL))
12196 return(-1);
12197
12198 if (ctxt->valueTab == NULL) {
12199 /* Allocate the value stack */
12200 ctxt->valueTab = (xmlXPathObjectPtr *)
12201 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
12202 if (ctxt->valueTab == NULL) {
12203 xmlXPathPErrMemory(ctxt);
12204 return(-1);
12205 }
12206 ctxt->valueNr = 0;
12207 ctxt->valueMax = 10;
12208 ctxt->value = NULL;
12209 }
12210 #ifdef XPATH_STREAMING
12211 if (ctxt->comp->stream) {
12212 int res;
12213
12214 if (toBool) {
12215 /*
12216 * Evaluation to boolean result.
12217 */
12218 res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, NULL, 1);
12219 if (res != -1)
12220 return(res);
12221 } else {
12222 xmlXPathObjectPtr resObj = NULL;
12223
12224 /*
12225 * Evaluation to a sequence.
12226 */
12227 res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, &resObj, 0);
12228
12229 if ((res != -1) && (resObj != NULL)) {
12230 valuePush(ctxt, resObj);
12231 return(0);
12232 }
12233 if (resObj != NULL)
12234 xmlXPathReleaseObject(ctxt->context, resObj);
12235 }
12236 /*
12237 * QUESTION TODO: This falls back to normal XPath evaluation
12238 * if res == -1. Is this intended?
12239 */
12240 }
12241 #endif
12242 comp = ctxt->comp;
12243 if (comp->last < 0) {
12244 xmlXPathErr(ctxt, XPATH_STACK_ERROR);
12245 return(-1);
12246 }
12247 oldDepth = ctxt->context->depth;
12248 if (toBool)
12249 return(xmlXPathCompOpEvalToBoolean(ctxt,
12250 &comp->steps[comp->last], 0));
12251 else
12252 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
12253 ctxt->context->depth = oldDepth;
12254
12255 return(0);
12256 }
12257
12258 /************************************************************************
12259 * *
12260 * Public interfaces *
12261 * *
12262 ************************************************************************/
12263
12264 /**
12265 * xmlXPathEvalPredicate:
12266 * @ctxt: the XPath context
12267 * @res: the Predicate Expression evaluation result
12268 *
12269 * Evaluate a predicate result for the current node.
12270 * A PredicateExpr is evaluated by evaluating the Expr and converting
12271 * the result to a boolean. If the result is a number, the result will
12272 * be converted to true if the number is equal to the position of the
12273 * context node in the context node list (as returned by the position
12274 * function) and will be converted to false otherwise; if the result
12275 * is not a number, then the result will be converted as if by a call
12276 * to the boolean function.
12277 *
12278 * Returns 1 if predicate is true, 0 otherwise
12279 */
12280 int
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt,xmlXPathObjectPtr res)12281 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
12282 if ((ctxt == NULL) || (res == NULL)) return(0);
12283 switch (res->type) {
12284 case XPATH_BOOLEAN:
12285 return(res->boolval);
12286 case XPATH_NUMBER:
12287 return(res->floatval == ctxt->proximityPosition);
12288 case XPATH_NODESET:
12289 case XPATH_XSLT_TREE:
12290 if (res->nodesetval == NULL)
12291 return(0);
12292 return(res->nodesetval->nodeNr != 0);
12293 case XPATH_STRING:
12294 return((res->stringval != NULL) &&
12295 (xmlStrlen(res->stringval) != 0));
12296 default:
12297 break;
12298 }
12299 return(0);
12300 }
12301
12302 /**
12303 * xmlXPathEvaluatePredicateResult:
12304 * @ctxt: the XPath Parser context
12305 * @res: the Predicate Expression evaluation result
12306 *
12307 * Evaluate a predicate result for the current node.
12308 * A PredicateExpr is evaluated by evaluating the Expr and converting
12309 * the result to a boolean. If the result is a number, the result will
12310 * be converted to true if the number is equal to the position of the
12311 * context node in the context node list (as returned by the position
12312 * function) and will be converted to false otherwise; if the result
12313 * is not a number, then the result will be converted as if by a call
12314 * to the boolean function.
12315 *
12316 * Returns 1 if predicate is true, 0 otherwise
12317 */
12318 int
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr res)12319 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
12320 xmlXPathObjectPtr res) {
12321 if ((ctxt == NULL) || (res == NULL)) return(0);
12322 switch (res->type) {
12323 case XPATH_BOOLEAN:
12324 return(res->boolval);
12325 case XPATH_NUMBER:
12326 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
12327 return((res->floatval == ctxt->context->proximityPosition) &&
12328 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
12329 #else
12330 return(res->floatval == ctxt->context->proximityPosition);
12331 #endif
12332 case XPATH_NODESET:
12333 case XPATH_XSLT_TREE:
12334 if (res->nodesetval == NULL)
12335 return(0);
12336 return(res->nodesetval->nodeNr != 0);
12337 case XPATH_STRING:
12338 return((res->stringval != NULL) && (res->stringval[0] != 0));
12339 default:
12340 break;
12341 }
12342 return(0);
12343 }
12344
12345 #ifdef XPATH_STREAMING
12346 /**
12347 * xmlXPathTryStreamCompile:
12348 * @ctxt: an XPath context
12349 * @str: the XPath expression
12350 *
12351 * Try to compile the XPath expression as a streamable subset.
12352 *
12353 * Returns the compiled expression or NULL if failed to compile.
12354 */
12355 static xmlXPathCompExprPtr
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt,const xmlChar * str)12356 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
12357 /*
12358 * Optimization: use streaming patterns when the XPath expression can
12359 * be compiled to a stream lookup
12360 */
12361 xmlPatternPtr stream;
12362 xmlXPathCompExprPtr comp;
12363 xmlDictPtr dict = NULL;
12364 const xmlChar **namespaces = NULL;
12365 xmlNsPtr ns;
12366 int i, j;
12367
12368 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
12369 (!xmlStrchr(str, '@'))) {
12370 const xmlChar *tmp;
12371 int res;
12372
12373 /*
12374 * We don't try to handle expressions using the verbose axis
12375 * specifiers ("::"), just the simplified form at this point.
12376 * Additionally, if there is no list of namespaces available and
12377 * there's a ":" in the expression, indicating a prefixed QName,
12378 * then we won't try to compile either. xmlPatterncompile() needs
12379 * to have a list of namespaces at compilation time in order to
12380 * compile prefixed name tests.
12381 */
12382 tmp = xmlStrchr(str, ':');
12383 if ((tmp != NULL) &&
12384 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
12385 return(NULL);
12386
12387 if (ctxt != NULL) {
12388 dict = ctxt->dict;
12389 if (ctxt->nsNr > 0) {
12390 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
12391 if (namespaces == NULL) {
12392 xmlXPathErrMemory(ctxt);
12393 return(NULL);
12394 }
12395 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
12396 ns = ctxt->namespaces[j];
12397 namespaces[i++] = ns->href;
12398 namespaces[i++] = ns->prefix;
12399 }
12400 namespaces[i++] = NULL;
12401 namespaces[i] = NULL;
12402 }
12403 }
12404
12405 res = xmlPatternCompileSafe(str, dict, XML_PATTERN_XPATH, namespaces,
12406 &stream);
12407 if (namespaces != NULL) {
12408 xmlFree((xmlChar **)namespaces);
12409 }
12410 if (res < 0) {
12411 xmlXPathErrMemory(ctxt);
12412 return(NULL);
12413 }
12414 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
12415 comp = xmlXPathNewCompExpr();
12416 if (comp == NULL) {
12417 xmlXPathErrMemory(ctxt);
12418 xmlFreePattern(stream);
12419 return(NULL);
12420 }
12421 comp->stream = stream;
12422 comp->dict = dict;
12423 if (comp->dict)
12424 xmlDictReference(comp->dict);
12425 return(comp);
12426 }
12427 xmlFreePattern(stream);
12428 }
12429 return(NULL);
12430 }
12431 #endif /* XPATH_STREAMING */
12432
12433 static void
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,xmlXPathStepOpPtr op)12434 xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
12435 xmlXPathStepOpPtr op)
12436 {
12437 xmlXPathCompExprPtr comp = pctxt->comp;
12438 xmlXPathContextPtr ctxt;
12439
12440 /*
12441 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
12442 * internal representation.
12443 */
12444
12445 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
12446 (op->ch1 != -1) &&
12447 (op->ch2 == -1 /* no predicate */))
12448 {
12449 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
12450
12451 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
12452 ((xmlXPathAxisVal) prevop->value ==
12453 AXIS_DESCENDANT_OR_SELF) &&
12454 (prevop->ch2 == -1) &&
12455 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
12456 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
12457 {
12458 /*
12459 * This is a "descendant-or-self::node()" without predicates.
12460 * Try to eliminate it.
12461 */
12462
12463 switch ((xmlXPathAxisVal) op->value) {
12464 case AXIS_CHILD:
12465 case AXIS_DESCENDANT:
12466 /*
12467 * Convert "descendant-or-self::node()/child::" or
12468 * "descendant-or-self::node()/descendant::" to
12469 * "descendant::"
12470 */
12471 op->ch1 = prevop->ch1;
12472 op->value = AXIS_DESCENDANT;
12473 break;
12474 case AXIS_SELF:
12475 case AXIS_DESCENDANT_OR_SELF:
12476 /*
12477 * Convert "descendant-or-self::node()/self::" or
12478 * "descendant-or-self::node()/descendant-or-self::" to
12479 * to "descendant-or-self::"
12480 */
12481 op->ch1 = prevop->ch1;
12482 op->value = AXIS_DESCENDANT_OR_SELF;
12483 break;
12484 default:
12485 break;
12486 }
12487 }
12488 }
12489
12490 /* OP_VALUE has invalid ch1. */
12491 if (op->op == XPATH_OP_VALUE)
12492 return;
12493
12494 /* Recurse */
12495 ctxt = pctxt->context;
12496 if (ctxt != NULL) {
12497 if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
12498 return;
12499 ctxt->depth += 1;
12500 }
12501 if (op->ch1 != -1)
12502 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
12503 if (op->ch2 != -1)
12504 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
12505 if (ctxt != NULL)
12506 ctxt->depth -= 1;
12507 }
12508
12509 /**
12510 * xmlXPathCtxtCompile:
12511 * @ctxt: an XPath context
12512 * @str: the XPath expression
12513 *
12514 * Compile an XPath expression
12515 *
12516 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
12517 * the caller has to free the object.
12518 */
12519 xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt,const xmlChar * str)12520 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
12521 xmlXPathParserContextPtr pctxt;
12522 xmlXPathCompExprPtr comp;
12523 int oldDepth = 0;
12524
12525 #ifdef XPATH_STREAMING
12526 comp = xmlXPathTryStreamCompile(ctxt, str);
12527 if (comp != NULL)
12528 return(comp);
12529 #endif
12530
12531 xmlInitParser();
12532
12533 pctxt = xmlXPathNewParserContext(str, ctxt);
12534 if (pctxt == NULL)
12535 return NULL;
12536 if (ctxt != NULL)
12537 oldDepth = ctxt->depth;
12538 xmlXPathCompileExpr(pctxt, 1);
12539 if (ctxt != NULL)
12540 ctxt->depth = oldDepth;
12541
12542 if( pctxt->error != XPATH_EXPRESSION_OK )
12543 {
12544 xmlXPathFreeParserContext(pctxt);
12545 return(NULL);
12546 }
12547
12548 if (*pctxt->cur != 0) {
12549 /*
12550 * aleksey: in some cases this line prints *second* error message
12551 * (see bug #78858) and probably this should be fixed.
12552 * However, we are not sure that all error messages are printed
12553 * out in other places. It's not critical so we leave it as-is for now
12554 */
12555 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
12556 comp = NULL;
12557 } else {
12558 comp = pctxt->comp;
12559 if ((comp->nbStep > 1) && (comp->last >= 0)) {
12560 if (ctxt != NULL)
12561 oldDepth = ctxt->depth;
12562 xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
12563 if (ctxt != NULL)
12564 ctxt->depth = oldDepth;
12565 }
12566 pctxt->comp = NULL;
12567 }
12568 xmlXPathFreeParserContext(pctxt);
12569
12570 if (comp != NULL) {
12571 comp->expr = xmlStrdup(str);
12572 }
12573 return(comp);
12574 }
12575
12576 /**
12577 * xmlXPathCompile:
12578 * @str: the XPath expression
12579 *
12580 * Compile an XPath expression
12581 *
12582 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
12583 * the caller has to free the object.
12584 */
12585 xmlXPathCompExprPtr
xmlXPathCompile(const xmlChar * str)12586 xmlXPathCompile(const xmlChar *str) {
12587 return(xmlXPathCtxtCompile(NULL, str));
12588 }
12589
12590 /**
12591 * xmlXPathCompiledEvalInternal:
12592 * @comp: the compiled XPath expression
12593 * @ctxt: the XPath context
12594 * @resObj: the resulting XPath object or NULL
12595 * @toBool: 1 if only a boolean result is requested
12596 *
12597 * Evaluate the Precompiled XPath expression in the given context.
12598 * The caller has to free @resObj.
12599 *
12600 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12601 * the caller has to free the object.
12602 */
12603 static int
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt,xmlXPathObjectPtr * resObjPtr,int toBool)12604 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
12605 xmlXPathContextPtr ctxt,
12606 xmlXPathObjectPtr *resObjPtr,
12607 int toBool)
12608 {
12609 xmlXPathParserContextPtr pctxt;
12610 xmlXPathObjectPtr resObj = NULL;
12611 #ifndef LIBXML_THREAD_ENABLED
12612 static int reentance = 0;
12613 #endif
12614 int res;
12615
12616 if (comp == NULL)
12617 return(-1);
12618 xmlInitParser();
12619
12620 xmlResetError(&ctxt->lastError);
12621
12622 #ifndef LIBXML_THREAD_ENABLED
12623 reentance++;
12624 if (reentance > 1)
12625 xmlXPathDisableOptimizer = 1;
12626 #endif
12627
12628 pctxt = xmlXPathCompParserContext(comp, ctxt);
12629 if (pctxt == NULL)
12630 return(-1);
12631 res = xmlXPathRunEval(pctxt, toBool);
12632
12633 if (pctxt->error == XPATH_EXPRESSION_OK) {
12634 if (pctxt->valueNr != ((toBool) ? 0 : 1))
12635 xmlXPathErr(pctxt, XPATH_STACK_ERROR);
12636 else if (!toBool)
12637 resObj = valuePop(pctxt);
12638 }
12639
12640 if (resObjPtr)
12641 *resObjPtr = resObj;
12642 else
12643 xmlXPathReleaseObject(ctxt, resObj);
12644
12645 pctxt->comp = NULL;
12646 xmlXPathFreeParserContext(pctxt);
12647 #ifndef LIBXML_THREAD_ENABLED
12648 reentance--;
12649 #endif
12650
12651 return(res);
12652 }
12653
12654 /**
12655 * xmlXPathCompiledEval:
12656 * @comp: the compiled XPath expression
12657 * @ctx: the XPath context
12658 *
12659 * Evaluate the Precompiled XPath expression in the given context.
12660 *
12661 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12662 * the caller has to free the object.
12663 */
12664 xmlXPathObjectPtr
xmlXPathCompiledEval(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctx)12665 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
12666 {
12667 xmlXPathObjectPtr res = NULL;
12668
12669 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
12670 return(res);
12671 }
12672
12673 /**
12674 * xmlXPathCompiledEvalToBoolean:
12675 * @comp: the compiled XPath expression
12676 * @ctxt: the XPath context
12677 *
12678 * Applies the XPath boolean() function on the result of the given
12679 * compiled expression.
12680 *
12681 * Returns 1 if the expression evaluated to true, 0 if to false and
12682 * -1 in API and internal errors.
12683 */
12684 int
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)12685 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
12686 xmlXPathContextPtr ctxt)
12687 {
12688 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
12689 }
12690
12691 /**
12692 * xmlXPathEvalExpr:
12693 * @ctxt: the XPath Parser context
12694 *
12695 * Parse and evaluate an XPath expression in the given context,
12696 * then push the result on the context stack
12697 */
12698 void
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt)12699 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
12700 #ifdef XPATH_STREAMING
12701 xmlXPathCompExprPtr comp;
12702 #endif
12703 int oldDepth = 0;
12704
12705 if (ctxt == NULL)
12706 return;
12707 if (ctxt->context->lastError.code != 0)
12708 return;
12709
12710 #ifdef XPATH_STREAMING
12711 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
12712 if ((comp == NULL) &&
12713 (ctxt->context->lastError.code == XML_ERR_NO_MEMORY)) {
12714 xmlXPathPErrMemory(ctxt);
12715 return;
12716 }
12717 if (comp != NULL) {
12718 if (ctxt->comp != NULL)
12719 xmlXPathFreeCompExpr(ctxt->comp);
12720 ctxt->comp = comp;
12721 } else
12722 #endif
12723 {
12724 if (ctxt->context != NULL)
12725 oldDepth = ctxt->context->depth;
12726 xmlXPathCompileExpr(ctxt, 1);
12727 if (ctxt->context != NULL)
12728 ctxt->context->depth = oldDepth;
12729 CHECK_ERROR;
12730
12731 /* Check for trailing characters. */
12732 if (*ctxt->cur != 0)
12733 XP_ERROR(XPATH_EXPR_ERROR);
12734
12735 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
12736 if (ctxt->context != NULL)
12737 oldDepth = ctxt->context->depth;
12738 xmlXPathOptimizeExpression(ctxt,
12739 &ctxt->comp->steps[ctxt->comp->last]);
12740 if (ctxt->context != NULL)
12741 ctxt->context->depth = oldDepth;
12742 }
12743 }
12744
12745 xmlXPathRunEval(ctxt, 0);
12746 }
12747
12748 /**
12749 * xmlXPathEval:
12750 * @str: the XPath expression
12751 * @ctx: the XPath context
12752 *
12753 * Evaluate the XPath Location Path in the given context.
12754 *
12755 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12756 * the caller has to free the object.
12757 */
12758 xmlXPathObjectPtr
xmlXPathEval(const xmlChar * str,xmlXPathContextPtr ctx)12759 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
12760 xmlXPathParserContextPtr ctxt;
12761 xmlXPathObjectPtr res;
12762
12763 if (ctx == NULL)
12764 return(NULL);
12765
12766 xmlInitParser();
12767
12768 xmlResetError(&ctx->lastError);
12769
12770 ctxt = xmlXPathNewParserContext(str, ctx);
12771 if (ctxt == NULL)
12772 return NULL;
12773 xmlXPathEvalExpr(ctxt);
12774
12775 if (ctxt->error != XPATH_EXPRESSION_OK) {
12776 res = NULL;
12777 } else if (ctxt->valueNr != 1) {
12778 xmlXPathErr(ctxt, XPATH_STACK_ERROR);
12779 res = NULL;
12780 } else {
12781 res = valuePop(ctxt);
12782 }
12783
12784 xmlXPathFreeParserContext(ctxt);
12785 return(res);
12786 }
12787
12788 /**
12789 * xmlXPathSetContextNode:
12790 * @node: the node to to use as the context node
12791 * @ctx: the XPath context
12792 *
12793 * Sets 'node' as the context node. The node must be in the same
12794 * document as that associated with the context.
12795 *
12796 * Returns -1 in case of error or 0 if successful
12797 */
12798 int
xmlXPathSetContextNode(xmlNodePtr node,xmlXPathContextPtr ctx)12799 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
12800 if ((node == NULL) || (ctx == NULL))
12801 return(-1);
12802
12803 if (node->doc == ctx->doc) {
12804 ctx->node = node;
12805 return(0);
12806 }
12807 return(-1);
12808 }
12809
12810 /**
12811 * xmlXPathNodeEval:
12812 * @node: the node to to use as the context node
12813 * @str: the XPath expression
12814 * @ctx: the XPath context
12815 *
12816 * Evaluate the XPath Location Path in the given context. The node 'node'
12817 * is set as the context node. The context node is not restored.
12818 *
12819 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12820 * the caller has to free the object.
12821 */
12822 xmlXPathObjectPtr
xmlXPathNodeEval(xmlNodePtr node,const xmlChar * str,xmlXPathContextPtr ctx)12823 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
12824 if (str == NULL)
12825 return(NULL);
12826 if (xmlXPathSetContextNode(node, ctx) < 0)
12827 return(NULL);
12828 return(xmlXPathEval(str, ctx));
12829 }
12830
12831 /**
12832 * xmlXPathEvalExpression:
12833 * @str: the XPath expression
12834 * @ctxt: the XPath context
12835 *
12836 * Alias for xmlXPathEval().
12837 *
12838 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12839 * the caller has to free the object.
12840 */
12841 xmlXPathObjectPtr
xmlXPathEvalExpression(const xmlChar * str,xmlXPathContextPtr ctxt)12842 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
12843 return(xmlXPathEval(str, ctxt));
12844 }
12845
12846 /************************************************************************
12847 * *
12848 * Extra functions not pertaining to the XPath spec *
12849 * *
12850 ************************************************************************/
12851 /**
12852 * xmlXPathEscapeUriFunction:
12853 * @ctxt: the XPath Parser context
12854 * @nargs: the number of arguments
12855 *
12856 * Implement the escape-uri() XPath function
12857 * string escape-uri(string $str, bool $escape-reserved)
12858 *
12859 * This function applies the URI escaping rules defined in section 2 of [RFC
12860 * 2396] to the string supplied as $uri-part, which typically represents all
12861 * or part of a URI. The effect of the function is to replace any special
12862 * character in the string by an escape sequence of the form %xx%yy...,
12863 * where xxyy... is the hexadecimal representation of the octets used to
12864 * represent the character in UTF-8.
12865 *
12866 * The set of characters that are escaped depends on the setting of the
12867 * boolean argument $escape-reserved.
12868 *
12869 * If $escape-reserved is true, all characters are escaped other than lower
12870 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
12871 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
12872 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
12873 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
12874 * A-F).
12875 *
12876 * If $escape-reserved is false, the behavior differs in that characters
12877 * referred to in [RFC 2396] as reserved characters are not escaped. These
12878 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
12879 *
12880 * [RFC 2396] does not define whether escaped URIs should use lower case or
12881 * upper case for hexadecimal digits. To ensure that escaped URIs can be
12882 * compared using string comparison functions, this function must always use
12883 * the upper-case letters A-F.
12884 *
12885 * Generally, $escape-reserved should be set to true when escaping a string
12886 * that is to form a single part of a URI, and to false when escaping an
12887 * entire URI or URI reference.
12888 *
12889 * In the case of non-ascii characters, the string is encoded according to
12890 * utf-8 and then converted according to RFC 2396.
12891 *
12892 * Examples
12893 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
12894 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
12895 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
12896 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
12897 *
12898 */
12899 static void
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt,int nargs)12900 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
12901 xmlXPathObjectPtr str;
12902 int escape_reserved;
12903 xmlBufPtr target;
12904 xmlChar *cptr;
12905 xmlChar escape[4];
12906
12907 CHECK_ARITY(2);
12908
12909 escape_reserved = xmlXPathPopBoolean(ctxt);
12910
12911 CAST_TO_STRING;
12912 str = valuePop(ctxt);
12913
12914 target = xmlBufCreateSize(64);
12915
12916 escape[0] = '%';
12917 escape[3] = 0;
12918
12919 if (target) {
12920 for (cptr = str->stringval; *cptr; cptr++) {
12921 if ((*cptr >= 'A' && *cptr <= 'Z') ||
12922 (*cptr >= 'a' && *cptr <= 'z') ||
12923 (*cptr >= '0' && *cptr <= '9') ||
12924 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
12925 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
12926 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
12927 (*cptr == '%' &&
12928 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
12929 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
12930 (cptr[1] >= '0' && cptr[1] <= '9')) &&
12931 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
12932 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
12933 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
12934 (!escape_reserved &&
12935 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
12936 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
12937 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
12938 *cptr == ','))) {
12939 xmlBufAdd(target, cptr, 1);
12940 } else {
12941 if ((*cptr >> 4) < 10)
12942 escape[1] = '0' + (*cptr >> 4);
12943 else
12944 escape[1] = 'A' - 10 + (*cptr >> 4);
12945 if ((*cptr & 0xF) < 10)
12946 escape[2] = '0' + (*cptr & 0xF);
12947 else
12948 escape[2] = 'A' - 10 + (*cptr & 0xF);
12949
12950 xmlBufAdd(target, &escape[0], 3);
12951 }
12952 }
12953 }
12954 valuePush(ctxt, xmlXPathCacheNewString(ctxt, xmlBufContent(target)));
12955 xmlBufFree(target);
12956 xmlXPathReleaseObject(ctxt->context, str);
12957 }
12958
12959 /**
12960 * xmlXPathRegisterAllFunctions:
12961 * @ctxt: the XPath context
12962 *
12963 * Registers all default XPath functions in this context
12964 */
12965 void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)12966 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
12967 {
12968 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
12969 xmlXPathBooleanFunction);
12970 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
12971 xmlXPathCeilingFunction);
12972 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
12973 xmlXPathCountFunction);
12974 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
12975 xmlXPathConcatFunction);
12976 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
12977 xmlXPathContainsFunction);
12978 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
12979 xmlXPathIdFunction);
12980 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
12981 xmlXPathFalseFunction);
12982 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
12983 xmlXPathFloorFunction);
12984 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
12985 xmlXPathLastFunction);
12986 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
12987 xmlXPathLangFunction);
12988 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
12989 xmlXPathLocalNameFunction);
12990 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
12991 xmlXPathNotFunction);
12992 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
12993 xmlXPathNameFunction);
12994 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
12995 xmlXPathNamespaceURIFunction);
12996 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
12997 xmlXPathNormalizeFunction);
12998 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
12999 xmlXPathNumberFunction);
13000 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
13001 xmlXPathPositionFunction);
13002 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
13003 xmlXPathRoundFunction);
13004 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
13005 xmlXPathStringFunction);
13006 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
13007 xmlXPathStringLengthFunction);
13008 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
13009 xmlXPathStartsWithFunction);
13010 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
13011 xmlXPathSubstringFunction);
13012 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
13013 xmlXPathSubstringBeforeFunction);
13014 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
13015 xmlXPathSubstringAfterFunction);
13016 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
13017 xmlXPathSumFunction);
13018 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
13019 xmlXPathTrueFunction);
13020 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
13021 xmlXPathTranslateFunction);
13022
13023 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
13024 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
13025 xmlXPathEscapeUriFunction);
13026 }
13027
13028 #endif /* LIBXML_XPATH_ENABLED */
13029